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

📄 spokepov.lss

📁 旋转16个LED灯控制程序
💻 LSS
📖 第 1 页 / 共 3 页
字号:
 19c:	0f b6       	in	r0, 0x3f	; 63
 19e:	0f 92       	push	r0
 1a0:	11 24       	eor	r1, r1
 1a2:	8f 93       	push	r24
  
  // Wait until button no longer pressed
  
  while (! (BUTTON_PIN & _BV(BUTTON))) {
 1a4:	82 9b       	sbis	0x10, 2	; 16
 1a6:	fe cf       	rjmp	.-4      	; 0x1a4 <__vector_1+0xc>
  }
  
  if (sensor_timer.bytes.high_byte == 0xFF) {
 1a8:	80 91 66 00 	lds	r24, 0x0066
 1ac:	8f 3f       	cpi	r24, 0xFF	; 255
 1ae:	29 f4       	brne	.+10     	; 0x1ba <__vector_1+0x22>
    
    // so in this instance, we set the watchdog to reset us
    
    sensor_timer.bytes.high_byte = 0x00;
 1b0:	10 92 66 00 	sts	0x0066, r1
      
    // Re-enable the watchdog timer, then loop until
    // it fires off.
      
    WDTCSR = _BV(WDE);
 1b4:	88 e0       	ldi	r24, 0x08	; 8
 1b6:	81 bd       	out	0x21, r24	; 33
    for (;;);
 1b8:	ff cf       	rjmp	.-2      	; 0x1b8 <__vector_1+0x20>
      
  } 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;
 1ba:	8f ef       	ldi	r24, 0xFF	; 255
 1bc:	80 93 66 00 	sts	0x0066, r24
 1c0:	8f 91       	pop	r24
 1c2:	0f 90       	pop	r0
 1c4:	0f be       	out	0x3f, r0	; 63
 1c6:	0f 90       	pop	r0
 1c8:	1f 90       	pop	r1
 1ca:	18 95       	reti

000001cc <set_all>:
      
  }

}

// Interrupt 1 executes when the hall effect sensor fires

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

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

  // 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
  // value, then we use it to reset the TIMER1 clock.
    
  if ((sensor_timer.bytes.low_byte < 0xFF) && (sensor_timer.bytes.low_byte > 0x3)) {
    
    // TIMER1 works differently from TIMER0.  It's a 16-bit timer
    // that apparently increments at the system clock rate.
    //
    // Because TIMER0 increments at 1/256 of the clock rate, and
    // fires the interrupt only when it overflows, sensor_timer
    // is incremented once ever 256*256 cycles.
    //
    // We want TIMER1 to fire off 256 times around the loop, so
    // we can display 256 lines of pixels.  We do this by putting
    // sensor_timer into the high byte of TIMER1's comparator
    // value, and the residual of TIMER0 (what it's counted up
    // to since the last time sensor_timer was incremented) into
    // the low byte, effectively a fractional value!
    //
    // Since TIMER0 is incrementing at 1/256 of the rate of TIMER1,
    // this results in TIMER1 firing off 256 times per rotation,
    // with excellent time resolution.
    //
    // I was quite touched by the elegance of how this works out;
    // it may be able to handle the extreme RPMs of BrightSaber
    // without modification...
      
    // Set the TIMER1 comparator value.  As a hack to Limor's hack,
    // reduce the timing a little bit so that the display doesn't
    // span the full 360 degrees, thus giving us a little more time
    // around hall-effect interrupt time to do things.  An attempt
    // to get more speed, it doesn't seem to help - so back to the
    // old way of doing things.
    
    // OCR1A = ((sensor_timer << 8) | TCNT0) - (sensor_timer);
    
    // OCR1A = ((sensor_timer << 8) | TCNT0);
    
    OCR1AH = sensor_timer.bytes.low_byte;
    OCR1AL = TCNT0;
    
    // Clear the residual of TIMER0
      
    TCNT0 = 0;


    // Check the line timer; if it has reached a particular value
    // then decrement curTime.  If that hits zero, then increment
    // the curElementPtr and load in the new data
    
    if (line_timer >= SCROLLSPEED) {
    
      line_timer = line_timer - SCROLLSPEED;	// reset in a safe way that retains any residual
      
      curTime--;
      
      if (curTime == 0x00) {
      
        curElementPtr++;
        
        if (curElementPtr == NUM_ELEMENTS) {
          curElementPtr = 0;
        }
        
        curElement = pgm_read_byte(elementList+curElementPtr);
        curTime = pgm_read_byte(elementTime+curElementPtr);
        
      }

    }
    
    // figure out the eeprom start position
    
    eepromPtr.bytes.high_byte = curElement << 2;
    eepromPtr.bytes.low_byte = 0x00;
    
    // and the end position
    
    eepromLimit.bytes.high_byte = eepromPtr.bytes.high_byte+4;
    eepromLimit.bytes.low_byte = 0x04;
    
    // Start TIMER1 on its merry way...
      
    TCCR1B |= _BV(CS10);		// increment at clock/1
    TIMSK |= _BV(OCIE1A);		// enable interrupt when it matches OCR1A
    
  } else {
    
    // Since we don't have a valid setting for the rotation
    // speed, set a couple of LEDs to let the human know we
    // aren't dead yet, and turn off the timer.
      
    set_all(~0x03);
      
    TCCR1B &= ~_BV(CS10);		// no incrementing = no interrupting
    
    // reset the line timers so that when we get a valid spinup,
    // they will start clocking the lines across the display
    
    line_timer = SCROLLSPEED;		// delay figure, will trigger wrap
    
  }   
    
  // Whether we're displaying or not, we reset sensor_timer so we can
  // time the next revolution.
    
  sensor_timer.word = 0;

  }
  
  // Finally, reset hall_debounce so we won't execute the timer reset code
  // until the Hall Effect sensor hasn't bothered us for a reasonable while.
  
  hall_debounce = 0;
  
  // *** PORTB &= ~0x8;

}

// Initialize the IO pins on the ATMEL.

void ioinit(void) {

  // Set the data direction for the PORTD and PORTB pins; see the
  // circuit diagram for more information on this.
  
  DDRD = 0x73; // input on PD2 (button), PD3 (sensor), all other output
  DDRB = 0xDF; // input on MOSI/DI (for SPI), all others output

  // Deselect EEPROM.  Not being an EE, I'm not going to worry about
  // how the ATMEL talks to the EEPROM.  It's black magic.
  
  PORTB = _BV(SPIEE_CS);

  // Just above, we set PD2 and PD3 to input.  If we now set those
  // bits to 1, they set into pullup mode (again, not EE, claim
  // ignorance), which is essential for them to work.  We also set
  // the SENSORPOWER bit to 1, which sends out little dribbles of
  // electrons to the hall effect sensor (see circuit diagram)
  //
  // Finally, we write 0's to the FRONT and BACK pins, which control
  // which bank of 30 LEDs we are talking to.  Having both of these
  // on at the same time probably causes horrible things to happen.
  
  PORTD = (_BV(BUTTON) | _BV(SENSOR) | _BV(SENSORPOWER))  
    & ~_BV(FRONT) & ~_BV(BACK);

  // Rather than poll to see when the hall effect sensor and
  // button are pressed, we configure an interrupt handler.  If you
  // look at the circuit diagram, you'll see that PD3 and PD2, which
  // are wired to SENSOR IN and BUTTON IN, do double-duty as INT1
  // and INT0.  They are both SUPPOSEDLY set to interrupt on the
  // falling edge of a pulse from the devices.  (Page 63)
  
  // POSSIBLE BUG: ISC0{1,0} seems to be being set to 00, not 10
  // as ISC1{1,0} is being set to.  So ISC0 will trigger when
  // the button interrupt line goes low.  Either this is a bug,
  // or the original comment was not correct (likely, IMHO)
  
  MCUCR = _BV(ISC11) & ~_BV(ISC01) & ~_BV(ISC00) &  ~_BV(ISC10);

  // Activate the interrupts by setting the General Interrupt Mask
  // Register (Page 63)
  
  GIMSK = _BV(INT1) | _BV(INT0);

  // The ATMEL has built-in timers that can trigger an interrupt.
  // SpokePOV uses them to update the LEDs 256 times per rotation.
  
  // Timer 0 is set to update at a rate system-clock / 256 and
  // interrupt when it overflows (8 bit).  This means that it
  // triggers every 65536 cycles.
  
  TCCR0A = 0;				// normal, overflow (count up to 256 == num pixels)
  TCCR0B = _BV(CS02);		// clk/256
  TIMSK |= _BV(TOIE0);		// turn on overflow interrupt
  
  // Timer 1 (T1) is the pixel timer, which is used to update the
  // LEDs 256 times per rotation.  It's set up as a normal timer
  // as well.  See Page 108&71; it is apparently being set into CTC
  // mode 4.  This means that the counter is compared to a 16-bit value
  // and interrupts when it reaches this value.
  //
  // Adjusting this value is how the SpokePOV compensates for
  // changes in the rotation speed of the device.
  //
  // Note that at this point, the timer is initialized, but not
  // activated.
  
  TCCR1A = 0;
  TCCR1B = _BV(WGM12);

  // Clear the debounce values, which I haven't sussed out yet.
  
  hall_debounce = 0;
  sensor_timer.word = 0;
  
  // set the element variables so they'll wrap around.
  
  curElementPtr = NUM_ELEMENTS-1;
  curTime = 0x01;
  
}

// Set all the LEDs on a side to have the same
// repeating 8-bit value (ie: 0x00 = all on, 0xFF = all off)
// Added by RJW to permit a more comprehensive reset display

void set_all(uint8_t blockValue) {

  fleds[0] = fleds[1] = fleds[2] = fleds[3] = blockValue;
 1cc:	80 93 6c 00 	sts	0x006C, r24
 1d0:	80 93 6b 00 	sts	0x006B, r24
 1d4:	80 93 6a 00 	sts	0x006A, r24
 1d8:	80 93 69 00 	sts	0x0069, r24
  
  clock_scroll(0);
 1dc:	80 e0       	ldi	r24, 0x00	; 0
 1de:	43 df       	rcall	.-378    	; 0x66 <clock_scroll>
 1e0:	08 95       	ret

000001e2 <__vector_2>:
 1e2:	1f 92       	push	r1
 1e4:	0f 92       	push	r0
 1e6:	0f b6       	in	r0, 0x3f	; 63
 1e8:	0f 92       	push	r0
 1ea:	11 24       	eor	r1, r1
 1ec:	2f 93       	push	r18
 1ee:	3f 93       	push	r19
 1f0:	4f 93       	push	r20
 1f2:	5f 93       	push	r21
 1f4:	6f 93       	push	r22
 1f6:	7f 93       	push	r23
 1f8:	8f 93       	push	r24
 1fa:	9f 93       	push	r25
 1fc:	af 93       	push	r26
 1fe:	bf 93       	push	r27
 200:	ef 93       	push	r30
 202:	ff 93       	push	r31
 204:	a8 95       	wdr
 206:	80 91 64 00 	lds	r24, 0x0064
 20a:	85 30       	cpi	r24, 0x05	; 5
 20c:	08 f4       	brcc	.+2      	; 0x210 <__vector_2+0x2e>
 20e:	66 c0       	rjmp	.+204    	; 0x2dc <__vector_2+0xfa>
 210:	1d bc       	out	0x2d, r1	; 45
 212:	1c bc       	out	0x2c, r1	; 44
 214:	80 91 65 00 	lds	r24, 0x0065
 218:	8f 3f       	cpi	r24, 0xFF	; 255
 21a:	09 f4       	brne	.+2      	; 0x21e <__vector_2+0x3c>
 21c:	53 c0       	rjmp	.+166    	; 0x2c4 <__vector_2+0xe2>
 21e:	80 91 65 00 	lds	r24, 0x0065
 222:	84 30       	cpi	r24, 0x04	; 4
 224:	08 f4       	brcc	.+2      	; 0x228 <__vector_2+0x46>
 226:	4e c0       	rjmp	.+156    	; 0x2c4 <__vector_2+0xe2>
 228:	80 91 65 00 	lds	r24, 0x0065
 22c:	8b bd       	out	0x2b, r24	; 43
 22e:	82 b7       	in	r24, 0x32	; 50
 230:	8a bd       	out	0x2a, r24	; 42
 232:	12 be       	out	0x32, r1	; 50
 234:	80 91 60 00 	lds	r24, 0x0060
 238:	80 31       	cpi	r24, 0x10	; 16
 23a:	68 f1       	brcs	.+90     	; 0x296 <__vector_2+0xb4>
 23c:	80 91 60 00 	lds	r24, 0x0060
 240:	80 51       	subi	r24, 0x10	; 16
 242:	80 93 60 00 	sts	0x0060, r24
 246:	80 91 63 00 	lds	r24, 0x0063
 24a:	81 50       	subi	r24, 0x01	; 1
 24c:	80 93 63 00 	sts	0x0063, r24
 250:	90 91 63 00 	lds	r25, 0x0063

⌨️ 快捷键说明

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