Proteus传感器+气体浓度检测的报警方式控制仿真

1 实验意义理解

基于前两个实验,我们已经成功的实现:

  • 对传感器的数据进行采样、转换
  • 拟合采样值
  • 对拟合的数据在HDG12864F-1显示屏上显示

似乎,该得到的数据已经拿到了,还能干啥?

是的,我们还能利用数据干一些东西,比如说当这个气体浓度超范围的时候我们怎么去控制解决。

那么就引出了这个实验,怎么控制解决?

其实,我们在平时生活中见到过很多,当气体浓度超过一定范围:

  • 报警
    • 开警报灯
    • 蜂鸣器出警报声音
  • 疏通
    • 开启风扇通风
    • ……
  • ……

如上,我们这次实验就是采取了前三个小点的方式来控制解决。

此外,我们还要优化LCD显示,就是在屏幕上显示转动的风扇。

2 主要实验器件

  1. CPU处理器

    • AT89C52
  2. LCD显示

    • HDG12864F-1
  3. AD转换器

    • ADC0834
  4. 传感器

    • 温湿度:SHT10
    • 光传感器:TORCH_LDR
    • 瓦斯浓度传感器:LDR
    • 一氧化碳浓度传感器:LDR
    • 气压传感器:MPX4115
  5. 控制相关

    • 报警灯:RGBLED-CC
    • 蜂鸣器:SOUNDER
    • 通风控制:FAN

3 实验参考电路

  1. 未运行时

  2. 运行时

  3. 说明

    • 有蜂鸣器声音
    • 显示中第一行的channel后面的字母会根据当前正在采样转换的通道不同而改变
    • 所有数据仅为转换后显示,并未存储下来,若要存储显示,只需要开几个全局变量保存一下即可

4 实验中的问题思考

4.1 实现转动的风扇

要实现这个功能,我们只要知道两个关键点就好了:

  • HDG12864F-1液晶显示如果你不对一个像素覆盖写入值,则会保持显示上次写入的值
  • 任何动态效果实质上是由一个个静态图画“快速”播放而成的

因此,实现这个就很容易了:

  • 找到几个不一样(转动角度不一样)的静态风扇图(最好大小一样,这样方便写入,完全覆盖)
  • 对这几个静态风扇图取模
  • 调用HDG12864F-1绘制图片函数将一个静态图写入
  • 让处理器去干别的事情,比如:执行几句其他的语句,或者直接延时等待
  • 调用HDG12864F-1绘制图片函数写入另一个静态图
  • ……

那么,中间为什么会有“让处理器去干别的事情,比如:执行几句其他的语句,或者直接延时等待”这一点呢?

其实这是一个控制模拟风扇转动速度的。你想想如果快速切换两张图片,你眼睛还没视觉残留呢,就没了,估计会闪瞎狗眼……所以,选择一个合适的切换时间间隔也是挺重要的……

第二个,这个静态图画至少两幅,这个大家应该很好理解,如果一幅的话,没有变化,换来换去不就那个玩意儿吗……

4.2 控制部分

首先,我们来看一下控制部分的原理图:

下面,我们分别说一下各个部分。

  1. 报警灯

    这个RGBLED-CC要想让它工作,首先就是K端给个低电平。

    RGB端,输入1为亮,0为不亮。

    然后,在这个实验中,其实我们只需要用到红和绿两种颜色,所以直接给B端接地,然后R和G端分别绑定到处理器的引脚上。

    运行中判断,如果达到危险值或者恢复至安全值,则处理器重置相应的引脚值。

  2. 蜂鸣器

    主要是SOUNDER元件,一端加电压,另一端需要给脉冲信号

    这个脉冲信号很重要,一开始,本菜狗就对这个输入的脉冲信号没有设置(默认频率很小),因此都听不出来发声了……

    后来双击输入的SW1(A),调整了一下参数,然后就听到了,可参考下图是我调整的:

    当然这里拓展一下,怎么让它放音乐呢??

    这里有两段经历让我对这个有了进一步的认识:

    • 大二学校暑假实习的时候,做电子钟,当时用verilog写的,那个如果要让蜂鸣器放出来的不仅仅是那种很难听的一直尖叫,而是播放音乐啊啥的,需要给不同的频率

    • 大三上微机原理课设,使用笔记本内置的芯片,做了一个基于x86的时钟(用的汇编语言写的)。其中,闹钟功能,铃声我想换成音乐怎么办?

      • 找到音乐的谱子和对应的音符频率,相对延时
      • 分别将频率和延时写成“表”,依次延时输出

      这里,再次拓展一下,如果你想听快速版的音乐怎么办?想要听降调,升调的版本怎么办?

      • 频率:控制音调
      • 延时:控制速度

    然后,再说一下,怎么控制这个声音的开关

    这里使用的是DSWITCH元件,可以把它看成一个三态门

    • BP端置为1,接收SW1(A)的输入
    • BP端置为0,高阻态,不发声
  3. 避风控制

    这个模块主要是由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液晶屏

posted on 2020-05-09 17:02  菜狗Zero  阅读(5633)  评论(2编辑  收藏  举报