main.c

来自「旋转16个LED灯控制程序」· C语言 代码 · 共 1,554 行 · 第 1/4 页

C
1,554
字号
// 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++;  #if NUM_LINES > 0    // Increment the line timer - we only need to do this    // if we are scrolling      line_timer++;				// increment the low byte    #endif  #ifdef DYNAMIC_TIME      // Increment the dynamic time fractional seconds byte        dynamicTimeCounter.word += DYNAMIC_TIME_CALIBRATION;        if (dynamicTimeCounter.bytes.high_byte > 0x7F) {          // wrap the counter             dynamicTimeCounter.bytes.high_byte &= 0x7F;             // Add 1 second to the time HH:MM:SS      //                          76-43-10      // Bytes in reverse order            // Increment seconds             dynamicTime[0]++;             // Check for units seconds overflow - has the digit become 10?             if ( dynamicTime[0] == ':' ) {               // If so, reset it and increment 10's digit                  dynamicTime[0] = '0';        dynamicTime[1]++;                // Repeat the process for the 10s seconds digit, has it become        // 6?                  if ( dynamicTime[1] == '6' ) {                     // reset it and increment minutes digit                        dynamicTime[1] = '0';           dynamicTime[3]++;                        // Repeat process for minutes                        if ( dynamicTime[3] == ':' ) {                 	 // You should get the idea now...          	           	 dynamicTime[3] = '0';          	 dynamicTime[4]++;                              	 if ( dynamicTime[4] == '6' ) {                         dynamicTime[4] = '0';               dynamicTime[6]++;                            // and 10s of hours                              if ( dynamicTime[6] == ':' ) {                                dynamicTime[6] = '0';                 dynamicTime[7]++;                                }                              // handle special wrap               			   #ifdef DYNAMIC_TIME_12H			   			     if ( (dynamicTime[7] == '1') && (dynamicTime[6] == '3') ) {			     			        dynamicTime[7] = '0';			        dynamicTime[6] = '1';			        			     }			     			   #else			   			     if ( (dynamicTime[7] == '2') && (dynamicTime[6] == '4') ) {			     			        dynamicTime[7] = dynamicTime[6] = '0';			        			     }			     			   #endif			                }           }         }       }     }       #endif                         // *** PORTB &= ~0x1;}// Hack - I used to copy the topChar, etc. variables into local// variables in the TIMER1 routine, but I am running out of stack space.  So instead// I'm going to keep interrupts off during this routine and// use the regular versions.  To make it easy to do this I'm// remapping the local variables with defines.  // #define USE_LOCAL_TIMER1	1// If USE_LOCAL_TIMER1 is not defined, then the TIMER1 routine will not// enable interrupts.  // As we sweep around the circle, we display 256 radial pixel// lines, once per TIMER1 interrupt.  This is broken down into// 16 16-pixel wide characters, and we have two characters// stacked vertically.  To save time, we keep track of the// character number, pixel number (in the character), and// pointers into the eeprom for each of the two chars being// displayed.// This code has to be fast enough to complete execution before// it gets interrupted again - and it must not make any subroutine// calls, since that'll mess up the stack and cause the entire// system to reset.volatile uint16_t topChar = 0;		// top character being displayed (address in EEPROM of data)volatile uint16_t botChar = 0;		// bottom character being displayedvolatile uint8_t charNum = 31;		// character numbervolatile uint8_t pixelNum = 15;		// pixel number#ifdef USE_LOCAL_TIMER1  volatile uint8_t clean = 0;	    // have these values been changed outside TIMER1?#endif#ifdef SMOOTHSCROLL  volatile uint16_t scrollChar = 0;	// extra scroll character#endif// 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.SIGNAL (SIG_TIMER1_COMPA) {  #ifdef USE_LOCAL_TIMER1      uint16_t tChar;					// local copies of the values    uint16_t bChar;    uint8_t cNum;						    uint8_t pNum;      #ifdef SMOOTHSCROLL      uint16_t sChar;					// extra scroll character    #endif    // When an interrupt routine is called, interrupts are disabled.    // but it's important to let other interrupts interrupt us, so    // they need to be re-enabled.	    sei();    // Copy the volatile variables into their local equivalents      tChar = topChar;    bChar = botChar;    cNum = charNum;    pNum = pixelNum;    #ifdef SMOOTHSCROLL       sChar = scrollChar;    #endif      #else      #define	tChar	topChar    #define	bChar	botChar    #define	cNum	charNum    #define	pNum	pixelNum    #define	sChar	scrollChar      #endif  // 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)    if (sensor_timer.bytes.high_byte < ( (F_CPU/NUM_PIXELS)/256 * STANDBY_TIMEOUT) / 256) {            // *** PORTA |= 0x1;        // The first thing we do is increment our character position; this    // is done here to avoid code duplication.  This means that the    // Hall Effect interrupt routine must set them up so they "wrap"    // into the first valid values.        // Move to the next pixel in the character        pNum++;        // If we have moved off the edge of the character, then    // we need to move to the next character        if (pNum == 16) {          // If we will wrap around to the first character, turn off the pixel      // timer, clear the display, and exit.  Might speed things up a bit            if (cNum == 15) {        TCCR1B &= ~0x7;        set_all(~0x00);        return;      }      pNum = 0;					// reset to first pixel      cNum = (cNum+1) & 0x0F;	// move, with wrap, to next character position                  // Now we need to reset the pointers to the correct addresses      // in the EEPROM for the characters they display.  With the new      // interleaved character sets, this becomes much easier            tChar = (topLine[cNum]-32) << 1;		// character offset for the top char, 0-95      // Ditto for bChar...            bChar = (botLine[cNum]-32) << 1;      	  #ifdef SMOOTHSCROLL			// and if smooth scrolling, sChar		  		sChar = (scrollLine[cNum]-32) << 1;		  	  #endif    } else {          // If we haven't wrapped around a character boundary, we just move      // to the next 2-byte line in the character set, which will be 192 bytes      // away            tChar += 192;      bChar += 192;      	  #ifdef SMOOTHSCROLL				sChar += 192;			  #endif    }         // 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.        spieeprom_read(tChar,fleds,2);		// the top 2 bytes    spieeprom_read(bChar,fleds+2,2);	// and the bottom 2        #ifdef SMOOTHSCROLL      spieeprom_read(sChar,fleds+4,2);	// and the scroll characters    #endif	// However, we do have a fancy trick of our own.  If we are	// smooth scrolling, then we clock out an extra line_shift	// BITS, thus implementing the smooth scrolling	    #ifdef SMOOTHSCROLL	  clock_scroll(line_shift);			// send 0-15 extra bits..	    #else      clock_scroll(0);					// just send the 4 bytes        #endif    // Now we increment the variables.  However, we    // only do it IF haven't been touched by some other part    // of the code while we were displaying the pixels.  Also, we    // turn interrupts off so that nobody else can touch them    // while we are at it        #ifdef USE_LOCAL_TIMER1        cli();        if (clean) {	  topChar = tChar;	  botChar = bChar;	  charNum = cNum;	  pixelNum = pNum;	        #ifdef SMOOTHSCROLL	    scrollChar = sChar;	      #endif

⌨️ 快捷键说明

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