I’m having a bit of trouble with scanning the button inputs, maybe someone with better C skills can point out my error? My problem is that I can only seem to read inputs from button 1 and 6. I’m thinking that I am missing something at a higher level and that’s causing my problem.
I’ll attach my code at the bottom, but in short when I try to cycle through the pins and change to the second pin it has problems. Pretty much if I only call activatePort(PD5) once then things work fine so I’m messing it up on the next call some how. “activatePort(PD6) ;”
Oh this is how the buttons should work in case you don’t know the board.
The ports are connected with
pull down resistors and are read as “0”. To scan
the buttons user should set one of the ports in “1”
and to check the other two ports.
Oh one more thing, when I walk through the code in AVR Studio in debug mode, I notice that the PIND setting, remains at 1 for PD5 when I turn on PB6. Why is this? I am setting 5 to 0 on the PORTD
Any ideas?
void activatePort(unsigned int pinx)
{
DDRB &= ~(_BV(5) |_BV(6) | _BV(7));
PORTB = DDRB;
DDRB |= _BV(pinx);
switch(pinx)
{
case 5:
DDRB &= ~(_BV(6) | _BV(7));
break;
case 6:
DDRB &= ~(_BV(5) | _BV(7));
break;
case 7:
DDRB &= ~(_BV(5) | _BV(6));
break;
}
switch(pinx)
{
case 5:
DDRB &= ~(_BV(6) | _BV(7));
break;
case 6:
DDRB &= ~(_BV(5) | _BV(7));
break;
case 7:
DDRB &= ~(_BV(5) | _BV(6));
break;
PORTB |= _BV(pinx);
}
int main(void)
{
volatile unsigned char button;
button = 0;
DDRD = _BV(PD3);
asm volatile("nop");
while(1)
{
activatePort(PB5);
if(PINB & _BV(6) && button != 1)
{
button = 1;
relayON();
}
else if(PINB & PB7 && button != 6)
{
button = 6;
relayOFF();
}
if(!button)
{ //move to pin6
activatePort(PB6);
asm volatile("nop");
if(PINB & _BV(PB5) && button != 4)
{
button = 4;
relayON();
}
else if(PINB & _BV(PB7) && button != 2)
{
button = 2;
relayOFF();
}
}
if(!button)
{ //move to pin6
activatePort(PB7);
asm volatile("nop");
if(PINB & _BV(PB5) && button != 3)
{
button = 3;
relayON();
}
else if(PINB & _BV(PB6) && button != 5)
{
button = 5;
relayOFF();
}
}
}
[/code]
Seems like a LOT more code than needed.
If I understand…
There is a pull-down on each port B pin.
Each button connects to a Port B pin and the other side of the button connects to what?
A conventional way to wire this is to use pull-ups on each port pin. Each button connects to the Port pin and the other side of the buttons all go to ground. With this, you have like 2 lines of code. (there is a pull-up built into the AVRs - high value resistor. OK if wires are short.)
In your case or the above, you have to de-bounce the buttons. That’s another subject.
Also… the “_BV” macro in GCC became obsolete quite a while ago. Not supported in the last few releases. I prefer coding with the obvious:
_BV(3) is the same as this constant:
(1 << 3)
which works in every C compiler and is arguably easier to read.
Each button connects to a Port B pin and the other side of the button connects to what?
From my understanding, (and the [schematic) it looks like all 6 buttons connect to 3 pins on portB, when you activate one pin it allows the other end of a couple of the pins to complete the circuit back to one of the two inactive pins. Honesty it makes more since when you look at the schematic, that’s how I came to understand it as well.
Because of this it seems that you have to quickly cycle through the pins providing voltage to one at a time and checking the other 2 pins for a 1. This dev board seems to be the only AVR board with this button config, the 128 version has a nice simple 5 button to 5 pins.
Oh how do you debounce the buttons? I guess that’s what my code is , unsuccessfully attempting?
BTW, thanks for the tip on the_BV(), I thought it was an odd function to exist, purging…](http://www.olimex.com/dev/images/avr-mt-sch.gif)
Looking at the schematic - I see. The 6 buttons are multiplexed on 3 I/O pins, so you have to scan them.
Switch debouncing - best done with special hardware chip.
Next best is a simple algorithm that goes something like this.
Set a variable that remembers the prior state of the switch(es).
Start with all “false”.
When a switch apparently changes state (mismatches the prior state), then wait x amount of time then see if it is still in the same changed state. If not, ignore the whole thig. The value of x depends on how cheap/crummy the buttons are, like 100 mSec or so.
Another technique is…
scan/poll until a switch changes state. Then delay x. Then loop for y amount of time and confirm that it remains unchanged (not bouncing). If it doesn’t change state, it’s validated.
In either case, you update the variable that remembers the changed state for next time, e.g., to detect when the button is un-pressed.
There are far more elaborate schemes using interrupts and not needing processor looping.
Hope this helps.
I guess I should post some example code of my own design.
Hey Steve thanks for the info.
I would greatly apreciate any code samples, probably make it easyer to absorb the details quickly. I’m surprised at how very complicated this little dev board has turned out to be! Nice tight design with the ATtiny2313, but not entirely beginner friendly from a coding persepctive!