📄 spokepov.lss
字号:
// 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 + -