📄 ledflash.c
字号:
/*
* Funny AVR demonstration. Controls 8 LEDs which are directly
* connected to VCC. Additional to the nice illumination this
* program demonstrates the usage of the async timer and the
* sleep modes to save power.
*
* The port pins for the LEDs are in a way selected, that it is
* easy to put these around the chip. If you want to change the
* port pins (maybe for another mcu), simply change it in the file
* hardware.h. It doesn't matter which port pins you select. You
* can control the brightness by changing the values in the section
* Timings in globals.h.
* Additional to the LEDs you can connect 2 keys to the mcu. The
* function of the keys is either to select the mode of illumination
* and to switch it on and off. If you hold the mode-key for about
* 1,5 seconds an auto mode will be selected. In this mode all
* illumination effects are automatic periodically selected.
* The shutdown is realised through the power down mode of the mcu.
* While the program is running, the power save mode is used to
* reduce the power assumption.
*
* The build_*.* files are usefull for calculating build numbers,
* but it is written for win2k. I didn't try it on other win os's.
* And it didn't work on other OS I assume.
*
* To the hardware:
* Connect the LEDs to the pins which are defined in hardware.h, the
* same for the keys. No external pull-ups are required. But you need
* a 32.768KHz oscillator on the TOSC1 and TOSC2 pins.
*
* Compiled with WinAVR January 2003 distribution. You need avr-sizex
* too. You find it here:
* Otherwise you can delete the sizex usage in the makefile.
*
* Note: There is a small bug in avr/sleep.h of the january distribution
* Please check line 97. It should be:
* #define set_sleep_mode(mode) (MCUCR = ((MCUCR & ~SLEEP_MODE_MASK) | (mode)))
*
* Written by Volkmar Dierkes 06. February 2003
*/
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/sleep.h>
#include "hardware.h"
#include "globals.h"
#include "build_no.h"
void Init_Ports(void)
{
/* Define all Port pins for input/pull up as necessary */
asm("nop"); // Needed to see the first source line in this function
//Keys
KEY1_DDR &= ~_BV(KEY1_BIT); //Input
KEY1_PORT |= _BV(KEY1_BIT); //Enable Pull-Up
KEY2_DDR &= ~_BV(KEY2_BIT); //Input
KEY2_PORT |= _BV(KEY2_BIT); //Enable Pull-Up
//LEDs
LED1_PORT |= _BV(LED1_BIT); //Output should be high for light off
LED1_DDR |= _BV(LED1_BIT); //Output
LED2_PORT |= _BV(LED2_BIT); //Output should be high for light off
LED2_DDR |= _BV(LED2_BIT); //Output
LED3_PORT |= _BV(LED3_BIT); //Output should be high for light off
LED3_DDR |= _BV(LED3_BIT); //Output
LED4_PORT |= _BV(LED4_BIT); //Output should be high for light off
LED4_DDR |= _BV(LED4_BIT); //Output
LED5_PORT |= _BV(LED5_BIT); //Output should be high for light off
LED5_DDR |= _BV(LED5_BIT); //Output
LED6_PORT |= _BV(LED6_BIT); //Output should be high for light off
LED6_DDR |= _BV(LED6_BIT); //Output
LED7_PORT |= _BV(LED7_BIT); //Output should be high for light off
LED7_DDR |= _BV(LED7_BIT); //Output
LED8_PORT |= _BV(LED8_BIT); //Output should be high for light off
LED8_DDR |= _BV(LED8_BIT); //Output
}
void Init_Timer(void)
{
TIMSK = 0;
/* Define Timer2 for Async and RTC */
TIMSK &= ~( _BV(TOIE2) | _BV(OCIE2) ); // Disable all Timer2 interrupts
ASSR |= _BV(AS2); // Set Timer0 to asynchronous 32.768KHz clock
TCNT2 = 0;
while(ASSR & ( _BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB) ) ); //wait until data is processed
#if ASYNC_TIMER == 1
TCCR2 |= _BV(CS22) | _BV(CS20); // Set clock-divisor to 1/128 (1 int per second)
#else
#if ASYNC_TIMER == 128
TCCR2 |= _BV(CS20); // Set clock-divisor to 1 (128 ints per second)
#else
error("wrong value for ASYNC_TIMER")
#endif
#endif
while(ASSR & ( _BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB) ) ); //wait until data is processed
TIMSK |= _BV(TOIE2); // Set Timer overflow interrupt enable flag
}
SIGNAL(SIG_INTERRUPT0)
{
//No code necessary, only for wake up after sleeping
}
SIGNAL(SIG_OVERFLOW2)
{
/* Primary timer subroutine */
new_tick = 1; // Mark the event
key_new = 0; // Look for pressed keys
if ((KEY1_PIN & _BV(KEY1_BIT)) == 0)
key_new |= 1;
if ((KEY2_PIN & _BV(KEY2_BIT)) == 0)
key_new |= 2;
if(key_new != key_old)
key_cnt = 0;
else
if (key_cnt != KEY_OFF)
if(key_cnt++ >= KEY_ENTPRELL) { // Keys are only valid after some time
key_cnt = KEY_OFF;
key = key_new; // Key is valid
}
key_old = key_new;
}
void set_led(uint8_t val)
{
/* Set all keys according to val */
if (_BV(0) & val)
LED1_PORT &= ~_BV(LED1_BIT);
else
LED1_PORT |= _BV(LED1_BIT);
if (_BV(1) & val)
LED2_PORT &= ~_BV(LED2_BIT);
else
LED2_PORT |= _BV(LED2_BIT);
if (_BV(2) & val)
LED3_PORT &= ~_BV(LED3_BIT);
else
LED3_PORT |= _BV(LED3_BIT);
if (_BV(3) & val)
LED4_PORT &= ~_BV(LED4_BIT);
else
LED4_PORT |= _BV(LED4_BIT);
if (_BV(4) & val)
LED5_PORT &= ~_BV(LED5_BIT);
else
LED5_PORT |= _BV(LED5_BIT);
if (_BV(5) & val)
LED6_PORT &= ~_BV(LED6_BIT);
else
LED6_PORT |= _BV(LED6_BIT);
if (_BV(6) & val)
LED7_PORT &= ~_BV(LED7_BIT);
else
LED7_PORT |= _BV(LED7_BIT);
if (_BV(7) & val)
LED8_PORT &= ~_BV(LED8_BIT);
else
LED8_PORT |= _BV(LED8_BIT);
}
// ***********************************************************
// Main program
//
int main(void)
{
uint8_t bright_cnt;
uint8_t speed_cnt, speed_factor;
uint8_t auto_mode;
uint8_t mode_cnt;
uint16_t auto_cnt;
uint8_t i, key_hold;
Init_Ports();
Init_Timer();
//Define mode, speed and brightness
speed_factor = SPEED_FACTOR; // 1 = fastest, period = speed_period*bright_period in steps of async speed
led_mode = 0; // 0 = all on
// 1 = 7->0 dec
// 2 = 0->7->0
// 3 = 10001000 shifting
// 4 = 0->7 inc
// 5 = 01010101 10101010
// 6 = 10000001 01000010 00100100 00011000
// 7 = 10011001 01100110
// 8 = all flashing
auto_mode = 0; // 1 = change automatically through the modes
//Init variables
new_tick = 0;
bright_cnt = 0;
speed_cnt = 0;
mode_cnt = 0;
auto_cnt = 0;
key_old = 0;
key_new = 0;
key_cnt = KEY_OFF;
key = 0;
key_hold = 0;
sei(); // Allow the interrupts in general
while(1) { // Infinite loop; define here the
if (key == 1) { // Process the power on/off key
key |= 128; // Mark the key as processed
key_hold = 0;
set_led(0); // shut all leds off
for(i=0;i<10;i++) { //wait some time until key is released
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
sleep_mode(); //Go to sleep while waiting
if (key != 0) //If a key is already pressed, wait again
i = 0;
}
GIFR |= _BV(INTF0); //Clear pending interrupts
GICR |= _BV(INT0); //Enable Int0 (and only int0!) for wake up
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode(); // Go to power down until 'on'-key is pressed
GICR &= ~_BV(INT0); // Disable Int0, isn't necessary anymore
for(i=0;i<10;i++) { // wait some time until key is released
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
sleep_mode(); // Go to sleep while waiting
if (key != 0) // If a key is already pressed, wait again
i = 0;
}
}
else if (key == 2) { // Process the mode key
key |= 128;
key_hold = 0;
if (++led_mode > MODE_MAX) // Switch to next mode
led_mode = 0; // Back if max number is reached
}
else if (key == 128+2) { // Check if key is already pressed
if (++key_hold >= KEY_SETAUTO) { // If yes, is it long enough?
key = 255; // Mark the key as processed
auto_mode ^= 1; // Toggle Auto mode on/off
led_mode = 0; // To get response to the user, swith for a short time to all on
auto_cnt = AUTO_PERIOD-128/BRIGHT_PERIOD;
}
}
if (new_tick != 0) { // Now check if new tick is available
if (++bright_cnt == BRIGHT_ONTIME) { // Shut all LEDs off if bright time is over
set_led(0);
}
else if (bright_cnt >= BRIGHT_PERIOD) { // If period end is reached, start the period again
bright_cnt = 0;
}
if (bright_cnt == 0) {
if (auto_mode != 0) { // Check if auto selecting the mode
if (++auto_cnt >= AUTO_PERIOD) {
auto_cnt = 0;
if (++led_mode > MODE_MAX) { // Use next mode
led_mode = 1; // Or start from the beginning
}
}
}
/* Handle the different modes */
/* You can change it if you want. */
/* But if you change the number of */
/* modes, you have to change the */
/* MODE_MAX in globals.h too */
if (led_mode == 0) {
set_led(0xFF);
}
else if (led_mode == 1) {
set_led(_BV(7-mode_cnt));
if (speed_cnt == 0)
if (++mode_cnt >= 8)
mode_cnt = 0;
}
else if (led_mode == 2) {
if (mode_cnt < 8)
set_led(_BV(mode_cnt));
else
set_led(_BV(14-mode_cnt));
if (speed_cnt == 0)
if (++mode_cnt >= 14)
mode_cnt = 0;
}
else if (led_mode == 3) {
if (mode_cnt == 0)
set_led(0x11);
else if (mode_cnt == 1)
set_led(0x22);
else if (mode_cnt == 2)
set_led(0x44);
else if (mode_cnt == 3)
set_led(0x88);
if (speed_cnt == 0)
if (++mode_cnt >= 4)
mode_cnt = 0;
}
else if (led_mode == 4) {
set_led(_BV(mode_cnt));
if (speed_cnt == 0)
if (++mode_cnt >= 8)
mode_cnt = 0;
}
else if (led_mode == 5) {
if (mode_cnt == 0)
set_led(0x55);
else if (mode_cnt == 1)
set_led(0xAA);
if (speed_cnt == 0)
if (++mode_cnt >= 2)
mode_cnt = 0;
}
else if (led_mode == 6) {
if (mode_cnt == 0)
set_led(0x81);
else if (mode_cnt == 1)
set_led(0x42);
else if (mode_cnt == 2)
set_led(0x24);
else if (mode_cnt == 3)
set_led(0x18);
else if (mode_cnt == 4)
set_led(0x24);
else if (mode_cnt == 3)
set_led(0x42);
if (speed_cnt == 0)
if (++mode_cnt >= 4)
mode_cnt = 0;
}
else if (led_mode == 7) {
if (mode_cnt == 0)
set_led(0x99);
else if (mode_cnt == 1)
set_led(0x66);
if (speed_cnt == 0)
if (++mode_cnt >= 2)
mode_cnt = 0;
}
else if (led_mode == 8) {
if (mode_cnt == 0)
set_led(0xFF);
if (speed_cnt == 0)
if (++mode_cnt >= 4)
mode_cnt = 0;
}
if (++speed_cnt >= speed_factor) {
speed_cnt = 0;
}
}
}
new_tick = 0; // Mark the tick as processed
//Sleep until next async tick to reduce power
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
sleep_mode();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -