|
|
|
|
#include <avr/io.h>
|
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
|
#include <avr/pgmspace.h>
|
|
|
|
|
#include <avr/eeprom.h>
|
|
|
|
|
#include <util/delay.h>
|
|
|
|
|
#include <util/atomic.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include <usbdrv/usbdrv.h>
|
|
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
#include "display.h"
|
|
|
|
|
#include "spi.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t newThermoData = 1;
|
|
|
|
|
static uint16_t thermoData[] = {1024, 814, 2475, 2243};
|
|
|
|
|
volatile uint16_t timer1_acc;
|
|
|
|
|
|
|
|
|
|
#define SOFTTIMERNUMS 4
|
|
|
|
|
uint16_t softtimer_last[SOFTTIMERNUMS];
|
|
|
|
|
|
|
|
|
|
void softtimer_reset(uint8_t timernum){
|
|
|
|
|
softtimer_last[SOFTTIMERNUMS] = timer1_acc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t softtimer(uint8_t timernum, uint16_t interval){
|
|
|
|
|
uint16_t timer1_acc_tmp = timer1_acc; // because of volatile
|
|
|
|
|
if((uint16_t)(timer1_acc_tmp - (uint16_t)(softtimer_last[timernum]) >= interval )){
|
|
|
|
|
softtimer_last[timernum] = timer1_acc_tmp;
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define SOFTTIMER(n,a) if(softtimer((n),(a*4)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void hardinit() {
|
|
|
|
|
/* initializes the hardware */
|
|
|
|
|
DDRB = _BV(1) | _BV(2) | _BV(0);
|
|
|
|
|
DDRC = 0x3f;
|
|
|
|
|
|
|
|
|
|
// no pullups; all digital outputs can take care of themselves
|
|
|
|
|
PORTB = 0x00;
|
|
|
|
|
PORTC = 0x00;
|
|
|
|
|
PORTD = 0x00;
|
|
|
|
|
|
|
|
|
|
// hardware pwm for brightness/contrast:
|
|
|
|
|
TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
|
|
|
|
|
TCCR1B = _BV(WGM12) | _BV(CS11); // clk/8 prescaler, 4kHz PWM-freq.
|
|
|
|
|
|
|
|
|
|
OCR1A = 15; // contrast
|
|
|
|
|
OCR1B = 50; // brightness
|
|
|
|
|
|
|
|
|
|
// init LCD:
|
|
|
|
|
lcd_init(1);
|
|
|
|
|
lcd_clrscr(1);
|
|
|
|
|
|
|
|
|
|
sei();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void softinit() {
|
|
|
|
|
lcd_defchar(1, LCD_CHAR_HALFBAR, lcd_halfbar_char);
|
|
|
|
|
lcd_defchar(1, LCD_CHAR_BAR, lcd_bar_char);
|
|
|
|
|
lcd_defchar(1, LCD_CHAR_DEGREE, lcd_degree_char);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbMsgLen_t usbFunctionSetup(uchar data[8]) {
|
|
|
|
|
usbRequest_t *rq = (void *)data;
|
|
|
|
|
static uchar dataBuffer[4];
|
|
|
|
|
|
|
|
|
|
if(rq->bRequest == 1){
|
|
|
|
|
dataBuffer[0] = (thermoData [0] & 0xff00)>>8;
|
|
|
|
|
dataBuffer[1] = thermoData [0] & 0x00ff;
|
|
|
|
|
dataBuffer[2] = (thermoData [1] & 0xff00)>>8;
|
|
|
|
|
dataBuffer[3] = thermoData [1] & 0x00ff;
|
|
|
|
|
usbMsgPtr = dataBuffer;
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(rq->bRequest == 2){
|
|
|
|
|
dataBuffer[0] = (thermoData [2] & 0xff00)>>8;
|
|
|
|
|
dataBuffer[1] = thermoData [2] & 0x00ff;
|
|
|
|
|
dataBuffer[2] = (thermoData [3] & 0xff00)>>8;
|
|
|
|
|
dataBuffer[3] = thermoData [3] & 0x00ff;
|
|
|
|
|
usbMsgPtr = dataBuffer;
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateDisplay() {
|
|
|
|
|
if(newThermoData==1) {
|
|
|
|
|
newThermoData = 0;
|
|
|
|
|
|
|
|
|
|
char str[34];
|
|
|
|
|
snprintf(str, 34, "%3d.%02d\x03 %3d.%02d\x03\n%3d.%02d\x03 %3d.%02d\x03", thermoData[0]/100, thermoData[0]%100,
|
|
|
|
|
thermoData[1]/100, thermoData[1]%100,
|
|
|
|
|
thermoData[2]/100, thermoData[2]%100,
|
|
|
|
|
thermoData[3]/100, thermoData[3]%100
|
|
|
|
|
);
|
|
|
|
|
display_gotoyx(0,0);
|
|
|
|
|
display_puts(str);
|
|
|
|
|
display_update();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int __attribute__((noreturn)) main(void) {
|
|
|
|
|
int i=0;
|
|
|
|
|
hardinit();
|
|
|
|
|
softinit();
|
|
|
|
|
usbInit();
|
|
|
|
|
|
|
|
|
|
display_puts("Hallo, Welt!\n\n");
|
|
|
|
|
display_update();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(;;){
|
|
|
|
|
usbPoll();
|
|
|
|
|
|
|
|
|
|
SOFTTIMER(1,100){
|
|
|
|
|
updateDisplay();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
thermoData[0]=thermoData[0]+5;
|
|
|
|
|
thermoData[1]=thermoData[1]+15;
|
|
|
|
|
thermoData[2]=thermoData[2]+7;
|
|
|
|
|
thermoData[3]=thermoData[3]+18;
|
|
|
|
|
i++; if(i%200 == 0) newThermoData = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
ISR(TIMER1_OVF_vect, ISR_NAKED){
|
|
|
|
|
asm volatile ("in %0, %1\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG)));
|
|
|
|
|
timer1_acc++;
|
|
|
|
|
asm volatile ("out %1, %0\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG)));
|
|
|
|
|
reti();
|
|
|
|
|
}*/
|
|
|
|
|
ISR(TIMER1_OVF_vect,ISR_NOBLOCK){
|
|
|
|
|
uint16_t temp;
|
|
|
|
|
temp=timer1_acc;
|
|
|
|
|
temp++;
|
|
|
|
|
ATOMIC_BLOCK(ATOMIC_FORCEON){
|
|
|
|
|
timer1_acc=temp;
|
|
|
|
|
}
|
|
|
|
|
/* the ATOMIC is acutally only needed if timer1_acc is never read from an ISR, which
|
|
|
|
|
* is probably the case.
|
|
|
|
|
* ATOMIC_FORCEON: the ISR_NOBLOCK sets sei() a few cycles before.
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|