📄 windmtr.c
字号:
/** Version 1.54 - 52% mem used **/
#define sleep() __asm__ __volatile__ ("sleep")
#define wdr() __asm__ __volatile__ ("wdr")
#define sei() __asm__ __volatile__ ("sei" ::)
#define cli() __asm__ __volatile__ ("cli" ::)
#define UART_CPU 4096000 // 4.096Mhz
#define UART_BAUD_RATE 2400 // baud rate
#define UART_BAUD_SELECT (UART_CPU/(UART_BAUD_RATE*16l)-1)
#define PRINT(string) (UART_PrintfProgStr(PSTR(string)))
#define eeHIm 0
#define eeLOm 1
#define eeLOb 2
#define eemth 3
#define eemax 23
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
extern void UART_PrintfProgStr(unsigned char* pBuf);
void printu16(unsigned int x);
void TXbyte(char data );
void Display(unsigned int data[]);
void ewrite(int address, char data);
unsigned char eread(int address);
unsigned int scan(void);
void measr(void);
void selmonth(void);
unsigned char month; //current month
unsigned char getmonth; //set by selmonth()
unsigned int monthtimer; //30.41667 day timer (1/12 of 365)
unsigned char monthsec; //minuet timer for monthtimer
unsigned char sec[18]; //Current Month's 'seconds' buffer
unsigned int crnt[18]; //Current Month's Data
unsigned int temp[18]; //Temp Month's Data
unsigned int rollavg[4]; //used to average input captures
unsigned int timer0; // 1/16s timer
unsigned int timer1; // 3 hr timer
unsigned int m; //Slope for speed calculation
unsigned int add; //Used for month data EEPROM storage
unsigned char tempos; //Used for month data EEPROM storage
unsigned char spd; //Current Speed
unsigned char max; //maximum Speed for month
unsigned char rollpos; //position of rolling average
unsigned char nowind; //Flag to start TC1 if their has been no wind
unsigned char b; //Offset for speed calculation
unsigned char cal; //Calibration mode flag
unsigned char reset; //reset indicator
int main(void)
{
cli();
//setup WatchDog Timer
WDTCR = 0x18; //Allow WatchDag Chnage
WDTCR = 0x0F; //Enable WatchDog
//Setup Ports
PORTB = 0x01; //Set Pull up on ICP PB0
//Setup UATRT
UBRRL = (char)UART_BAUD_SELECT;
UCSRA = 0x00;
UCSRB = 0x98; //enable Rx, Rx IQR & Tx
//Setup Timers
TCCR2 = 0x0F; //1024 Prescaller & CTC mode
OCR2 = 249; //timer= 1/16 secs @ 4.096s
TCCR1A = 0x00;
TCCR1B = 0x05; //1024 Prescaller
OCR1A = 0xFFF0;
TIMSK = 0xB0; //Enable ICP1, TCO2 & OC2
//Setup MCU
MCUCR = 0x80; //Setup Sleep mode & enable sleep
sei();
if(eread(23)!=0x69) { //clear eeprom if first run at programming
for(add=24;add<468;add++) ewrite(add,0);
ewrite(23,0x69); //mark first boot erace
ewrite(eemth,1); //set month = Jan
}
cal = 0;
month = eread(eemth);
getmonth = month;
max = eread (eemax + month);
PRINT ("\fReset v1.54");
//Restore current month's data from EEPROM
add=month*36; //calc eeprom addresses based on month
for(tempos=0;tempos<18;tempos++) { //transfer eeprom data to array
crnt[tempos] = 0;
crnt[tempos]|= (int)(eread (add)) << 8;
crnt[tempos]|= eread (add + 1);
monthtimer+= crnt[tempos]; //get aprox monthtimer from saved data
add+=2;
}
//Restore m & b for speed calc.
m = (eread(eeHIm) << 8) | eread(eeLOm);
b = eread(eeLOb);
if (m < 64000) OCR1A = m + 1500; //Set zero speed cutoff
for(;;) sleep();
}
SIGNAL(SIG_INPUT_CAPTURE1)
{
TCNT1 = 0; //Reset TC1 to measure next pulse.
if (nowind == 1) { //If 1,Was no wind
nowind = 0;
TCCR1B = 0x05; //Restart TC1
}
if (rollpos >=4) rollpos = 0;
rollavg[rollpos] = ICR1;
rollpos++;
spd = b + m / (((long int)rollavg[0] + rollavg[1] + rollavg[2] + rollavg[3]) >> 2);
if (spd > max) {
max = spd;
ewrite(eemax + month, max);
}
if (cal) {
PRINT("\r");
printu16 (((long int)rollavg[0] + rollavg[1] + rollavg[2] + rollavg[3]) >> 2);
}
}
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
cli();
TCCR1B = 0; //Stop TC1
nowind = 1; //Remember to restart on next ICP
spd = 0; //Set speed to Zero
sei();
}
SIGNAL(SIG_OUTPUT_COMPARE2)
{
timer0++;
wdr();
if (timer0 >= 16) { //True Every 1.000 seconds
timer0 = 0;
if (spd > 17) spd = 17; //Any speed above max put in "17 & up" bin
if(sec[spd] < 59) sec[spd]++; //count seconds at each speed
else {
crnt[spd]++; //incement crnt as per 60 seconds per speed
sec[spd] = 0;
}
if(monthsec < 59) monthsec++; //count seconds for monthtimer
else {
monthsec = 0;
monthtimer++; //count minuets for monthtimer
if (monthtimer >= 43800) { //True Every 30.41667 days (1/12 of 356 days)
monthtimer = 0;
add=month*36; //calc eeprom addresses based on month
for(tempos=0;tempos<18;tempos++) { //transfer eeprom data to array
ewrite (add,(int)(crnt[tempos] >> 8));
ewrite (add + 1,crnt[tempos]);
add+=2;
crnt[tempos] = 0;
}
if(month < 12) month++;
else month = 1;
ewrite(eemth, month); //save which month it is
max = 0; //clear maximum speed
ewrite(eemax + month, max); //save cleared maximum
}
}
timer1++;
if (timer1 >= 10800) { //Save Current Data Every 3 Hours
timer1 = 0;
add=month*36; //calc eeprom addresses based on month
for(tempos=0;tempos<18;tempos++) { //transfer eeprom data to array
ewrite (add,(int)(crnt[tempos] >> 8));
ewrite (add + 1,crnt[tempos]);
add+=2;
}
}
}
}
SIGNAL(SIG_UART_RECV)
{
switch (UDR) {
case 'g':
PRINT ("\fGet Data for which Month?");
selmonth();
if(getmonth != month) { //test if requested data is for current month
add=getmonth*36; //calc eeprom addresses based on entered month
for(tempos=0;tempos<18;tempos++) { //transfer eeprom data to array
temp[tempos] = 0;
temp[tempos]|= (int)(eread (add)) << 8;
temp[tempos]|= eread (add + 1);
add+=2;
}
Display(temp);
}
else Display(crnt);
PRINT ("\n\n\rMonth's Maximum speed = ");
printu16 (eread (eemax + getmonth));
break;
case 's':
PRINT ("\fSet Month");
selmonth();
month = getmonth;
ewrite(eemth, month);
max = 0; //clear maximum speed
ewrite(eemax + month, max); //save cleared maximum
monthtimer = 0;
add=month*36; //calc eeprom addresses based on month
for(tempos=0;tempos<18;tempos++) { //transfer eeprom data to array
ewrite (add,0);
ewrite (add + 1,0);
add+=2;
crnt[tempos] = 0;
}
reset = 1;
break;
case 'm':PRINT ("\fm = ");
printu16 (m);
PRINT ("\n\rEnter Slope ");
m = scan();
ewrite (eeHIm,(m >> 8));
ewrite (eeLOm,m);
PRINT ("\rm = ");
printu16 (m);
if (m < 64000) OCR1A = m + 1500; //Set zero speed cutoff
break;
case 'b':PRINT ("\fb = ");
printu16 (b);
PRINT ("\n\rEnter Offset ");
b = scan();
ewrite (eeLOb,b);
PRINT ("\rb = ");
printu16 (b);
break;
case 'v':measr();
break;
case 't':if (!cal) {
cal = 1;
PRINT ("\fCalibration Mode ON");
}
else {
cal = 0;
PRINT ("\fCalibration Mode OFF");
}
break;
case 'r':WDTCR = 0x18; //Allow WatchDag Chnage
WDTCR = 0x08; //Enable WatchDog
while(1);
}
PRINT ("\n\n\rCurrent speed = ");
printu16(spd);
PRINT("\n\rDays logged this month = ");
printu16(monthtimer / 1440);
PRINT("\n\rReset since month set : ");
if(reset) PRINT("No");
else PRINT("Yes");
PRINT("\n\rPress [g]et data, [s]et month");
PRINT("\r[m]slope, [b]offset, [t]oggle calibration mode, [v]cc, [r]eset");
}
void Display (unsigned int data[])
{
PRINT("\n\rno wind = ");
printu16 (data[0]);
PRINT(" \t9.0 - 9.9 = ");
printu16 (data[9]);
PRINT("\n\r1.0 - 1.9 = ");
printu16 (data[1]);
PRINT(" \t10.0 - 10.9 = ");
printu16 (data[10]);
PRINT("\n\r2.0 - 2.9 = ");
printu16 (data[2]);
PRINT(" \t11.0 - 11.9 = ");
printu16 (data[11]);
PRINT("\n\r3.0 - 3.9 = ");
printu16 (data[3]);
PRINT(" \t12.0 - 12.9 = ");
printu16 (data[12]);
PRINT("\n\r4.0 - 4.9 = ");
printu16 (data[4]);
PRINT(" \t13.0 - 13.9 = ");
printu16 (data[13]);
PRINT("\n\r5.0 - 5.9 = ");
printu16 (data[5]);
PRINT(" \t14.0 - 14.9 = ");
printu16 (data[14]);
PRINT("\n\r6.0 - 6.9 = ");
printu16 (data[6]);
PRINT(" \t15.0 - 15.9 = ");
printu16 (data[15]);
PRINT("\n\r7.0 - 7.9 = ");
printu16 (data[7]);
PRINT(" \t16.0 - 16.9 = ");
printu16 (data[16]);
PRINT("\n\r8.0 - 8.9 = ");
printu16 (data[8]);
PRINT(" \t17.0 & Up = ");
printu16 (data[17]);
}
void UART_PrintfProgStr(unsigned char* pBuf)
{
wdr();
while (PRG_RDB(pBuf)!=0) {
UDR = PRG_RDB(pBuf);
pBuf++;
while ( !(UCSRA & (1<<UDRE)) );
}
}
void printu16 (unsigned int x)
{
TXbyte (x / 10000 + 0x30); //Add ASCI offset for digits (0-9)-> 0x30
x=x % 10000;
TXbyte (x / 1000 + 0x30);
x=x % 1000;
TXbyte (x / 100 + 0x30);
x=x % 100;
TXbyte (x / 10 + 0x30);
x=x%10;
TXbyte (x + 0x30);
TXbyte (0x00);
}
void TXbyte ( char data )
{
while (!(UCSRA & (1<<UDRE))); //wait for empty transmit buffer
UDR = data; //start transmission
}
void ewrite (int address, char data)
{
cli();
while ((EECR >> EEWE) & 1);
EEAR = address;
EEDR = data;
sbi (EECR,2);
sbi (EECR,1);
sei();
}
unsigned char eread (int address)
{
EEAR = address;
sbi (EECR,0);
return (EEDR);
}
#define ENTER 13
#define BACKSPACE 8
unsigned int scan (void)
{
unsigned int value;
unsigned char indata,pos,i;
unsigned char data[5];
UCSRB = 0x18; //Disable RX INT
value = 0;
pos = 0;
i = 0;
data[0] = 0; //Clear Array
data[1] = 0;
data[2] = 0;
data[3] = 0;
data[4] = 0;
for (;;) {
while (!(UCSRA & (1<<RXC))) wdr(); //Wait for RX flag
indata = UDR;
if(indata == ENTER) { //loop until ENTER is pressed
while(pos > 0) {
value *= 10; //Build U16 number from ASCII array
value += data[i++];
pos--;
}
UCSRB = 0x98; //Enable RX INT
return(value);
}
if(indata== BACKSPACE) { //backspace action
if(pos!=0) {
pos--;
data[pos] = 0;
TXbyte(BACKSPACE);
TXbyte(0x20);
TXbyte(BACKSPACE);
}
}
else { //fill array with numbers only until full
if(pos<5 && indata>=0x30 && indata<=0x39) {
data[pos] = indata - 0x30;
pos++;
TXbyte(indata); //Print key just pressed
}
}
}
}
void selmonth(void)
{
unsigned char inbyte;
UCSRB = 0x18;
//getmonth = month;
inbyte = 69;
PRINT("\n\rUse ARROW Keys to select month\r");
for (;;) {
if(inbyte>=65 && inbyte<=69) {
switch (getmonth) {
case 1: PRINT ("Jan");
break;
case 2: PRINT ("Feb");
break;
case 3: PRINT ("Mar");
break;
case 4: PRINT ("Apr");
break;
case 5: PRINT ("May");
break;
case 6: PRINT ("Jun");
break;
case 7: PRINT ("Jul");
break;
case 8: PRINT ("Aug");
break;
case 9: PRINT ("Sep");
break;
case 10: PRINT ("Oct");
break;
case 11: PRINT ("Nov");
break;
case 12: PRINT ("Dec");
break;
}
TXbyte (BACKSPACE);
TXbyte (BACKSPACE);
TXbyte (BACKSPACE);
}
while (!(UCSRA & (1<<RXC))) wdr(); //Wait for RX flag
inbyte = UDR;
if(inbyte == ENTER) { //If ENTER is pressed
UCSRB = 0x98;
return;
}
if(inbyte == 66 || inbyte == 67) { //If "<--" is pressed
if(getmonth < 12) getmonth++;
else getmonth = 1;
}
if(inbyte == 65 || inbyte == 68) { //If "-->" is pressed
if(getmonth > 1) getmonth--;
else getmonth = 12;
}
}
}
void measr (void)
{
unsigned int x;
ADMUX = 0xC0; //Set ACDC0, 2.56v ref
ADCSR = 0xC7; //Start conversion, /128 ck
while (!(ADCSR >> 4) & 0x01); //Wait for conversion to complete
PRINT ("\fVbatt = ");
x = ADCW * 2;
ADCSR = 0x00; //Disable ADC to save power
TXbyte (x / 1000 + 0x30);
x=x % 1000;
TXbyte (x / 100 + 0x30);
x=x % 100;
TXbyte (0x2E);
TXbyte (x / 10 + 0x30);
x=x%10;
TXbyte (x + 0x30);
TXbyte (0x76);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -