spokepov.lss

来自「旋转16个LED灯控制程序」· LSS 代码 · 共 1,919 行 · 第 1/5 页

LSS
1,919
字号
  // likely the 1-second reset timer will go off before
  // this ends.  But no biggy, since if it does, it'll
  // reset the LEDs..
  
}
 
 
int main(void) {

  uint8_t buff[16];		// a buffer of 16 bytes read/written to EEPROM
  uint8_t i, n;			// loop variables
  uint8_t cmd;			// the reason we reset
  uint16_t addr;		// address to read/write in EEPROM

  // MCUSR is the MCU Status Register (page 40).  It tells us
  // why we reset, and a reset is the only way to get here.
  
  cmd = MCUSR;
  
  // The first order of business is to tell the chip that
  // we've got things under control.
  
  MCUSR = 0;
  
  // Turn on watchdog timer immediately, this protects against
  // a 'stuck' system by resetting it.
  
  // WDTCSR is the Watchdog Timer Control Register (page 45).
  // We set it so that it'll generate a watchdog interrupt
  // every second.  The idea is that if things mess up,
  // the watchdog will kickstart us.
  
  WDTCSR = _BV(WDE) | _BV(WDP2) | _BV(WDP1); // 1 second
  
  // Initialize the various pins of the ATMEL, and set up
  // the interrupts.
  
  ioinit();
  
  // We saved the reason for the reset of the chip.  If
  // it's a power-on, then we run a test pattern through
  // the LEDs.  Note that because we've set a 1-second
  // watchdog timer (in ioinit), if this test sequence
  // takes more than a second, the chip will reset.  But
  // since we'll know it isn't a power-on, the test
  // sequence won't run...
  
  if ((cmd & _BV(PORF)) != 0)
    test_leds();

  // display the reason for the reset on the LEDs.
  
  set_led(cmd+2);

  // enable the interrupts.  I think this is not needed
  // since it'll immediately be done by the loop, below.
  
  sei();
  
  // Now loop processing commands that come in over the
  // dongle.  This is how the EEPROMs are programmed.
  
  while (1) {
  
  	// Enable interrupts again
  	
  	sei();
    cmd = tx_computer_byte(0);

	// This break is the only way out of
	// this loop.  If it executes (probably because of
	// a timeout in tx_computer_byte()), then there is
	// no way back other than resetting the chip by
	// a long button-push.
	
    if (cmd == 0)
      break;
    else
    
      // Disable interrupts during command processing.
      
      cli();

	// Sensor_timer does double-duty here, as a timeout counter for
	// the communications link.  But this is OK since we never do
	// comm and display at the same time...
	
	// POSSIBLE BUG: it isn't cleared before the original cmd
	// byte read, and since interrupts are off, it won't be
	// incremented by the interrupt routine!
	
    sensor_timer = 0;      // overloaded to reset communications timeout

    switch (cmd) {

		// Read either a single byte, or 16 bytes, from either
		// the external or internal EEPROM.  If the high bit of
		// the address is 1, then it's an internal read.
		
		case COMP_CMD_RDEEPROM:
		case COMP_CMD_RDEEPROM16:

		  if  (cmd == COMP_CMD_RDEEPROM16)
			n = 16;
		  else
			n = 1;
	
		  // read 2 bytes to get the address
		  
		  addr = tx_computer_byte(0);
		  addr <<= 8;
		  addr |= tx_computer_byte(0);
		  
		  // internal or external?
		  
		  if ((addr & 0x8000) != 0) {
		  
		  	// there are only 256 bytes of internal eeprom
		  	
			tx_computer_byte(internal_eeprom_read(addr & 0xFF));
			
		  } else {
		
			// read and transfer 1 or 16 bytes
			
			spieeprom_read(addr, buff, n);
			for (i=0; i<n; i++) {
			  tx_computer_byte(buff[i]);
			}
			
		  }
	
		  // Tell the PC we're copacetic
		  
		  tx_computer_byte(COMP_SUCCESS);
		  break;
	
		// Write either a single byte or a block of 16.  Same
		// idea as above...
		
		case COMP_CMD_WREEPROM:
		case COMP_CMD_WREEPROM16:
		  
		  if (cmd == COMP_CMD_WREEPROM16)
			n = 16;
		  else
			n = 1;
	
		  addr = tx_computer_byte(0);
		  addr <<= 8;
		  addr |= tx_computer_byte(0);
		  
		  // Give a visual indication that we're loading data
		  
		  set_led((addr/16)%32); 
		  
		  // Receive the bytes
		  
		  for (i=0; i<n; i++) {
			buff[i] = tx_computer_byte(0);
		  }
	
		  // Tell the PC we got the data...
		  
		  tx_computer_byte(COMP_SUCCESS);
	
		  // ...and actually do the write
		  
		  if ((addr & 0x8000) != 0) {
			internal_eeprom_write(addr & 0xFF, buff[0]);
		  } else {
			spieeprom_write(addr, buff, n);
		  }
		  break;
    }
  
  }

  // Loop until we timeout, at which point the ATMEL is
  // put to sleep.  If the communications routine timed
  // out, or the user pressed the button for >500ms,
  // then sensor_timer will be 0xFFFF and we'll immediately
  // sleep.
  
  while (1) {
  
    // Reset the watchdog Timer.
    //
    // QUESTION: What's with toggling the PD0 output line here?
    // it doesn't seem to be connected to anything according to
    // the circuit diagram...
    
    PORTD |= 0x1;
    asm("wdr");
    PORTD &= ~0x1;

	// If the sensor_timer (incremented by TIMER0) maxes out
	// (in about 3 minutes), then sleep everything.
	
    if (sensor_timer == 0xFFFF) {
      
      // Avoid pesky interruptions
      
      cli();
      
      // Turn off all LEDs - I guess LED 0 is one of the "invisible ones"
      
      set_led(0);
      
      // Turn off power to the Hall Effect sensor.
      
      SENSOR_PORT &= ~_BV(SENSORPOWER);
      
      // Deselect EEPROM
      
      SPIEE_CS_PORT |= _BV(SPIEE_CS);      // pull CS high to deselect
      
      // Turn off Watchdog (must be restarted when we get the wakeup)
      // Wakeup will be via the button interrupt.
      
      WDTCSR |= _BV(WDCE) | _BV(WDE);
      WDTCSR = 0;
      MCUCR |= _BV(SM1) | _BV(SM0) | _BV(SE);
      
      // Re-enable interrupts so we can get the wakeup!
      
      sei();
     
      // Go into sleep mode
      
      asm("sleep");
    }
  }
  PORTD |= 0x2;
}

// Talk to the PC.  First a byte is sent, then a byte
// is received.  This is a simple form of handshaking.
//
// The assembly wdr instruction resets the watchdog
// timer so it won't cause everything to abort.
//
// POSSIBLE BUG: this function quits when sensor_timer
// maxes out.  But sensor_timer is incremented in an
// interrupt routine, and AFAICT interrupts are turned
// off in the communications loop (except for the
// cmd read, which is possibly the only time it's
// needed).  But in addition, it isn't cleared before
// that read, so the timeout may occur a lot faster
// that expected.
//
// POSSIBLE BUG: if it does time out, then the returned
// value v is undefined.
//
// I won't worry at this point about figuring out how
// this works!

uint8_t tx_computer_byte(uint8_t b) {
  uint8_t v;

  DDRA = 0x0;           				// outputs
  DDRB = 0x5F;          				// input on MOSI/DI (for SPI), all others output
  USICR = _BV(USIWM0) | _BV(USICS1);
  USIDR = b;                 			// transfer 0x0
  USISR = _BV(USIOIF);       			// ready
  while (! (USISR & _BV(USIOIF)) ) {
    asm("wdr");

    if (sensor_timer == 0xFFFF) { 
      stopcomputertx = 1;
    }
    
    if (stopcomputertx) {
      break;
    }
    
  }

  v = USIDR;

  DDRB = 0xDF; 
  USICR = 0;

  return v;
}

// Move data over the serial link (to the 1K/4K EEPROM or the
// LED shift registers, or both!)  This is black magic to me!

uint8_t spi_transfer(uint8_t c) {

  USIDR = c;
 17a:	8f b9       	out	0x0f, r24	; 15
  USISR = _BV(USIOIF);
 17c:	80 e4       	ldi	r24, 0x40	; 64
 17e:	8e b9       	out	0x0e, r24	; 14

  while (! (USISR & _BV(USIOIF))) {

    USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);
 180:	76 99       	sbic	0x0e, 6	; 14
 182:	04 c0       	rjmp	.+8      	; 0x18c <spi_transfer+0x12>
 184:	8b e1       	ldi	r24, 0x1B	; 27
 186:	8d b9       	out	0x0d, r24	; 13
 188:	76 9b       	sbis	0x0e, 6	; 14
 18a:	fd cf       	rjmp	.-6      	; 0x186 <spi_transfer+0xc>
    //NOP;  // slow down so that the eeprom isnt overwhelmed

  }

  return USIDR;
 18c:	8f b1       	in	r24, 0x0f	; 15

}
 18e:	99 27       	eor	r25, r25
 190:	08 95       	ret

00000192 <clock_leds>:
 192:	80 91 90 00 	lds	r24, 0x0090
 196:	f1 df       	rcall	.-30     	; 0x17a <spi_transfer>
 198:	80 91 8f 00 	lds	r24, 0x008F
 19c:	ee df       	rcall	.-36     	; 0x17a <spi_transfer>
 19e:	80 91 8e 00 	lds	r24, 0x008E
 1a2:	eb df       	rcall	.-42     	; 0x17a <spi_transfer>
 1a4:	80 91 8d 00 	lds	r24, 0x008D
 1a8:	e8 df       	rcall	.-48     	; 0x17a <spi_transfer>
 1aa:	94 9a       	sbi	0x12, 4	; 18
	...
 1b4:	94 98       	cbi	0x12, 4	; 18
 1b6:	08 95       	ret

000001b8 <set_led>:
 1b8:	28 2f       	mov	r18, r24
 1ba:	8f ef       	ldi	r24, 0xFF	; 255
 1bc:	80 93 90 00 	sts	0x0090, r24
 1c0:	80 93 8f 00 	sts	0x008F, r24
 1c4:	80 93 8e 00 	sts	0x008E, r24
 1c8:	80 93 8d 00 	sts	0x008D, r24
 1cc:	82 2f       	mov	r24, r18
 1ce:	86 95       	lsr	r24
 1d0:	86 95       	lsr	r24
 1d2:	86 95       	lsr	r24
 1d4:	e8 2f       	mov	r30, r24
 1d6:	ff 27       	eor	r31, r31
 1d8:	e3 57       	subi	r30, 0x73	; 115
 1da:	ff 4f       	sbci	r31, 0xFF	; 255
 1dc:	27 70       	andi	r18, 0x07	; 7
 1de:	81 e0       	ldi	r24, 0x01	; 1
 1e0:	90 e0       	ldi	r25, 0x00	; 0
 1e2:	02 c0       	rjmp	.+4      	; 0x1e8 <set_led+0x30>
 1e4:	88 0f       	add	r24, r24
 1e6:	99 1f       	adc	r25, r25
 1e8:	2a 95       	dec	r18
 1ea:	e2 f7       	brpl	.-8      	; 0x1e4 <set_led+0x2c>
 1ec:	80 95       	com	r24
 1ee:	80 83       	st	Z, r24
 1f0:	d0 df       	rcall	.-96     	; 0x192 <clock_leds>
 1f2:	08 95       	ret

000001f4 <__vector_2>:
 1f4:	1f 92       	push	r1
 1f6:	0f 92       	push	r0
 1f8:	0f b6       	in	r0, 0x3f	; 63
 1fa:	0f 92       	push	r0
 1fc:	11 24       	eor	r1, r1
 1fe:	2f 93       	push	r18
 200:	3f 93       	push	r19
 202:	4f 93       	push	r20
 204:	5f 93       	push	r21
 206:	6f 93       	push	r22
 208:	7f 93       	push	r23
 20a:	8f 93       	push	r24
 20c:	9f 93       	push	r25
 20e:	af 93       	push	r26
 210:	bf 93       	push	r27
 212:	ef 93       	push	r30
 214:	ff 93       	push	r31
 216:	c3 9a       	sbi	0x18, 3	; 24
 218:	80 91 8a 00 	lds	r24, 0x008A
 21c:	85 30       	cpi	r24, 0x05	; 5
 21e:	b0 f1       	brcs	.+108    	; 0x28c <__vector_2+0x98>
 220:	81 e0       	ldi	r24, 0x01	; 1
 222:	80 93 89 00 	sts	0x0089, r24
 226:	1d bc       	out	0x2d, r1	; 45

⌨️ 快捷键说明

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