NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Support Forum » Flagging Data

September 17, 2010
by jbrad
jbrad's Avatar

I have set the kit up to output temperature data, Data Rate(Hz), tagged with time to the LCD and the serial/USB device. I also have an LED set to flash when data is transmitted. The Temp Sensor is on PC0, the LED is on PC4, I plan on keeping PC1 available for a pressure sensor and PC2&3 for possible additional sensors.

I'd like to add a flag(0=Log Off, 1 = Log on)to the output that would be toggled each time a button was pressed to tell my receiving script to start or stop logging the incoming data. I need to wire the switch that came with the kit into the breadboard and I assume the circuit would involve the "Common" and the "Normally Open" terminals of the switch.

Assuming I wish to read from PC5 on the MCU, Do I connect the "common terminal" to the Ground Rail and then jumper the "NO" terminal to PC5 on the MCU, leaving the "NC" terminal unconnected? If not how should I wire it?

How do I code for the MCU to read the button state?

September 17, 2010
by bretm
bretm's Avatar

Connect one end of the switch to GND and the other end to PC5. You can use either common and NO, or common and NC, in either direction. Just don't use both NO and NC.

Turn on the pin's pullup resistor by doing PORTC |= _BV(PC5);

To read the state, check if (PINC & _BV(PC5)) is zero or not. If you're using the NO side of the switch, it will be zero when the button is pressed because the pin will be connected to GND. If you're using the NC side of the switch, it will be non-zero when the button is pressed because the connection to GND will be broken and the pin will connect to VCC through the internal pull-up resistor.

Don't accidentally configure the pin as output (input is the default) otherwise you would short the pin to GND when you drive the pin to VCC which is what would happen instead of turning on the pull-up resistor.

Note that if you read the button state very frequently, the MCU will see it switching on and off rapidly for a period of time after you press or release the button, due to mechanical bounce and to voltages outside valid logic ranges.

September 17, 2010
by jbrad
jbrad's Avatar

Thanks for the quick reply, I am still in need of some guidance though...

"Turn on the pin's pullup resistor by doing PORTC |= _BV(PC5)" & "check if (PINC & _BV(PC5)) is zero or not."

I have wired the NO side of the switch and used the following code which doesn't recognise the button clicks, the compiler choked on the _BV in the above code the code below compiled but doesn't do what I want, any suggestions?

   // turn on Switch 
   PORTC |= (1<<PC5);

   while(1){
    // check state and count button clicks by incrementing counter
  if(PINC & (1<<PC5)==0){
  counter++;
  }
    }
September 17, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi jbrad,

I think there is an order of operations problem in your code snippet. In C the == actually has precedence over the bitwise AND operator. So you are first comparing (1<<PC5)==0, then ANDing the result with the PINC register. I think if you add an extra parenthesis you might get a more expected result

// turn on Switch 
PORTC |= (1<<PC5);

while(1){
  // check state and count button clicks by incrementing counter
  if((PINC & (1<<PC5))==0){
    counter++;
  }
}

We have a pretty extensive section on using buttons on the digital calipers DRO video and there are examples in the code.

Humberto

September 17, 2010
by bretm
bretm's Avatar

The _BV macro is defined in avr/io.h along with all the pin names, so if you're using Avr libraries it should compile _BV(PC5) ok. I'm not sure what the issue is there.

That code won't count the button clicks. At best it would count the number of times that the the button was observed to be down while the while loop runs. I.e. if the loop runs a million times and the button is held down for half the time, the counter will increment 500,000 times. It's only vaguely related to counting button clicks.

But it doesn't even do that because of a tricky detail of operator precendence in the C language. The "==" operator is evaluated before the "&" operator. PINC & (1<<PC5)==0 is interpreted as PINC & ((1<<PC5)==0) which is the same as PINC & (32 == 0) which is the same as PINC & 0 which is just 0, so the counter will never increment.

You have to put parentheses around the "&" expression so that it is evaluated before the "==" expression, e.g ((PINC & (1<<PC5))==0). That will allow your counter to start incrementing.

The other problem is trickier. A crude method of debouncing and counting button presses could go something like this:

uint8_t buttonHistory;

buttonHistory = 1;

while (1)
{
    delay_ms(20);
    uint8_t buttonState = (PINC >> PC5) & 1;
    buttonHistory = (buttonHistory << 1) | buttonState;

    if (buttonHistory == 0b10000000)
    {
        counter++;
    }
}

What this does is check the button every 20ms and keeps track of the last 8 button states. If the button state history looks like 1, 0, 0, 0, 0, 0, 0, 0 in binary that means the button was up 8 loops ago but has been pressed continually for the last 7 loops. That means it was just pressed and has probably finished bouncing. If the button remains pressed, the history changes to all 0's and the counter doesn't keep incrementing.

See A Guide to Debouncing for more info.

September 17, 2010
by bretm
bretm's Avatar

"..but has been pressed continually for the last 7 loops..."

You're crazy, it doesn't mean that. It only means that it was down every time that we checked, the last 7 times. It could have been released and then pressed again inside one of those 20ms gaps.

September 18, 2010
by jbrad
jbrad's Avatar

Bretm and Hevans:

Thanks for the help, I have the switch working as needed

Post a Reply

Please log in to post a reply.

Did you know that interrupts can cause problems if you're not careful about timing and memory access? Learn more...