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

📄 spokepov.lss

📁 旋转16个LED灯控制程序
💻 LSS
📖 第 1 页 / 共 5 页
字号:
        
        // 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 global versions.

// 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 displayed
volatile uint8_t charNum = 31;		// character number
volatile uint8_t pixelNum = 15;		// pixel number

#ifdef HALFSHIFT

  volatile uint8_t charNum2 = 31;		// character number
  volatile uint8_t pixelNum2 = 15;	// pixel number
	
#endif

#ifdef SMOOTHSCROLL

  volatile uint16_t scrollChar = 0;	// extra scroll character

  #ifdef HALFSHIFT

	volatile uint8_t charNum3 = 31;		// character number
	volatile uint8_t pixelNum3 = 15;	// pixel number
	
  #endif

#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) {

  // Because of the way the code's evolved, I have the vars just
  // defined above renamed via defines right here.  Just haven't
  // gotten around to grepping them...
  
  #define	tChar	topChar
  #define	bChar	botChar
  #define	cNum	charNum
  #define	pNum	pixelNum
  #define	sChar	scrollChar
  #define	cNum2	charNum2
  #define	cNum3	charNum3
  #define	pNum2	pixelNum2
  #define	pNum3	pixelNum3

  // 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;
    
    // If we are in normal mode, we use one shift for everyone
    
    #ifndef HALFSHIFT
    
      // 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

      }
     
    #else
    
      // Okay, we are doing half-shifts.  So we effectively have to do the
      // above code once for each line
      
      // Do for the first line.  Also use this to turn off the display if
      // we get to the end.  If first line is shifted, this'll turn us off
      // a half-char early, so other lines can't have anything in the last
      // character space...
      
      pNum++;
    
      if (pNum == 16) {
    
        if (cNum == 15) {
          TCCR1B &= ~0x7;
          set_all(~0x00);
          return;
        }

        pNum = 0;
        cNum = (cNum+1) & 0x0F;
            
        tChar = (topLine[cNum]-32) << 1;		// character offset for the top char, 0-95

      } else {
    
        tChar += 192;

      }
      
      // do for second line
      
      pNum2++;
    
      if (pNum2 == 16) {
    
        pNum2 = 0;
        cNum2 = (cNum2+1) & 0x0F;
            
        bChar = (botLine[cNum2]-32) << 1;

      } else {
    
        bChar += 192;

      }
      
      // and scroll line
      
      #ifdef SMOOTHSCROLL
      
        pNum3++;
    
        if (pNum3 == 16) {
    
          pNum3 = 0;
          cNum3 = (cNum3+1) & 0x0F;
            
          sChar = (scrollLine[cNum]-32) << 1;

        } else {
    
          sChar += 192;

        }
      
      #endif

    #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

  }

  // *** PORTB &= ~0x2;
  
}

// 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.
      
    sensor_timer.bytes.high_byte = 0xFF;
      
  }

}

// Interrupt 1 executes when the hall effect sensor fires

// QUESTION: unlike the pixel output interrupt, this one
// doesn't sei().  Why?

SIGNAL (SIG_INT1) {
  
  #if NUM_LINES > 0

    uint8_t cLine;		// temp var used in scroll code
 
  #endif
  
  #ifdef DYNAMIC
  
  	uint8_t dCode;		// temp var mostly used in dynamic code
  	
  #else					// also needed in this case
  
    #if NUM_LINES > 0
    
      uint8_t dCode;
      
    #endif
    
  #endif

  // make sure we don't get bitten by the watchdog
  
  asm("wdr");

  // *** PORTB |= 0x8;

  // The first issue we need to deal with when the hall-effect
  // sensor tells us it sees the magnet is to avoid doing any
  // processing if we get an interrupt too soon after the previous
  // interrupt.
  
  // hall_debounce is incremented by TIMER0, which fires every 3ms
  // or so.  At the current setting of 4, this means that at least
  // 15ms must elapse per trigger, which translates to about 4000
  // rpm.
  
  if (hall_debounce > HALL_DEBOUNCE_THRESH) {


  // We know the number of ms since the last hall sensor trigger
  // and there are 128 radial 'pixels' per sweep so divide to get
  // the necessary ms between the pixel interrupts
    
  // QUESTION: 128 or 256?
    
  // Then we just make TIMER1 trigger at that rate!
    
  // Reset the Timer Count Register for TIMER1 to 0, so it will
  // begin counting up.
    
  TCNT1 = 0;
    
  // sensor_timer contains the number of TIMER0 interrupts since
  // the last time we updated TIMER1.  If it has a reasonable

⌨️ 快捷键说明

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