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

📄 main copy.c

📁 旋转16个LED灯控制程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/******************************************CharPOV V1.07 firmwareCharPOV 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;/* Cute flag that can be used to easily comment out blocks of code			*/#define DONOTCOMPILE	1/* flag to determine whether we compile version that does smooth scrolling	*//* between lines, or the simpler jumping.  COMMENT OUT to disable!			*/#define SMOOTHSCROLL	1/* How many 8msec delays between each smooth scrolling increment.  This     *//* time * 16 is the line scroll delay time, even if not smooth scrolling	*/#define SCROLLSPEED		16/* Do we need the code for dynamic line update (RPM, etc)?	COMMENT OUT		*//* to disable this feature.													*/// #define DYNAMIC	1/* Define what dynamic features are being used (comment out to disable)		*///#define	DYNAMIC_REVCOUNT	1		// blade revolution counter//#define DYNAMIC_RPM			1		// RPM value//#define DYNAMIC_TIME		1		// Time of Day Clock (faked, of course)/* Do we permit half-shifted lines (so that odd and even length lines will	*//* center nicely.  Uses up extra memory.  Due to cheap way it's implemented,*//* must ensure first char of next line being displayed is blank!			*/#define HALFSHIFT	1/* The number of lines in our message - basically limited by the amount of	*//* program memory left over.  If NumLines is 0, then no scrolling will      *//* happen, and the display will be static (and must have 2 lines)		    */#define NUM_LINES 18/****************************************************************************//*                                                                          *//* 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 text of the message.  Since this is stored in FLASH, it requires		*//* a special method of accessing it.										*//* 0x7F is the last character, now a full block of bits, so useful for      *//* doing speed calculations vs. video										*//* First we have an array of offsets into the lines[] array.  For each		*//* line that is displayed, this points to the BYTE in lines[] the data is	*//* actually stored.  This level of indirection has two advantages; repeated	*//* lines (such as fully blank ones) need only be stored once, and we can	*//* eliminate the << 4 (*16) operation needed to go from line number to		*//* line offset in the PROGMEM												*//* As a further code-saving trick, lineOffsets must have NUM_LINES+2		*//* entries, and the last 2 entries duplicate the first two.  This means  	*//* that our lookup routine does not have to worry about wrapping around 	*//* when it indexes, which makes life simpler!								*//* lineOffsets is NOT used when NUM_LINES is 0; that would be a waste of	*//* time.																	*/#if (NUM_LINES != 0)  const uint8_t lineOffsets[] PROGMEM = {0x00,0x10,0x20,0x00,0x30,0x40,0x00,  										 0x50,0x60,0x70,0x80,0x90,0xA0,0xB0,0xC0,0xD0,0x00,  										 0xE0,0x00,0x10};#endif/* IMPORTANT: for some bizarre reason, if the firmware tries to display a	*//* colon in offset +7 (character 8) of the innermost line of the display,	*//* the atmel resets.  It's totally weird.  So either avoid that case, or use*//* a modified character set (I created one with | the same as :)			*//* semi-colon also has this problem AFAICT.									*//* If hibit of first byte is set, then the line is half-shifted RIGHT		*//* so 0xA0 is a space, set to half-shift the line							*/const char lines[] PROGMEM =	"                " // 00	"\xA0   T.O. 2006   " // 10	"   Thank-yous   " // 20	"\xA0  Peter Smith  " // 30	"\xA0  Nick Martin  " // 40	"   Solidworks   " // 50	"     Metfab     " // 60	"  Titanium Joe  " // 70	"  Team Whyachi  " // 80	"\xA0  Battlepacks  " // 90	"    Duralite    " // A0	"\xA0     Limor     " // B0	"\xA0     ATMEL     " // C0	"\xA0   AVRFreaks   " // D0	"\xA0 And Many More " // E0	;/* If we have dynamic data, then we need to define what it is and where it	*//* goes.  An array of bytes, 1 per line in lineOffsets[], tells us this		*//* info.  Note that this means that like lineOffsets, you need NUM_LINES+2	*//* entries, with the last 2 a duplicate of the first two...					*//* In order to keep things reasonable, you can only have one bit of dynamic *//* data being displayed at any time.  In other words, one per 2 lines if	*//* doing normal scrolling, or every 3 lines if doing smooth scrolling		*//* The high 4 bit define what we display, and the low 4 bits define what	*//* character position it ENDS at.  Like lines[], this is a PROGMEM.		    *//* Dynamic Info Codes:														*//*																			*//*		00 - No dynamic data in line										*//*		1x - 4 digit Rev Counter at character x-3							*//*		2x - 3 digit RPM display at character x-2 (note difference!)		*//*		3x - Time display (12:34:56)										*//* Note that you define pos of LAST character of the dynamic data, not the  *//* first.  Makes code simpler. 												*/#ifdef DYNAMIC  const uint8_t dInfo[] PROGMEM = {0x00,0x3B,0x00,0x00,0x2A,0x00,0x00,0x3B};  // We also need to store the current dynamic effect, and the location that  // needs to be updated in the RAM lines.  As this updating is done in the  // main loop, we need two copies of the pointer, since the interrupt  // routines will likely update the pointer while the main loop is trying  // to write stuff.  The reason we do updates in the main loop is in order  // to make the interrupt routines as fast as possible; the dynamic updating  // thus gets done with spare CPU cycles.    // Since only one active line can have a dynamic data, when the display  // scrolls and updates the ...Line[] arrays, the address will certainly  // change, so this is a reliable detection method.    // QUESTION: is the compiler smart enough to know that these pointers  // should only be 8 bits?    volatile char *dynamicPtr = NULL;  volatile uint8_t dynamicType = 0x00;    #ifdef DYNAMIC_REVCOUNT      volatile char dynamicREV[4] = "0000";		// 4 byte rev counter      // QUESTION: BCD to save ram space?      #endif    #ifdef DYNAMIC_RPM       volatile char dynamicRPM[3] = "000";		// 3 byte RPM counter       	 // Our big problem with RPM calculations is multiplication and division  	 // which we don't have space to do properly.  Now, at 8mhz, if the pixel  	 // clock is exactly 0x0100 (ie: TIMER0 counted exactly once per rev), then  	 // the revolution took (256*256)/8,000,000 of a second, or 0.008192 seconds.  	 // That corresponds to 7324.2 RPM, a speed we are unlikely to see anytime  	 // soon.  For simplicity, we'll only keep the top 3 digits of RPM and make  	 // the bottom digit 0.  	 //  	 // However, to get from our pixel clock timer value to the RPM/10 means we  	 // need to do (binary fractions) 732.0 / timerhi.timerlo, which is ugly.  	 // And on top of that, we then need to do /10's to get the digits.  Yuck!  	 //  	 // Instead, we use a special table lookup to compute the RPM directly into  	 // a 3 digit decimal number, using the usual sleazy tricks.  	 //  	 // QUESTION: can this be done BCD in order to save space?  	      const char div732[] PROGMEM =            /* UNCALIBRATED RPM VALUES.  Use these as a starting point              "\x00\x00\x01"		// use escapes so we don't have to convert between       "\x00\x00\x03"		// the actual digits and the ascii digit representation       "\x00\x00\x06"		// (+48).  Saves us a few bytes of code.       "\x00\x01\x01"       "\x00\x02\x03"       "\x00\x04\x06"       "\x00\x09\x02"       "\x01\x08\x03"       "\x03\x06\x06";  	     	   */  	     	   /* CALIBRATED RPM VALUES for my SpokePOV */  	     	   "\x00\x00\x01"  	   "\x00\x00\x03"  	   "\x00\x00\x05"  	   "\x00\x01\x01"  	   "\x00\x02\x02"  	   "\x00\x04\x03"  	   "\x00\x08\x06"  	   "\x01\x07\x03"  	   "\x03\x04\x05";  	     #endif    #ifdef DYNAMIC_TIME    	// Since we don't have a real clock source on the SpokePOV, we have to  	// fake it.  The trick here is to have a preset time that the chip  	// resets to when powered up or reset.  Start time is in reverse order,  	// so seconds come  first.  	  	// I modified my character set so that the | character is also :.  This  	// catches the weird "spastic colon" bug.  	  	volatile char dynamicTime[8] = "53|85|21";	// 12:58:35!  	  	// And a counter to store the fractions of a second.  Since our counting  	// interrupt happens about every 8ms, this needs to be a word.  We will  	// only use the first 15 bits though, so that the high bit can be used  	// to detect overflow.  Uninitialized to save space, this will cause at  	// most a 1 second error - so who cares!  	  	volatile var16bit dynamicTimeCounter;  	  	// We also need the amount to increment the fractional counter every  	// interrupt.  Since this happens about every 8ms, this number is a  	// starting point.  It will have to be tuned to give good time.  	  	// In my case, with the basic calibration of 262UL interrupts per  	// second, I was getting about 78 counts in 80 seconds.  So I made  	// the adjustment to make it a closer fit.  	  	#define DYNAMIC_TIME_CALIBRATION	(262UL * 80UL) / 78UL  	  	// Comment this out to have a 24H clock  	  	#define DYNAMIC_TIME_12H	1  	  #endif  #endif/* The following two 16-character arrays  define the message				*//* the SpokePOV is currently displaying.  They get updated from lines  		*/uint8_t topLine[16];uint8_t botLine[16];#ifdef SMOOTHSCROLL  uint8_t scrollLine[16];							// the extra line for doing the smooth scrolling#endif#ifdef HALFSHIFT  uint8_t halfSpace = ' ';							// empty char, halfspace overrun buffer!  #endif// QUESTION: What clock speed is the ATMEL set to run at in the SpokePOV kits?// QUESTION: How does one change that?// 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 seconds// How long until the SpokePOV goes into sleep mode.// NOTE: not actually used, it's hard-coded instead!#define POWEROFF_TIMEOUT 2*60   			// in seconds// Internal EEPROM storage locations		// not used in this app (yet)#define EEPROM_ROTATION_OFFSET 0x00			// rotation offset to compensate for magnet position#define EEPROM_MIRROR 0x01					// flag telling whether oppposite side LEDs are mirrored#define EEPROM_ANIMATION 0x02				// animation activation flag#ifdef SMOOTHSCROLL							// should also take into account NUM_LINES?  uint8_t fleds[6];							// pixel array for the front LEDs (need 6 bytes)#else  uint8_t fleds[4];							// pixel array for the front LEDs (need only 4)#endifvolatile uint8_t hall_debounce;				// count (via TIMER0) since last *used* Hall Effect detection

⌨️ 快捷键说明

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