Why not bit() macros?

I don't see much use of the bit() macros. Is it considered bad practice? I have included 2 versions of a basic debounce routine that both do the exact same thing, version "A" uses the "standard" Arduino digital commands and has a flash size of 1082 bytes and runs in 16 micros, version "B" uses the bit() macros, uses 604 bytes and runs in 8 micros. The sketches are only 18 lines of code, imagine the difference in flash consumption if they were 200 lines.

Am I failing to see something obvious?

Also while this debouncing task is very simple, it still takes over 600 bytes, can the size of sketch "B" be reduced any more without resorting to assembler?

  // sketch "debounce_A" on Arduino Nano

#define buttonPin 4  // pushbutton pin number
#define led 5        // LED pin number

const byte debounceDelay = 250; // debounce time, long for debug, typical 15 - 30
unsigned long startTime;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);  // PULLUP pin 4
  pinMode(led, OUTPUT);              // Pin 5 is OUTPUT
}
void loop() {
  static bool buttonState, flip;  // if unwanted blink on reset initilize buttonState to true
  bool timing;
  
  if(flip != digitalRead(buttonPin)){  //if buttonPin has changed
    startTime = millis();  // reset timer
    flip = !flip;          // flip = buttonPin
    timing = true;
  }
    // skipped if not timing
  if(timing == true && (millis() - startTime) > debounceDelay){
    timing = false;
    buttonState = flip;
  }    
  digitalWrite(led, !buttonState);  //switch output pin
}

Sketch uses 1,082 bytes (3%) of program storage space. Maximum is 30,720 bytes. Global variables use 15 bytes (0%) of dynamic memory, leaving 2,033 bytes for local variables. Maximum is 2,048 bytes

  // sketch "debounce_B" on Arduino Nano

#define buttonPin 4  // pushbutton pin number
#define led 5        // LED pin number

const byte debounceDelay = 250; // debounce time, long for debug, typical 15 - 30
unsigned long startTime;

void setup() {
  bitSet(PORTD,4);    // PULLUP pin 4
  bitSet(DDRD,5);     // Pin 5 is OUTPUT
}
void loop() {
  static bool buttonState, flip;  // if unwanted blink on reset initilize buttonState to 1
  bool timing;
  
  if(flip != bitRead(PIND,(buttonPin))){
    startTime = millis();  // reset timer
    flip = !flip;          // flip = buttonPin
    timing = 1;
  }
    // skipped if not timing
  if(timing && (millis() - startTime) > debounceDelay){
    timing = 0;
    buttonState = flip;
  }    
  bitWrite(PORTD,led,!buttonState);  //switch output pin
}

Sketch uses 604 bytes (1%) of program storage space. Maximum is 30,720 bytes. Global variables use 15 bytes (0%) of dynamic memory, leaving 2,033 bytes for local variables. Maximum is 2,048 bytes

Yup, doing direct port manipulation makes for smaller faster code. No surprise there.

But it is a bit complex for the raw newbie.

I think it would also be informative for you to look at the source code for digitalRead and digitalWrite. They do a few other things besides.

Yes, I see what you mean. Kind of "pre error handling". TNX for reply.

The bitXXXX() macros are fine. But using PORTB and other AVR register names is frowned upon because it makes the code not portable to other boards (ie Arduino MEGA, Leonardo, Gemma) even in the same chip family. While code written with digitalRead()/etc is slower, it will run unchanged on Due, TI Launchpads, PIC32 ChipKit boards, Maple Minis, and so on.) (this is in addition to the "extra" work that the functions do, which has already been mentioned.)

See also Analysis of an empty arduino sketch

Noted: TNX @westfw: Read your link, very informative, never thought of killing unused peripherals, will try that one day. Again, many TNX

Declaring a variable to be type "bool", and then assigning 1 and 0 to it, isn't really good.

michinyon: Declaring a variable to be type "bool", and then assigning 1 and 0 to it, isn't really good.

There is nothing wrong with it. The standard clearly defines this conversion. It is seen everywhere:

int foo; if( foo ){ }else{ }

Well, when I'm writing code I'm talking to a compiler, not a computer science professor. Does the code work as intended? If yes, I'm satisfied, I'm not going to publish it and if it fails I'm not going to call a professional programmer to fix it.

klubfingers: Does the code work as intended?

Maybe. Maybe not. You failed to initialize timing...

void loop() {
  static bool buttonState, flip;  // if unwanted blink on reset,
  bool timing;                    // initilize buttonState to 1

  timing = false;
...

Or, it was meant to be static.

And startTime is not the correct type...

unsigned long startTime;

klubfingers:
Well, when I’m writing code I’m talking to a compiler, not a computer science professor. Does the code work as intended? If yes, I’m satisfied, I’m not going to publish it and if it fails I’m not going to call a professional programmer to fix it.

I used to think like that, until I started to reuse and maintain my own code. After a few months or years, your own code might as well be written by someone else. Now I try to write it so anybody can read it. Sometimes I wing through with rough stuff just to solve a problem, but I generally go back and edit, document and clean up once things are working. Having code that I might be able to get advice on is just a bonus.

Doing things “right” is also a good sanity check on your own thinking at the time of coding, and reduces unexpected results. Say what you do, do what you say.

It’s not great to use the scope of what C++ permits as a guideline for design. This language puts a lot of responsibility in the hands of the programmer. The power of this flexibility is desirable but should be managed carefully.

pYro_65:
There is nothing wrong with it. The standard clearly defines this conversion.
It is seen everywhere:

int foo;

if( foo ){

}else{

}

Yes, but you aren’t assigning 1 to a bool there.

michinyon:
Declaring a variable to be type “bool”, and then assigning 1 and 0 to it, isn’t really good.

michinyon is right. A variable of type bool should have true or false assigned to it. That’s all he was saying.

In any case, I think the standard says that 0 is false and not-zero is true. So, not-zero is not quite the same thing as 1, is it? For example, 2 is not-zero.

  bitSet(DDRD,5);     // Pin 5 is OUTPUT

Recently someone had a post where they thought this was setting the pin to input.

Plus, do you mean pin 5 on the chip? Or pin 11 on the Uno? Things get a bit muddy when you use direct port manipulation where it isn't really needed.

michinyon: Declaring a variable to be type "bool", and then assigning 1 and 0 to it, isn't really good.

What else would you assign to a 1 bit variable? Elaborate?

A bool is an 8 bit variable.

pYro_65:
There is nothing wrong with it. The standard clearly defines this conversion.
It is seen everywhere:

int foo;
if( foo ){
}else{
}


You missed the point there, bigtime.

klubfingers: What else would you assign to a 1 bit variable? Elaborate?

A bool is supposed to be a type specifically for logical values. True or false. If you want an integer type, use an integer type, why would you use bool ?

C/C++ is probably the only language that allows this.

It is poor programming style. Confusing. It is about as stupid as using floats to count sheep.

@Coding Badly: I know you don't think so, but I do know that millis() returns a 4 byte unsigned long integer, "long startTime" was a typo, one of those things that happen to people in the lower 99.9 intellect percentile but never to you.

@Delta_G: I am aware of that.

To avoid being barked at for not including code, I typed up and tested the examples in about an hour just to show you what I was talking about.

Under the C++ standard:

3.9.1.6

Values of type bool are either true or false.

The number 1 is not literally true or false (it is 1).

There is a note (47):

Using a bool value in ways described by this International Standard as “undefined,” such as by examining the value of an uninitialized automatic object, might cause it to behave as if it is neither true nor false.

So with a bool, you are entitled to consider it contains true or false. So if you are going to put 1 into a bool and call it true, you may as well put 2 into it, eg.

bool foo = 2;

However now foo is now neither true nor false (possibly). It is undefined.

I think the point here is that you should put into a type what it is supposed to have in it. Saying:

bool foo = 1;

And then saying "ah yes, but I know that is the same as "true" is like saying:

digitalWrite (13, 0);
digitalWrite (13, 1);

And arguing that you "know" that 0 and 1 are the same as LOW and HIGH. But what if they aren't one day?

klubfingers: I know you don't think so...

You need a new crystal ball. The one you using to divine my thoughts is badly broken.

I will give you a hint about my intent... you are not the only person who has read or will read my posts.

...but I do know that millis() returns a 4 byte unsigned long integer, "long startTime" was a typo...

In which case I assume you will edit your posted code to help people new to Arduino learn to use millis correctly.

...one of those things that happen to people in the lower 99.9 intellect percentile but never to you.

Strange that you would include an ad hominem attack after acknowledging your mistake. You don't seem to understand how ad hominem attacks are supposed to work.