【原創+整理】基於紅外通信的溫度監測仿真+用到的知識整理
一、總線
1、總線概述
計算機系統是以微處理器爲核心的,各器件要與微處理器相連,且必須協調工作,所以在微處理機中引入了總線的概念,各器件共同享用總線,任何時候只能有一個器件發送數據(可以有多個器件同時接收數據) 。
計算機的總線分爲控制總線、地址總線和數據總線等三種。而數據總線用於傳送數據,控制總線用於傳送控制信號, 地址總線則用於選擇存儲單元或外設。
2、51單片機的三總線結構
數據總線是P0口,共8位;地址總線高8位是P2口,低8位是P0口,共16位。;數據總線有WR,RD等。
(1)數據總線
51 單片機的數據總線爲P0 口,P0 口爲雙向數據通道,CPU 從P0 口送出和讀回數據。
(2)地址總線
51 系列單片機的地址總線爲16 位。
爲了節約芯片引腳,採用P0 口複用方式,除了作爲數據總線外,在ALE 信號時序匹配下,通過外置的數據鎖存器,在總線訪問前半週期從P0口送出低8位地址,後半週期從P0 口送出8 位數據。
高8位地址則通過P2 口送出。
(3)控制總線
51 系列單片機的控制總線包括讀控制信號P3.7 和寫控制信號P3.6 等,二者分別作爲總線模式下數據讀和數據寫的使能信號。
原文鏈接:https://blog.csdn.net/lijinshanba/article/details/80911816
二、DS18B20溫度傳感器
DS18B20性能
①獨特的單線接口方式,DS18B20在與微處理器連接時僅需要一條口線即可實現微處理器與DS18B20的雙向通訊。
②測溫範圍-55℃~+125℃,固有測溫誤差(注意,不是分辨率,這裏之前是錯誤的)1℃。
③支持多點組網功能,多個DS18B20可以並聯在唯一的三線上,最多隻能並聯8個,實現多點測溫,如果數量過多,會使供電電源電壓過低,從而造成信號傳輸的不穩定。
④工作電源:3.0~5.5V/DC(可以數據線寄生電源)
⑤在使用中不需要任何外圍元件
⑥測量結果以9~12位數字量方式串行傳送
⑦不鏽鋼保護管直徑Φ6
⑧適用於DN1525,DN40DN250各種介質工業管道和狹小空間設備測溫
⑨標準安裝螺紋M10X1,M12X1.5,G1/2”任選
⑩PVC電纜直接出線或德式球型接線盒出線,便於與其它電器設備連接。
**
DS18B20引腳圖及功能
DS18B20內部結構主要由四部分組成:64位光刻ROM、溫度傳感器、非揮發的溫度報警觸發器TH和TL、配置寄存器。
利用DS18B20做一個溫控器(DS18B20引腳圖_工作原理及應用電路)
1、GND爲電源地
2、DQ爲數字信號輸入/輸出端
3、VDD爲外接供電電源輸入端(在寄生電源接線方式時接地)。
DS18B20工作原理
DS18B20的讀寫時序和測溫原理與DS1820相同,只是得到的溫度值的位數因分辨率不同而不同,且溫度轉換時的延時時間由2s減爲750ms。
DS18B20測溫原理如圖所示。
圖中低溫度係數晶振的振盪頻率受溫度影響很小,用於產生固定頻率的脈衝信號送給計數器1。
高溫度係數晶振隨溫度變化其振盪率明顯改變,所產生的信號作爲計數器2的脈衝輸入。
計數器1和溫度寄存器被預置在-55℃所對應的一個基數值。計數器1對低溫度係數晶振產生的脈衝信號進行減法計數,
當計數器1的預置值減到0時,溫度寄存器的值將加1,計數器1的預置將重新被裝入,計數器1重新開始對低溫度係數晶振產生的脈衝信號進行計數,
如此循環直到計數器2計數到0時,停止溫度寄存器值的累加,此時溫度寄存器中的數值即爲所測溫度。
斜率累加器用於補償和修正測溫過程中的非線性,其輸出用於修正計數器1的預置值。
DS18B20指令及寄存器
1、溫度寄存器
2、精度寄存器
3、ROM指令表
4、RAM指令表
參考鏈接:https://blog.csdn.net/zhangxuechao_/article/details/74991985
三、AMPIRE128X64型LCD屏
1、引腳作用
CS1:左半屏選擇引腳,低電平有效。該引腳有效時左半屏幕操作有效。
CS2:右半屏選擇引腳,低電平有效。該引腳有效時右半屏幕操作有效。
GND:電源地
VCC:電源正
V0:LCD的驅動電壓,其實可以用它來調節LCD藍哇哇的皮膚的深淺。
RS:命令/數據控制引腳。該腳爲高電平是DB數據線上傳輸的是數據,該腳爲低電平是DB數據線上傳輸的是命令。
R/W:讀/寫控制引腳。該腳爲高電平時從LCD模塊中毒數據,該腳爲低電平時寫數據到LCD模塊中。
E:LCD讀寫使能引腳(E表示模塊使能引腳,但是注意這裏表示的是讀寫使能引腳,最好初始化的時候給個低電平,)
DB:數據總線。
RST:復位腳
-Vout:LCD的驅動電源。
2、軟件驅動程序
(1)選擇需要顯示的屏幕
通過CS1,CS2組合來選擇驅動的是左半邊屏幕還是右半邊屏幕,還是兩邊的屏幕一起驅動,還是說兩邊的屏幕都不驅動顯示。具體組合如下。
並不是說CS1==0 CD2 == 1就只顯示左邊屏幕而不顯示右邊屏幕。而是描述的是接下來的操作只與左邊屏幕有關,與右邊屏幕沒有關係。
當你在操作屏幕顯示的時候必須先指明要修改哪一邊屏幕的內容。
我們只需要知道要想讓屏幕顯示,就得先告訴他左右哪邊的屏幕顯示。
(2)設置顯示的行
整個屏幕從上到下共有64行
但是
但是
但是
真正讓我們選擇的只有8行
只有8行
一行就是一行164個像素點,也就是說所謂的設置顯示的行只是選擇顯示的在哪一頁
搞清楚了設置顯示的行(頁)的問題,那麼所謂的64行是什麼玩意,那又是怎麼回事呢。
其實還有條指令是設置開始顯示的首行位置,
也就是說,你可以通過設置開始行來選擇第一行的位置,
如果你設置第開始行是0行,
那麼第1頁就是0-7行,
第二頁就是8-15行,
如果你設置的開始行數是第1行,
那麼第一頁就是1-8行,
第二頁就是9-16行…。
其可以表示爲設置的首行爲x(x<64)行,
那麼第y頁的起始行數是 (y8+x)%64,
結束行數是(y*8+x+7)%64;
不可以實現從任意行顯示。
(3)設置顯示的開始列
整個屏幕共有64128個像素點,也就是說共有64行和128列
前面說過,該LCD分爲左右兩塊屏幕,兩塊屏幕需要通過CS1與CS2組合來進行控制。這兩塊屏幕各佔64列,也就是說一塊屏幕的像素點是6464,所以我們在設置顯示起始列的時候實際上能選擇的只有0-63列這個範圍。
起始列設置的在哪一列開始顯示,就在那一列開始顯示,並且每顯示完一列就自動加1。
(4)設置顯示的數據(圖像)
該LCD顯示的方式是一列一列開始顯示,每顯示完一列,記錄列數的地址自動加1,也就是說如果你送入的數據是0x88,那麼就會顯示當前頁的當前列的8個相熟點,由上往下爲10001000,瞭解這個對取模至關重要。
驅動的常用指令
#define LCD_CLEAR 0X01 //lcd清屏
#define LCD_SHOW_MODE(x) (0x02+x) //選擇顯示模式 0允許輸入IRAM地址 1允許輸入垂直捲動地址
#define LCD_SHOW_OFF 0X3E //lcd顯示關
#define LCD_SHOW_ON 0X3F //lcd顯示開
#define LCD_PAGE(x) (0xb8+x) //設置頁數
#define LCD_HANG(x) (0xc0+x) //設置起始行
#define LCD_LEI(x) (0x40+x) //設置起始列
寫一條數據到LCD中的流程
(1)查忙。
(2)RS = H/L(H:顯示數據 L:操作指令)
(3)RW = L(寫數據)
(4)E = H (使能讀寫數據)
(5)送入數據到DB口
(6)E = L (送入數據)
具體程序如下所示
void lcd12864_WriteCommed (unsigned char commed) //12864寫命令
{
lcd12864_Busy (); //12864查忙
lcdRsPin(PIN_LOW);
lcdRwPin(PIN_LOW);
lcdEnPin(PIN_HIGH);
LCD_DATA = commed;
lcd12864_delay (5); //延時函數
LCD_EN = 0;
}
void lcd12864_WriteData (unsigned char dat) //12864寫數據
{
lcd12864_Busy (); //12864查忙
lcdRsPin(PIN_HIGH);
lcdRwPin(PIN_LOW);
lcdEnPin(PIN_HIGH);
LCD_DATA = dat;
lcd12864_delay (5); //延時函數
lcdEnPin(PIN_LOW) ;
}
void lcd12864_Busy (void) //12864查忙
{
LCD_DATA = 0XFF;
lcdRsPin(PIN_LOW);
lcdRwPin(PIN_HIGH);
lcdEnPin(PIN_HIGH);
while(LCD_DATA&0x80);
lcdEnPin(PIN_LOW) ;
}
https://blog.csdn.net/qq_33784286/article/details/103067878
四、程序實例
(一)發射端程序
1、DS18B20 溫度傳感器驅動程序
DS18B20.h
#ifndef __18B20_H__
#define __18B20_H__
#define uchar unsigned char
#define uint unsigned int
sbit DQ=P1^0;
void delay_18B20(unsigned int i); //DS18B20延時
Init_DS18B20(void); //DS18B20初始化函數
unsigned char ReadOneChar(void); //讀取一個字節
WriteOneChar(unsigned char dat); //寫入一個字節
unsigned char ds18b2o_s(void);
#endif
、
、
、
DS18B20.c
#include<reg52.h>
#include"18b20.h"
#include<intrins.h>
/***********ds18b20延遲函數*******/
void delay_18B20(uint i)
{
while(i--);
}
/**********ds18b20初始化函數**********************
Init_DS18B20(void)
{
bit flag;
DQ=1; //DQ復位 DQ--數字信號輸入輸出端
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
DQ=0; //單片機將DQ拉低
delay_18B20(80); //精確延時 大於 480us
DQ=1; //拉高總線
delay_18B20(2);
if(DQ==1) flag=1 ;
else flag=0;
delay_18B20(20);
}
/************從DS18B20讀取一個字節數據**************/
unsigned char ReadOneChar(void)
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{ _nop_();
DQ=0; // 給脈衝信號
DQ=1;
dat>>=1; //右移一位,空位補0
delay_18B20(2);
if(DQ)
dat|=0x80; //1000 0000 按位或 1|0=1 1|1=1 0|0=0
delay_18B20(4);
}
return(dat);
}
/*********向DS18B20寫入一個字節***********/
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ=0;
delay_18B20(1);
DQ = dat&0x01; 按位或與 0 & 0=0 0 & 1= 0 1 & 0= 0 1 & 1= 1。
delay_18B20(5);
DQ=1;
dat>>=1;
}
delay_18B20(4);
}
/**************讀取ds18b20當前溫度************/
uchar ds18b2o_s(void)
{
uchar temp;
while(Init_DS18B20()==1) ;
WriteOneChar(0xCC); // 跳過讀序號列號的操作 讀寫指令,可由上文ROM、RAM指令集查找
WriteOneChar(0x44); // 啓動溫度轉換
delay_18B20(1500); // this message is wery important
while(Init_DS18B20()==1) ;
WriteOneChar(0xCC); //跳過讀序號列號的操作
WriteOneChar(0xBE); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度
delay_18B20(1500);
DPL=ReadOneChar(); //讀取溫度值低位
DPH=ReadOneChar(); //讀取溫度值高位
temp=(((DPH)*256+DPL)>>4); //當前採集溫度值除16得實際溫度值 0.0625約爲1/16'c
return(temp);
}
2、紅外發射程序
hongwaifashe.h
#ifndef __HONGWAIFASHE_H__
#define __HONGWAIFASHE_H__
#define uchar unsigned char
#define uint unsigned int
extern uchar setdata[2];
void ZZ(uchar x);
void Z0(uchar temp);
void TT0(bit BT,uint x);
#define SBM 0x80 //識別碼
#define m9 (65536-9000) //約9mS
#define m4_5 (65536-4500) //約4.5mS
#define m1_68 (65536-1680) //約1.68mS
//#define m_65 (65536-580) //約0.65mS
#define m_56 (65536-560) //約0.56mS
#define m40 (65536-40000) //約40mS
//#define m56 (65536-56000) //56mS
//#define m2_25 (65536-2250) //約2.25mS
sbit IR = P3^0; //定義發射引腳(接PNP三極管基極,) 三極管起電流放大作用
extern void hongwaifashe(void);
#endif
/
/
/
/
hongwaifashe.c
#include <reg52.h>
#include <intrins.h>
#include "hongwaifashe.h"
void hongwaifashe(void)
{
TMOD = 0x01; //T0 16位工作方式
IR=1; //發射端口常態爲高電平
ZZ(setdata[0]);
ZZ(setdata[1]);
}
void ZZ(uchar x)
{
TT0(1,m9); //高電平9mS
TT0(0,m4_5); //低電平4.5mS
/*┈ 發送4幀數據 ┈*/
Z0(SBM);
Z0(~SBM);
Z0(x);
Z0(~x);
/*┈┈ 結束碼 ┈┈*/
TT0(1,m_56);
TT0(0,m40);
}
/*┈┈┈┈┈┈┈單幀發送程序┈┈┈┈┈┈┈┈*/
void Z0(uchar temp)
{
uchar v;
for (v=0;v<8;v++) //循環8次移位
{
TT0(1,m_56); //高電平0.65mS
if(temp&0x01) TT0(0,m1_68); //發送最低位
else TT0(0,m_56);
temp >>= 1; //右移一位
}
}
/*┈┈┈┈┈┈┈38KHz脈衝發射 + 延時┈┈┈┈┈┈*/
void TT0(bit BT,uint x)
{
TH0 = x>>8; //輸入T0初始值
TL0 = x;
TF0=0; //清0
TR0=1; //啓動定時器0
if(BT == 0) while(!TF0); //BT=0時不發射38KHz脈衝只延時;BT=1發射38KHz脈衝且延時;
else while(1) //38KHz脈衝,佔空比1:5
{
IR = 0;
if(TF0)break;
if(TF0)break;
IR = 1;
if(TF0)break;
if(TF0)break;
if(TF0)break;
if(TF0)break;
if(TF0)break;
if(TF0)break;
if(TF0)break;
if(TF0)break;
if(TF0)break;
if(TF0)break;
}
TR0=0; //關閉定時器0
TF0=0; //標誌位溢出則清0
IR =1; //脈衝停止後,發射端口常態爲高電平
}
3、主函數
main.c
#include<reg52.h>
#include"18b20.h"
#include"lamp.h"
#include "hongwaifashe.h"
#define uchar unsigned char
#define uint unsigned int
uchar setdata[2];
void main(void)
{
while(1)
{
setdata[0]=ds18b20_s();
setdata[1]=lamp();
hongwaifashe();
}
}
## (二)接收端程序
**1、LCD 12864 驅動程序**
LCD.h
```c
#ifndef _12864_H_
#define _12864_H_
#define LCD P0 /*LCD端口*/
#define uint unsigned int
#define uchar unsigned char
/****漢字數組聲明****/
extern uchar code WUYOU[2][32];
extern uchar code XIAN[32];
extern uchar code HUAN[32];
extern uchar code JING[32];
extern uchar code JIAN[32];
extern uchar code CE[32];
extern uchar code WEN[32];
extern uchar code DU[32];
extern uchar code MAOHAO[32];
extern uchar code LIANG[32];
extern uchar code DUHAO[32];
extern uchar code SHUZI[10][32];
/*控制信號宏定義*/
sbit CS1 = P2^1;
sbit CS2 = P2^0;
sbit E = P2^3;
sbit RW = P2^4;
sbit RS = P2^5;
sbit busy_bit =P0^7;
extern void lcd_mwc( uchar i);
extern void lcd_mwd( uchar i );
extern void lcd_clear(void);
extern void lcd_init(void);
extern void dispm_zi_up( uchar code *zi);
extern void dispm_zi_down( uchar code *zi);
#endif
/
/
/
LCD.c
#include<reg52.h>
#include"12864.h"
#include<intrins.h>
uchar code WUYOU[2][32]={{0x00,0x40,0x42,0x42,0x42,0x42,0xFE,0x42,
0xC2,0x42,0x43,0x42,0x60,0x40,0x00,0x00,
0x00,0x80,0x40,0x20,0x18,0x06,0x01,0x00,
0x3F,0x40,0x40,0x40,0x40,0x40,0x70,0x00},
{0x04,0x04,0x04,0x84,0xE4,0x3C,0x27,0x24,
0x24,0x24,0x24,0xF4,0x24,0x06,0x04,0x00,
0x04,0x02,0x01,0x00,0xFF,0x09,0x09,0x09,
0x09,0x49,0x89,0x7F,0x00,0x00,0x00,0x00}};
uchar code XIAN[32]={0x00,0x20,0x30,0xAC,0x63,0x20,0x30,0x20,
0x20,0xFF,0x90,0x92,0x94,0xD0,0x80,0x00,
0x20,0x62,0x23,0x12,0x12,0x12,0x41,0x41,
0x21,0x17,0x18,0x24,0x42,0x80,0xE0,0x00};
uchar code HUAN[32]={0x42,0x42,0xFE,0x43,0x42,0x04,0x04,0x04,
0x84,0xE4,0x1C,0x84,0x04,0x06,0x04,0x00,
0x20,0x60,0x3F,0x10,0x10,0x04,0x02,0x01,
0x00,0xFF,0x00,0x00,0x01,0x03,0x06,0x00};
uchar code JING[32]={0x20,0x20,0xFF,0x20,0x20,0x24,0xA4,0xAC,
0xB5,0xA6,0xB4,0xAC,0xE6,0xB4,0x20,0x00,
0x10,0x30,0x1F,0x08,0x88,0x80,0x4F,0x3A,
0x0A,0x0A,0x7A,0x8A,0x8F,0x80,0xE0,0x00};
uchar code JIAN[32]={0x00,0x00,0xFC,0x00,0x00,0xFF,0x00,0x20,
0x10,0x0F,0x18,0x28,0x6C,0x08,0x00,0x00,
0x40,0x40,0x7E,0x42,0x42,0x7F,0x42,0x42,
0x42,0x7E,0x42,0x42,0x7F,0x42,0x40,0x00};
uchar code CE[32]={0x10,0x22,0x6C,0x00,0x80,0xFC,0x04,0xF4,
0x04,0xFE,0x04,0xF8,0x00,0xFE,0x00,0x00,
0x04,0x04,0xFE,0x01,0x40,0x27,0x10,0x0F,
0x10,0x67,0x00,0x47,0x80,0x7F,0x00,0x00};
uchar code WEN[32]={0x10,0x22,0x64,0x0C,0x80,0x00,0xFE,0x92,
0x92,0x92,0x92,0x92,0xFF,0x02,0x00,0x00,
0x04,0x04,0xFE,0x01,0x40,0x7E,0x42,0x42,
0x7E,0x42,0x7E,0x42,0x42,0x7E,0x40,0x00};
uchar code DU[32]={0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0xA5,
0xA6,0xA4,0xFC,0x24,0x34,0x26,0x04,0x00,
0x40,0x20,0x9F,0x80,0x42,0x42,0x26,0x2A,
0x12,0x2A,0x26,0x42,0x40,0xC0,0x40,0x00};
uchar code MAOHAO[32]={0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,
0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x31,
0x31,0x30,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code DUHAO[32]={ 0x00,0x06,0x09,0x09,0xE6,0xF0,0x18,0x08,
0x08,0x08,0x18,0x30,0x78,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x07,0x0F,0x18,0x30,
0x20,0x20,0x20,0x10,0x08,0x00,0x00,0x00};
uchar code LIANG[32]={0x00,0x02,0x02,0x7A,0x4A,0x4A,0x4A,0x4B,
0x4A,0x4A,0x4A,0x7E,0x0B,0x02,0x00,0x00,
0x04,0x83,0x81,0x41,0x3D,0x05,0x05,0x05,
0x05,0x05,0x7F,0x85,0x81,0x85,0xE3,0x00};
uchar code SHUZI[10][32]={{0x00,0x00,0xE0,0xF0,0xF0,0x18,0x08,0x08,
0x08,0x08,0x08,0x38,0xF0,0xE0,0xC0,0x00,
0x00,0x01,0x0F,0x1F,0x1F,0x30,0x20,0x20,
0x20,0x20,0x20,0x38,0x1F,0x0F,0x07,0x00},
{0x00,0x00,0x00,0x00,0x10,0x10,0x10,0xF8,
0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x3F,
0x3F,0x3F,0x20,0x20,0x20,0x20,0x00,0x00},
{0x00,0x00,0x20,0x70,0x78,0x08,0x08,0x08,
0x08,0x08,0x88,0xF8,0xF8,0x70,0x00,0x00,
0x00,0x00,0x30,0x30,0x38,0x3C,0x34,0x36,
0x32,0x33,0x31,0x31,0x30,0x38,0x08,0x00},
{0x00,0x00,0x30,0x30,0x38,0x08,0x88,0x88,
0x88,0x88,0xD8,0xF8,0x70,0x20,0x00,0x00,
0x00,0x00,0x18,0x18,0x38,0x20,0x21,0x21,
0x21,0x21,0x21,0x3B,0x1E,0x1E,0x04,0x00},
{0x00,0x00,0x00,0x00,0x80,0x80,0x40,0x60,
0x30,0xF0,0xF8,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x06,0x07,0x05,0x04,0x24,0x24,
0x24,0x3F,0x3F,0x3F,0x24,0x24,0x24,0x00},
{0x00,0x00,0x00,0xF8,0xF8,0x88,0x88,0x88,
0xC8,0xC8,0x88,0x88,0x88,0x08,0x00,0x00,
0x00,0x00,0x18,0x1D,0x39,0x20,0x20,0x20,
0x20,0x20,0x20,0x3B,0x1F,0x0F,0x06,0x00},
{0x00,0x00,0xC0,0xE0,0xF0,0x98,0x88,0x88,
0x88,0x88,0x98,0x98,0xB8,0x10,0x00,0x00,
0x00,0x03,0x0F,0x1F,0x1F,0x31,0x20,0x20,
0x20,0x20,0x20,0x31,0x1F,0x1F,0x0E,0x00},
{0x00,0x00,0x30,0x38,0x18,0x18,0x08,0x08,
0x08,0x88,0xC8,0x68,0x38,0x18,0x08,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x3E,
0x3F,0x03,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x70,0xF0,0xD8,0xC8,0x88,0x88,
0x88,0x88,0x88,0x88,0xF8,0x70,0x20,0x00,
0x00,0x08,0x1E,0x1E,0x33,0x21,0x21,0x21,
0x21,0x21,0x23,0x23,0x1E,0x1E,0x0C,0x00},
{0x00,0x00,0x70,0xF0,0xD8,0xC8,0x88,0x88,
0x88,0x88,0x88,0x88,0xF8,0x70,0x20,0x00,
0x00,0x08,0x1E,0x1E,0x33,0x21,0x21,0x21,
0x21,0x21,0x23,0x23,0x1E,0x1E,0x0C,0x00}};
/*發命令i到主窗口*/
extern void lcd_mwc( uchar i)
{
RW=1;
RS=0;
do{ _nop_(); E=1;E=0;}
while(busy_bit);
RW=0;
E=1;
LCD=i;
E=0;
}
/*發數據i到主窗口*/
extern void lcd_mwd( uchar i )
{
RW=1;
RS=0;
do{ _nop_(); E=1;E=0;}
while(busy_bit);
RW=0;
RS=1;
E=1;
LCD=i;
E=0;
}
/*清屏*/
void lcd_clear(void)
{
uchar i,page;
for(page=0xb8;page<0xc0;page++)
{
lcd_mwc(page);
lcd_mwc(0x40);
for(i=0;i<64;i++)
lcd_mwd(0x00);
}
}
/*初始化LCD*/
extern void lcd_init(void)
{
lcd_mwc(0x3f);
lcd_mwc(0x0c0);
}
/*dispm_zi_up()顯示漢字上半部*/
extern void dispm_zi_up(uchar code *zi)
{
uchar i;
for(i=0;i<16;i++)
lcd_mwd(*(zi+i));
}
/*dispm_zi_down()顯示漢字下半部*/
extern void dispm_zi_down(uchar code *zi)
{
uchar i;
for(i=16;i<32;i++)
lcd_mwd(*(zi+i));
}
2、主函數
main.c
#include<reg52.h>
#include"12864.h"
#include<intrins.h>
sbit IR=P3^2; //將IR位定義爲P3.2引腳
unsigned char a[4]; //儲存用戶碼、用戶反碼與鍵數據碼、鍵數據反碼
unsigned char zai=0,om,pm,qm;
unsigned int LowTime,HighTime; //儲存高、低電平的寬度
void fenjie()
{
if(a[2]==0x80)
zai=0;
else if(a[2]==0xc0)
zai=1;
else
{
om=a[2]/100;
pm=a[2]/10%10;
qm=a[2]%100%10;
}
}
bit DeCode(void)
{
unsigned char i,j;
unsigned char temp; //儲存解碼出的數據
for(i=0;i<4;i++) //連續讀取4個用戶碼和鍵數據碼
{
for(j=0;j<8;j++) //每個碼有8位數字
{
temp=temp>>1; //temp中的各數據位右移一位,因爲先讀出的是高位數據
TH0=0; //定時器清0
TL0=0; //定時器清0
TR0=1; //開啓定時器T0
while(IR==0) //如果是低電平就等待
; //低電平計時
TR0=0; //關閉定時器T0
LowTime=TH0*256+TL0; //保存低電平寬度
TH0=0; //定時器清0
TL0=0; //定時器清0
TR0=1; //開啓定時器T0
while(IR==1) //如果是高電平就等待
;
TR0=0; //關閉定時器T0
HighTime=TH0*256+TL0; //保存高電平寬度
if((LowTime<360)||(LowTime>680))
return 0; //如果低電平長度不在合理範圍,則認爲出錯,停止解碼
if((HighTime>400)&&(HighTime<680)) //如果高電平時間在560微秒左右,即計數560/1.085=516次
temp=temp&0x7f; //(520-100=420, 520+100=620),則該位是0
if((HighTime>1400)&&(HighTime<1850)) //如果高電平時間在1680微秒左右,即計數1680/1.085=1548次
temp=temp|0x80; //(1550-250=1300,1550+250=1800),則該位是1
}
a[i]=temp; //將解碼出的字節值儲存在a[i]
}
if(a[2]=~a[3]) //驗證鍵數據碼和其反碼是否相等,一般情況下不必驗證用戶碼
return 1; //解碼正確,返回1
}
void init(void)
{
E=1;
CS1=0;CS2=0;
lcd_clear();
lcd_init();
EA=1; //開啓總中斷
ET0=1; //定時器T0中斷允許
IT0=1; //外中斷的下降沿觸發
TMOD=0x01; //使用定時器T0的模式1
TR0=0; //定時器T0關閉
EX0=1; //開外中斷0
}
void display()
{
CS1=0;
CS2=1;
lcd_mwc(0xb8); // 無線環境監測
lcd_mwc(0x50);
dispm_zi_up(&WUYOU[0][0]);
dispm_zi_up(&XIAN);
dispm_zi_up(&HUAN);
lcd_mwc(0xb9);
lcd_mwc(0x50);
dispm_zi_down(&WUYOU[0][0]);
dispm_zi_down(&XIAN);
dispm_zi_down(&HUAN);
lcd_mwc(0xba); // 溫度
lcd_mwc(0x40);
dispm_zi_up(&WEN);
dispm_zi_up(&DU);
dispm_zi_up(&MAOHAO);
dispm_zi_up(&SHUZI[om][0]);
lcd_mwc(0xbb);
lcd_mwc(0x40);
dispm_zi_down(&WEN);
dispm_zi_down(&DU);
dispm_zi_down(&MAOHAO);
dispm_zi_down(&SHUZI[om][0]);
lcd_mwc(0xbc); //亮度
lcd_mwc(0x40);
dispm_zi_up(&LIANG);
dispm_zi_up(&DU);
dispm_zi_up(&MAOHAO);
lcd_mwc(0xbd);
lcd_mwc(0x40);
dispm_zi_down(&LIANG);
dispm_zi_down(&DU);
dispm_zi_down(&MAOHAO);
CS1=1;
CS2=0;
lcd_mwc(0xb8); // 無線環境監測
lcd_mwc(0x40);
dispm_zi_up(&JING);
dispm_zi_up(&JIAN);
dispm_zi_up(&CE);
lcd_mwc(0xb9);
lcd_mwc(0x40);
dispm_zi_down(&JING);
dispm_zi_down(&JIAN);
dispm_zi_down(&CE);
lcd_mwc(0xba); // 溫度
lcd_mwc(0x40);
dispm_zi_up(&SHUZI[pm][0]);
dispm_zi_up(&SHUZI[qm][0]);
dispm_zi_up(&DUHAO);
lcd_mwc(0xbb);
lcd_mwc(0x40);
dispm_zi_down(&SHUZI[pm][0]);
dispm_zi_down(&SHUZI[qm][0]);
dispm_zi_down(&DUHAO);
lcd_mwc(0xbc); //亮度
lcd_mwc(0x40);
dispm_zi_up(&WUYOU[zai][0]);
lcd_mwc(0xbd);
lcd_mwc(0x40);
dispm_zi_down(&WUYOU[zai][0]);
}
void main(void)
{
init();
while(1)
{
// fenjie();
display();
}
}
/************紅外線觸發的外中斷處理************/
void Int0(void) interrupt 0
{
EX0=0; //關閉外中斷0,不再接收二次紅外信號的中斷,只解碼當前紅外信號
TH0=0; //定時器T0的高8位清0
TL0=0; //定時器T0的低8位清0
TR0=1; //開啓定時器T0
while(IR==0); //如果是低電平就等待,給引導碼低電平計時
TR0=0; //關閉定時器T0
LowTime=TH0*256+TL0; //保存低電平時間
if(((LowTime>8500)&&(LowTime<9500))!=1) {EX0=1;return;}
TH0=0; //定時器T0的高8位清0
TL0=0; //定時器T0的低8位清0
fenjie(); TR0=1; //開啓定時器T0
while(IR==1); //如果是高電平就等待,給引導碼高電平計時
TR0=0; //關閉定時器T0
HighTime=TH0*256+TL0; //保存引導碼的高電平長度
if((HighTime>4000)&&(HighTime<5000))
{
DeCode();
fenjie();
}
EX0=1;
}
五、proteus仿真
仿真圖如下
原文鏈接:https://blog.csdn.net/qq_33784286/article/details/103067878