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

📄 main.c

📁 旋转16个LED灯控制程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************************************Background V1.00 firmwareDisplays various background images on a SpokePOVIntended mostly for multicolor displaysBackground firmware is distributed under CC license. For more info on CC go to www.creativecommons.orgFor more info on SpokePOV go to www.ladyada.net/make/spokepovCreative Commons DeedAttribution-NonCommercial-ShareAlike 2.5You are free:    * to copy, distribute, display, and perform the work    * to make derivative worksUnder the following conditions:Attribution.   You must attribute the work in the manner specified by the    author or licensor.Noncommercial.    You may not use this work for commercial purposes.Share Alike.    If you alter, transform, or build upon this work, you may    distribute the resulting work only under a license identical to this one.    * For any reuse or distribution, you must make clear to others       the license terms of this work.    * Any of these conditions can be waived if you get permission       from the copyright holder.Your fair use and other rights are in no way affected by the above.A more detailed version of this license is available at:http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode******************************************//* Modified from SpokePOV 1.01 by RJW to display messages from a character	*//* set instead of simple bitmaps.  The character set (ascii 32-127) is 		*//* stored in the first 3 banks of the external EEPROM						*//*																			*//* Currently does not use the rotation offset or backside leds				*//* ANNOTATED by RJW - trebor@animeigo.com - to further my understanding		*//* of the code and environment before proceeding to make mods.  All page	*//* numbers refer to the ATMEL ATTiny2313 documentation located at			*//* http://www.atmel.com/dyn/resources/prod_documents/doc2543.pdf			*//* Any comments implying any ignorance were made by RJW!  The esteemed		*//* original author is by definition omniscient, and, it is feared,			*//* omnipotent as well...													*/#include <avr/io.h>#include <avr/interrupt.h>/* We now store the message to be scrolled out on the SpokePOV in the flash	*//* memory.  This requires using the PROGMEM routines.  For more info about	*//* them, see: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38003 *//* IMPORTANT: read the erratta postings after the main posting, there are   *//* a couple that can bite you in the ass (esp: pgm_read_byte example)		*/#include <avr/pgmspace.h>/* The spi_ transfer routines are now in eeprom.c.  There is a define in	*//* eeprom.c as to whether they are functions or inline code					*/#include "main.h"#include "eeprom.h"/* We always need to define nothing...										*/#define NULL ((void *)0)/* Define a composite type that can be used to access a 16-bit variable in	*//* a variety of ways.  This will help with code-squeezing because it lets   *//* us often init variables with only 8 bit constants, lets us do 8 bit		*//* shifts for free, etc.  The cost, of course, is a little code readability,*//* so please forgive me for this.											*/typedef union {  uint16_t	word;    struct {      uint8_t low_byte;    uint8_t high_byte;      } bytes;    char *ptr;  } var16bit;typedef union {  uint32_t	longWord;    struct {      uint16_t	low_word;    uint16_t	high_word;    } words;    struct {      uint8_t low_byte;		// named this way for consistency with var16bit    uint8_t byte_1;    uint8_t byte_2;    uint8_t high_byte;      } bytes;  } var32bit;/* Cute flag that can be used to easily comment out blocks of code			*/#define DONOTCOMPILE	1/* How many 8msec delays between each smooth scrolling increment.  This     *//* time * 16 is the line scroll delay time in the charPOV software, and that*//* is what we use to sync up two displays.									*/#define SCROLLSPEED		16/* Which way is the SpokePOV rotating.  If clockwise, we scan up through	*//* the bitmap, otherwise, we have to scan down...							*/// #define CLOCKWISE	1/****************************************************************************//*                                                                          *//* IMPORTANT NOTE ABOUT VARIABLES!                                          *//*                                                                          *//* This firmware is on the ragged edge of running out of RAM for variables  *//* and stack when all the features (SMOOTHSCROLL,DYNAMIC) are turned on.    *//*                                                                          *//* If you modify it and start seeing displays where some of the characters	*//* are displayed OK but others are mangled, this is a symptom that you have *//* run out of RAM!                                                          *//*                                                                          *//* REMEMBER: function calls use up RAM as well...							*//*                                                                          *//****************************************************************************//* The number of elements in our background sequence list, which defines	*//* what background images are displayed, and for how long.					*/#define NUM_ELEMENTS 5/* The list of elements to be displayed by the software.  These can be		*//* mixed up in order to display things in different order.					*//*																			*//* Valid codes are:															*//*																			*//* 	00 - display image 00													*//* 	01 - display image 01													*//* 	02 - display image 02													*//* 	03 - display image 03													*//*																			*//*  04 - display BLANK background (0xFF to the display bits)				*//*  05 - display FULL ON background (0x00 to the display bits)				*//*																			*//*  06 - display 16 1-pixel bars, rotation each 16 revs						*//*  07 - Invert of 06, background is on, bars are off						*//*  08 - display 1 16-pixel bar, rotation each 16 revs						*//*  09 - Invert of 08, background is on, big bar is off						*//*																			*//*  10 - 2-banded, 50% on, shifting towards center one pixel per rev		*//*  11 - 2-banded, 25% on, shifting towards center one pixel per rev		*//*  12 - 2-banded, 75% on, shifting towards center one pixel per rev		*//*  13 - 4-banded, 50% on, shifting towards center one pixel per rev		*//*  18 - 2-banded, 50% on, shifting towards edge one pixel per rev			*//*  19 - 2-banded, 25% on, shifting towards edge one pixel per rev			*//*  1A - 2-banded, 75% on, shifting towards edge one pixel per rev			*//*  1B - 4-banded, 50% on, shifting towards edge one pixel per rev			*/const uint8_t elementList[] PROGMEM = {0x05,0x08,0x09,0x06,0x07};/* The visibility time of each element.  Since charPOV scrolls 16 scanline	*//* characters, a visibility that is in multiples of 16 will sync to the		*//* scrolling of text														*/const uint8_t elementTime[] PROGMEM = {0x20,0x30,0x30,0x30,0x30};/* index of the current effect, plus local copies of the current array		*//* elements																	*/volatile uint8_t curElementPtr = 0x00;volatile uint8_t curElement;volatile uint8_t curTime;volatile var16bit eepromPtr;				// pointer into the eeprom of imagevolatile uint8_t curPixel;					// how many pixels have we clocked out?											volatile uint8_t curRev;					// how many revs in the current effect?											// How many ~3ms delays (-1) must elapse before we consider// a subsequent hall-effect sensor interrupt to be valid?#define HALL_DEBOUNCE_THRESH 4				// ~15ms// How many msecs the button must be held down before it is// considered to be an actual button press.#define BUTTON_DEBOUNCE  10// How many pixels in a full rotation of the SpokePOV#define NUM_PIXELS 256     					// max is 255 (since it is 8 bit value)// How long after the SpokePOV stops rotating will the display continue?#define STANDBY_TIMEOUT 5       			// in secondsuint8_t fleds[4];							// pixel array of the pixels to shift to the displayvolatile uint8_t hall_debounce;				// count (via TIMER0) since last *used* Hall Effect detectionvolatile var16bit sensor_timer;				// count (via TIMER0) since last actual Hall Effect detectionvolatile uint8_t line_timer = 0x00;			// counter for scrolling/line stepping; realized it only needs to be 8 bitsvolatile var32bit shiftReg;					// shift animation registervolatile uint8_t shiftDir;					// direction of shift (0=none,1=left,2=right)// Sends the 4-byte LED pixel data block out// over the serial link.  Front LEDs only// Sends 4 bytes + sCount extra bits over the serial link// to implement smooth scrolling.  Can be used with a 0// parameter to just send out the regular 4 bytes.void clock_scroll(uint8_t sCount) {  // First, send the basic 4 bytes, they go no matter what    spi_transfer(fleds[0]);  spi_transfer(fleds[1]);  spi_transfer(fleds[2]);  spi_transfer(fleds[3]);   // If there is anything to do..    if (sCount != 0) {      // If we have < 8 bits to transfer        if (sCount < 8) {           // Then that is all that we need to do              spi_transfer_n(fleds[4],sCount);           } else {          // First latch out the full first 8 bits         	  spi_transfer(fleds[4]);  	     	  // How many bits left to do?  	     	  sCount = sCount - 8;  	     	  if (sCount != 0) {  	           spi_transfer_n(fleds[5],sCount);           	  }  	     	}  	  }     // finally, latch the bits into the LEDS    LATCH_SELECT_PORT |= _BV(FRONT);  NOP; NOP; NOP; NOP;  LATCH_SELECT_PORT &= ~_BV(FRONT);}// TIMER0 interrupt handler.  This runs about every 8ms// AFAICT.  It increments the hall_debounce and sensor_timer// values until they pin.// QUESTION: what's with the setting and clearing of PORTB0?// According to the wiring diagram, it isn't connected to// anything.  Is this vestigial code from when you were using// Pin Change Interrupts?  Or is it debugger code so you// can monitor the pins and tell when something happens.SIGNAL (SIG_TIMER0_OVF) {  // *** PORTB |= 0x1;  // Let hall_debounce just wrap around.  At worst it'll just  // mess things up for one of the initial speedup rotations  // of the blade...    // if (hall_debounce != 0xFF)    hall_debounce++;    if (sensor_timer.bytes.high_byte != 0xFF)    sensor_timer.word++;  // Increment the line timer.    line_timer++;				// increment the low byte            }// This routine gets called every time the pixel timer runs down;// in other words, once per "scan line", 256 times per revolution// of the SpokePOV.  Its purpose is to update the LEDs.  All it// has to do at this point is copy from the EEPROMSIGNAL (SIG_TIMER1_COMPA) {  // make sure we don't get bitten by the watchdog    asm("wdr");  // If it has been less than STANDBY_TIMEOUT seconds since the last time we  // got a Hall Effect sensor update, then proceed as normal and  // update the LEDs.    // QUESTION: what is F_CPU?  ANSWER: FREQUENCY OF CPU (clocks/second)    // disabled because we only do 256 lines out, then turn ourselves off    // if (sensor_timer.bytes.high_byte < ( (F_CPU/NUM_PIXELS)/256 * STANDBY_TIMEOUT) / 256) {            // Increment # of pixels clocked out        curPixel++;        // If we have done all 256, then don't display anything more        if ( curPixel == 0 ) {          fleds[0] = fleds[1] = fleds[2] = fleds[3] = 0xFF;      TCCR1B &= ~_BV(CS10);		// no incrementing = no interrupting        } else if ( (curElement & 0xF0) == 0x10 ) {           // These are the shift modes; since shifting is done in the      // rev counter update, all we do is copy             fleds[0] = shiftReg.bytes.low_byte;      fleds[1] = shiftReg.bytes.byte_1;      fleds[2] = shiftReg.bytes.byte_2;      fleds[3] = shiftReg.bytes.high_byte;       } else if (curElement < 0x04) {          // Unfortunately, we can't do the cute "read from the EEPROM right      // into the LEDs trick" that limor can do in SpokePOV.  We have to      // read the data into the ATMEL and then write it out.          // In this early version, we could, but later versions will have      // some tricks, so keep it simple          // Modes 00,01,02,03 are the bitmap display modes          spieeprom_read(eepromPtr.word,fleds,4);	// read in the 4 bytes          #ifdef CLOCKWISE            eepromPtr.word += 4;						// increment the pointer          #else            eepromPtr.word -= 4;            #endif        } else if (curElement < 0x0A) {      // Assume all LEDs will be OFF - that's mode 0x04, btw...      // This is a space/time tradeoff here, with some careful      // ordering of the tests to binary-chop the possibilities            fleds[0] = 0xFF;                  if (curElement == 0x05) {                 // 0x05 - All LEDS on                fleds[0] = 0x00;                  } else if (curElement > 0x07) {            	// Modes 0x08 and 0x09      	        // compare the top 4 bits of curPixel with the lower 4 bits of        // curRev, if equal, let there be light, otherwise, we've already        // set it off.              if ( ( (curPixel >> 4) & 0x0F) == (curRev & 0x0F) ) {                fleds[0] = 0x00;                }                // Inverted version?                if (curElement == 0x09) {                  fleds[0] = ~fleds[0];                  }              } else if (curElement > 0x05) {        	// Modes 0x06 and 0x07    	        // compare the bottom 4 bits of curPixel with the lower 4 bits of        // curRev, if equal, let there be light, otherwise, we've already        // set it off.              if ( (curPixel & 0x0F) == (curRev & 0x0F) ) {                fleds[0] = 0x00;                }                // Inverted version?                if (curElement == 0x07) {                  fleds[0] = ~fleds[0];                  }              }            // Copy to all 4 led arrays               fleds[1] = fleds[2] = fleds[3] = fleds[0];             }        clock_scroll(0);							// send the 4 bytes  // }}// Interrupt 0 executes when the button is pressed.// QUESTION: unlike the pixel output interrupt, this one// doesn't sei().  Why?SIGNAL (SIG_INT0) {    // Wait until button no longer pressed    while (! (BUTTON_PIN & _BV(BUTTON))) {  }    if (sensor_timer.bytes.high_byte == 0xFF) {        // so in this instance, we set the watchdog to reset us        sensor_timer.bytes.high_byte = 0x00;          // Re-enable the watchdog timer, then loop until    // it fires off.          WDTCSR = _BV(WDE);    for (;;);        } else {          // We want to shut everything down.  Setting sensor_timer    // to the pin value will cause both the communications    // loop and the regular timeout loop in the main() to    // give up, which results in the device going to sleep.      

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -