自帶吐槽功能。
估計每年都會有好多苦逼畢業設計是做這個吧,送上源代碼:
#include
#include
#include <1602.h>
#include
unsigned char i;
int temp;
void timer0_init()
{
DDRD|=0x30; //PortD=00110000,OC1B(PortD4)引腳輸出
TCCR1A|=0x63; //01(匹配時電平取反)10(匹配時清零,TOP時置位)0011(15模式)
TCCR1B|=0x1A; //00011(15模式) 010(8分頻)
OCR1A=2499; //TOP值(OCR1A):1MHZ/目標50HZ/8分頻-1=2499
OCR1B=63; //匹配值:占空比20%,則=TOP值*0.2 舵機:2.5% ~ 12.5% : 63~300
}
void SetMotor(int tmp)
{
int i;
int start=130;
int end=300; //該模塊只響應 -5 ~ 45 攝氏度的范圍 63
tmp=tmp+5-2; //變成0~50度范圍,偏移2度
i=(end-start)/50; //求出1攝氏度等于舵機轉多少角度
if(tmp>48) //輸出改變舵機角度
{ OCR1B=start; }
else if(tmp<-2)
{ OCR1B=end; }
else
{ OCR1B=end-i*tmp; }
}
int main(void)
{
lcd_init(); //lcd初始化
lcd_dictate(1); //清屏,光標回位
timer0_init();
lcd_gotoxy(0,0);
lcd_putsf("Checking Sensor",15); //溫度傳感器檢測
gettemperature();
SetMotor(0);
_delay_ms(500);_delay_ms(500);
SetMotor(52);
_delay_ms(500);_delay_ms(500);
lcd_dictate(1);
while(1)
{
lcd_gotoxy(0,0);
lcd_putsf("Temperature:",12);
lcd_gotoxy(15,0);
lcd_putsf("C",1);
temp=gettemperature();
if(negative) {lcd_gotoxy(12,0);lcd_putsf("-",1);}
lcd_gotoxy(13,0);
lcd_byte(integer);
if(integer>=35&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Go Naked...",16);}
else if(integer>=29&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Buy Aircon!",16);}
else if(integer>=20&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Go Travel!!",16);}
else if(integer>=10&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Let's BBQ!",15);}
else{lcd_gotoxy(0,1);lcd_putsf("Tips:Hibernate..",16);}
SetMotor(temp);
}
}
=================分割線==================
#ifndef _1602lcd_INCLUDED_ //如果原來沒有宏定義本名字就...
#define _1602lcd_INCLUDED_ //定義一下,防止多次被頭文件包含
#include //本例使用7線連接(也可以使用6線,但是沒有讀"忙"功能,不推薦)
//寫LCD, datas是數據,高4位有效,rs決定datas是顯示還是指令,read_lcd決定是否需要讀取忙標志BF
void lcd_h(unsigned char datas,unsigned char rs,unsigned char read_lcd)
{
DDRA=0xFF; //RS/RW/E設置為輸出
if(read_lcd)
{
DDRB=0x00; //先把4個數據口設置為輸入
PORTA&=~(1<<0); //RS=0;
PORTA|=(1<<1); //RW=1 讀BF
PORTA|=(1<<2); //E=1
_delay_ms(10); //等待,直到DB7=0,這里不等了
}
if(rs==1) //RS=rs,寫指令或者數據
{
PORTA|=(1<<0);
}else{
PORTA&=~(1<<0);
}
PORTA&=~(1<<1); //RW=0,寫
DDRB=0xFF; //把4個數據口設置為輸出
PORTA|=(1<<2); //E=1
if(datas&128) PORTB|=(1<<3); else PORTB&=~(1<<3);
if(datas&64) PORTB|=(1<<2); else PORTB&=~(1<<2);
if(datas&32) PORTB|=(1<<1); else PORTB&=~(1<<1);
if(datas&16) PORTB|=(1<<0); else PORTB&=~(1<<0);
PORTA&=~(1<<2); //E=0;LCD在E下降沿時對RS與DB4-DB7進行取樣
}
void lcd_dictate(unsigned char data) //寫指令函數
{
lcd_h(data,0,1); //輸出高4位
lcd_h(data*16,0,1); //輸出低4位
}
void lcd_putchar(unsigned char data) //寫顯示函數
{
lcd_h(data,1,1); //輸出高4位
lcd_h(data*16,1,1); //輸出低4位
}
//初始化函數
void lcd_init(void)
{
_delay_ms(40);
lcd_h(48,0,0); _delay_ms(12); //這3條是初始化語句
lcd_h(48,0,0); _delay_ms(10);
lcd_h(48,0,0);
lcd_h(32,0,1); //使能4位數據線
lcd_dictate(40); //顯示參數設定
lcd_dictate(12); //顯示參數設定
}
//列/行定位函數,最開頭的地址是0列0行
void lcd_gotoxy(unsigned char x, unsigned char y) //列/行定位函數
{
if(x<=19 && y<=3) //防止輸入的數據不正確
{
if(y==0) lcd_dictate(x+128); //第0行的地址是從128開始
if(y==1) lcd_dictate(x+192); //第1行......
if(y==2) lcd_dictate(x+148);
if(y==3) lcd_dictate(x+212);
}
}
void lcd_hex(unsigned char byte_data) //以十六進制顯示一個字節變量
{
unsigned char data;
data=byte_data>>4; //求高4位
if(data<10) data+=48; else data+=55; //轉化為ASCII值
lcd_putchar(data); //顯示
data=byte_data&15; //求低4位
if(data<10) data+=48; else data+=55; //轉化為ASCII值
lcd_putchar(data); //顯示
}
void lcd_byte(unsigned char byte_data) //以十進制顯示一個字節變量
{
unsigned char data;
data=byte_data/100; //求百位數
lcd_putchar(data+48); //轉化為ASCII值再顯示
data=byte_data/10; //求十位數
lcd_putchar(data+48); //轉化為ASCII值再顯示
data=byte_data; //求個位數
lcd_putchar(data+48); //轉化為ASCII再再顯示
}
void lcd_putsf(flash unsigned char *string , unsigned char n) //顯示FLASH里面的字符串
{
unsigned char i=0;
while(i
{
lcd_putchar( string[ i ] ) ; //順序顯示字符
i++;
}
}
#endif
=================分割線==================
//monobus.h文件,用于操作DS18B20/DS2401等單總線器件,本單片機頻率有點快,//delay_us(480)代表延時480微妙,實際要用2條指令達到480us,其他單片機延時準確的話可以用一條
#define monobus_1 DDRC&=~(1<<1) //設置單片機IO為輸入,由于總線存在上拉電阻,所以此時電平是1
#define monobus_0 DDRC|=(1<<1) //設置單片機IO為輸出,配合默認的 PORTC.0=0 則輸出0電平
#define monobus_in PINC&(1<<1) //檢測總線(從機)的電平狀態
#include
unsigned char negative,integer; //求出溫度的符號,整數部分
void monobus_init(void) //復位,不檢測從機設備是否存在(只要沒有虛焊就肯定存在的)
{
monobus_0;
//delay_us(480);
_delay_us(480);
_delay_us(480);
monobus_1;
while(monobus_in);
while(!monobus_in);
//delay_us(480);
_delay_us(480);
_delay_us(480);
}
void write_monobus(unsigned char data) //向單總線的從機寫入數據(先寫低位再寫高位,與SPI相反)
{
unsigned char n=1;
while(n)
{
monobus_0;
//delay_us(2); //拉低總線1-3us,通知從機準備收發數據
_delay_us(4);
if(data&n) monobus_1; else monobus_0; //向總線寫數據的某一位(1或者0)
//delay_us(75); //等待90us,保證從機有足夠的時間進行采樣(24-210us)
_delay_us(150);
monobus_1; //釋放總線
//delay_us(2); //釋放總線時間要大于1us
_delay_us(3);
n<<=1;
}
}
unsigned char read_monobus(void) //讀單總線的從機數據(先傳輸低位后傳輸高位,與SPI相反)
{
unsigned char data_18b20=0;
unsigned char n=1;
while(n)
{
monobus_0;
//delay_us(2); //拉低總線1-3us,通知從機準備收發數據
_delay_us(3);
monobus_1; //釋放總線
//delay_us(5); //從機在1-25us內會向總線輸出數據的某一位(1或者0)
_delay_us(10);
if(monobus_in)
data_18b20+=n; //讀取總線數據
//delay_us(55); //等待從機釋放總線
_delay_us(110);
n<<=1; //挪夠8位則等于清零
}
return data_18b20;
}
int gettemperature(void)
{
unsigned char data_L,data_H;
int data_T;
float data_D;
monobus_init(); //單總線復位
write_monobus(0xCC); //跳過ID碼匹配,適用于一個DS18B20
write_monobus(0x44); //啟動溫度轉換
_delay_ms(500); //等待轉換
_delay_ms(500);
monobus_init(); //單總線復位
write_monobus(0xCC); //跳過ID碼匹配
write_monobus(0xBE); //通知DS18B20,準備讀數據
data_L=read_monobus(); //讀取第一個數據(溫度低字節)
data_H=read_monobus(); //讀取第二個數據(溫度高字節)
//可以繼續讀取第三個到第九個RAM數據
//data_T=data_H*256+data_L; //合并后得到原始溫度數據
if(data_H>15) negative=1; //data_H的4到7位為正負符,例如溫度為負時是1111 1xxx,為正是0000 0xxx
//data_L的8位和data_H的前3位共同表達溫度,可以表達-55 ~ 125,
if(!negative) //為正溫度 //負數用補碼表達, 反回來
{
data_T=data_H*256+data_L;
data_T/=16;
} else {
data_T=~data_H;
data_T<<=8;
data_T=data_T|~data_L;
data_T=data_T+1;
data_D=data_T*0.0625;
data_T=data_D*10+0.5;
}
integer=data_T;
return data_T; //沒要求則返回整數部分
}
=================分割線==================