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 + -
显示快捷键?