Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
mochi321
PostPosted: Jul 08, 2012 - 07:58 AM
Newbie


Joined: Jul 08, 2012
Posts: 8


I am working on an LED. I am now able to control the marquee of the LED. But when i want use switches to control the LED ,it doesnt respond according to the switches.

this is my code:-
Quote:

#include <avr/io.h>

int main( void )
{
DDRD = 0x00;
DDRB = 0xFF;


switch (PIND)
{
case '0x01':
PORTB = 0x01;
case '0xfe':
PORTB = 0x02;
case '0x04':
PORTB = 0x04;
case '0x08':
PORTB = 0x08;
case '0x10':
PORTB = 0x10;
case '0x20':
PORTB = 0x20;
case '0x40':
PORTB = 0x40;
case '0x80':
PORTB = 0x80;
default:
PORTB = 0x00;

}
return 0;
}

Can anyone help to figure out what is wrong with the code please?

i am using STK500 and ATMEGA168 to do the work.
 
 View user's profile Send private message  
Reply with quote Back to top
larryvc
PostPosted: Jul 08, 2012 - 08:21 AM
Raving lunatic


Joined: Dec 06, 2007
Posts: 2512
Location: Redmond, WA USA

Your program falls right out the bottom with the return 0; statement and terminates. You need to enclose your switch and case statements within a while loop. Even then it will not work as coded.

_________________
Larry

Those afraid to embrace the future will quickly fade into the past. - larryvc


Last edited by larryvc on Jul 08, 2012 - 08:26 AM; edited 1 time in total
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jul 08, 2012 - 08:24 AM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England

mochi321 wrote:
I am working on an LED. I am now able to control the marquee of the LED. But when i want use switches to control the LED ,it doesnt respond according to the switches.

this is my code:-
Quote:

Code:
#include <avr/io.h>

int main( void )
{
    DDRD = 0x00;
    DDRB = 0xFF;

                              
switch (PIND)
{
   case '0x01':
         PORTB = 0x01;
   case '0xfe':
         PORTB = 0x02;
   case '0x04':
         PORTB = 0x04;
   case '0x08':
         PORTB = 0x08;
   case '0x10':
         PORTB = 0x10;
   case '0x20':
         PORTB = 0x20;
   case '0x40':
         PORTB = 0x40;
   case '0x80':
         PORTB = 0x80;
   default:
         PORTB = 0x00;

}
    return 0;
}

Can anyone help to figure out what is wrong with the code please?

i am using STK500 and ATMEGA168 to do the work.


The switch() statement normally uses a break; between every case clause.
The case takes a numeric value like 0x41 or 'A'.
'0x41' is not a valid expression.

It you trace your program by hand, you will see that for any value of PIND it will end up with the default case. i.e. all LEDs on.

Also note that your fingers will struggle to achieve any value like 0x80. You need to press all the switches SW0..SW6 while starting your program.

A pressed switch is 0 and not 1.
You normally use 'internal pull-ups' on a pin that is connected to a switch. The STK500 already has some external pull-ups (I think).

If you put the switch inside a while () loop, it will work continuously. Your program just reads the value of PIND at program start-up.

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
mochi321
PostPosted: Jul 09, 2012 - 08:47 AM
Newbie


Joined: Jul 08, 2012
Posts: 8


Hi David, I follow your suggestion to write this code is
Code:
#include <avr/io.h>

int main( void )
{
    DDRD = 0x00;
    DDRB = 0xFF;

while(1)
{                              
switch (PIND)
{
   case 'FE':
         PORTB = 0x01;
       break;
   case 'FD':
         PORTB = 0x02;
       break;
   case 'FA':
         PORTB = 0x04;
       break;
   case 'F8':
         PORTB = 0x08;
       break;
   case 'EF':
         PORTB = 0x10;
       break;
   case 'DF':
         PORTB = 0x20;
       break;
   case 'AF':
         PORTB = 0x40;
       break;
   case '8F':
         PORTB = 0x80;
       break;
   default:
         PORTB = 0xff;
       break;

}
}
}
$ Fixed CODE tags - JS $

but it still doesn't respond according to the switches.

Can you help to figure out what is wrong with the code or would it be possible for me to have some sample code from you please?
 
 View user's profile Send private message  
Reply with quote Back to top
snigelen
PostPosted: Jul 09, 2012 - 08:55 AM
Posting Freak


Joined: Jan 08, 2009
Posts: 1148
Location: Lund, Sweden

Did you get any warnings?
Try something like this:
Code:
   switch (PIND)
   {
   case 0xFE:
       PORTB = 0x01;
       break;
   case 0xFD:
       PORTB = 0x02;
       break;
...
 
 View user's profile Send private message  
Reply with quote Back to top
js
PostPosted: Jul 09, 2012 - 09:06 AM
10k+ Postman


Joined: Mar 28, 2001
Posts: 20311
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)

mochi321 please use the CODE button when posting code, I have fixed the post above.

_________________
John Samperi
Ampertronics Pty. Ltd.
www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
mochi321
PostPosted: Jul 09, 2012 - 09:23 AM
Newbie


Joined: Jul 08, 2012
Posts: 8


For snigelen
I get the warnings to following:

../LED_switch.c:12:9: warning: character constant too long for its type
../LED_switch.c: In function 'main':
../LED_switch.c:12: warning: case label value exceeds maximum value for type
../LED_switch.c:15:9: warning: character constant too long for its type
../LED_switch.c:15: warning: case label value exceeds maximum value for type


I try your suggestion ,but i get the same result.
 
 View user's profile Send private message  
Reply with quote Back to top
thygate
PostPosted: Jul 09, 2012 - 09:31 AM
Resident


Joined: Sep 19, 2005
Posts: 765
Location: Belgium

Quote:
For snigelen
I get the warnings to following:

../LED_switch.c:12:9: warning: character constant too long for its type
../LED_switch.c: In function 'main':
../LED_switch.c:12: warning: case label value exceeds maximum value for type
../LED_switch.c:15:9: warning: character constant too long for its type
../LED_switch.c:15: warning: case label value exceeds maximum value for type

I try your suggestion ,but i get the same result.
From those warnings it is clear you did not remove the quotes.
Lose the quotes, you cannot compare strings in a switch statement anyway.
single quotes are used for single characters, double quotes for strings. You want a numeric value that you represent in hexadecimal, so only use the 0x prefix.

change
Code:
case 'FE':
to
Code:
case 0xFE:
as was explained by David, and repeated by snigelen.
david.prentice wrote:
The case takes a numeric value like 0x41 or 'A'.
'0x41' is not a valid expression.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 09, 2012 - 10:01 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62209
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

For snigelen
I get the warnings to following:

../LED_switch.c:12:9: warning: character constant too long for its type

Did that not make you wonder "why is it telling me that the character constant is too long?". Did it not prompt you to take a look at your C manual and find out how to specify integer constants. All these are valid (in GCC)

1
0b1011
037
0x4F
'A'
'\r'

While none of these are

4F
'hello'
'FA'
'037'
'0x47'

If you don't understand why this is it's time to hit the books and brush up on some fundamentals of C programming.

Anyway it seems like madness to try and act on all 8 bits of PIND at once. You are likely only interested in whether one button (one bit) is set or clear at any one time so I'd do something like:
uint8_t switch;
Code:
switch = PIND;
if (switch & (1<<0)) {
  // do stuff for button 0 being pressed
}
if (switch & (1<<1)) {
  // do stuff for button 1 being pressed
}
if (switch & (1<<2)) {
  // do stuff for button 2 being pressed
}
if (switch & (1<<3)) {
  // do stuff for button 3 being pressed
}
etc.

For the STK500 where the buttons are active low then you would actually invert that using C's NOT operator:
Code:
switch = PIND;
if (!(switch & (1<<0))) {
  // do stuff for button 0 being pressed
}
if (!(switch & (1<<1))) {
  // do stuff for button 1 being pressed
}
if (!(switch & (1<<2))) {
  // do stuff for button 2 being pressed
}
if (!(switch & (1<<3))) {
  // do stuff for button 3 being pressed
}
etc.


I wouldn't have said that either a switch()/case or if()/else if()/else if() construct would be appropriate here as you might want to act on the fact that both button 0 and button 3 are both pressed. Those two constructs tend to imply you are only willing to consider one of the 8 buttons being pressed.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
mochi321
PostPosted: Jul 09, 2012 - 11:00 AM
Newbie


Joined: Jul 08, 2012
Posts: 8


My revised code:

#include <avr/io.h>

Code:
int main( void )
{
    DDRD = 0x00;
    DDRB = 0xFF;

while(1)
{                              
switch (PIND)
{
   case  0xFE:
         PORTB = 0x01;
       break;
   case  0xFD:
         PORTB = 0x02;
       break;
   case  0xFA:
         PORTB = 0x04;
       break;
   case  0xF8:
         PORTB = 0x08;
       break;
   case  0xEF:
         PORTB = 0x10;
       break;
   case  0xDF:
         PORTB = 0x20;
       break;
   case  0xAF:
         PORTB = 0x40;
       break;
   case  0x8F:
         PORTB = 0x80;
       break;
   default:
         PORTB = 0xff;
       break;

}
}
}

the code don't has any error and warning,
but it doesn't respond according to the switches.
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jul 09, 2012 - 11:20 AM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England

Code:

#include <avr/io.h>

int main(void)
{
    DDRD = 0x00;                // switches are input
    PORTD = 0xFF;               // internal pull-ups on switches.
    DDRB = 0xFF;                // LEDs are output

    while (1)                   // loop forever
    {
        switch (~PIND)          // human readable switches
        {
        case 0x01:
            PORTB = ~0x01;      // active-low LEDs
            break;
        default:
            PORTB = ~0x00;      // active-low
            break;
        }
    }
}


It takes a little while to get your head around active-low. Personally, I just work in human, and then invert the result when I write to the PORT.

Likewise, I read the switches and turn them into human (with the ~ operator).

Note that you can read several switches at a time as a separate case. i.e. all 256 possible finger combinations of the 8 push-buttons.

If you just want to consider switches as 8 different combinations, you use the if ((PIND & 0x01) == 0) style.

Again, I would use a human_switch = ~PIND variable.
Then you can use if (human_switch & 0x01) ...

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
danni
PostPosted: Jul 09, 2012 - 12:09 PM
Raving lunatic


Joined: Sep 05, 2001
Posts: 2496


clawson wrote:
I wouldn't have said that either a switch()/case or if()/else if()/else if() construct would be appropriate here as you might want to act on the fact that both button 0 and button 3 are both pressed. Those two constructs tend to imply you are only willing to consider one of the 8 buttons being pressed.


But it's an impossible task to press two keys simultaneous from the CPU view Exclamation
Since no human was able to press both within the same microsecond or so.
Thus CPU see always a single press at first.

Also testing only a single bit would be smaller and faster code, since then the compiler can use the bit instructions (SBIS, CBIS).


Peter
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 09, 2012 - 12:13 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62209
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

But it's an impossible task to press two keys simultaneous from the CPU view Exclamation
Since no human was able to press both within the same microsecond or so.

Eh? On my STK500 I can happily hold down 3/4/5 of the buttons at the same time? In fact if I really tried I reckon I could hold down all 8 at the same time.

EDIT: no I tried it about 7 is the most I can press at once as need a finger/thumb to grip the STK500 board itself while I'm trying to do this.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
danni
PostPosted: Jul 09, 2012 - 01:01 PM
Raving lunatic


Joined: Sep 05, 2001
Posts: 2496


clawson wrote:
Eh? On my STK500 I can happily hold down 3/4/5 of the buttons at the same time?


I meant not the pressed state.
I meant the moment, when the key was closed.

The CPU see at first only a single key press, then two, then three and so on.
Since you can not press all keys at the same time.
There are several milliseconds difference.


Peter
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 09, 2012 - 01:03 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62209
Location: (using avr-gcc in) Finchingfield, Essex, England

Yeah but OP is sitting in a while() loop polling PIND. My contention is that on any of the reads of PIND either 0 or 1 or 2 or 3 or 4 or 5 or 6 or 7 or 8 buttons may be found to be pressed. If the code processing that PIND reading just handled the first button it found pressed and stopped it would miss the fact that others were also being held.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
mochi321
PostPosted: Jul 09, 2012 - 01:11 PM
Newbie


Joined: Jul 08, 2012
Posts: 8


For David
I try your code,but it still doesn't respond according to the switches.

so I maybe to try "if" to revised the code
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jul 09, 2012 - 01:41 PM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England

Oops. I should have tested the code that I posted.
Code:
        switch (~PIND & 0xFF)   // human readable switches


What happens with a straight ~PIND is that you get PIND extended to an int before the NOT is applied. Hence 0xFE is extended to 0x00FE and when inverted you get 0xFF01.

I am sorry for complicating matters. If you use an 'unsigned char' for the state of the switches:



David.
Code:

int main(void)
{
    unsigned char human;
    DDRD = 0x00;                // switches are input
    PORTD = 0xFF;               // internal pull-ups on switches.
    DDRB = 0xFF;                // LEDs are output

    while (1)                   // loop forever
    {
        human = ~PIND;          // don't need to worry about int extension.
        switch (human)          // human readable switches
        {
        case 0x01:
            PORTB = ~0x01;      // active-low LEDs
            break;
        default:
            PORTB = ~0x00;      // active-low
            break;
        }
    }
}
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
danni
PostPosted: Jul 09, 2012 - 03:03 PM
Raving lunatic


Joined: Sep 05, 2001
Posts: 2496


mochi321 wrote:
For David
I try your code,but it still doesn't respond according to the switches.

so I maybe to try "if" to revised the code


That's why you still not follow the suggestions to test only a single pin instead the whole byte. Crying or Very sad

Especially on the ATmega168 PORTB may be no fully accessible. Exclamation

And if accessible, then on the STK500 PB6,7 are routed to the XTAL1,2 connector.

Thus checking the bit was always the favoured way to read a key.


Peter
 
 View user's profile Send private message  
Reply with quote Back to top
mochi321
PostPosted: Jul 10, 2012 - 08:37 AM
Newbie


Joined: Jul 08, 2012
Posts: 8


My code finally works!
Thanks everyone for your kind help, I greatly appreciate it.
My code is

Code:
#include <avr/io.h>
int main(void)
{
    unsigned char human;
    DDRD = 0x00;                // switches are input
    PORTD = 0xFF;               // internal pull-ups on switches.
    DDRB = 0xFF;                // LEDs are output

    while (1)                   // loop forever
    {
        human = ~PIND;          // don't need to worry about int extension.
        if (human == 0x01)
          PORTB = ~0x01;
         else if (human == 0x02)
         PORTB = ~0x02;
         else if (human == 0x04)
         PORTB = ~0x04;
         else if (human == 0x08)
         PORTB = ~0x08;
         else if (human == 0x10)
         PORTB = ~0x10;
         else if (human == 0x20)
         PORTB = ~0x20;
         else if (human == 0x40)
         PORTB = ~0x0F;
         else if (human == 0x80)
         PORTB = ~0x30;
         else
         PORTB = ~0x3f;
    }
}
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jul 10, 2012 - 09:00 AM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England

Your if else-if structure where you test for specific values with == is exactly the same as using switch - case - default.

If you use another variable, it means you can keep your human brain at room temperature:

Code:

int main(void)
{
    unsigned char human, leds;
    DDRD = 0x00;                // switches are input
    PORTD = 0xFF;               // internal pull-ups on switches.
    DDRB = 0xFF;                // LEDs are output

    while (1)                   // loop forever
    {
        human = ~PIND;          // don't need to worry about int extension.
        switch (human)          // human readable switches
        {
        case 0x01:
            leds = 0x01;        // keep regular logic
            break;
        case 0x02:
            leds = 0x02;        // keep regular logic
            break;
        case 0x04:
            leds = 0x04;        // keep regular logic
            break;
        case 0x08:
            leds = 0x08;        // keep regular logic
            break;
        case 0x10:
            leds = 0x10;        // keep regular logic
            break;
        case 0x40:
            leds = 0x0F;        // keep regular logic
            break;
        case 0x80:
            leds = 0x30;        // keep regular logic
            break;
        default:
            leds = 0x3F;        // light 7 leds
            break;
        }
        PORTB = ~leds;          // active-low for LED to light.
    }
}


Note that you can easily change your PORT or active-high / active-low sense. You might also prefer showing which LED in a more intuitive way:
Code:

        case 0x80:
            leds = 0b00110000;  // keep regular logic
            break;

The 0b notation for binary constants is supported by avr-gcc but is not regular C.

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
mochi321
PostPosted: Jul 10, 2012 - 09:09 AM
Newbie


Joined: Jul 08, 2012
Posts: 8


David wrote:
Quote:
Your if else-if structure where you test for specific values with == is exactly the same as using switch - case - default.

If you use another variable, it means you can keep your human brain at room temperature:


I try this code,but it doesn't works.
I don't know what's wrong happen
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jul 10, 2012 - 09:23 AM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England

Just saying "I try this code,but it doesn't works" is not very helpful to you or your readers.

Please describe what you expected, and what you got.

I confess. I just wrote the example code, and never tested it in real-life.

I have just tried it, and it behaves as I expected. The STK500 has PORTB.6 and PORTB.7 on the PORTE/AUX header.

David.

Oops. I forgot the 0x20 case. I leave this as an exercise for the reader.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
mochi321
PostPosted: Jul 10, 2012 - 09:55 AM
Newbie


Joined: Jul 08, 2012
Posts: 8


sorry, i want expected when i try your code by using switch - case - default.
Code:
#include <avr/io.h>
int main(void)
{
    unsigned char human, leds;
    DDRD = 0x00;                // switches are input
    PORTD = 0xFF;               // internal pull-ups on switches.
    DDRB = 0xFF;                // LEDs are output

    while (1)                   // loop forever
    {
        human = ~PIND;          // don't need to worry about int extension.
        switch (human)          // human readable switches
        {
        case 0x01:
            leds = 0x01;        // keep regular logic
            break;
        case 0x02:
            leds = 0x02;        // keep regular logic
            break;
        case 0x04:
            leds = 0x04;        // keep regular logic
            break;
        case 0x08:
            leds = 0x08;        // keep regular logic
            break;
        case 0x10:
            leds = 0x10;        // keep regular logic
            break;
        case 0x40:
            leds = 0x0F;        // keep regular logic
            break;
        case 0x80:
            leds = 0x30;        // keep regular logic
            break;
        default:
            leds = 0x3F;        // light 7 leds
            break;
        }
        PORTB = ~leds;          // active-low for LED to light.
    }
}

but it doesn't light up when i press the swithches
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jul 10, 2012 - 10:18 AM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England

Well, I connected PORTD to switches and PORTB to LEDs with the two 10-way ribbons.

With no buttons pressed, all 6 LEDs light up. LED0..LED5
Press SW0 and just LED0 lights
ditto for SW1 to SW5.
Press SW6 and LED0..LED3 light.
Press SW7 and LED4,LED5 light.

Quote:
but it doesn't light up when i press the swithches

Do the switches light with no buttons pressed?
Did you copy-paste my code, or type it by hand?

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits