⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 windmtr.c

📁 这是一个有实用价值的制作。可记录 0-17米每秒的风速。可靠性高、架设容易、适用范围广。可存放30.46天的数据
💻 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 + -