/*
De FrequentieStandaard.
Pros 2010
*/
#define F_CPU 16000000UL
#define YES 0x55
#define NO 0xAA
#define RST 0x5A
#define MORE 0xA5
#define NOK 0x96
#define MAXLEN 170
#define MINLEN 95
#define REFLEN 133
#define DCF77PORT PIND
#define DCF77 PIND2
// Om te vermijden dat xemacs elke ISR als "ISR" in het Functions-menu toont:
#define ISR_TIMER0_COMPA ISR
#define ISR_TIMER2_COMPA ISR
#define ISR_USART_RX ISR
#define ISR_INT0 ISR
char text[64];
char *val, cmd;
volatile char hextekens[] = "0123456789ABCDEF";
volatile unsigned char DCF_compleet, PULS_stop, time_init = NOK;
volatile unsigned char dcf_minuten[3], dcf_uren[3], dcf_tm_cnt, DCF77_bits[60], DCF77_bitcnt;
volatile unsigned char frequentiekeuze, sign, verbose_flag, secondenflag, PULS_start, tcnt0_err;
volatile unsigned char my_seconden, my_minuten, my_uren, ovf_cnt, up_seconden, up_minuten, up_uren;
volatile unsigned int DCF77_stat, Afwijking;
volatile unsigned int tmp, adc, adc_gem, CNT_now, CNT_gem[2], up_dagen, milliseconden, DCF77_pulsduur, DCF77_minuut_cnt;
volatile unsigned long Err_H, Err_L, Err_OK, DCF77_tics, DCF77_errs, OCR1A_gemiddeld, Temperatuur;
#ifndef P
#define P(s) ({static const char c[] __attribute__ ((progmem)) = s;c;})
#endif
#define uart_sendstr_P(__s) uart_sendstr_p(P(__s))
#define uart_sendchar(x) loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = x
#define nl() loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = '\n'
#define OK() uart_sendstr_P(" OK\n")
#define ERR() uart_sendstr_P(" ERR\n")
#define UART_BUFSIZE 32
static char uart_outbuf[UART_BUFSIZE + 1], uart_rxbuf[UART_BUFSIZE + 1];
volatile unsigned char uart_pos, uart_linecomplete;
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <compat/deprecated.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util/delay.h>
#define delay(x) _delay_loop_1(x)
void delay_ms(unsigned int ms)
{
for (; ms > 0; ms--) {
_delay_ms(0.99);
}
}
void delay_us(unsigned int us)
{
for (; us > 0; us--) {
_delay_us(0.95);
}
}
#include "Version.h"
#include "3W-LCD.c"
ISR_TIMER0_COMPA(TIMER0_COMPA_vect)
{ // Hier komen we 125 maal per seconde voorbij
ovf_cnt++; // overflow-counter verhogen
if (ovf_cnt == 60) { // Staat de tellerstand op 60, dan geven we
secondenflag = 1; // main() een seintje, (begin nieuwe seconde),
PORTB |= _BV(PB0); // en maken we PB0 hoog, de LED licht op
} else if (ovf_cnt == 70) { // Als de teller op 15 staat,
PORTB &= ~(_BV(PB0)); // maken we PB0 laag - de LED dooft
} else if (ovf_cnt == 125) { // Als de overflow-counter op 125 staat
ovf_cnt = 0; // Maken we hem terug 0,
}
}
ISR_TIMER2_COMPA(TIMER2_COMPA_vect)
{ // Timer2 is zodanig ingesteld,
milliseconden++; // dat hij elke milliseconde een interrupt produceert
}
ISR_USART_RX(USART_RX_vect)
{ // Een interrupt van de UART
unsigned char c;
char *from, *to, cnt;
c = UDR0;
uart_rxbuf[uart_pos] = c; // In buffer plaatsen
if ((c == '\n') || (uart_pos > (UART_BUFSIZE - 1))) { // Buffer vol of EOL?
uart_rxbuf[uart_pos] = 0; // '\n' vervangen door 0
from = uart_rxbuf;
to = uart_outbuf;
for (cnt = 0; cnt < UART_BUFSIZE; cnt++) {
*to = *from; // Buffer copiëren
if (*to == 0) { // waarbij we stoppen als we een '0' tegenkomen
break;
}
from++;
to++;
}
uart_linecomplete = 1; // Signaleren aan main()
uart_pos = 0;
} else {
uart_pos++;
}
}
void uart_sendstr(char *s)
{ // send string to the rs232
while (*s) {
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = *s;
s++;
}
}
void uart_sendstr_p(const prog_char * progmem_s)
{ // print string from program memory on rs232
unsigned char c;
while (1) {
c = pgm_read_byte(progmem_s++);
if ((c == 0) || (c > 252)) {
return;
} else {
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
}
}
}
void UI2RS232(unsigned int getal)
{ // Verstuur een unsigned int over de RS232-lijn
unsigned char decade, nulflag = 0;
decade = 0;
while (getal > 9999) {
decade++;
getal -= 10000;
}
if (decade > 0) {
nulflag++;
uart_sendchar(decade + '0');
}
decade = 0;
while (getal > 999) {
decade++;
getal -= 1000;
}
if ((decade > 0) || (nulflag > 0)) {
nulflag++;
uart_sendchar(decade + '0');
}
decade = 0;
while (getal > 99) {
decade++;
getal -= 100;
}
if ((decade > 0) || (nulflag > 0)) {
nulflag++;
uart_sendchar(decade + '0');
}
decade = 0;
while (getal > 9) {
decade++;
getal -= 10;
}
if ((decade > 0) || (nulflag > 0)) {
nulflag++;
uart_sendchar(decade + '0');
}
uart_sendchar((unsigned char) (getal) + '0');
}
ISR_INT0(INT0_vect)
{ // Een interrupt van de DCF77-module
unsigned char tcnt0, ovcnt;
tcnt0 = TCNT0;
DCF77_pulsduur = milliseconden; // Noteren hoelang de DCF77-puls duurde
milliseconden = 0; // teller terug op 0 zetten
ovcnt = ovf_cnt;
// Het externe DCF77-signaal komt binnen via een optocoupler, die INVERTEERT!!!
CNT_now = tcnt0 + (ovcnt * 125);
if ((DCF77PORT & _BV(DCF77)) == 0) { // DCF77-pin laag = DCF77-signaal hoog = begin puls
PULS_start = YES;
if (DCF77_pulsduur > 1500) { // Seconde-puls gemist?
DCF77_bitcnt = 0; // De volgende puls is het begin van een nieuwe minuut
dcf_minuten[0] = dcf_minuten[1];
dcf_uren[0] = dcf_uren[1];
if (time_init == NOK) { // Moeten we de tijd nog instellen?
if ((DCF77_stat > 1000) && (up_minuten > 5)) {
TCNT0 = 60; // Seconden-tellers halfweg zetten
ovf_cnt = 60;
time_init = YES; // Dit doen we maar één maal, tenzij op bevel
my_seconden = 0; // Seconden op 0
my_minuten = dcf_minuten[1]; // Minuten overnemen
my_uren = dcf_uren[1]; // Uren overnemen
secondenflag = 0;
CNT_gem[0] = 37800;
CNT_gem[1] = 37800;
DCF77_errs = 0;
}
} else {
DCF_compleet = YES; // Melden aan main()
DCF77_stat++; // Betrouwbaarheids-cijfer verhogen
}
} else if (DCF77_pulsduur < 600) { // Vorige puls minder dan 600mS geleden?
DCF77_stat = 0; // Ook dat is niet normaal - melden aan loop()
DCF77_errs++;
if (verbose_flag != NO) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("ISR(INT0_vect) Twee pulsen kort na mekaar\n");
}
}
} else { // DCF77-pin hoog = DCF77-signaal laag = einde puls
PULS_stop = YES; // Signaleren
}
}
void check_puls(void)
{ // Verwerk een binnengekomen puls
unsigned char nibble_L, nibble_H;
PULS_stop = NO;
if (DCF77_pulsduur < (MINLEN / 2)) { // Héél korte puls?
DCF77_stat = 0; // Niet goed; status op 0
DCF77_errs++;
if (verbose_flag != NO) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("check_puls() DCF77_pulsduur te kort\n");
}
return;
} else if (DCF77_pulsduur < REFLEN) { // Korte puls?
DCF77_stat++;
DCF77_bits[DCF77_bitcnt] = 0;
} else if (DCF77_pulsduur > (MAXLEN * 2)) { // Puls véél te lang?
DCF77_stat = 0;
DCF77_errs++;
if ((verbose_flag != NO) && (time_init != NOK)) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("check_puls() DCF77_pulsduur te lang\n");
}
return;
} else { // Lange puls?
DCF77_bits[DCF77_bitcnt] = 1;
DCF77_stat++;
}
switch (DCF77_bitcnt) {
case 25: // Volgende minuut berekenen
dcf_minuten[2] = dcf_minuten[1] + 1;
if (dcf_minuten[2] > 59) {
dcf_minuten[2] = 0;
}
break;
case 27: // volle minuten ontvangen?
nibble_L = DCF77_bits[21]; // We gebruiken geen loop,
nibble_L |= (DCF77_bits[22] * 2); // maar gaan rechtuit.
nibble_L |= (DCF77_bits[23] * 4); // Dat levert een grotere code op,
nibble_L |= (DCF77_bits[24] * 8); // maar het gaat sneller vooruit
nibble_H = DCF77_bits[25];
nibble_H |= (DCF77_bits[26] * 2);
nibble_H |= (DCF77_bits[27] * 4);
dcf_minuten[1] = nibble_L + (nibble_H * 10);
break;
case 28:
if (dcf_minuten[1] > 59) {
DCF77_stat = 0; // Da's fout
DCF77_errs++;
if ((verbose_flag != NO) && (time_init != NOK)) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("check_puls() Meer dan 59 minuten\n");
}
}
break;
case 30: // Minuten checken
if (dcf_minuten[2] == dcf_minuten[1]) {
DCF77_stat++;
} else {
DCF77_stat = 0;
DCF77_errs++;
if ((verbose_flag != NO) && (time_init != NOK)) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("check_puls() Minuten stemmen niet overeen met hetgeen berekend was\n");
}
}
break;
case 32: // Volgend uur berekenen
if (dcf_minuten[2] == 0) {
dcf_uren[2] = dcf_uren[1] + 1;
if (dcf_uren[2] > 23) {
dcf_uren[2] = 0;
}
} else {
dcf_uren[2] = dcf_uren[1];
}
break;
case 34: // uren ontvangen?
nibble_L = DCF77_bits[29];
nibble_L |= (DCF77_bits[30] * 2);
nibble_L |= (DCF77_bits[31] * 4);
nibble_L |= (DCF77_bits[32] * 8);
nibble_H = DCF77_bits[33];
nibble_H |= (DCF77_bits[34] * 2);
dcf_uren[1] = nibble_L + (nibble_H * 10);
break;
case 35:
if (dcf_uren[1] > 23) {
DCF77_stat = 0;
DCF77_errs++;
if ((verbose_flag != NO) && (time_init != NOK)) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("check_puls() Meer dan 23 uren\n");
}
}
break;
case 36: // Uren checken
if (dcf_uren[2] == dcf_uren[1]) {
DCF77_stat++;
} else {
DCF77_stat = 0;
DCF77_errs++;
if ((verbose_flag != NO) && (time_init != NOK)) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("check_puls() Uren stemmen niet overeen met hetgeen berekend was\n");
}
}
break;
default: // De rest negeren we
break;
}
if (DCF77_bitcnt < 59) {
DCF77_bitcnt++;
} else { // Meer dan 59 DCF77-pulsen na mekaar?
DCF77_stat = 0; // Fout!
DCF77_errs++;
if ((verbose_flag != NO) && (time_init != NOK)) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
uart_sendstr_P("check_puls() DCF77_bitcnt te hoog\n");
}
}
if (DCF77_stat > 50000) {
DCF77_stat = 50000; // Overflow vermijden
}
}
void init(void)
{
unsigned char cnt;
unsigned long tmp;
CLKPR = (1 << CLKPCE);
CLKPR = 0; // Set max. system-clk
uart_pos = 0;
uart_linecomplete = 0; // Initialiseer de UART
UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0); // enable tx/rx and interrupt on rx
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); // 8N1
UBRR0H = 0;
UBRR0L = (F_CPU / (16 * 38400UL)) - 1; // set baudrate - 38400bd
lcd_init(); // Initialiseer het LCD
lcd_clrscr();
lcd_puts_P("FrequentieStandaard.");
lcd_gotoyx(3, 0);
lcd_puts_P(" Initialising.");
for (cnt = 0; cnt < 6; cnt++) {
delay_ms(500);
lcd_char('.');
}
lcd_gotoyx(4, 8);
lcd_puts_P("..done");
delay_ms(3000);
EICRA = _BV(ISC00); // Interrupt bij op- en neergaande flank
EIMSK = _BV(INT0); // Enable INT0
// Counter0, geholpen door de overflow-ISR, deelt de CPU-frequentie door 16000000
TCCR0A = _BV(WGM01); // CTC-mode
TCCR0B = _BV(CS00) | _BV(CS02); // 16000000 / 1024 = 15625
OCR0A = 124; // 15625 / 125 = 125
TCNT0 = 0;
TIMSK0 = _BV(OCIE0A); // Enable compare-interrupt
// Counter1 regelt de voedingsspanning v/d oscillator, daarmee kan de frequentie 80Hz gevarieerd worden
// Op een frequentie van 16MHz is dat 5ppm, minder dan 0.0005ppm/stap
TCCR1A = _BV(WGM11) | _BV(COM1A1); // 16-bit fast-PWM
ICR1 = 64999; // Resolutie = 1/65000 = 0.013mV
TCCR1B = _BV(CS10) | _BV(WGM12) | _BV(WGM13); // geen prescaler
OCR1A = 22000;
DDRB |= _BV(PB1); // OC1A (PB1) = PWM-uitgang
// Counter2 doet dienst als milliseconden-teller voor de DCF77-timing
TCNT2 = 0;
TCCR2A = _BV(WGM21); // CTC-mode
TCCR2B = _BV(CS22); // Prescaler = 64; CLK = 250kHz
OCR2A = 249; // 250kHz / 250 = 1kHz
TIMSK2 = _BV(OCIE2A); // Interrupt bij compare-match
// De ADC meet de temperatuur van de oven
ADMUX = _BV(REFS0) | _BV(REFS1); // 1.1V = ADC-ref
ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
ADCSRA |= _BV(ADSC); // Start dummy conversie
while ((ADCSRA & _BV(ADSC)) != 0) { // Effe wachten tot ADSC terug laag is
}
// Wat I/O-pinnen instellen
DDRD = _BV(PD5) | _BV(PD6) | _BV(PD7); // PD5, PD6 en PD7 sturen de frequentiekiezer (GAL16V8)
PORTD = _BV(PD2) | _BV(PD3); // Pull-ups van PD2 en PD3 activeren
frequentiekeuze = 4; // 1MHz = default uitgangsfrequentie
PORTD &= ~(_BV(PD5) | _BV(PD6) | _BV(PD7));
PORTD |= (frequentiekeuze << 5);
DDRB |= _BV(PB0); // PB0 gebruiken we om een seconden-LED te sturen
lcd_clrscr();
lcd_puts_P("FrequentieStandaard.");
lcd_gotoyx(2, 2);
lcd_puts(Versie);
lcd_gotoyx(3, 0);
lcd_puts_P(" Warming up ");
for (cnt = 0; cnt < 100; cnt++) {
ADCSRA |= _BV(ADSC);
while ((ADCSRA & _BV(ADSC)) != 0) {
}
tmp = (unsigned long) (ADC) * 11000UL; // 1023 = 1100mV = 110°C
tmp /= 1023;
lcd_gotoyx(3, 13);
UI2LCD(tmp);
lcd_char(0xDF);
lcd_char('C');
if (tmp > 360) { // Meer dan 38´C? OK
break;
}
delay_ms(1000);
}
delay_ms(2000);
CNT_gem[0] = 50000;
DCF77_errs = 0;
DCF77_minuut_cnt = 0;
DCF77_stat = 0;
DCF77_tics = 0;
Err_H = 0;
Err_L = 0;
Err_OK = 0;
PULS_start = NO;
milliseconden = 0;
my_minuten = 0;
my_seconden = 0;
my_uren = 0;
secondenflag = 0;
tcnt0_err = 0;
up_dagen = 0;
up_minuten = 0;
up_seconden = 0;
up_uren = 0;
verbose_flag = NO;
sei();
lcd_clrscr();
}
void init_again(void)
{
cli();
CNT_gem[0] = 50000;
DCF77_errs = 0;
DCF77_minuut_cnt = 0;
DCF77_stat = 0;
DCF77_tics = 0;
Err_H = 0;
Err_L = 0;
Err_OK = 0;
OCR1A = 22000;
PULS_start = NO;
milliseconden = 0;
my_minuten = 0;
my_seconden = 0;
my_uren = 0;
secondenflag = 0;
tcnt0_err = 0;
up_dagen = 0;
up_minuten = 0;
up_seconden = 0;
up_uren = 0;
if (verbose_flag != NO) {
sprintf(text, "%02d:%02d:%02d init_again()\n", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
}
sei();
lcd_clrscr();
}
void switch_freq(unsigned char hl)
{
if (hl == 0) { // Lagere frequentie?
frequentiekeuze++; // Dan hoger GAL-adres
if (frequentiekeuze > 6) { // hoger dan 6
frequentiekeuze = 0; // We hebben maar 7 standen (0 ... 6)
}
} else { // Hogere frequentie.
frequentiekeuze--; // Lager GAL=adres
if (frequentiekeuze > 6) { // 0x00 -> 0xFF?
frequentiekeuze = 6; // Dan springen we naar 1
}
}
frequentiekeuze &= 0x07;
PORTD &= ~(_BV(PD5) | _BV(PD6) | _BV(PD7));
PORTD |= (frequentiekeuze << 5);
}
// Lees een decimaal, hexadecimaal of binair getal.
unsigned int get_data(char *ptr)
{
unsigned int result = 0;
while (*ptr < '!') {
ptr++; // spaties en tabs overslaan
}
if (*ptr == '0') {
ptr++;
if (*ptr == 'x') { // hexadecimaal
ptr++;
goto get_X;
} else if (*ptr == 'b') { // binair
ptr++;
goto get_B;
} else if ((*ptr > '/') && (*ptr < ':')) { // decimaal
goto get_D;
} else {
return (0);
}
} else if ((*ptr > '/') && (*ptr < ':')) { // decimaal
goto get_D;
} else {
return (0);
}
get_X: // Een hexadecimaal getal
while (1) {
if ((*ptr > '/') && (*ptr < ':')) { // een decimaal karakter
result *= 16; // Alle bits 4 plaatsen naar links
result += (*ptr - '0');
} else if ((*ptr > '@') && (*ptr < 'G')) { // Een hoofdletter
result *= 16;
result += (*ptr - 55); // 'A' = 65, 'A' - 55 = 10
} else if ((*ptr > '`') && (*ptr < 'g')) { // Een kleine letter
result *= 16;
result += (*ptr - 87); // 'a' = 97, 'a' - 87 = 10
} else {
break;
}
ptr++;
}
return (result);
get_B: // Een binair getal
while ((*ptr == '0') || (*ptr == '1')) {
result = (result << 1) + (*ptr - '0');
ptr++;
}
return (result);
get_D: // Een decimaal getal
while ((*ptr > 47) && (*ptr < 58)) {
result *= 10;
result += (*ptr - '0');
ptr++;
}
return (result);
}
void check_RS232(void)
{
if ((uart_outbuf[0] == 'W') && (uart_outbuf[1] == 'h') && (uart_outbuf[2] == 'o')) {
uart_sendstr_P("FrequentieStandaard~"); // Ons ID wordt gevraagd
uart_sendstr(Versie);
} else {
cmd = uart_outbuf[0];
val = &(uart_outbuf[2]);
switch (cmd) {
case 'u':
case 'U': // Voedingsspanning oscillator bijstellen?
if ((uart_outbuf[2] == '?') || (uart_outbuf[2] == 0)) {
uart_sendstr_P("OCR1A = ");
UI2RS232(OCR1A);
nl();
} else {
OCR1A = get_data(val);
OK();
}
break;
case 'w':
case 'W': // DCF77-gegevens doorsturen?
sprintf(text, "DCF77_stat = %3u\tdcf_uren[1] = %3u\tdcf_minuten[1] = %3u\n", DCF77_stat,
dcf_uren[1], dcf_minuten[1]);
uart_sendstr(text);
sprintf(text, "DCF77_tics = 0x%08lX\tDCF77_errs = 0x%04lX\n", DCF77_tics, DCF77_errs);
uart_sendstr(text);
break;
case 'o':
case 'O': // De gemiddelde tellerstand wordt gevraagd
if (CNT_gem[0] == 48000) {
uart_sendstr_P("Waiting for initial time...\n");
} else {
uart_sendstr_P("CNT_gem[0] = ");
UI2RS232(CNT_gem[0]);
nl();
}
break;
case 'd':
case 'D': // De uptime wordt gevraagd
sprintf(text, "Uptime = %u dagen %02u:%02u:%02u\n", up_dagen, up_uren, up_minuten, up_seconden);
uart_sendstr(text);
nl();
break;
case 't':
case 'T': // De temperatuur wordt gevraagd
uart_sendstr_P("ADC0 = ");
UI2RS232(adc);
uart_sendstr_P("\tTemperatuur = ");
UI2RS232(Temperatuur);
nl();
break;
case 'e':
case 'E': // De errors worden opgevraagd
sprintf(text, "%9lu\t", Err_H);
uart_sendstr_P("Err_H = ");
uart_sendstr(text);
sprintf(text, "%9lu\t", Err_L);
uart_sendstr_P("Err_L = ");
uart_sendstr(text);
sprintf(text, "%9lu\n", Err_OK);
uart_sendstr_P("Err_OK = ");
uart_sendstr(text);
break;
case 'f':
case 'F': // Andere uitgangsfrequentie instellen?
if (uart_outbuf[2] == '+') {
switch_freq(1);
} else {
switch_freq(0);
}
OK();
break;
case 'i':
case 'I': // Forceer een initialisatie
DCF77_stat = 0;
DCF77_errs = 0;
Err_H = 0;
Err_L = 0;
Err_OK = 0;
time_init = NOK;
OK();
break;
case 'v': // Moeten we spraakzamer zijn,
case 'V': // of wat minder lullen?
if (uart_outbuf[2] == '+') { // Spraakzamer, dus...
if (verbose_flag == YES) {
verbose_flag = MORE;
} else {
verbose_flag = YES;
}
} else { // Minder spraakzaam?
if (verbose_flag == MORE) { // OK, maar dan mis je de nieuwste roddels!
verbose_flag = YES;
} else {
verbose_flag = NO;
}
}
OK();
break;
default: // 'k Zal het nog eens goed uiteggen:
uart_sendstr_P("Onbekende opdracht: ");
uart_sendstr(uart_outbuf);
uart_sendstr_P("\n\nGeldige opdrachten:\n===================\n\n");
uart_sendstr_P(" Who\t\tToon wie je bent!\n");
uart_sendstr_P(" d=[?]\t\tLaat zien hoe lang we uptime zijn\n");
uart_sendstr_P(" e=[?]\t\tToon de timing-errors\n");
uart_sendstr_P(" f=+\t\tZet de uitgangsfrequentie een stapje hoger\n");
uart_sendstr_P(" f=-\t\tZet de uitgangsfrequentie een stapje lager\n");
uart_sendstr_P(" i=\t\tReset de timing (kan enkele minuten in beslag nemen)\n");
uart_sendstr_P(" o=[?]\t\tGeef de gemiddelde tellerstand door (zie documentatie)\n");
uart_sendstr_P(" t=[?]\t\tGeef de oven-temperatuur op\n");
uart_sendstr_P(" u=16789\tStel de waarde van OCR1A in op 16789\n");
uart_sendstr_P(" u=[?]\t\tGeef de waarde van OCR1A\n");
uart_sendstr_P(" v=+\t\tWees breedsprakerig, en na een tweede maal nog meer\n");
uart_sendstr_P(" v=-\t\tKlets wat minder\n");
uart_sendstr_P(" w=\t\tToon enkele DCF77-gegevens\n");
uart_sendstr_P(" \t\t\n");
break;
}
}
uart_linecomplete = 0;
}
int main(void)
{
unsigned long key_cnt = 0;
unsigned char key;
init();
while (1) {
if (key_cnt > 0) { // Was er kortgeleden een toets ingedrukt?
key_cnt--; // dan tellen we verder af, en negeren de toetsen
} else {
key = PINC | 0xF9; // PC1 en PC2 zijn verbonden met de toetsen
if (key == (0xFF & ~(_BV(PC1)))) { // PC1 laag?
switch_freq(0); // Dan een hogere frequentie kiezen
key_cnt = 300000; // Afteltijd instellen -> contactdender elimineren
} else if (key == (0xFF & ~(_BV(PC2)))) { // PC2 laag?
switch_freq(1); // Een lagere frequentie kiezen
key_cnt = 300000;
}
}
if (PULS_stop == YES) { // Einde DCF77-puls?
check_puls(); // Pulsduur berekenen en interpreteren
} else if (PULS_start == YES) { // Een neergaande flank op DCF77-pin
PULS_start = NO; // kondigt het begin van een DCF77-puls aan
DCF77_tics++;
lcd_gotoyx(1, 0); // De DCF77-tijd weergeven
sprintf(text, " DCF77 = %02d:%02d:%02d", dcf_uren[0], dcf_minuten[0], DCF77_bitcnt);
lcd_puts(text); // De tijd volgens DCF77 tonen
lcd_gotoyx(4, 11);
if (CNT_gem[0] == 50000) { // Is de eerste maal na RESET?
CNT_gem[0] = 48000; // Die slaan we over
lcd_puts("II");
} else if (CNT_gem[0] == 48000) { // De tweede maal na RESET?
time_init = NOK; // Dan gaan we wat initialiseren
CNT_gem[0] = 37800;
CNT_gem[1] = 37800;
lcd_puts("II");
} else if (DCF77_stat > 1000) { // DCF77-ontvangst OK?
// Als we in de pas lopen, staat CNT_now op 7560
// Omdat er nogal wat jitter op de DCF77-pulsen zit, gaan we uitmiddelen
// We willen bij dat uitmiddelen liever geen unsigned long en zeker geen float gebruiken,
// dus werken we met een unsigned int, die gemiddeld het vijfvoud van 7560 is: 37800
CNT_gem[1] = CNT_gem[0];
CNT_gem[0] -= (CNT_gem[0] / 100); // CNT_gem[0] met 1/100 verminderen = 37422
CNT_gem[0] += (CNT_now / 20); // 37422 + (7560 / 20) = 37800
if (time_init == NOK) { // Tijd nog niet geïnitialiseerd?
lcd_puts("II"); // Dan valt er niets te regelen
CNT_gem[0] = 37800;
} else if ((CNT_gem[0] > 39000) || (CNT_gem[0] < 36600)) { // Hopeloze situatie
init_again(); // We herstarten
} else if (CNT_gem[0] > 37800) { // Oscillator loopt te snel
Err_H++;
Afwijking = CNT_gem[0] - 37800;
sign = '+';
lcd_puts("|>");
if ((CNT_gem[0] >= CNT_gem[1]) && (OCR1A < 60000)) { // Versnellen we?
OCR1A++; // Eén stapje erbij
}
} else if (CNT_gem[0] < 37800) { // Oscillator loopt te traag
Err_L++;
Afwijking = 37800 - CNT_gem[0];
sign = '-';
lcd_puts("<|");
if ((CNT_gem[1] >= CNT_gem[0]) && (OCR1A > 7)) {
OCR1A--; // Eén stapje minder
}
} else { // We lopen netjes in de pas
Err_OK++; // Houden, zo.
Afwijking = 0;
sign = ' ';
lcd_puts("OK");
}
if ((verbose_flag == MORE) || ((verbose_flag == YES) && (my_seconden == 30))) {
sprintf(text, "%02d:%02d:%02d\t", my_uren, my_minuten, my_seconden);
uart_sendstr(text);
sprintf(text, "CNT = %4d\tAfwijking = %c%03d\tOCR1A = %5u\n", CNT_now, sign, Afwijking / 5, OCR1A);
uart_sendstr(text);
}
}
} else if (uart_linecomplete != 0) { // Is er een RS232-opdracht gearriveerd?
check_RS232(); // Zoek dan uit wat ze nu weer willen...
}
if (secondenflag != 0) { // Nieuwe seconde volgens onze systeem-klok?
secondenflag = 0; // Vlag resetten
my_seconden++; // Seconde bijtellen
if (my_seconden > 59) { // De 60e seconde?
my_seconden = 0; // Seconden op 0,
my_minuten++; // en minuten verhogen
if (my_minuten > 59) { // De 60e minuut?
my_minuten = 0; // Minuten op 0
my_uren++; // En uren verhogen
if (my_uren > 23) { // Het 24e uur
my_uren = 0; // Uren terug op 0
} // Met dagen, maanden en jaren
} // bemoeien we ons niet
}
up_seconden++; // Ook de uptime passen we aan
if (up_seconden > 59) {
up_seconden = 0;
up_minuten++;
if (up_minuten > 59) {
up_minuten = 0;
up_uren++;
if (up_uren > 23) {
up_uren = 0;
up_dagen++;
}
}
}
lcd_gotoyx(2, 0);
sprintf(text, " OSC = %02d:%02d:%02d", my_uren, my_minuten, my_seconden);
lcd_puts(text); // Onze tijd tonen
adc = ADC; // LM35 bemonsteren
ADCSRA |= _BV(ADSC); // ADC herstarten
if ((up_seconden < 10) && (up_minuten == 0) && (up_uren == 0) && (up_dagen == 0)) {
adc_gem = adc * 10;
} else { // Gemiddelde berekenen
adc_gem -= (adc_gem / 10); // 1/10 aftrekken
adc_gem += adc; // Nieuwe waarde erbij tellen
}
Temperatuur = (unsigned long) (adc_gem) * 1100UL; // 1023 = 1100mV = 110°C
Temperatuur /= 1023;
lcd_gotoyx(4, 1);
UI2LCD(Temperatuur);
lcd_char(0xDF);
lcd_char('C');
lcd_gotoyx(3, 0);
lcd_puts(" Temp. Sync OUT ");
lcd_gotoyx(4, 15);
switch (frequentiekeuze) {
case 0:
lcd_puts(" 16MHz");
break;
case 1:
lcd_puts(" 8MHz");
break;
case 2:
lcd_puts(" 4MHz");
break;
case 3:
lcd_puts(" 2MHz");
break;
case 4:
lcd_puts(" 1MHz");
break;
case 5:
lcd_puts("500kHz");
break;
case 6:
lcd_puts("250kHz");
break;
default:
lcd_puts("??????");
break;
}
}
}
}