空調(diào)遙控器可以用來廟宇空調(diào)機(jī)的控制溫度(室內(nèi)溫度)、工作狀態(tài)(常態(tài)、除濕、通 風(fēng))、風(fēng)扇風(fēng)速(強(qiáng)、弱、中)以及定時時間(空調(diào)工作多少小時自動開機(jī)或延時多少小時自動開機(jī))。使用者在遙控器上廟宇預(yù)期的空調(diào)機(jī)工作狀態(tài)、控制溫度及 延時時間后,這些參數(shù)即送至空調(diào)機(jī),空調(diào)機(jī)按要求開始工作。
數(shù)字顯示器使用LCD1602顯示時間和溫度值,其中時間的切換利用AT89C51內(nèi)部自帶的定時器0,定時初值為3cb0,定時器工作模式為’01’16位定時器,工作狀態(tài)利用LED燈的亮滅來指示,其中LED亮代表相對應(yīng)的工作模式被選中,各種工作狀態(tài)的切換使用8個獨(dú)立按鍵來實(shí)現(xiàn),分別位‘工作狀態(tài)設(shè)定鍵’、‘延時狀態(tài)設(shè)定鍵’、‘風(fēng)速選定鍵’、‘溫度+鍵’、‘溫度-鍵’、‘延時時間位選定鍵’、‘延時時間設(shè)置鍵’、‘發(fā)送鍵’;按下‘發(fā)送鍵’后信息的發(fā)送使用串行口的方式發(fā)送給上位機(jī)并顯現(xiàn)出來,當(dāng)延時時間到啟動空調(diào)。
具體實(shí)現(xiàn):
經(jīng)分析將該設(shè)計(jì)劃分為如下4個模塊:按鍵模塊,LED狀態(tài)顯示模塊,LCD1602顯示模塊,雙機(jī)串口通信模塊
按鍵模塊:
仿真原理圖:
詳細(xì)描述:8個按鍵的功能如下表:
按鍵
|
功能
|
K1
|
工作狀態(tài)設(shè)定鍵(常態(tài)、除濕、通風(fēng)) |
K2
|
延時狀態(tài)設(shè)定鍵(延時開、延時關(guān)、取消) |
K3
|
風(fēng)速選定鍵(慢、中、快) |
K4
|
溫度設(shè)定鍵(增加+) |
K5
|
溫度設(shè)定鍵(減少-) |
K6
|
延時時間位選定鍵(XXXXXX) |
K7
|
延時時間設(shè)置鍵(默認(rèn)為循環(huán)增加) |
K8
|
發(fā)送鍵 |
當(dāng)K1按下時,保持P0高5位狀態(tài),按下第一次最后一位置0,倒數(shù)第二、三位置1按下第二次時到數(shù)第二位置0,倒數(shù)第一、三位置1,按下第三次時倒數(shù)第三位置0,倒數(shù)第一、二位置1,依次循環(huán),代碼實(shí)現(xiàn):P0=(states1[i]&(P0|0x07));
當(dāng)K2按下時,保持P0倒數(shù)第1、2、3位和正數(shù)第1、2、3狀態(tài)按下第一次時倒數(shù)第一位亮表示延時開,按下第二次時倒數(shù)第五位亮表示延時關(guān),按下第三次時倒數(shù)第3、4位皆滅表示取消延時,依次循環(huán),代碼實(shí)現(xiàn): P0=(states2[j]&(P0|0x18));
當(dāng)K3按下時,保持P0低5位不變,按下最高兩位置1,第三位置0,表示慢速,按下第二次時第二位置0,第一、三位置1,表示中速,按下第三次時第一位置0,第一、二位置1,依次循環(huán),代碼實(shí)現(xiàn):P0=(states3[k]&(P0|0xe0));
LED狀態(tài)顯示模塊:
仿真原理圖:
詳細(xì)描述:8個按鍵的功能如下表:
LED
|
狀態(tài)指示
|
D1
|
正常 |
D2
|
除濕 |
D3
|
通風(fēng) |
D4
|
延時開(如果D4/D5兩燈全滅則取消延時) |
D5
|
延時關(guān) |
D6
|
慢 |
D7
|
中 |
D8
|
高 |
LCD1602顯示模塊:
仿真原理圖:
詳細(xì)描述:LCD1602一共可以顯示16x2個字符,其中數(shù)據(jù)線為8位分別接AT89C51的P2端口的8個管腳,控制線為RS、RW、E分別接P3.3,P3.4,P3.5管腳,仿真電路中排阻是必要的它的功能是電阻作為有功原件串聯(lián)在電路中能消除振蕩,目的是得到更好的EMC性能。
主要子函數(shù)包括:(詳細(xì)代碼見附錄源程序LCD部分)
void initLCM( void); //LCD初始化子程序
void DisplayListChar(unsigned char X,unsigned char Y, unsigned char *DData); //顯示指定坐標(biāo)的一串字符子函數(shù)
void DisplayOneChar(uchar X,uchar Y,uchar DData);//顯示單個字符
雙機(jī)串口通信功能:
仿真原理圖:
詳細(xì)描述:
利用串口查詢的方式實(shí)現(xiàn)兩臺單片機(jī)之間通信的功能:單片機(jī)1(模擬遙控器)作為發(fā)送機(jī)其P3.0/RXD、P3.1/TXD分別接從機(jī)(模擬空調(diào))的P3.1/TXD、P3.0/RXD引腳。發(fā)送機(jī)和接收機(jī)串口采用方式1,8位UART,波特率可變,其中T1的采用方式3(8位自填裝模式),計(jì)數(shù)初值為f4f4,因此串口的波特率為2400bits
主要實(shí)現(xiàn)代碼如下:(詳細(xì)代碼見附錄源代碼部分:)
主機(jī)發(fā)送:
while(++counter<=8)
{SBUF=sender[counter-1];
while(TI==0);
TI=0;
while(RI==0);
RI=0;
}
從機(jī)接收:
counter++;
RI=0; //接受中斷標(biāo)志清零,可以接收新的數(shù)據(jù)
receive=SBUF; //開始接收新的數(shù)據(jù)
ADDRR[counter-1]=receive;//把接受的數(shù)據(jù)存入字符串?dāng)?shù)組ADDRR中
delay_LCM(100);
delay_LCM(100);
SBUF=ADDRR[counter-1];//由單片機(jī)2向單片機(jī)1發(fā)送數(shù)據(jù)
while(TI==0); //循環(huán)等待直到發(fā)送數(shù)據(jù)完畢
TI=0;
問題1、LCD1602不能夠顯示
最終解決方案:經(jīng)查閱相關(guān)資料與書上LCD1602電路連線圖相對照發(fā)現(xiàn)未接排阻。仿真電路中排阻是必要的它的功能是電阻作為有功原件串聯(lián)在電路中能消除振蕩,目的是得到更好的EMC性能。經(jīng)加入排阻后能夠正常顯示。
問題2、通過串口線兩片單片機(jī)不能正常的通信
最終解決方案:原因是在主機(jī)中由于我既用到了定時器來作為計(jì)時中斷,有用到了定時器為串口提供波提率,我誤把定時器0來為串口提供波特率,定時器1來為做計(jì)時時鐘,后查閱書籍在《單片機(jī)原理及控制技術(shù)》P161、L17中提到方式1和方式3的波特率“與定時器T1的溢出率有關(guān)。”也就是說串口通信方式1的波特率不能由定時器0來提供后經(jīng)改變兩定時器的功能后串口通信正常。
問題3、編譯程序代碼時總會出現(xiàn)“ERROR L107:ADDRESS SPACE OVERFLOW”.
最終解決方案:AT89C51有三種存儲器模式:“SMALL模式,COMPACT模式,LARGE模式。不同的存儲模式對變量的默認(rèn)的存儲器類型不一樣。”程序在編譯時默認(rèn)為小編譯模式,此時數(shù)據(jù)的存儲容量為128B當(dāng)我定義的數(shù)據(jù)變量所占據(jù)的地址空間超過128B時,編譯器就會報錯。我首先嘗試將編譯器的模式設(shè)置為CMOPACT模式,但發(fā)現(xiàn)編譯器雖無報錯但仿真的結(jié)果并不是我所期望的結(jié)果,最終我在SMALL模式下,將我所定義的數(shù)據(jù)變量盡量縮減,例如用10個字符“0123456789”來表示21個溫度數(shù)據(jù),這樣的缺點(diǎn)是給軟件的編寫帶來了較大的復(fù)雜度,優(yōu)點(diǎn)是可以節(jié)省內(nèi)存空間,最終將所用字節(jié)縮減至97遠(yuǎn)小于128B,編譯無錯誤,且仿真成功。
本次課程設(shè)計(jì)從審題、模塊的劃分、各個模塊的實(shí)現(xiàn)和各個模塊之間的連接均為自己獨(dú)立完成,無抄襲借鑒他人的現(xiàn)象發(fā)生,通過本次課程設(shè)計(jì)自己幾乎將單片機(jī)教材又細(xì)致的看了一遍尤其是中斷一章看了不下3遍 其中串口一節(jié)更是把每個字都仔細(xì)研究一番,最終完成了課程設(shè)計(jì)題目的要求。通過此次課程設(shè)計(jì)增強(qiáng)了我對學(xué)習(xí)單片機(jī)的信心,也激發(fā)了我對單片機(jī)設(shè)計(jì)的熱情。 成為我大學(xué)生涯中的一次難忘的經(jīng)歷,我會在今后生活中更加深入學(xué)習(xí)單片機(jī)知識,爭取設(shè)計(jì)出更多自己喜歡的又實(shí)用價值的作品。
軟件仿真圖:
源代碼:
第一部分:LCD顯示文件
******************************************************************/
#include<reg51.h>
#include<stdio.h>
#define uchar unsigned char
states1[3]={0xfe,0xfd,0xfb};
states2[3]={0xf7,0xef,0xff};
states3[3]={0xdf,0xbf,0x7f};
unsigned char inittempreture[12]="tempreture:";
unsigned char inittime[5]="time:";
//unsigned char time[10]="0123456789";
unsigned char tempreture[10]="0123456789";
sbit k1=P1^0;
sbit k2=P1^1;
sbit k3=P1^2;
sbit k4=P1^3;
sbit k5=P1^4;
sbit k6=P1^5;
sbit k7=P1^6;
sbit k8=P1^7;
#define uint unsigned int
#define uchar unsigned char
uchar datasend=0;
uchar keynum;
uchar timenum;
uchar n;
uchar count;
uchar counter=0;
unsigned char time[7]="000000";
unsigned char sender[9]="00000000";
extern void initLCM( void); //LCD初始化子程序
extern void DisplayListChar(unsigned char X,unsigned char Y, unsigned char *DData); //顯示指定坐標(biāo)的一串字符子函數(shù)
extern void DisplayOneChar(uchar X,uchar Y,uchar DData);
extern delay_LCM(unsigned int k);
extern void WriteCommandLCM(uchar WCLCM,uchar BusyC);
void delay(unsigned int i)
{unsigned int j;
unsigned char k;
for(j=i;j>0;j--)
for(k=255;k>0;k--);
}
void delay1ms()
{unsigned int i;
for(i=500000;i>0;i--);
}
Initial_time0com()
{
TMOD=0X21;
TL0=0Xb0;
TH0=0X3c;
IE=0x82;
TR0=0;
}
Initial_sconcom()
{
//TOMD=0X02;
TH1=0Xf4;
TL1=0Xf4;
PCON=0X00;
TR1=1;
SCON=0X50;
}
void main()
{
unsigned int i=0;
unsigned int j=0;
unsigned int k=0;
unsigned char l=0;
unsigned int m=0;
unsigned int n=0;
count=20;
n=count; //count和n配合使用得到1S鐘定時
keynum=0;//記錄按鍵被按了幾次
timenum=0;//記錄現(xiàn)在正在修改的是時分秒6位數(shù)字鐘的哪一位
initLCM();//lcd1602初始化
Initial_time0com();//定時器0的初始化在這里的作用是產(chǎn)生時分秒的進(jìn)位
Initial_sconcom();//串口和定時器1的初始化發(fā)送數(shù)據(jù)
/****************************************以下代碼為LCD1602一開始顯示的狀態(tài)*************************/
delay_LCM(100);
DisplayListChar(0,0,inittempreture);
delay_LCM(100);
DisplayListChar(0,1,inittime);
delay_LCM(100);
delay_LCM(100);
delay_LCM(50);
/*****************************************以上代碼為LCD1602一開始顯示的狀態(tài)*******************************************/
while(1) //通過大循環(huán)不斷掃描按鍵狀態(tài)
{
DisplayListChar(5,1,time); //顯示定時時間的初始狀態(tài)000000
delay_LCM(100);
/****************************如果按鍵1被按下3種狀態(tài)之間循環(huán)切換**********/
if(k1==0)
{
delay(255);
P0=(states1[i]&(P0|0x07));
datasend=(states1[i]&(datasend|0x07));
delay(255);
i++;
}
if(i==3)
i=0;
/****************************如果按鍵2被按下2種狀態(tài)之間循環(huán)切換**********/
if(k2==0)
{
delay(255);
P0=(states2[j]&(P0|0x18));
datasend=(states2[j]&(datasend|0x18));
delay(255);
j++;
}
if(j==3)
j=0;
/****************************如果按鍵3被按下3種狀態(tài)之間循環(huán)切換**********/
if(k3==0)
{
delay(255);
P0=(states3[k]&(P0|0xe0));
datasend=(states3[k]&(datasend|0xe0));
delay(255);
k++;
}
if(k==3)
k=0;
/****************************如果按鍵4、5被按下則根據(jù)按鍵次數(shù)l計(jì)算出溫度值顯示在LCD1602上**********/
if(k4==0)
{if(l!=21)
{l++;
}
delay_LCM(100);
if(l<=5)
{
delay_LCM(1000);
DisplayOneChar(11,0,tempreture[1]);
delay_LCM(100);
DisplayOneChar(12,0,tempreture[l+4]);
}
if((l>5)&&(l<=15))
{
delay_LCM(1000);
DisplayOneChar(11,0,tempreture[2]);
delay_LCM(100);
DisplayOneChar(12,0,tempreture[l-6]);
}
if(l>15)
{
delay_LCM(1000);
DisplayOneChar(11,0,tempreture[3]);
delay_LCM(100);
DisplayOneChar(12,0,tempreture[l-16]);
}
}
if(k5==0)
{
if(l>1)
{l--;
}
if(l<=5)
{
delay_LCM(1000);
DisplayOneChar(11,0,tempreture[1]);
delay_LCM(100);
DisplayOneChar(12,0,tempreture[l+4]);
}
if((l>5)&&(l<=15))
{
delay_LCM(1000);
DisplayOneChar(11,0,tempreture[2]);
delay_LCM(100);
DisplayOneChar(12,0,tempreture[l-6]);
}
if(l>15)
{
delay_LCM(1000);
DisplayOneChar(11,0,tempreture[3]);
delay_LCM(100);
DisplayOneChar(12,0,tempreture[l-16]);
}
}
/****************************如果按鍵6被按下定時0關(guān)閉,設(shè)置不同時間位置的定時時間,具體位置由按鍵次數(shù)循環(huán)切換**********/
if(k6==0)
{ TR0=0;
delay_LCM(100);
if(k6==0)
{
timenum++;
delay_LCM(100);
delay_LCM(100);
}
}
/****************************如果按鍵7被按下并且此時定時器0處于停止則每按一次按鍵定時值循環(huán)加1**********/
if((k7==0)&&(TR0==0))
{
delay_LCM(100);
if(k7==0)
{
delay_LCM(100);
time[((timenum-1)%6)]++;
if(time[((timenum-1)%6)]>'9')
time[((timenum-1)%6)]='0';
}
}
/****************************如果按鍵8被按下開定時器0發(fā)送數(shù)據(jù)并開始定時**********/
if(k8==0)
{ TR0=1;
sender[0]=datasend;
sender[1]=time[0];
sender[2]=time[1];
sender[3]=time[2];
sender[4]=time[3];
sender[5]=time[4];
sender[6]=time[5];
sender[7]=l;
while(++counter<=8)
{SBUF=sender[counter-1];
while(TI==0);
TI=0;
while(RI==0);
RI=0;
}
counter=0;
}
}
}
void time0_int(void) interrupt 1
{TL0=0xb0;
TH0=0x3c;
if((time[0]=='0')&&(time[1]=='0')&&(time[2]=='0')&&(time[3]=='0')&&(time[4]=='0')&&(time[5]=='0'))
{TR0=0;
delay_LCM(100);
}
n--;
if(n==0)
{ if(time[5]=='0')
{time[5]='9';
if(time[4]=='0')
{time[4]='5';
if(time[3]=='0')
{time[3]='9';
if(time[2]=='0')
{time[2]='5';
if(time[1]==0)
{TR0=0;
// p1_0=0;
//DisplayListChar(1,1,kaiji);
}
else
time[1]--;
}
else
time[2]--;}
else
time[3]--;}
else
time[4]--;
}
else
time[5]--;
n=count;}
}
/*******************************************************************/
//Name of this design: LCD show Electric Clock
//Author: 張騰
//Date: 20014-6-02
/*******************************************************************/
#include <reg51.h>
#include <intrins.h>
#include <string.h>
#include <absacc.h>
#define uchar unsigned char
#define uint unsigned int
#define BUSY 0x80 //lcd忙檢測標(biāo)志
#define DATAPORT P2 //定義P0口為LCD通訊端口
//sbit light=P1^3; //????????????????????????????????????????/
//sbit LCM_RS=P2^0; //數(shù)據(jù)/命令端
sbit LCM_RS=P3^3;
sbit LCM_RW=P3^4; //讀/寫選擇端
sbit LCM_EN=P3^5; //使能信號
void delay_LCM(uint); //LCD延時子程序
void lcd_wait(void); //LCD檢測忙子程序
void WriteCommandLCM(uchar WCLCM,uchar BusyC); //寫指令到ICM子函數(shù)
void WriteDataLCM(uchar WDLCM); //寫數(shù)據(jù)到LCM子函數(shù)
void DisplayOneChar(uchar X,uchar Y,uchar DData); //顯示指定坐標(biāo)的一個字符子函數(shù)
void initLCM( void); //LCD初始化子程序
void DisplayListChar(uchar X,uchar Y, unsigned char *DData); //顯示指定坐標(biāo)的一串字符子函數(shù)
/*********延時K*1ms,12.000mhz**********/
void delay_LCM(uint k)
{
uint i,j;
for(i=0;i<k;i++)
{
for(j=0;j<60;j++)
{;}
}
}
/**********寫指令到LCM子函數(shù)************/
void WriteCommandLCM(uchar WCLCM,uchar BusyC)
{
if(BusyC)lcd_wait(); //lcd如果忙就一直檢測,直到不忙為止
DATAPORT=WCLCM;
LCM_RS=0; // 選中指令寄存器
LCM_RW=0; // 寫模式
LCM_EN=1; //下跳沿時執(zhí)行命令
_nop_();
_nop_();
_nop_();
LCM_EN=0;
}
/**********寫數(shù)據(jù)到LCM子函數(shù)************/
void WriteDataLCM(uchar WDLCM)
{
lcd_wait( ); //檢測忙信號
DATAPORT=WDLCM;
LCM_RS=1; // 選中數(shù)據(jù)寄存器
LCM_RW=0; // 寫模式
LCM_EN=1;
_nop_();
_nop_();
_nop_();
LCM_EN=0;
}
/***********lcm內(nèi)部等待函數(shù)*************/
void lcd_wait(void)
{
DATAPORT=0xff;
LCM_EN=1;
LCM_RS=0;
LCM_RW=1;
_nop_();
while(DATAPORT&BUSY) //如果忙的話就一直檢測
{ LCM_EN=0;
_nop_();
_nop_();
LCM_EN=1;
_nop_();
_nop_();
}
LCM_EN=0;
}
/**********LCM初始化子函數(shù)***********/
void initLCM( )
{
DATAPORT=0;
delay_LCM(15);
WriteCommandLCM(0x38,0); //三次顯示模式設(shè)置,不檢測忙信號
delay_LCM(5);
WriteCommandLCM(0x38,0);
delay_LCM(5);
WriteCommandLCM(0x38,0);
delay_LCM(5);
WriteCommandLCM(0x38,1); //8bit數(shù)據(jù)傳送,2行顯示,5*7字型,檢測忙信號
WriteCommandLCM(0x08,1); //關(guān)閉顯示,檢測忙信號
WriteCommandLCM(0x01,1); //清屏,檢測忙信號 光標(biāo)復(fù)位到00H
WriteCommandLCM(0x06,1); //顯示光標(biāo)右移設(shè)置,檢測忙信號
WriteCommandLCM(0x0c,1); //顯示屏打開,光標(biāo)不顯示,不閃爍,檢測忙信號
}
/****************顯示指定坐標(biāo)的一個字符子函數(shù)*************/
void DisplayOneChar(uchar X,uchar Y,uchar DData)
{
uchar mx,my;
my=Y&1;
mx=X&0xf;
if(my>0)mx+=0x40; //若y為1(顯示第二行),地址碼+0X40
mx+=0x80; //指令碼為地址碼+0X80
WriteCommandLCM(mx,0);
WriteDataLCM(DData);
}
/***********顯示指定坐標(biāo)的一串字符子函數(shù)***********/
void DisplayListChar(uchar X,uchar Y, unsigned char *DData)
{
uchar i=0,n;
Y&=0x01;
X&=0x0f;
n=strlen(DData);
while(i<n)
{
DisplayOneChar(X,Y,DData[i]);
i++;
X++;
}
}