Satashnik. More...
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include "usrat.h"
#include "rtc.h"
#include "util.h"
#include "voltage.h"
#include "buttonry.h"
#include "modes.h"
#include "cal.h"
Defines | |
#define | TIMERCOUNT 25 |
Functions | |
void | savingmode_keep (uint16_t hhmm) |
void | initdisplay () |
Init display-related DDRs. | |
uint8_t | swapbits (uint8_t x) |
Rehash bits to match the schematic. | |
uint16_t | getrawdigits (uint8_t h1, uint8_t h2, uint8_t m1, uint8_t m2) |
get raw digits from hh:mm | |
uint16_t | getrawdigits_bcd (uint16_t time) |
get raw digits from a BCD value | |
uint8_t | display_currentdigit (uint8_t n) |
Output the current digit code to ID1. | |
void | display_selectdigit (uint8_t n) |
void | fadeto (uint16_t t) |
uint16_t | get_display_value () |
Return current BCD display value. | |
void | timer0_init () |
ISR (TIMER0_OVF_vect) | |
void | calibrate_blinking () |
Calibrate blink counters to quarters of second. | |
int | main () |
Program main. | |
Variables | |
volatile uint16_t | time = 0 |
current display value | |
volatile uint16_t | timef = 0 |
fadeto display value | |
volatile uint8_t | digitmux = 0 |
displayed digit, 0..3 | |
volatile uint16_t | digitsraw = 0 |
raw port values | |
volatile uint16_t | rawfadefrom = 0177777 |
digitsraw fade from | |
volatile uint16_t | rawfadeto = 0177777 |
digitsraw fade to | |
volatile uint8_t | blinktick = 0 |
1 when a pressed button is autorepeated | |
volatile uint16_t | blinkctr |
blinkmode counter | |
volatile uint8_t | blinkduty |
blinkmode duty | |
volatile uint8_t | fadeduty |
volatile uint8_t | fadectr |
crossfade counters | |
volatile int16_t | fadetime |
crossfade time and trigger, write "-1" to start fade to timef | |
volatile uint8_t | halfbright |
keep low duty | |
uint16_t | bcq1 |
Values for blinking, calibrated to quarters of a second at startup. | |
uint16_t | bcq2 |
uint16_t | bcq3 |
Satashnik.
#define TIMERCOUNT 25 |
void calibrate_blinking | ( | ) |
Calibrate blink counters to quarters of second.
00289 { 00290 bcq1 = bcq2 = bcq3 = 65535; 00291 for(bcq1 = rtc_gettime(1); bcq1 == rtc_gettime(1);); 00292 blinkctr = 0; 00293 for(bcq1 = rtc_gettime(1); bcq1 == rtc_gettime(1);); 00294 cli(); 00295 bcq1 = blinkctr/4; 00296 bcq2 = 2*blinkctr/4; 00297 bcq3 = 3*blinkctr/4; 00298 sei(); 00299 }
uint8_t display_currentdigit | ( | uint8_t | n | ) |
void display_selectdigit | ( | uint8_t | n | ) |
Shut off previous anode, wait to prevent ghosting, output new digit code to ID1 and enable new anode
00123 { 00124 switch (n) { 00125 case SA1: 00126 PORTSA234 &= ~BV3(5,6,7); 00127 _delay_ms(0.01); //ghosting prevention 00128 if (display_currentdigit(n)) { 00129 PORTSA1 |= _BV(0); 00130 } 00131 break; 00132 case SA2: 00133 case SA3: 00134 case SA4: 00135 PORTSA1 &= ~_BV(0); 00136 PORTSA234 &= ~BV3(5,6,7); 00137 _delay_ms(0.01); //ghosting prevention 00138 if (display_currentdigit(n)) { 00139 PORTSA234 |= 0200 >> (n-1); 00140 } 00141 break; 00142 default: 00143 PORTSA234 &= ~BV3(5,6,7); 00144 PORTSA1 &= ~_BV(0); 00145 break; 00146 } 00147 }
void fadeto | ( | uint16_t | t | ) |
Start fading time to given value. Transition is performed in TIMER0_OVF_vect and takes FADETIME cycles.
00151 { 00152 uint16_t raw = getrawdigits_bcd(t); // takes time 00153 cli(); 00154 timef = t; 00155 rawfadeto = raw; 00156 fadetime = -1; 00157 sei(); 00158 }
uint16_t get_display_value | ( | ) | [inline] |
Return current BCD display value.
00161 { 00162 return timef; 00163 }
uint16_t getrawdigits | ( | uint8_t | h1, | |
uint8_t | h2, | |||
uint8_t | m1, | |||
uint8_t | m2 | |||
) |
uint16_t getrawdigits_bcd | ( | uint16_t | time | ) |
get raw digits from a BCD value
00103 { 00104 return getrawdigits((time & 0xf000)>>12, (time & 0x0f00)>>8, (time & 0x00f0)>>4, time & 0x000f); 00105 }
void initdisplay | ( | ) |
ISR | ( | TIMER0_OVF_vect | ) |
00173 { 00174 uint16_t toDisplay = time; 00175 static uint8_t odd = 0; 00176 00177 TCNT0 = 256-TIMERCOUNT; 00178 00179 odd += 1; 00180 00181 // Handle the dot, which must be sustained at all times 00182 // High-frequency short-duty seems to be an acceptable way 00183 // of keeping the gas ionized, yet practically invisible 00184 if ((odd & 7) < (( (dotmode == DOT_OFF || blinkctr>bcq2) && !(dotmode == DOT_ON)) ? 0:1) 00185 || ((dotmode == DOT_BLINK) && ((blinkctr <= 4) || ((odd & 0x7f) == 0)))) { 00186 PORTDOT |= _BV(DOT); 00187 } else { 00188 PORTDOT &= ~_BV(DOT); 00189 } 00190 00191 // Signal the main loop to continue rolling 00192 if ((odd & 0x3f) == 0) { 00193 blinktick |= _BV(2); 00194 } 00195 00196 // A "slow" cycle every 32 fast cycles, display business 00197 if ((odd & 0x1f) == 0) { 00198 // keep blinkctr for things that happen on 1/4ths of a second 00199 blinkctr++; 00200 if (blinkctr > (bcq2<<1)) { 00201 blinkctr = 0; 00202 } 00203 00204 // signal the main loop to autorepeat buttons when needed 00205 if (blinkmode_get() != BLINK_NONE) { 00206 if (blinkctr == bcq1 || blinkctr == bcq2 || blinkctr == bcq3 || blinkctr == 1) { 00207 blinktick |= _BV(1); 00208 } 00209 } 00210 00211 // fadetime == -1 indicates start of fade 00212 if (fadetime == -1) { 00213 if (fade_get() == FADE_OFF) { 00214 fadeduty = 1; 00215 fadetime = 1; 00216 } else { 00217 // start teh fade 00218 fadetime = fadetime_full; 00219 fadeduty = 4; 00220 fadectr = 0; 00221 } 00222 } 00223 00224 if (fadetime != 0) { 00225 fadetime--; 00226 00227 if (fadetime % fadetime_quart == 0) { 00228 fadeduty--; 00229 } 00230 00231 if (fadetime == 0) { 00232 fadectr = 0; 00233 time = timef; // end fade 00234 rawfadefrom = rawfadeto; 00235 } 00236 } 00237 00238 if ((fadectr>>3) < fadeduty) { 00239 toDisplay = rawfadefrom; 00240 } else { 00241 toDisplay = rawfadeto; 00242 } 00243 fadectr = (fadectr + 1) & 037; 00244 00245 // blinking (blinkmode & 0200 temporarily disables blinking) 00246 if (blinkmode_get() != BLINK_NONE && (blinkmode_get() & 0200) == 0 && blinkctr > bcq2) { 00247 switch (blinkmode_get()) { 00248 case BLINK_HH: 00249 toDisplay |= 0xff00; 00250 break; 00251 case BLINK_MM: 00252 toDisplay |= 0x00ff; 00253 break; 00254 case BLINK_ALL: 00255 toDisplay |= 0xffff; 00256 break; 00257 default: 00258 break; 00259 } 00260 } 00261 00262 digitsraw = toDisplay; 00263 } 00264 00265 // every other "slow" cycle, select the next digit... 00266 if ((odd & 0x1f) == 0) { 00267 display_selectdigit(digitmux); 00268 digitmux = (digitmux + 1) & 3; 00269 } else { 00270 // switch bright digits earlier 00271 if ((odd & 0x1f) == 0x18) { 00272 switch (PORTDIGIT & 017) { 00273 case 0x0a: // "3" 00274 display_selectdigit(0377); 00275 break; 00276 } 00277 } 00278 // shorten duty cycle for cathode-preserving modes 00279 if (halfbright == 2 && (odd & 0x1f) == 0x8) { 00280 display_selectdigit(0377); 00281 } 00282 if (halfbright == 1 && (odd & 0x1f) == 0x10) { 00283 display_selectdigit(0377); 00284 } 00285 } 00286 }
int main | ( | ) |
Program main.
00302 { 00303 uint8_t i; 00304 uint16_t rtime; 00305 uint8_t byte; 00306 volatile uint16_t skip = 0; 00307 uint8_t uart_enabled = 0; 00308 volatile uint16_t mmss, mmss1; 00309 00310 pump_nomoar(); 00311 00312 usart_init(F_CPU/16/19200-1); 00313 00314 printf_P(PSTR("\033[2J\033[HB%s WHAT DO YOU MEAN? %02x\n"), BUILDNUM, MCUCSR); 00315 00316 sei(); 00317 00318 voltage_start(); // start HV generation 00319 initdisplay(); 00320 dotmode_set(DOT_OFF); 00321 rtc_init(); 00322 buttons_init(); 00323 00324 // display greeting 00325 fade_set(FADE_SLOW); 00326 rtime = time = timef = 0xffff; 00327 timer0_init(); 00328 fadeto(0x1838); 00329 00330 // calibrate blink quarters and fadeout 00331 calibrate_blinking(); 00332 fade_set(FADE_SLOW); 00333 fadeto(0xffff); 00334 _delay_ms(500); 00335 00336 dotmode_set(DOT_BLINK); 00337 00338 wdt_enable(WDTO_250MS); 00339 00340 set_sleep_mode(SLEEP_MODE_IDLE); 00341 00342 for(i = 0;;i++) { 00343 wdt_reset(); 00344 00345 // handle keyboard commands 00346 if (uart_available()) { 00347 byte = uart_getchar(); 00348 switch (uart_enabled) { 00349 case 0: if (byte == 'z') 00350 uart_enabled = 1; 00351 else 00352 uart_enabled = 0; 00353 break; 00354 case 1: if (byte == 'c') 00355 uart_enabled = 2; 00356 else 00357 uart_enabled = 0; 00358 break; 00359 case 2: 00360 switch (byte) { 00361 case '`': pump_nomoar(); 00362 break; 00363 case '.': break; 00364 case '=': // die 00365 for(;;); 00366 break; 00367 default: 00368 break; 00369 } 00370 00371 if (byte >= '0' && byte <= '9') { 00372 byte = byte - '0'; 00373 fadeto((byte<<12)+(byte<<8)+(byte<<4)+byte); 00374 skip = 255; 00375 } 00376 00377 printf_P(PSTR("OCR1A=%d ICR1=%d S=%d V=%d, Time=%04x\n"), OCR1A, ICR1, voltage_setpoint_get(), voltage_get(), time); 00378 break; 00379 } 00380 } 00381 00382 buttonry_tick(); 00383 00384 if ((blinktick & _BV(1)) != 0) { 00385 blinktick &= ~_BV(1); 00386 if (blinkhandler != NULL) { 00387 blinkhandler(1); 00388 } 00389 } 00390 00391 if (skip != 0) { 00392 skip--; 00393 } else { 00394 mmss = rtc_gettime(1); 00395 if (!is_setting() && mmss != mmss1) { 00396 mmss1 = mmss; 00397 cli(); blinkctr = 0; sei(); 00398 } 00399 00400 rtime = rtc_gettime(0); 00401 00402 update_daylight(rtime); 00403 00404 savingmode_keep(rtime); 00405 00406 switch (mode_get()) { 00407 case HHMM: 00408 rtime = rtc_gettime(0); 00409 break; 00410 case MMSS: 00411 rtime = mmss; 00412 break; 00413 case VOLTAGE: 00414 rtime = voltage_getbcd(); 00415 break; 00416 } 00417 00418 if (!is_setting() && rtime != time && rtime != timef) { 00419 fadeto(rtime); 00420 } 00421 } 00422 00423 // just waste time 00424 while((blinktick & _BV(2)) == 0) { 00425 sleep_enable(); 00426 sleep_cpu(); 00427 } 00428 blinktick &= ~_BV(2); 00429 } 00430 }
void savingmode_keep | ( | uint16_t | hhmm | ) |
00059 { 00060 switch (savingmode_get()) { 00061 case SAVENIGHT: 00062 if (hhmm > 0x0100 && hhmm < 0x0700) { 00063 voltage_set(VOLTAGE_SAVE); 00064 halfbright = 2; // darkest 00065 } else if (hhmm < 0x0800) { 00066 voltage_set(VOLTAGE_SAVE); 00067 halfbright = 1; // dark 00068 } else { 00069 voltage_set(VOLTAGE_WASTE); 00070 halfbright = 0; // normal 00071 } 00072 break; 00073 case SAVE: 00074 voltage_set(VOLTAGE_SAVE); 00075 halfbright = 1; 00076 break; 00077 case WASTE: 00078 voltage_set(VOLTAGE_WASTE); 00079 halfbright = 0; 00080 break; 00081 } 00082 }
uint8_t swapbits | ( | uint8_t | x | ) |
void timer0_init | ( | ) |
Start timer 0. Timer0 runs at 1MHz The speed is dictated by the need to keep the neon dot ionized at all times
00167 { 00168 TIMSK |= _BV(TOIE0); // enable Timer0 overflow interrupt 00169 TCNT0 = 256-TIMERCOUNT; 00170 TCCR0 = _BV(CS01); 00171 }
uint16_t bcq1 |
Values for blinking, calibrated to quarters of a second at startup.
uint16_t bcq2 |
uint16_t bcq3 |
volatile uint16_t blinkctr |
blinkmode counter
volatile uint8_t blinkduty |
blinkmode duty
volatile uint8_t blinktick = 0 |
1 when a pressed button is autorepeated
volatile uint8_t digitmux = 0 |
displayed digit, 0..3
volatile uint16_t digitsraw = 0 |
raw port values
volatile uint8_t fadectr |
crossfade counters
volatile uint8_t fadeduty |
volatile int16_t fadetime |
crossfade time and trigger, write "-1" to start fade to timef
volatile uint8_t halfbright |
keep low duty
volatile uint16_t rawfadefrom = 0177777 |
digitsraw fade from
volatile uint16_t rawfadeto = 0177777 |
digitsraw fade to
volatile uint16_t time = 0 |
current display value
volatile uint16_t timef = 0 |
fadeto display value