Save program (flash) memory by bit banging the led?

I have run out of program space and the most common line of code I have is turning on and off the led. In other words:

digitalWrite(13, HIGH)

shows up a lot in my code.

Can I save machine instructions by replacing digitalWrite() with a bit banging command? If so, what is that command? I would like to know the commands for HIGH and LOW. I am using a nano. Thank you.

Do an experiment.
Compile your sketch (record memory used) then add one digitaWrite(13,HIGH); then compile again, how much more memory is used.

Edit:
See

Attach your code using the </> icon on the left side of the posting menu.
Put your sketch between the code tags ``
Or
Attach the ino file.

.

Datasheet

Section 14 -> I/O ports.

Also for interest...I have not read this yet but it came up on a search high up as "What is the code behind DigitalWrite"

PS edit:
The article the above says to go on reading is this. A very nice comparison:

Basically...if you can use port manipulation via registers...do it.

OK, I have re-read your post.

I an now assuming (due to the lack of code) that you are sending data via an LED.

For example, to send the number 27, you are physically writing a piece of code that has the list of DigitWrite commands needed to turn on and off the LED with delays appropiate...or the like, for each possible value that you may require.
Basically a massive Look Up Table?

ShiftOut may be the one your after?

You give me too much credit. I’m just blinking the LED to provide visual queues as to events that are happening in the code.

I used PORTB to flip the bit controlling the LED state and by replacing all digitalWrites I saved about 500+ bytes of space. Awesome.

If only there was a replacement for delay() that saved that much.

Use millis() and BWD techniques to get rid of delay()

//Blink without Delay skeleton example using a structure.
//LarryD

//======================================================================
struct timer
{
  //lastMillis = the time this "timer" was (re)started
  //waitMillis = delay time (mS) we are looking for. You can use math 60*60*1000 for 1 hour
  //restart    = do we start "this timer" again and again  
  //enableFlag = is "this timer" enabled/allowed to be accessed
  //**********************
  //For each timer object you need: 
  //Example:
  //   timer myTimer = //give the timer a name "myTimer"
  //   {
  //     0, 200UL, true, true  //lastMillis, waitMillis, restart, enableFlag 
  //   };
  // You have access to: 
  // myTimer.lastMillis, myTimer.waitMillis, myTimer.restart, myTimer.enableFlag, myTimer.CheckTime() 
  //**********************

  unsigned long lastMillis; 
  unsigned long waitMillis; 
  bool          restart; 
  bool          enableFlag;
  
  bool CheckTime() //Delay time expired function "CheckTime()"
  {
    //is the time up for this task?
    if (enableFlag && millis() - lastMillis >= waitMillis) 
    //Note: if delays of < 2 millis are needed use micros() and adjust waitMillis as needed
    {
      //should this start again? 
      if(restart)
      {
        //get ready for the next iteration
        lastMillis += waitMillis;  
      }
      //time was reached
      return true;
    }
    //time was not reached
    return false;
  } //END of CheckTime()

}; //END of structure timer
//======================================================================


//**********************************************************************
//Let's create 6 timer objects and initialize them in this sketch
//**********************************************************************
timer pin13 = //create timer pin13
{
  0, 200UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin12 = //create timer pin12
{
  0, 3*1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin11 = //create timer pin11
{
  0, 10*1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin10 = //create timer pin10
{
  0, 6*1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer Toggle10 = //create timer Toggle10
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer checkSwitches = //create timer checkSwitches
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************

byte lastMySwitchState = 1; //for mySwitch on Pin 2
byte counter           = 0; 

const byte Pin13 = 13;
const byte Pin12 = 12;
const byte Pin11 = 11;
const byte Pin10 = 10;
const byte Pin9  =  9;

const byte mySwitch = 2;

//**********************************************************************

void setup()
{
  Serial.begin(9600);

  pinMode(Pin13,OUTPUT);
  pinMode(Pin12,OUTPUT);
  pinMode(Pin11,OUTPUT);
  pinMode(Pin10,OUTPUT);
  pinMode(Pin9, OUTPUT);

  digitalWrite(Pin13,LOW);
  digitalWrite(Pin12,LOW);
  digitalWrite(Pin11,LOW);
  digitalWrite(Pin10,LOW);
  digitalWrite(Pin9, LOW);

  pinMode(mySwitch,INPUT_PULLUP);


} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<


void loop()
{
  //Below are examples demonstrating different timing situations 

  //***************************
  //example 1    Toggle Pin13 every 200ms
  if (pin13.CheckTime())
  {
    //Toggle Pin13
    digitalWrite(Pin13,!digitalRead(Pin13));

    //if you only want this section of code to happen once
    //uncomment the next line 
    //pin13.enableFlag = false;
  }

  //***************************
  //example 2    After 3 seconds, Pin12 goes and stays HIGH 
  if (pin12.CheckTime())
  {
    //Make Pin12 HIGH now
    digitalWrite(Pin12,HIGH);
    //disable timing section of code 
    pin12.enableFlag = false;
  }

  //***************************
  //example 3    Pin11 is HIGH for 10 seconds, then goes and stays LOW
  if (pin11.enableFlag && !pin11.CheckTime())
  {
    digitalWrite(Pin11,HIGH);
  }
  //10 seconds is now up now, leave the Pin11 LOW
  else
  {
    digitalWrite(Pin11,LOW);
    //disable timing section of code 
    pin11.enableFlag = false;
  }

  //***************************
  //example 4    For 6 seconds, toggle Pin10
  if (pin10.enableFlag && !pin10.CheckTime())
  {
    //example 5  Toggling Pin10 every 50mS
    if(Toggle10.CheckTime())
    {  
      //toggle Pin10
      digitalWrite(Pin10,!digitalRead(Pin10));    
    }
  }
  //6 seconds is now up, toggling is stopped
  else
  {
    digitalWrite(Pin10,LOW);
    //disable timing section of code 
    pin10.enableFlag = false;
  }

  //***************************
  //example 6    Is it time to check the switches?
  if (checkSwitches.CheckTime())
  {
    //time to read the switches
    Switches();      
  } 

  //**********************************
  //Put other non-blocking stuff here
  //**********************************

} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<


//======================================================================
//                      F U N C T I O N S
//======================================================================


//**********************************************************************
//switches are checked every checkSwitches.waitMillis milli seconds 
//no minimum switch press time is validated with this code (i.e. No glitch filter)
void Switches()  
{
  boolean thisState; //re-usable for all the switches      

  //*************************** mySwitch Pin 2 code  
  //check if this switch has changed state
  thisState = digitalRead(mySwitch); 
  if (thisState != lastMySwitchState)
  {  
    //update the switch state
    lastMySwitchState = thisState;  

    //This switch position has changed, let's do some stuff

    //"HIGH condition code"
    //switch goes from LOW to HIGH
    if(thisState == HIGH)        
    {
      //example: LED on Pin9 is Push ON, Push OFF
      digitalWrite(Pin9,!digitalRead(Pin9)); 
    }

    //"LOW condition code"
    //switch goes from HIGH to LOW
    else                          
    {
      //example: display the current switch push count 
      Serial.println(++counter);      
    }
  } //END of mySwitch Pin 2 code

  //******************************************  
  //similar code for other switches goes here 
  //******************************************  

} //END of Switches()


//======================================================================
//                        E N D  O F  C O D E
//======================================================================

.

Not doubting you but this code seems rather convoluted for something that is supposed to take less memory than "delay()". Does this actually save resources?

Does this actually save resources?

Depends on whether you view time as a resource

I have not done any testing.
It is something left up to you. :wink:

However, it aids in creating non blocking code which is always something to strive for.

Without seeing the sketch, it becomes nearly impossible to to make suggestions.

.

seems rather convoluted for . . .

Maybe a bit easier to understand example:

//**********************************************************************

//need similar two lines for each new timer
unsigned long Millis13 = millis();
unsigned long currentMillis = millis();
//

void setup()
{
  Serial.begin(9600);

  pinMode(13, OUTPUT);

} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<


void loop()
{
  //leave this line of code at the top of loop()
  currentMillis = millis();

  //*************************
  if(CheckTime(Millis13,1000UL,true))
  {
  //toggle LED 13
  digitalWrite(13, !digitalRead(13));
  }  
  //*************************
  
// Other non blocking code 

} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<


//======================================================================
//                      F U N C T I O N S
//======================================================================


//**********************************************************************
//Delay time expired function
//lastMillis = time we started, wait = delay in mS, restart = do we start again  
boolean CheckTime(unsigned long &lastMillis, unsigned long wait,boolean restart) 
{
  //is the time up for this task?
  if (currentMillis - lastMillis >= wait) 
  {
    //should this start again? 
    if(restart)
    {
      //get ready for the next iteration
      lastMillis = millis();  //get ready for the next iteration
    }
    return true;
  }
  return false;

} // END of CheckTime()


//**********************************************************************

//======================================================================
//                      E N D  O F  C O D E
//======================================================================

Or

//Blink without Delay Function skeleton 
//LarryD

unsigned long currentMillis;

//each new timer requires similar three lines of code
unsigned long Millis13;
boolean       repeat13    = true; //repeat this sequence?
boolean       flag13      = true; //is this timer enabled?
//

//**********************************************************************

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);


} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<


void loop()
{
  //leave this line of code at the top of loop()
  currentMillis = millis();

  //***************************
  //toggle pin 13 every 200mS
  if (flag13 == true && CheckTime(Millis13, 200UL, repeat13))
  {
    //toggle pin 13
    digitalWrite(13,!digitalRead(13));
    
    //if you only want this section of code to happen once
    //uncomment the next line 
    //flag13 = false; //disables the above code
  }
  //***************************

  
  //put other non-blocking stuff here


} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<


//======================================================================
//                      F U N C T I O N S
//======================================================================

//**********************************************************************
//Delay time expired function
//lastMillis = time we started, wait = delay in mS, restart = do we start again  
boolean CheckTime(unsigned long &lastMillis, unsigned long wait,boolean restart) 
{
  //is the time up for this task?
  if (currentMillis - lastMillis >= wait) 
  {
    //should this start again? 
    if(restart)
    {
      //get ready for the next iteration
      lastMillis = millis(); //get ready for the next iteration
    }
    return true;
  }
  return false;

} // END of CheckTime()

//**********************************************************************

//======================================================================
//                      E N D  O F  C O D E
//======================================================================

I just tested it, each digitalWrite() invocation adds 8 bytes to your compiled code.

You better post your sketch, maybe there are other things that can be simplified.