Proteus傳感器+氣體濃度檢測的報警方式控制仿真
1 實驗意義理解
基於前兩個實驗,我們已經成功的實現:
- 對傳感器的數據進行采樣、轉換
- 擬合采樣值
- 對擬合的數據在HDG12864F-1顯示屏上顯示
似乎,該得到的數據已經拿到了,還能干啥?
是的,我們還能利用數據干一些東西,比如說當這個氣體濃度超范圍的時候我們怎么去控制解決。
那么就引出了這個實驗,怎么控制解決?
其實,我們在平時生活中見到過很多,當氣體濃度超過一定范圍:
- 報警
- 開警報燈
- 蜂鳴器出警報聲音
- 疏通
- 開啟風扇通風
- ……
- ……
如上,我們這次實驗就是采取了前三個小點的方式來控制解決。
此外,我們還要優化LCD顯示,就是在屏幕上顯示轉動的風扇。
2 主要實驗器件
-
CPU處理器
- AT89C52
-
LCD顯示
- HDG12864F-1
-
AD轉換器
- ADC0834
-
傳感器
- 溫濕度:SHT10
- 光傳感器:TORCH_LDR
- 瓦斯濃度傳感器:LDR
- 一氧化碳濃度傳感器:LDR
- 氣壓傳感器:MPX4115
-
控制相關
- 報警燈:RGBLED-CC
- 蜂鳴器:SOUNDER
- 通風控制:FAN
3 實驗參考電路
-
未運行時
-
運行時
-
說明
- 有蜂鳴器聲音
- 顯示中第一行的channel后面的字母會根據當前正在采樣轉換的通道不同而改變
- 所有數據僅為轉換后顯示,並未存儲下來,若要存儲顯示,只需要開幾個全局變量保存一下即可
4 實驗中的問題思考
4.1 實現轉動的風扇
要實現這個功能,我們只要知道兩個關鍵點就好了:
- HDG12864F-1液晶顯示如果你不對一個像素覆蓋寫入值,則會保持顯示上次寫入的值
- 任何動態效果實質上是由一個個靜態圖畫“快速”播放而成的
因此,實現這個就很容易了:
- 找到幾個不一樣(轉動角度不一樣)的靜態風扇圖(最好大小一樣,這樣方便寫入,完全覆蓋)
- 對這幾個靜態風扇圖取模
- 調用HDG12864F-1繪制圖片函數將一個靜態圖寫入
- 讓處理器去干別的事情,比如:執行幾句其他的語句,或者直接延時等待
- 調用HDG12864F-1繪制圖片函數寫入另一個靜態圖
- ……
那么,中間為什么會有“讓處理器去干別的事情,比如:執行幾句其他的語句,或者直接延時等待”這一點呢?
其實這是一個控制模擬風扇轉動速度的。你想想如果快速切換兩張圖片,你眼睛還沒視覺殘留呢,就沒了,估計會閃瞎狗眼……所以,選擇一個合適的切換時間間隔也是挺重要的……
第二個,這個靜態圖畫至少兩幅,這個大家應該很好理解,如果一幅的話,沒有變化,換來換去不就那個玩意兒嗎……
4.2 控制部分
首先,我們來看一下控制部分的原理圖:

下面,我們分別說一下各個部分。
-
報警燈
這個RGBLED-CC要想讓它工作,首先就是K端給個低電平。
RGB端,輸入1為亮,0為不亮。
然后,在這個實驗中,其實我們只需要用到紅和綠兩種顏色,所以直接給B端接地,然后R和G端分別綁定到處理器的引腳上。
運行中判斷,如果達到危險值或者恢復至安全值,則處理器重置相應的引腳值。
-
蜂鳴器
主要是SOUNDER元件,一端加電壓,另一端需要給脈沖信號。
這個脈沖信號很重要,一開始,本菜狗就對這個輸入的脈沖信號沒有設置(默認頻率很小),因此都聽不出來發聲了……
后來雙擊輸入的SW1(A),調整了一下參數,然后就聽到了,可參考下圖是我調整的:
當然這里拓展一下,怎么讓它放音樂呢??
這里有兩段經歷讓我對這個有了進一步的認識:
-
大二學校暑假實習的時候,做電子鍾,當時用verilog寫的,那個如果要讓蜂鳴器放出來的不僅僅是那種很難聽的一直尖叫,而是播放音樂啊啥的,需要給不同的頻率
-
大三上微機原理課設,使用筆記本內置的芯片,做了一個基於x86的時鍾(用的匯編語言寫的)。其中,鬧鍾功能,鈴聲我想換成音樂怎么辦?
- 找到音樂的譜子和對應的音符頻率,相對延時
- 分別將頻率和延時寫成“表”,依次延時輸出
這里,再次拓展一下,如果你想聽快速版的音樂怎么辦?想要聽降調,升調的版本怎么辦?
- 頻率:控制音調
- 延時:控制速度
然后,再說一下,怎么控制這個聲音的開關?
這里使用的是DSWITCH元件,可以把它看成一個三態門:
- BP端置為1,接收SW1(A)的輸入
- BP端置為0,高阻態,不發聲
-
-
避風控制
這個模塊主要是由FAN+繼電器PCJ-112D3MH來實現的,這個我在IC網上也沒找到它的DATASHEET,所以,就照着老師的原理圖畫了之后個人理解了一下。
首先,怎么控制它的開關?
-
我們可以看到它左邊連接了一個NPN型的三極管,主要使用也就是
- FAN置為1,打開電風扇
- FAN置為0,打開電風扇
至於,關於這個型號的三極管的具體功能,還有與PNP類型的三極管有啥區別?
我就上網搜了一下問答,可以參考:NPN與PNP三極管的詳解與區別
或許……大家按照上面的寫完代碼之后發現……為啥我明明程序給它關了,這個仿真的風扇還在轉着?!
是我輸入的時長不夠嗎?!FAN=0,FAN=0,FAN=0,FAN=0,……
nm(不能爆粗口)還是不對……實質上吧,這個風扇的實際停止是根據它下面的顯示方框中的數字來決定的。
- 當風扇開啟的時候,這個數字會增長;
-
- 當風扇關閉的時候,這個數字會下降;
- 當為0.00的時候,自己就會停止。
當然,不立即停止也是符合現實生活中的情形的,我認為這主要是因為繼電器的問題,這個了解了一下是用來用弱電控制強電的(如果有興趣的話,大家可以自行去了解)……
當然,這個風扇的具體參數可以雙擊這個元件之后進去修改。
5 實驗參考代碼
下面給出參考代碼,這里的控制標准是:
- CH4濃度<20,則正常-綠色-風扇關閉-蜂鳴器關閉
- CH4濃度>=20 & <40,則警示-黃色-風扇開啟-蜂鳴器關閉
- CH4濃度>=40,則危險-紅色-風扇關閉-蜂鳴器開啟
#include <reg52.h>
#include <intrins.h>
#include<math.h>
#define NOP _nop_()
#define uint unsigned int
#define uchar unsigned char
#define ACK 1
#define noACK 0
#define DISPLAY_LEFT_TO_RIGHT 1 //從左邊數計算列位置,每寫完一個字節,列數自動向右移動一個
#define DISPLAY_RIGHT_TO_LEFT 0 //從右邊數計算列位置,每寫完一個字節,列數自動向左移動一個
//SHT10指令集
//寫狀態寄存器
#define STATUS_REG_W 0x06
//讀狀態寄存器
#define STATUS_REG_R 0x07
//溫度測量
#define MEASURE_TEMP 0x03
//濕度測量
#define MEASURE_HUMI 0x05
//軟復位
#define RESET 0x1E
//枚舉選擇溫度/濕度測量
enum {TEMP,HUMI};
//ADC0834
sbit CS=P1^1;//ADC0834片選信號
sbit CLK=P1^0;//ADC0834時鍾信號
//sbit SARS0834=P1^2;//轉換狀態輸出,低電平表示轉換完成
sbit DO=P1^5;//ADC0834數據接口
sbit DI=P1^4;//ADC0834通道選擇
//HDG12864F-1
sbit cs1 = P2^4;//-cs,片選,低電平有效
sbit rst = P2^3;//-rst,復位,低電平有效
sbit a0 = P2^2;//寫命令、寫數據控制位。1=Display data; 0=Control data;
sbit scl = P2^1;//Shift clock input,時鍾輸入
sbit si = P2^0;//Serial data input,串口數據輸入
//SHT10
sbit SCK=P1^2;
sbit DATA=P1^3;
//控制相關
sbit LEDR=P1^6;
sbit LEDG=P1^7;
sbit FAN=P2^5;
sbit BP=P2^6;
//ADC
unsigned int temp,humi;
unsigned char ad_res = 0;
unsigned char ad_res1 = 0;
unsigned char ad_res2 = 0;
unsigned char ad_res3 = 0;
unsigned char ad_res4 = 0;
double dat=0.0;
//ADC0834通道切換
unsigned int code channel0834[8]={0,0,1,0,0,1,1,1};
//風扇
uchar code pic_data1[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xFC,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFC,0xF8,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xC0,0xF0,0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFC,0xFC,0xBC,0xE8,0xF7,0xFF,0xFF,
0xFF,0xFF,0xFF,0xEF,0xEF,0xE3,0xF0,0xF0,0xF8,0xFC,0xFC,0xFC,0xF8,0xF0,0xC0,0x00,
0x00,0x01,0x07,0x0F,0x1F,0x1F,0x1F,0x0F,0x07,0x07,0xE3,0xFB,0xFB,0xFF,0xFF,0xFF,
0xFF,0xFF,0xF7,0x8F,0x0E,0x1F,0x1F,0x3F,0x3F,0x3F,0x3F,0x1F,0x0F,0x07,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x1F,0x3F,0x3F,0x3F,
0x3F,0x3F,0x3F,0x1F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
uchar code pic_data2[]=
{0x00,0x80,0xE0,0xF0,0xF8,0xFC,0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFC,0xF8,0xF0,0xE0,
0x00,0x00,0x00,0x80,0xF8,0xFC,0xFC,0xFE,0xFE,0xFC,0xFC,0xF8,0xF8,0xF0,0xC0,0x00,
0x00,0x03,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x3F,0x3F,0x7F,0xDF,0xEF,0xF7,0xFF,0xFF,
0xFF,0xF8,0xFC,0xFF,0xEF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x7F,0x3F,0x1F,0x06,
0x00,0xE0,0xF8,0xFC,0xFC,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xF7,0xEF,0xDF,0x3F,0x3F,
0xFF,0xFF,0xDF,0xFF,0xFF,0xFB,0xFD,0xF9,0xF9,0xF0,0xF0,0xF0,0xF0,0xF0,0xC0,0x00,
0x00,0x03,0x0F,0x1F,0x3F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x3F,0x1F,0x00,0x00,0x00,
0x03,0x0F,0x1F,0x7F,0x7F,0xFF,0xFF,0xFF,0x7F,0x7F,0x7F,0x3F,0x1F,0x0F,0x07,0x00,
};
//字符庫
uchar code BMP[][6]=
{
//字符顯示對應的二維十六進制數組
{0x00,0x00,0x00,0x00,0x00,0x00}, // 0位 顯示空白
{0x00,0x00,0x00,0x00,0x00,0x00}, // 1
{0x00,0x00,0x00,0x00,0x00,0x00}, // 2
{0x00,0x00,0x00,0x00,0x00,0x00}, // 3
{0x00,0x00,0x00,0x00,0x00,0x00}, // 4
{0x00,0x00,0x00,0x00,0x00,0x00}, // 5
{0x00,0x00,0x00,0x00,0x00,0x00}, // 6
{0x00,0x00,0x00,0x00,0x00,0x00}, // 7
{0x00,0x00,0x00,0x00,0x00,0x00}, // 8
{0x00,0x00,0x00,0x00,0x00,0x00}, // 9
{0x00,0x00,0x00,0x00,0x00,0x00}, // 10
{0x00,0x00,0x00,0x00,0x00,0x00}, // 11
{0x00,0x00,0x00,0x00,0x00,0x00}, // 12
{0x00,0x00,0x00,0x00,0x00,0x00}, // 13
{0x00,0x00,0x00,0x00,0x00,0x00}, // 14
{0x00,0x00,0x00,0x00,0x00,0x00}, // 15
{0x00,0x00,0x00,0x00,0x00,0x00}, // 16
{0x00,0x00,0x00,0x00,0x00,0x00}, // 17
{0x00,0x00,0x00,0x00,0x00,0x00}, // 18
{0x00,0x00,0x00,0x00,0x00,0x00}, // 19
{0x00,0x00,0x00,0x00,0x00,0x00}, // 20
{0x00,0x00,0x00,0x00,0x00,0x00}, // 21
{0x00,0x00,0x00,0x00,0x00,0x00}, // 22
{0x00,0x00,0x00,0x00,0x00,0x00}, // 23
{0x00,0x00,0x00,0x00,0x00,0x00}, // 24
{0x00,0x00,0x00,0x00,0x00,0x00}, // 25
{0x00,0x00,0x00,0x00,0x00,0x00}, // 26
{0x00,0x00,0x00,0x00,0x00,0x00}, // 27
{0x00,0x00,0x00,0x00,0x00,0x00}, // 28
{0x00,0x00,0x00,0x00,0x00,0x00}, // 29
{0x00,0x00,0x00,0x00,0x00,0x00}, // 30
{0x00,0x00,0x00,0x00,0x00,0x00}, // 31
{0x00,0x00,0x00,0x00,0x00,0x00}, // sp 32
{0x00,0x00,0x2f,0x00,0x00,0x00}, // ! 33
{0x00,0x07,0x00,0x07,0x00,0x00}, // " 34
{0x14,0x7f,0x14,0x7f,0x14,0x00}, // # 35
{0x24,0x2a,0x7f,0x2a,0x12,0x00}, // $ 36
{0xc4,0xc8,0x10,0x26,0x46,0x00}, // % 37
{0x36,0x49,0x55,0x22,0x50,0x00}, // & 38
{0x00,0x05,0x03,0x00,0x00,0x00}, // ' 39
{0x00,0x1c,0x22,0x41,0x00,0x00}, // ( 40
{0x00,0x41,0x22,0x1c,0x00,0x00}, // ) 41
{0x14,0x08,0x3E,0x08,0x14,0x00}, // * 42
{0x08,0x08,0x3E,0x08,0x08,0x00}, // + 43
{0x00,0x00,0x50,0x30,0x00,0x00}, // , 44
{0x10,0x10,0x10,0x10,0x10,0x00}, // - 45
{0x00,0x60,0x60,0x00,0x00,0x00}, // . 46
{0x20,0x10,0x08,0x04,0x02,0x00}, // / 47
{0x3E,0x51,0x49,0x45,0x3E,0x00}, // 0 48
{0x00,0x42,0x7F,0x40,0x00,0x00}, // 1 49
{0x42,0x61,0x51,0x49,0x46,0x00}, // 2 50
{0x21,0x41,0x45,0x4B,0x31,0x00}, // 3 51
{0x18,0x14,0x12,0x7F,0x10,0x00}, // 4 52
{0x27,0x45,0x45,0x45,0x39,0x00}, // 5 53
{0x3C,0x4A,0x49,0x49,0x30,0x00}, // 6 54
{0x01,0x71,0x09,0x05,0x03,0x00}, // 7 55
{0x36,0x49,0x49,0x49,0x36,0x00}, // 8 56
{0x06,0x49,0x49,0x29,0x1E,0x00}, // 9 57
{0x00,0x36,0x36,0x00,0x00,0x00}, // : 58
{0x00,0x56,0x36,0x00,0x00,0x00}, // ; 59
{0x08,0x14,0x22,0x41,0x00,0x00}, // < 60
{0x14,0x14,0x14,0x14,0x14,0x00}, // = 61
{0x00,0x41,0x22,0x14,0x08,0x00}, // > 62
{0x02,0x01,0x51,0x09,0x06,0x00}, // ? 63
{0x32,0x49,0x59,0x51,0x3E,0x00}, // @ 64
{0x7E,0x11,0x11,0x11,0x7E,0x00}, // A 65
{0x7F,0x49,0x49,0x49,0x36,0x00}, // B 66
{0x3E,0x41,0x41,0x41,0x22,0x00}, // C 67
{0x7F,0x41,0x41,0x22,0x1C,0x00}, // D 68
{0x7F,0x49,0x49,0x49,0x41,0x00}, // E 69
{0x7F,0x09,0x09,0x09,0x01,0x00}, // F 70
{0x3E,0x41,0x49,0x49,0x7A,0x00}, // G 71
{0x7F,0x08,0x08,0x08,0x7F,0x00}, // H 72
{0x00,0x41,0x7F,0x41,0x00,0x00}, // I 73
{0x20,0x40,0x41,0x3F,0x01,0x00}, // J 74
{0x7F,0x08,0x14,0x22,0x41,0x00}, // K 75
{0x7F,0x40,0x40,0x40,0x40,0x00}, // L 76
{0x7F,0x02,0x0C,0x02,0x7F,0x00}, // M 77
{0x7F,0x04,0x08,0x10,0x7F,0x00}, // N 78
{0x3E,0x41,0x41,0x41,0x3E,0x00}, // O 79
{0x7F,0x09,0x09,0x09,0x06,0x00}, // P 80
{0x3E,0x41,0x51,0x21,0x5E,0x00}, // Q 81
{0x7F,0x09,0x19,0x29,0x46,0x00}, // R 82
{0x46,0x49,0x49,0x49,0x31,0x00}, // S 83
{0x01,0x01,0x7F,0x01,0x01,0x00}, // T 84
{0x3F,0x40,0x40,0x40,0x3F,0x00}, // U 85
{0x1F,0x20,0x40,0x20,0x1F,0x00}, // V 86
{0x3F,0x40,0x38,0x40,0x3F,0x00}, // W 87
{0x63,0x14,0x08,0x14,0x63,0x00}, // X 88
{0x07,0x08,0x70,0x08,0x07,0x00}, // Y 89
{0x61,0x51,0x49,0x45,0x43,0x00}, // Z 90
{0x00,0x7F,0x41,0x41,0x00,0x00}, // [ 91
{0x55,0x2A,0x55,0x2A,0x55,0x00}, //55 92
{0x00,0x41,0x41,0x7F,0x00,0x00}, // ] 93
{0x04,0x02,0x01,0x02,0x04,0x00}, // ^ 94
{0x40,0x40,0x40,0x40,0x40,0x00}, // _ 95
{0x00,0x01,0x02,0x04,0x00,0x00}, // ' 96
{0x20,0x54,0x54,0x54,0x78,0x00}, // a 97
{0x7F,0x48,0x44,0x44,0x38,0x00}, // b 98
{0x38,0x44,0x44,0x44,0x20,0x00}, // c 99
{0x38,0x44,0x44,0x48,0x7F,0x00}, // d 100
{0x38,0x54,0x54,0x54,0x18,0x00}, // e 101
{0x08,0x7E,0x09,0x01,0x02,0x00}, // f 102
{0x0C,0x52,0x52,0x52,0x3E,0x00}, // g 103
{0x7F,0x08,0x04,0x04,0x78,0x00}, // h 104
{0x00,0x44,0x7D,0x40,0x00,0x00}, // i 105
{0x20,0x40,0x44,0x3D,0x00,0x00}, // j 106
{0x7F,0x10,0x28,0x44,0x00,0x00}, // k 107
{0x00,0x41,0x7F,0x40,0x00,0x00}, // l 108
{0x7C,0x04,0x18,0x04,0x78,0x00}, // m 109
{0x7C,0x08,0x04,0x04,0x78,0x00}, // n 110
{0x38,0x44,0x44,0x44,0x38,0x00}, // o 111
{0x7C,0x14,0x14,0x14,0x08,0x00}, // p 112
{0x08,0x14,0x14,0x18,0x7C,0x00}, // q 113
{0x7C,0x08,0x04,0x04,0x08,0x00}, // r 114
{0x48,0x54,0x54,0x54,0x20,0x00}, // s 115
{0x04,0x3F,0x44,0x40,0x20,0x00}, // t 116
{0x3C,0x40,0x40,0x20,0x7C,0x00}, // u 117
{0x1C,0x20,0x40,0x20,0x1C,0x00}, // v 118
{0x3C,0x40,0x30,0x40,0x3C,0x00}, // w 119
{0x44,0x28,0x10,0x28,0x44,0x00}, // x 120
{0x0C,0x50,0x50,0x50,0x3C,0x00}, // y 121
{0x44,0x64,0x54,0x4C,0x44,0x00}, // z 122
{0xD5,0x01,0x80,0x01,0x80,0xAB}, // <50 123
{0xFF,0x81,0x81,0x81,0x81,0xFF}, //50<= <100 124
{0xFF,0x81,0xBD,0xBD,0x81,0xFF}, //100<= <150 125
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, //>=150 126
{0x00,0x00,0x00,0x00,0x00,0x00} // sp 127
};
unsigned char code myChannel[7]={'C','h','a','n','n','e','l'};
unsigned char code myTemp[4]={'T','e','m','p'};
unsigned char code myHumi[4]={'H','u','m','i'};
unsigned char code myCO[2]={'C','O'};
unsigned char code myCH4[3]={'C','H','4'};
unsigned char code myLight[5]={'L','i','g','h','t'};
unsigned char code myAir[7]={'A','i','r','-','p','r','e'};
unsigned char code **msg[7]={myChannel,myTemp,myHumi,myCO,myCH4,myLight,myAir};
//延時函數
void Delayms(uint x )
{
uint t;
while(x--)
for (t= 0; t<120; t++);
}
//HDG12864F-1
//寫命令
void wrt_cmd(unsigned char command)
{
unsigned char i = 8;//8位
cs1 = 0;//片選,低電平有效
a0 = 0;//0=Control data,命令置0
while(i--)
{
scl = 0;
si = (bit) (command & 0x80);//先寫高位
scl = 1;//上升沿
command <<= 1;//左移一位
}
scl = 0;
}
//寫數據
void wrt_dt(unsigned char data_)
{
unsigned char i = 8;//8位
cs1 = 0;//片選,低電平有效
a0 = 1;//1=Display data,寫數據置1
while(i--)
{
scl = 0;
si = (bit) (data_ & 0x80);//先寫高位
scl = 1;//上升沿
data_ <<= 1;//左移一位 0
}
scl = 0;
}
//設置列位置,其中參數address:0~127
void HDG12864F1_SetColumnAddress(unsigned char address)
{ //寫列要分成兩步走,先寫高四位,再寫低四位
//手冊Column Address Set
wrt_cmd(0x10 + (address >> 4 & 0x0f));//C中右移是算術右移,必須&0x0f去掉高4位才能得到正確的結果
wrt_cmd(address & 0x0f);
}
//設置縱向位置,其中參數pageAddress:0~8
void HDG12864F1_SetPageAddress(unsigned char pageAddress)
{ //手冊Page Address Set
wrt_cmd(0xb0 + pageAddress);//1011+頁碼
}
//寫數據
void HDG12864F1_WriteData(unsigned char data_)
{
wrt_dt(data_);
}
//設置寫的方向:從右向左為正
void HDG12864F1_Direction(unsigned char direction)
{ //手冊ADC Select
wrt_cmd(0xa0+direction);
}
//對寫好的屏幕內容向上滾屏,滾出上邊的部分會從屏幕下邊冒出來
void HDG12864F1_SetStartLine(unsigned char line)
{ //參數line取值范圍0~63
wrt_cmd(0x40 + line);
}
//寫英文字符,數字占上下1個8*6點陣
void HDG12864F1_WriteEnglishChar(unsigned char *pEChar, unsigned char column, unsigned char page)
{
unsigned char i;
HDG12864F1_Direction(DISPLAY_LEFT_TO_RIGHT);//DISPLAY_LEFT_TO_RIGHT是一個宏,值為1,代表從屏幕左側寫入
HDG12864F1_SetColumnAddress(column);//設開始寫的橫向坐標
HDG12864F1_SetPageAddress(page);//設開始寫的縱向Page
for(i=0; i<6; i++)
HDG12864F1_WriteData(*(pEChar + i));//連續寫英文
}
//圖片32*32
void HDG12864F1_DrawPic(unsigned char *pChar, unsigned char column, unsigned char page)
{
unsigned char i,j;
HDG12864F1_Direction(DISPLAY_LEFT_TO_RIGHT);//DISPLAY_LEFT_TO_RIGHT是一個宏,值為1,代表從屏幕左側寫入
for(i=0;i<4;i++)
{
HDG12864F1_SetColumnAddress(column);//設開始寫的橫向坐標
HDG12864F1_SetPageAddress(page+i);//設開始寫的縱向Page
for(j=0;j<32;j++)
{
HDG12864F1_WriteData(*(pChar + i*32+j));//連續寫英文
}
}
}
//ADC0834
unsigned char AD0834_conv(unsigned int n)
{
unsigned char i,com;
CS=1;
CS=0; _nop_(); _nop_();//CS置低,啟動轉換
DI=1; _nop_(); _nop_();//啟動,准備輸出數據 第一個脈沖
CLK=1; _nop_(); _nop_();
CLK=0; _nop_(); _nop_();
//選擇通道,第二個脈沖
DI=1;
CLK=1; _nop_(); _nop_();
CLK=0; _nop_(); _nop_();
DI=channel0834[n*2];
CLK=1; _nop_(); _nop_();
CLK=0; _nop_(); _nop_();
DI=channel0834[n*2+1];
CLK=1; _nop_(); _nop_();
CLK=0; _nop_(); _nop_();
DI=1;
CLK=1; _nop_(); _nop_();
CLK=0; _nop_(); _nop_();
//開始采集轉換數據
for(i=8;i>0;i--)
{
com<<=1;//左移,先采最高位
if(DO)com=com|0x01;//采當前數據
CLK=1;
CLK=0;
_nop_();
_nop_();
}
CS=1;//關閉片選,禁用
return com;
}
//LDR傳感器數據擬合
unsigned char ChangeDataLDR(unsigned char res)
{
unsigned char com;
com=0.00000000221308*res*res*res*res*res
-0.0000009287723*res*res*res*res
+ 0.0001465584*res*res*res
- 0.008997464*res*res
+ 0.2657836*res - 0.5918848;
return com;
}
//MPX4115傳感器數據擬合
unsigned char ChangeDataMPX(unsigned char res)
{
unsigned char com;
//自己擬合
com=0.436*res+9.053;
return com;
}
//SHT10
//寫字節
char s_write_byte(uchar value)
{
uchar i,error=0;
//分別取出指令的對應位串傳輸
//從高位開始
for(i=0x80;i>0;i>>=1)
{
if(i&value) DATA=1;
else DATA=0;
SCK=1;
//保持SCK高電平
_nop_();_nop_();_nop_();
SCK=0;
}
DATA=1;
SCK=1;
error=DATA;//ACK
_nop_();_nop_();_nop_();
SCK=0;
DATA=1;
return error;
}
//讀字節
char s_read_byte(uchar ack)
{
uchar i,val=0;
DATA=1;
//讀取一個字節的數據
for(i=0x80;i>0;i>>=1)
{
SCK=1;
if(DATA) val=(val|i);
SCK=0;
}
if(ack==1)DATA=0;//通過下拉DATA為低電平以確認每個字節
else DATA=1; //如果是校驗 (ack==0) ,讀取完后保持ACK高電平結束通訊
_nop_();_nop_();_nop_(); //pulswith approx. 3 us
SCK=1; //clk #9 for ack
_nop_();_nop_();_nop_(); //pulswith approx. 3 us
SCK=0;
_nop_();_nop_();_nop_(); //pulswith approx. 3 us
DATA=1; //釋放DATA-line
return val;
}
//啟動傳輸
void s_transstart(void)
{
DATA=1; SCK=0;
_nop_();
SCK=1;
_nop_();
DATA=0;
_nop_();
SCK=0;
_nop_();_nop_();_nop_();
SCK=1;
_nop_();
DATA=1;
_nop_();
SCK=0;
}
//連接復位
void s_connectionreset(void)
{
//通訊中斷需要通訊復位
//DATA保持高電平並觸發SCK時鍾9次或更多
uchar i;
DATA=1;SCK=0;
for(i=0;i<9;i++)
{
SCK=1;
SCK=0;
}
//發送一個傳輸啟動時序
s_transstart();
//復位串口而狀態寄存器內容仍然保留
}
//溫濕度測量
char s_measure(uchar *p_value,uchar *p_checksum,uchar mode)
{
unsigned error=0;
unsigned int i;
s_transstart();
switch(mode)
{
case TEMP:
error+=s_write_byte(MEASURE_TEMP); break;
case HUMI:
error+=s_write_byte(MEASURE_HUMI); break;
default: break;
}
//在結束測量后Sensor會把DATA線拉低
//等待測量結束時間根據不同位數的測量不同
for(i=0;i<65535;i++) if(DATA==0) break;//2^16
if(DATA) error+=1;//說明沒有結束
//傳輸2個字節的測量數據和1個字節的CRC奇偶校驗
*(p_value)=s_read_byte(ACK);
*(p_value+1)=s_read_byte(ACK);
*p_checksum=s_read_byte(noACK);
return error;
}
//溫濕度值標度變換及溫度補償
void calc_sth10(float *p_humidity,float *p_temperature)
{
// input : humi [Ticks] (12 bit)
// temp [Ticks] (14 bit)
// output: humi [%RH]
const float C1=-2.0468; // for 12 Bit
const float C2=+0.0367; // for 12 Bit
const float C3=-0.0000015955; // for 12 Bit
const float T1=+0.01; // for 12 Bit @ 5V
const float T2=+0.00008; // for 12 Bit @ 5V
float rh=*p_humidity;// rh: Humidity [Ticks] 12 Bit
float t=*p_temperature; // t: Temperature [Ticks] 14 Bit
float rh_lin;// rh_lin: Humidity linear
float rh_ture;// rh_true: Temperature compensated humidity
float t_C;// t_C : Temperature [C]
t_C=t*0.01-40;//溫度轉換[C]
rh_lin=C3*rh*rh+C2*rh+C1;//相對濕度非線性補償[%RH]
rh_ture=(t_C-25)*(T1+T2*rh)+rh_lin;//濕度信號的溫度補償[%RH]
//超范圍處理
if(rh_ture>100) rh_ture=100;
if(rh_ture<0.1) rh_ture=0.1;
//將結果傳輸回去
*p_temperature=t_C;//[C]
*p_humidity=rh_ture;//[%RH]
}
typedef union
{
unsigned int i;
float f;
}value;
void main(void)
{
int i=0;
int j=0;
int mycol=0;
value humi_val,temp_val;
uchar error;
uchar check_sum;//校驗和
int flag;//判斷溫度符號
BP=0;
FAN=0;
while(1)
{
mycol=0;
for(i=0;i<7;i++)
HDG12864F1_WriteEnglishChar(BMP[myChannel[i]],i*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[':'],7*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['A'],8*8,mycol);
mycol=mycol+1;
//溫濕度
error=0;
error+=s_measure((uchar*)&humi_val.i,&check_sum,HUMI);
error+=s_measure((uchar*)&temp_val.i,&check_sum,TEMP);
if(error!=0)//說明通訊中斷且沒有測量完
s_connectionreset();
else//已經測量完
{
humi_val.f=(float)humi_val.i;
temp_val.f=(float)temp_val.i;
//溫濕度補償
calc_sth10(&humi_val.f,&temp_val.f);
//判斷符號
if(temp_val.f<0)
{
flag='-';
temp_val.f=-temp_val.f+2;
}
else
flag='+';
//可以顯示小數位后一位
temp=temp_val.f*10;
humi=humi_val.f*10;
}
//溫度
for(i=0;i<4;i++)
HDG12864F1_WriteEnglishChar(BMP[myTemp[i]],i*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[':'],4*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[flag],5*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[temp/1000+'0'],6*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[temp%1000/100+'0'],7*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[temp%100/10+'0'],8*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['C'],9*8,mycol);
mycol=mycol+1;
//濕度
for(i=0;i<4;i++)
HDG12864F1_WriteEnglishChar(BMP[myHumi[i]],i*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[':'],4*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[humi/1000+'0'],5*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[humi%1000/100+'0'],6*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[humi%100/10+'0'],7*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['%'],8*8,mycol);
mycol=mycol+1;
ad_res=AD0834_conv(0);
ad_res1=ad_res;
for(i=0;i<5;i++)
HDG12864F1_WriteEnglishChar(BMP[myLight[i]],i*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[':'],5*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res1%1000/100+'0'],6*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res1%100/10+'0'],7*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res1%10+'0'],8*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['L'],9*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['x'],10*8,mycol);
mycol=mycol+1;
ad_res=AD0834_conv(1);
ad_res2=ChangeDataLDR(ad_res);
for(i=0;i<2;i++)
HDG12864F1_WriteEnglishChar(BMP[myCO[i]],i*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[':'],2*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res2%1000/100+'0'],3*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res2%100/10+'0'],4*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res2%10+'0'],5*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['p'],6*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['p'],7*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['m'],8*8,mycol);
mycol=mycol+1;
ad_res=AD0834_conv(2);
ad_res3=ChangeDataLDR(ad_res);
//控制RGB-LED與BP與FAN
if(ad_res3<20)//正常-綠色-風扇關閉-蜂鳴器關閉
{
LEDR=0;
LEDG=1;
BP=0;
FAN=0;
}
else if(ad_res3>=20 & ad_res3<40)//警示-黃色-風扇開啟-蜂鳴器關閉
{
LEDR=1;
LEDG=1;
BP=0;
FAN=1;
}
else//危險-紅色-風扇關閉-蜂鳴器開啟
{
LEDR=1;
LEDG=0;
BP=1;
FAN=0;
}
for(i=0;i<3;i++)
HDG12864F1_WriteEnglishChar(BMP[myCH4[i]],i*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[':'],3*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res3%1000/100+'0'],4*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res3%100/10+'0'],5*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res3%10+'0'],6*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['p'],7*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['p'],8*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['m'],9*8,mycol);
mycol=mycol+1;
ad_res=AD0834_conv(3);
ad_res4=ChangeDataMPX(ad_res);
for(i=0;i<7;i++)
HDG12864F1_WriteEnglishChar(BMP[myAir[i]],i*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[':'],7*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res4%1000/100+'0'],8*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res4%100/10+'0'],9*8,mycol);
HDG12864F1_WriteEnglishChar(BMP[ad_res4%10+'0'],10*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['k'],11*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['P'],12*8,mycol);
HDG12864F1_WriteEnglishChar(BMP['a'],13*8,mycol);
//轉動的風扇
HDG12864F1_DrawPic(&pic_data1,90,0);
Delayms(800);//延時顯示
HDG12864F1_DrawPic(&pic_data2,90,0);
Delayms(700);//延時顯示
}
}
其中,HDG12864F-1部分的程序是參考:使用Proteus模擬操作HDG12864F-1液晶屏