Stepping through multiple LED's w/ one switch

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I'm new to C and AVR's but have done a lot of studying and wanted to get ideas on this before proceeding. I want to have one switch to toggle through 4 LED's. Obviously this would be common but I couldn't find any code snippets to learn from so having a go at my own and asking for input on most efficient way to do this. Ultimately this will be a function within a larger program but I want to keep it simple for now.

I figure the program flow would go like this:

1. Initialize PORTA.
a) Switch is active low on PA0. Set as input, enable pullup.
b) LED's active high on PA1-PA4 Set as outputs, initialize to low state (off).

2. Initilize Timer. Set to compare mode, enable compare match interrupt and set OCR register value for ~1ms scanning.

3. Initialize a variable that will keep track of which LED is ON (call it led_on).

4. while(1)

5. Is key press detected? (w/ appropriate debounce code).
a) if yes then figure out which LED is currently ON
and turn on the next one.
b) if no do nothing.

I can do everything including the debouncing and detecting of the key press, it's just the approach for toggling through the LED's I'm wondering about (most efficient, easiest etc..)

Would you use the switch function to detect which LED is currently ON and then turn ON the next one..?

switch (led_on)
case 0 turn off LED1, turn on LED2 and increment variable led_on
case 1 turn off LED2, turn on LED3 and increment variable led_on
case 2 turn off LED3, turn on LED4 and increment variable led_on
case 3 turn off LED1, turn on LED1 and reset variable led_on to 0

Would you use a series of IF statements?

if led_on=0 turn off LED1, turn on LED2 and increment led_on
else if led_on=1 turn off LED2, turn on LED3 and increment led_on
else if led_on=2 turn off LED3, turn on LED4 and increment led_on
else if led_on=2 turn off LED4, turn on LED1 and reset led_on to 0

Is there an easier way or a way that is most efficient. Do the two samples above even make sense? Are they really just doing the same thing?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First, get the code working, then optimize. Personally I like using the switch statement. It makes the intention fairly obvious. The if then else chain is basically the same. Another alternative is to shift bits. If you were counting processor cycles, then you might want to optimize but in this instance, I don't think it is warranted.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I am very surprised since this is my first time ever to try to write C code but it works. Does this implementation look good? Is there anything silly I'm doing? Am I over-complicating it?

/******************************************************
* Program to cycle through four LED's with one switch *
* Target Device = ATMEGA2560 @ 16MHz                  *      
* Development Board = STK600                          *
******************************************************/  

/*Key detection and debounce code from Danni
https://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=1801 */

#include 
#include 
#include 

#define F_CPU 16000000UL
#define KEY_PIN		PINA
#define KEY_PORT	PORTA
#define KEY_DDR		DDRA
#define KEY0 0              // PA0
#define LED0 0              // PB0
#define LED1 1              // PB1
#define LED2 2              // PB2
#define LED3 3              // PB3
#define LED_DDR		DDRB
#define LED_PORT	PORTB

uint8_t key_press;         // debounced & inverted, 1=key pressed
uint8_t key_state;         // key press detect
uint8_t led_count = 0;

/**********************
* FUNCTION PROTOTYPES *
**********************/

void io_init(void);
void timer0_init(void);
uint8_t get_key_press(uint8_t key_mask); 
 
 
/***********
* FUNCTIONS *
***********/

void io_init() {
	
	 KEY_DDR= 0x0;          // Switches - all inputs
	 KEY_PORT = 0xFF;       // enable pullups 
	 LED_DDR = 0xFF;        // all outputs for LED
	 LED_PORT = 0xFE;		// LED's are active low (STK600)
} 

void timer0_init(void) {
	
	  TCCR0A = (1 << WGM01);           // CTC Mode
	  TCCR0B = (1<<CS02) | (1<<CS00);  // clk/1024
	  TIMSK0 = (1<<OCIE0A);            // Output CompareA Enable
	  OCR0A = 156;             		   // Compare ISR at 10mS
  }	

uint8_t get_key_press(uint8_t key_mask) 
{
	ATOMIC_BLOCK(ATOMIC_FORCEON){  // read and clear atomic
	key_mask &= key_press;         // read key
	key_press ^= key_mask;         // clear key
}
return key_mask;
} 

/*****************************
* INTERRUPT SERVICE ROUTINES *
*****************************/

ISR( TIMER0_COMPA_vect )        // every 10ms
{
	static uint8_t ct0 = 0xFF, ct1 = 0xFF;  
	uint8_t i;

	i = ~KEY_PIN;               // read keys (low active)
	i ^= key_state;             // key changed ?
	ct0 = ~( ct0 & i );         // reset or count ct0
	ct1 = ct0 ^ (ct1 & i);      // reset or count ct1
	i &= ct0 & ct1;             // count until roll over ?
	key_state ^= i;             // then toggle debounced state
	key_press |= key_state & i; // 0->1: key press detect
}

/*******
* MAIN *
*******/

int main( void )
{
	io_init();
	timer0_init();
	key_state = ~KEY_PIN;	     // no action on key during reset
	sei();                       // enable global interrupts
 
 while(1) {
	 
	 if( get_key_press( 1<<KEY0 )) {
	 switch(led_count) {
	 
	 case 0:	 
	   LED_PORT |= 1<<LED0;      // set LED0 bit (TURN OFF LED0)
	   LED_PORT &= ~(1<<LED1);   // clear LED1 bit (TURN ON LED1) 
	   led_count = 1;            // increment LED count
	   break;
	   
	case 1:
	  LED_PORT |= 1<<LED1;       // set LED1 bit (TURN OFF LED1)
	  LED_PORT &= ~(1<<LED2);    // clear LED2 bit (TURN ON LED2)
	  led_count = 2;             // increment LED count
	  break;
	  
	case 2:
	   LED_PORT |= 1<<LED2;      // set LED2 bit (TURN OFF LED2)
	   LED_PORT &= ~(1<<LED3);   // clear LED3 bit (TURN ON LED3)
	   led_count = 3;            // increment LED count
	   break;
	
	case 3:
	   LED_PORT |= 1<<LED3;      // set LED3 bit (TURN OFF LED3)
	   LED_PORT &= ~(1<<LED0);   // clear LED0 bit (TURN ON LED0)
	   led_count = 0;            // reset LED count
	   break; 
	 }
	 }	
 }
 }
 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good work for a beginner.
Now you could try to simplify the code in the while() loop.

Something like this

unsigned char pin=0;
while(1)
{
  if (buton_pressed)
  {
    switch all leds off 
    clear PORT.pin       //led on
    increment pin
    if (pin>3) pin=0
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Now you could try to simplify the code in the while() loop.
nice, this is exactly the kind of stuff I want to know. It is the first program I've written myself but I have read tons of code the past two months and getting very much used to it. But I know I don't yet have the instinct of when to use while, switch, if, for etc.. in each circumstance to make the code the most efficient. I also don't visualize right away the best way of masking bits and stuff I have to think about it and view examples..