⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ledflash.c

📁 AVR单片机有趣的展示
💻 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 + -