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,则危险-红色-风扇关闭-蜂鸣器开启
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #include<math.h>
  4. #define NOP _nop_()
  5. #define uint unsigned int
  6. #define uchar unsigned char
  7. #define ACK 1
  8. #define noACK 0
  9. #define DISPLAY_LEFT_TO_RIGHT 1 //从左边数计算列位置,每写完一个字节,列数自动向右移动一个
  10. #define DISPLAY_RIGHT_TO_LEFT 0 //从右边数计算列位置,每写完一个字节,列数自动向左移动一个
  11. //SHT10指令集
  12. //写状态寄存器
  13. #define STATUS_REG_W 0x06
  14. //读状态寄存器
  15. #define STATUS_REG_R 0x07
  16. //温度测量
  17. #define MEASURE_TEMP 0x03
  18. //湿度测量
  19. #define MEASURE_HUMI 0x05
  20. //软复位
  21. #define RESET 0x1E
  22. //枚举选择温度/湿度测量
  23. enum {TEMP,HUMI};
  24. //ADC0834
  25. sbit CS=P1^1;//ADC0834片选信号
  26. sbit CLK=P1^0;//ADC0834时钟信号
  27. //sbit SARS0834=P1^2;//转换状态输出,低电平表示转换完成
  28. sbit DO=P1^5;//ADC0834数据接口
  29. sbit DI=P1^4;//ADC0834通道选择
  30. //HDG12864F-1
  31. sbit cs1 = P2^4;//-cs,片选,低电平有效
  32. sbit rst = P2^3;//-rst,复位,低电平有效
  33. sbit a0 = P2^2;//写命令、写数据控制位。1=Display data; 0=Control data;
  34. sbit scl = P2^1;//Shift clock input,时钟输入
  35. sbit si = P2^0;//Serial data input,串口数据输入
  36. //SHT10
  37. sbit SCK=P1^2;
  38. sbit DATA=P1^3;
  39. //控制相关
  40. sbit LEDR=P1^6;
  41. sbit LEDG=P1^7;
  42. sbit FAN=P2^5;
  43. sbit BP=P2^6;
  44. //ADC
  45. unsigned int temp,humi;
  46. unsigned char ad_res = 0;
  47. unsigned char ad_res1 = 0;
  48. unsigned char ad_res2 = 0;
  49. unsigned char ad_res3 = 0;
  50. unsigned char ad_res4 = 0;
  51. double dat=0.0;
  52. //ADC0834通道切换
  53. unsigned int code channel0834[8]={0,0,1,0,0,1,1,1};
  54. //风扇
  55. uchar code pic_data1[]=
  56. {
  57. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xFC,0xFE,0xFE,0xFE,
  58. 0xFE,0xFE,0xFE,0xFC,0xF8,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  59. 0x00,0xC0,0xF0,0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFC,0xFC,0xBC,0xE8,0xF7,0xFF,0xFF,
  60. 0xFF,0xFF,0xFF,0xEF,0xEF,0xE3,0xF0,0xF0,0xF8,0xFC,0xFC,0xFC,0xF8,0xF0,0xC0,0x00,
  61. 0x00,0x01,0x07,0x0F,0x1F,0x1F,0x1F,0x0F,0x07,0x07,0xE3,0xFB,0xFB,0xFF,0xFF,0xFF,
  62. 0xFF,0xFF,0xF7,0x8F,0x0E,0x1F,0x1F,0x3F,0x3F,0x3F,0x3F,0x1F,0x0F,0x07,0x01,0x00,
  63. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x1F,0x3F,0x3F,0x3F,
  64. 0x3F,0x3F,0x3F,0x1F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  65. };
  66. uchar code pic_data2[]=
  67. {0x00,0x80,0xE0,0xF0,0xF8,0xFC,0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFC,0xF8,0xF0,0xE0,
  68. 0x00,0x00,0x00,0x80,0xF8,0xFC,0xFC,0xFE,0xFE,0xFC,0xFC,0xF8,0xF8,0xF0,0xC0,0x00,
  69. 0x00,0x03,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x3F,0x3F,0x7F,0xDF,0xEF,0xF7,0xFF,0xFF,
  70. 0xFF,0xF8,0xFC,0xFF,0xEF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x7F,0x3F,0x1F,0x06,
  71. 0x00,0xE0,0xF8,0xFC,0xFC,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xF7,0xEF,0xDF,0x3F,0x3F,
  72. 0xFF,0xFF,0xDF,0xFF,0xFF,0xFB,0xFD,0xF9,0xF9,0xF0,0xF0,0xF0,0xF0,0xF0,0xC0,0x00,
  73. 0x00,0x03,0x0F,0x1F,0x3F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x3F,0x1F,0x00,0x00,0x00,
  74. 0x03,0x0F,0x1F,0x7F,0x7F,0xFF,0xFF,0xFF,0x7F,0x7F,0x7F,0x3F,0x1F,0x0F,0x07,0x00,
  75. };
  76. //字符库
  77. uchar code BMP[][6]=
  78. {
  79. //字符显示对应的二维十六进制数组
  80. {0x00,0x00,0x00,0x00,0x00,0x00}, // 0位 显示空白
  81. {0x00,0x00,0x00,0x00,0x00,0x00}, // 1
  82. {0x00,0x00,0x00,0x00,0x00,0x00}, // 2
  83. {0x00,0x00,0x00,0x00,0x00,0x00}, // 3
  84. {0x00,0x00,0x00,0x00,0x00,0x00}, // 4
  85. {0x00,0x00,0x00,0x00,0x00,0x00}, // 5
  86. {0x00,0x00,0x00,0x00,0x00,0x00}, // 6
  87. {0x00,0x00,0x00,0x00,0x00,0x00}, // 7
  88. {0x00,0x00,0x00,0x00,0x00,0x00}, // 8
  89. {0x00,0x00,0x00,0x00,0x00,0x00}, // 9
  90. {0x00,0x00,0x00,0x00,0x00,0x00}, // 10
  91. {0x00,0x00,0x00,0x00,0x00,0x00}, // 11
  92. {0x00,0x00,0x00,0x00,0x00,0x00}, // 12
  93. {0x00,0x00,0x00,0x00,0x00,0x00}, // 13
  94. {0x00,0x00,0x00,0x00,0x00,0x00}, // 14
  95. {0x00,0x00,0x00,0x00,0x00,0x00}, // 15
  96. {0x00,0x00,0x00,0x00,0x00,0x00}, // 16
  97. {0x00,0x00,0x00,0x00,0x00,0x00}, // 17
  98. {0x00,0x00,0x00,0x00,0x00,0x00}, // 18
  99. {0x00,0x00,0x00,0x00,0x00,0x00}, // 19
  100. {0x00,0x00,0x00,0x00,0x00,0x00}, // 20
  101. {0x00,0x00,0x00,0x00,0x00,0x00}, // 21
  102. {0x00,0x00,0x00,0x00,0x00,0x00}, // 22
  103. {0x00,0x00,0x00,0x00,0x00,0x00}, // 23
  104. {0x00,0x00,0x00,0x00,0x00,0x00}, // 24
  105. {0x00,0x00,0x00,0x00,0x00,0x00}, // 25
  106. {0x00,0x00,0x00,0x00,0x00,0x00}, // 26
  107. {0x00,0x00,0x00,0x00,0x00,0x00}, // 27
  108. {0x00,0x00,0x00,0x00,0x00,0x00}, // 28
  109. {0x00,0x00,0x00,0x00,0x00,0x00}, // 29
  110. {0x00,0x00,0x00,0x00,0x00,0x00}, // 30
  111. {0x00,0x00,0x00,0x00,0x00,0x00}, // 31
  112. {0x00,0x00,0x00,0x00,0x00,0x00}, // sp 32
  113. {0x00,0x00,0x2f,0x00,0x00,0x00}, // ! 33
  114. {0x00,0x07,0x00,0x07,0x00,0x00}, // " 34
  115. {0x14,0x7f,0x14,0x7f,0x14,0x00}, // # 35
  116. {0x24,0x2a,0x7f,0x2a,0x12,0x00}, // $ 36
  117. {0xc4,0xc8,0x10,0x26,0x46,0x00}, // % 37
  118. {0x36,0x49,0x55,0x22,0x50,0x00}, // & 38
  119. {0x00,0x05,0x03,0x00,0x00,0x00}, // ' 39
  120. {0x00,0x1c,0x22,0x41,0x00,0x00}, // ( 40
  121. {0x00,0x41,0x22,0x1c,0x00,0x00}, // ) 41
  122. {0x14,0x08,0x3E,0x08,0x14,0x00}, // * 42
  123. {0x08,0x08,0x3E,0x08,0x08,0x00}, // + 43
  124. {0x00,0x00,0x50,0x30,0x00,0x00}, // , 44
  125. {0x10,0x10,0x10,0x10,0x10,0x00}, // - 45
  126. {0x00,0x60,0x60,0x00,0x00,0x00}, // . 46
  127. {0x20,0x10,0x08,0x04,0x02,0x00}, // / 47
  128. {0x3E,0x51,0x49,0x45,0x3E,0x00}, // 0 48
  129. {0x00,0x42,0x7F,0x40,0x00,0x00}, // 1 49
  130. {0x42,0x61,0x51,0x49,0x46,0x00}, // 2 50
  131. {0x21,0x41,0x45,0x4B,0x31,0x00}, // 3 51
  132. {0x18,0x14,0x12,0x7F,0x10,0x00}, // 4 52
  133. {0x27,0x45,0x45,0x45,0x39,0x00}, // 5 53
  134. {0x3C,0x4A,0x49,0x49,0x30,0x00}, // 6 54
  135. {0x01,0x71,0x09,0x05,0x03,0x00}, // 7 55
  136. {0x36,0x49,0x49,0x49,0x36,0x00}, // 8 56
  137. {0x06,0x49,0x49,0x29,0x1E,0x00}, // 9 57
  138. {0x00,0x36,0x36,0x00,0x00,0x00}, // : 58
  139. {0x00,0x56,0x36,0x00,0x00,0x00}, // ; 59
  140. {0x08,0x14,0x22,0x41,0x00,0x00}, // < 60
  141. {0x14,0x14,0x14,0x14,0x14,0x00}, // = 61
  142. {0x00,0x41,0x22,0x14,0x08,0x00}, // > 62
  143. {0x02,0x01,0x51,0x09,0x06,0x00}, // ? 63
  144. {0x32,0x49,0x59,0x51,0x3E,0x00}, // @ 64
  145. {0x7E,0x11,0x11,0x11,0x7E,0x00}, // A 65
  146. {0x7F,0x49,0x49,0x49,0x36,0x00}, // B 66
  147. {0x3E,0x41,0x41,0x41,0x22,0x00}, // C 67
  148. {0x7F,0x41,0x41,0x22,0x1C,0x00}, // D 68
  149. {0x7F,0x49,0x49,0x49,0x41,0x00}, // E 69
  150. {0x7F,0x09,0x09,0x09,0x01,0x00}, // F 70
  151. {0x3E,0x41,0x49,0x49,0x7A,0x00}, // G 71
  152. {0x7F,0x08,0x08,0x08,0x7F,0x00}, // H 72
  153. {0x00,0x41,0x7F,0x41,0x00,0x00}, // I 73
  154. {0x20,0x40,0x41,0x3F,0x01,0x00}, // J 74
  155. {0x7F,0x08,0x14,0x22,0x41,0x00}, // K 75
  156. {0x7F,0x40,0x40,0x40,0x40,0x00}, // L 76
  157. {0x7F,0x02,0x0C,0x02,0x7F,0x00}, // M 77
  158. {0x7F,0x04,0x08,0x10,0x7F,0x00}, // N 78
  159. {0x3E,0x41,0x41,0x41,0x3E,0x00}, // O 79
  160. {0x7F,0x09,0x09,0x09,0x06,0x00}, // P 80
  161. {0x3E,0x41,0x51,0x21,0x5E,0x00}, // Q 81
  162. {0x7F,0x09,0x19,0x29,0x46,0x00}, // R 82
  163. {0x46,0x49,0x49,0x49,0x31,0x00}, // S 83
  164. {0x01,0x01,0x7F,0x01,0x01,0x00}, // T 84
  165. {0x3F,0x40,0x40,0x40,0x3F,0x00}, // U 85
  166. {0x1F,0x20,0x40,0x20,0x1F,0x00}, // V 86
  167. {0x3F,0x40,0x38,0x40,0x3F,0x00}, // W 87
  168. {0x63,0x14,0x08,0x14,0x63,0x00}, // X 88
  169. {0x07,0x08,0x70,0x08,0x07,0x00}, // Y 89
  170. {0x61,0x51,0x49,0x45,0x43,0x00}, // Z 90
  171. {0x00,0x7F,0x41,0x41,0x00,0x00}, // [ 91
  172. {0x55,0x2A,0x55,0x2A,0x55,0x00}, //55 92
  173. {0x00,0x41,0x41,0x7F,0x00,0x00}, // ] 93
  174. {0x04,0x02,0x01,0x02,0x04,0x00}, // ^ 94
  175. {0x40,0x40,0x40,0x40,0x40,0x00}, // _ 95
  176. {0x00,0x01,0x02,0x04,0x00,0x00}, // ' 96
  177. {0x20,0x54,0x54,0x54,0x78,0x00}, // a 97
  178. {0x7F,0x48,0x44,0x44,0x38,0x00}, // b 98
  179. {0x38,0x44,0x44,0x44,0x20,0x00}, // c 99
  180. {0x38,0x44,0x44,0x48,0x7F,0x00}, // d 100
  181. {0x38,0x54,0x54,0x54,0x18,0x00}, // e 101
  182. {0x08,0x7E,0x09,0x01,0x02,0x00}, // f 102
  183. {0x0C,0x52,0x52,0x52,0x3E,0x00}, // g 103
  184. {0x7F,0x08,0x04,0x04,0x78,0x00}, // h 104
  185. {0x00,0x44,0x7D,0x40,0x00,0x00}, // i 105
  186. {0x20,0x40,0x44,0x3D,0x00,0x00}, // j 106
  187. {0x7F,0x10,0x28,0x44,0x00,0x00}, // k 107
  188. {0x00,0x41,0x7F,0x40,0x00,0x00}, // l 108
  189. {0x7C,0x04,0x18,0x04,0x78,0x00}, // m 109
  190. {0x7C,0x08,0x04,0x04,0x78,0x00}, // n 110
  191. {0x38,0x44,0x44,0x44,0x38,0x00}, // o 111
  192. {0x7C,0x14,0x14,0x14,0x08,0x00}, // p 112
  193. {0x08,0x14,0x14,0x18,0x7C,0x00}, // q 113
  194. {0x7C,0x08,0x04,0x04,0x08,0x00}, // r 114
  195. {0x48,0x54,0x54,0x54,0x20,0x00}, // s 115
  196. {0x04,0x3F,0x44,0x40,0x20,0x00}, // t 116
  197. {0x3C,0x40,0x40,0x20,0x7C,0x00}, // u 117
  198. {0x1C,0x20,0x40,0x20,0x1C,0x00}, // v 118
  199. {0x3C,0x40,0x30,0x40,0x3C,0x00}, // w 119
  200. {0x44,0x28,0x10,0x28,0x44,0x00}, // x 120
  201. {0x0C,0x50,0x50,0x50,0x3C,0x00}, // y 121
  202. {0x44,0x64,0x54,0x4C,0x44,0x00}, // z 122
  203. {0xD5,0x01,0x80,0x01,0x80,0xAB}, // <50 123
  204. {0xFF,0x81,0x81,0x81,0x81,0xFF}, //50<= <100 124
  205. {0xFF,0x81,0xBD,0xBD,0x81,0xFF}, //100<= <150 125
  206. {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, //>=150 126
  207. {0x00,0x00,0x00,0x00,0x00,0x00} // sp 127
  208. };
  209. unsigned char code myChannel[7]={'C','h','a','n','n','e','l'};
  210. unsigned char code myTemp[4]={'T','e','m','p'};
  211. unsigned char code myHumi[4]={'H','u','m','i'};
  212. unsigned char code myCO[2]={'C','O'};
  213. unsigned char code myCH4[3]={'C','H','4'};
  214. unsigned char code myLight[5]={'L','i','g','h','t'};
  215. unsigned char code myAir[7]={'A','i','r','-','p','r','e'};
  216. unsigned char code **msg[7]={myChannel,myTemp,myHumi,myCO,myCH4,myLight,myAir};
  217. //延时函数
  218. void Delayms(uint x )
  219. {
  220. uint t;
  221. while(x--)
  222. for (t= 0; t<120; t++);
  223. }
  224. //HDG12864F-1
  225. //写命令
  226. void wrt_cmd(unsigned char command)
  227. {
  228. unsigned char i = 8;//8位
  229. cs1 = 0;//片选,低电平有效
  230. a0 = 0;//0=Control data,命令置0
  231. while(i--)
  232. {
  233. scl = 0;
  234. si = (bit) (command & 0x80);//先写高位
  235. scl = 1;//上升沿
  236. command <<= 1;//左移一位
  237. }
  238. scl = 0;
  239. }
  240. //写数据
  241. void wrt_dt(unsigned char data_)
  242. {
  243. unsigned char i = 8;//8位
  244. cs1 = 0;//片选,低电平有效
  245. a0 = 1;//1=Display data,写数据置1
  246. while(i--)
  247. {
  248. scl = 0;
  249. si = (bit) (data_ & 0x80);//先写高位
  250. scl = 1;//上升沿
  251. data_ <<= 1;//左移一位 0
  252. }
  253. scl = 0;
  254. }
  255. //设置列位置,其中参数address:0~127
  256. void HDG12864F1_SetColumnAddress(unsigned char address)
  257. { //写列要分成两步走,先写高四位,再写低四位
  258. //手册Column Address Set
  259. wrt_cmd(0x10 + (address >> 4 & 0x0f));//C中右移是算术右移,必须&0x0f去掉高4位才能得到正确的结果
  260. wrt_cmd(address & 0x0f);
  261. }
  262. //设置纵向位置,其中参数pageAddress:0~8
  263. void HDG12864F1_SetPageAddress(unsigned char pageAddress)
  264. { //手册Page Address Set
  265. wrt_cmd(0xb0 + pageAddress);//1011+页码
  266. }
  267. //写数据
  268. void HDG12864F1_WriteData(unsigned char data_)
  269. {
  270. wrt_dt(data_);
  271. }
  272. //设置写的方向:从右向左为正
  273. void HDG12864F1_Direction(unsigned char direction)
  274. { //手册ADC Select
  275. wrt_cmd(0xa0+direction);
  276. }
  277. //对写好的屏幕内容向上滚屏,滚出上边的部分会从屏幕下边冒出来
  278. void HDG12864F1_SetStartLine(unsigned char line)
  279. { //参数line取值范围0~63
  280. wrt_cmd(0x40 + line);
  281. }
  282. //写英文字符,数字占上下1个8*6点阵
  283. void HDG12864F1_WriteEnglishChar(unsigned char *pEChar, unsigned char column, unsigned char page)
  284. {
  285. unsigned char i;
  286. HDG12864F1_Direction(DISPLAY_LEFT_TO_RIGHT);//DISPLAY_LEFT_TO_RIGHT是一个宏,值为1,代表从屏幕左侧写入
  287. HDG12864F1_SetColumnAddress(column);//设开始写的横向坐标
  288. HDG12864F1_SetPageAddress(page);//设开始写的纵向Page
  289. for(i=0; i<6; i++)
  290. HDG12864F1_WriteData(*(pEChar + i));//连续写英文
  291. }
  292. //图片32*32
  293. void HDG12864F1_DrawPic(unsigned char *pChar, unsigned char column, unsigned char page)
  294. {
  295. unsigned char i,j;
  296. HDG12864F1_Direction(DISPLAY_LEFT_TO_RIGHT);//DISPLAY_LEFT_TO_RIGHT是一个宏,值为1,代表从屏幕左侧写入
  297. for(i=0;i<4;i++)
  298. {
  299. HDG12864F1_SetColumnAddress(column);//设开始写的横向坐标
  300. HDG12864F1_SetPageAddress(page+i);//设开始写的纵向Page
  301. for(j=0;j<32;j++)
  302. {
  303. HDG12864F1_WriteData(*(pChar + i*32+j));//连续写英文
  304. }
  305. }
  306. }
  307. //ADC0834
  308. unsigned char AD0834_conv(unsigned int n)
  309. {
  310. unsigned char i,com;
  311. CS=1;
  312. CS=0; _nop_(); _nop_();//CS置低,启动转换
  313. DI=1; _nop_(); _nop_();//启动,准备输出数据 第一个脉冲
  314. CLK=1; _nop_(); _nop_();
  315. CLK=0; _nop_(); _nop_();
  316. //选择通道,第二个脉冲
  317. DI=1;
  318. CLK=1; _nop_(); _nop_();
  319. CLK=0; _nop_(); _nop_();
  320. DI=channel0834[n*2];
  321. CLK=1; _nop_(); _nop_();
  322. CLK=0; _nop_(); _nop_();
  323. DI=channel0834[n*2+1];
  324. CLK=1; _nop_(); _nop_();
  325. CLK=0; _nop_(); _nop_();
  326. DI=1;
  327. CLK=1; _nop_(); _nop_();
  328. CLK=0; _nop_(); _nop_();
  329. //开始采集转换数据
  330. for(i=8;i>0;i--)
  331. {
  332. com<<=1;//左移,先采最高位
  333. if(DO)com=com|0x01;//采当前数据
  334. CLK=1;
  335. CLK=0;
  336. _nop_();
  337. _nop_();
  338. }
  339. CS=1;//关闭片选,禁用
  340. return com;
  341. }
  342. //LDR传感器数据拟合
  343. unsigned char ChangeDataLDR(unsigned char res)
  344. {
  345. unsigned char com;
  346. com=0.00000000221308*res*res*res*res*res
  347. -0.0000009287723*res*res*res*res
  348. + 0.0001465584*res*res*res
  349. - 0.008997464*res*res
  350. + 0.2657836*res - 0.5918848;
  351. return com;
  352. }
  353. //MPX4115传感器数据拟合
  354. unsigned char ChangeDataMPX(unsigned char res)
  355. {
  356. unsigned char com;
  357. //自己拟合
  358. com=0.436*res+9.053;
  359. return com;
  360. }
  361. //SHT10
  362. //写字节
  363. char s_write_byte(uchar value)
  364. {
  365. uchar i,error=0;
  366. //分别取出指令的对应位串传输
  367. //从高位开始
  368. for(i=0x80;i>0;i>>=1)
  369. {
  370. if(i&value) DATA=1;
  371. else DATA=0;
  372. SCK=1;
  373. //保持SCK高电平
  374. _nop_();_nop_();_nop_();
  375. SCK=0;
  376. }
  377. DATA=1;
  378. SCK=1;
  379. error=DATA;//ACK
  380. _nop_();_nop_();_nop_();
  381. SCK=0;
  382. DATA=1;
  383. return error;
  384. }
  385. //读字节
  386. char s_read_byte(uchar ack)
  387. {
  388. uchar i,val=0;
  389. DATA=1;
  390. //读取一个字节的数据
  391. for(i=0x80;i>0;i>>=1)
  392. {
  393. SCK=1;
  394. if(DATA) val=(val|i);
  395. SCK=0;
  396. }
  397. if(ack==1)DATA=0;//通过下拉DATA为低电平以确认每个字节
  398. else DATA=1; //如果是校验 (ack==0) ,读取完后保持ACK高电平结束通讯
  399. _nop_();_nop_();_nop_(); //pulswith approx. 3 us
  400. SCK=1; //clk #9 for ack
  401. _nop_();_nop_();_nop_(); //pulswith approx. 3 us
  402. SCK=0;
  403. _nop_();_nop_();_nop_(); //pulswith approx. 3 us
  404. DATA=1; //释放DATA-line
  405. return val;
  406. }
  407. //启动传输
  408. void s_transstart(void)
  409. {
  410. DATA=1; SCK=0;
  411. _nop_();
  412. SCK=1;
  413. _nop_();
  414. DATA=0;
  415. _nop_();
  416. SCK=0;
  417. _nop_();_nop_();_nop_();
  418. SCK=1;
  419. _nop_();
  420. DATA=1;
  421. _nop_();
  422. SCK=0;
  423. }
  424. //连接复位
  425. void s_connectionreset(void)
  426. {
  427. //通讯中断需要通讯复位
  428. //DATA保持高电平并触发SCK时钟9次或更多
  429. uchar i;
  430. DATA=1;SCK=0;
  431. for(i=0;i<9;i++)
  432. {
  433. SCK=1;
  434. SCK=0;
  435. }
  436. //发送一个传输启动时序
  437. s_transstart();
  438. //复位串口而状态寄存器内容仍然保留
  439. }
  440. //温湿度测量
  441. char s_measure(uchar *p_value,uchar *p_checksum,uchar mode)
  442. {
  443. unsigned error=0;
  444. unsigned int i;
  445. s_transstart();
  446. switch(mode)
  447. {
  448. case TEMP:
  449. error+=s_write_byte(MEASURE_TEMP); break;
  450. case HUMI:
  451. error+=s_write_byte(MEASURE_HUMI); break;
  452. default: break;
  453. }
  454. //在结束测量后Sensor会把DATA线拉低
  455. //等待测量结束时间根据不同位数的测量不同
  456. for(i=0;i<65535;i++) if(DATA==0) break;//2^16
  457. if(DATA) error+=1;//说明没有结束
  458. //传输2个字节的测量数据和1个字节的CRC奇偶校验
  459. *(p_value)=s_read_byte(ACK);
  460. *(p_value+1)=s_read_byte(ACK);
  461. *p_checksum=s_read_byte(noACK);
  462. return error;
  463. }
  464. //温湿度值标度变换及温度补偿
  465. void calc_sth10(float *p_humidity,float *p_temperature)
  466. {
  467. // input : humi [Ticks] (12 bit)
  468. // temp [Ticks] (14 bit)
  469. // output: humi [%RH]
  470. const float C1=-2.0468; // for 12 Bit
  471. const float C2=+0.0367; // for 12 Bit
  472. const float C3=-0.0000015955; // for 12 Bit
  473. const float T1=+0.01; // for 12 Bit @ 5V
  474. const float T2=+0.00008; // for 12 Bit @ 5V
  475. float rh=*p_humidity;// rh: Humidity [Ticks] 12 Bit
  476. float t=*p_temperature; // t: Temperature [Ticks] 14 Bit
  477. float rh_lin;// rh_lin: Humidity linear
  478. float rh_ture;// rh_true: Temperature compensated humidity
  479. float t_C;// t_C : Temperature [C]
  480. t_C=t*0.01-40;//温度转换[C]
  481. rh_lin=C3*rh*rh+C2*rh+C1;//相对湿度非线性补偿[%RH]
  482. rh_ture=(t_C-25)*(T1+T2*rh)+rh_lin;//湿度信号的温度补偿[%RH]
  483. //超范围处理
  484. if(rh_ture>100) rh_ture=100;
  485. if(rh_ture<0.1) rh_ture=0.1;
  486. //将结果传输回去
  487. *p_temperature=t_C;//[C]
  488. *p_humidity=rh_ture;//[%RH]
  489. }
  490. typedef union
  491. {
  492. unsigned int i;
  493. float f;
  494. }value;
  495. void main(void)
  496. {
  497. int i=0;
  498. int j=0;
  499. int mycol=0;
  500. value humi_val,temp_val;
  501. uchar error;
  502. uchar check_sum;//校验和
  503. int flag;//判断温度符号
  504. BP=0;
  505. FAN=0;
  506. while(1)
  507. {
  508. mycol=0;
  509. for(i=0;i<7;i++)
  510. HDG12864F1_WriteEnglishChar(BMP[myChannel[i]],i*8,mycol);
  511. HDG12864F1_WriteEnglishChar(BMP[':'],7*8,mycol);
  512. HDG12864F1_WriteEnglishChar(BMP['A'],8*8,mycol);
  513. mycol=mycol+1;
  514. //温湿度
  515. error=0;
  516. error+=s_measure((uchar*)&humi_val.i,&check_sum,HUMI);
  517. error+=s_measure((uchar*)&temp_val.i,&check_sum,TEMP);
  518. if(error!=0)//说明通讯中断且没有测量完
  519. s_connectionreset();
  520. else//已经测量完
  521. {
  522. humi_val.f=(float)humi_val.i;
  523. temp_val.f=(float)temp_val.i;
  524. //温湿度补偿
  525. calc_sth10(&humi_val.f,&temp_val.f);
  526. //判断符号
  527. if(temp_val.f<0)
  528. {
  529. flag='-';
  530. temp_val.f=-temp_val.f+2;
  531. }
  532. else
  533. flag='+';
  534. //可以显示小数位后一位
  535. temp=temp_val.f*10;
  536. humi=humi_val.f*10;
  537. }
  538. //温度
  539. for(i=0;i<4;i++)
  540. HDG12864F1_WriteEnglishChar(BMP[myTemp[i]],i*8,mycol);
  541. HDG12864F1_WriteEnglishChar(BMP[':'],4*8,mycol);
  542. HDG12864F1_WriteEnglishChar(BMP[flag],5*8,mycol);
  543. HDG12864F1_WriteEnglishChar(BMP[temp/1000+'0'],6*8,mycol);
  544. HDG12864F1_WriteEnglishChar(BMP[temp%1000/100+'0'],7*8,mycol);
  545. HDG12864F1_WriteEnglishChar(BMP[temp%100/10+'0'],8*8,mycol);
  546. HDG12864F1_WriteEnglishChar(BMP['C'],9*8,mycol);
  547. mycol=mycol+1;
  548. //湿度
  549. for(i=0;i<4;i++)
  550. HDG12864F1_WriteEnglishChar(BMP[myHumi[i]],i*8,mycol);
  551. HDG12864F1_WriteEnglishChar(BMP[':'],4*8,mycol);
  552. HDG12864F1_WriteEnglishChar(BMP[humi/1000+'0'],5*8,mycol);
  553. HDG12864F1_WriteEnglishChar(BMP[humi%1000/100+'0'],6*8,mycol);
  554. HDG12864F1_WriteEnglishChar(BMP[humi%100/10+'0'],7*8,mycol);
  555. HDG12864F1_WriteEnglishChar(BMP['%'],8*8,mycol);
  556. mycol=mycol+1;
  557. ad_res=AD0834_conv(0);
  558. ad_res1=ad_res;
  559. for(i=0;i<5;i++)
  560. HDG12864F1_WriteEnglishChar(BMP[myLight[i]],i*8,mycol);
  561. HDG12864F1_WriteEnglishChar(BMP[':'],5*8,mycol);
  562. HDG12864F1_WriteEnglishChar(BMP[ad_res1%1000/100+'0'],6*8,mycol);
  563. HDG12864F1_WriteEnglishChar(BMP[ad_res1%100/10+'0'],7*8,mycol);
  564. HDG12864F1_WriteEnglishChar(BMP[ad_res1%10+'0'],8*8,mycol);
  565. HDG12864F1_WriteEnglishChar(BMP['L'],9*8,mycol);
  566. HDG12864F1_WriteEnglishChar(BMP['x'],10*8,mycol);
  567. mycol=mycol+1;
  568. ad_res=AD0834_conv(1);
  569. ad_res2=ChangeDataLDR(ad_res);
  570. for(i=0;i<2;i++)
  571. HDG12864F1_WriteEnglishChar(BMP[myCO[i]],i*8,mycol);
  572. HDG12864F1_WriteEnglishChar(BMP[':'],2*8,mycol);
  573. HDG12864F1_WriteEnglishChar(BMP[ad_res2%1000/100+'0'],3*8,mycol);
  574. HDG12864F1_WriteEnglishChar(BMP[ad_res2%100/10+'0'],4*8,mycol);
  575. HDG12864F1_WriteEnglishChar(BMP[ad_res2%10+'0'],5*8,mycol);
  576. HDG12864F1_WriteEnglishChar(BMP['p'],6*8,mycol);
  577. HDG12864F1_WriteEnglishChar(BMP['p'],7*8,mycol);
  578. HDG12864F1_WriteEnglishChar(BMP['m'],8*8,mycol);
  579. mycol=mycol+1;
  580. ad_res=AD0834_conv(2);
  581. ad_res3=ChangeDataLDR(ad_res);
  582. //控制RGB-LED与BP与FAN
  583. if(ad_res3<20)//正常-绿色-风扇关闭-蜂鸣器关闭
  584. {
  585. LEDR=0;
  586. LEDG=1;
  587. BP=0;
  588. FAN=0;
  589. }
  590. else if(ad_res3>=20 & ad_res3<40)//警示-黄色-风扇开启-蜂鸣器关闭
  591. {
  592. LEDR=1;
  593. LEDG=1;
  594. BP=0;
  595. FAN=1;
  596. }
  597. else//危险-红色-风扇关闭-蜂鸣器开启
  598. {
  599. LEDR=1;
  600. LEDG=0;
  601. BP=1;
  602. FAN=0;
  603. }
  604. for(i=0;i<3;i++)
  605. HDG12864F1_WriteEnglishChar(BMP[myCH4[i]],i*8,mycol);
  606. HDG12864F1_WriteEnglishChar(BMP[':'],3*8,mycol);
  607. HDG12864F1_WriteEnglishChar(BMP[ad_res3%1000/100+'0'],4*8,mycol);
  608. HDG12864F1_WriteEnglishChar(BMP[ad_res3%100/10+'0'],5*8,mycol);
  609. HDG12864F1_WriteEnglishChar(BMP[ad_res3%10+'0'],6*8,mycol);
  610. HDG12864F1_WriteEnglishChar(BMP['p'],7*8,mycol);
  611. HDG12864F1_WriteEnglishChar(BMP['p'],8*8,mycol);
  612. HDG12864F1_WriteEnglishChar(BMP['m'],9*8,mycol);
  613. mycol=mycol+1;
  614. ad_res=AD0834_conv(3);
  615. ad_res4=ChangeDataMPX(ad_res);
  616. for(i=0;i<7;i++)
  617. HDG12864F1_WriteEnglishChar(BMP[myAir[i]],i*8,mycol);
  618. HDG12864F1_WriteEnglishChar(BMP[':'],7*8,mycol);
  619. HDG12864F1_WriteEnglishChar(BMP[ad_res4%1000/100+'0'],8*8,mycol);
  620. HDG12864F1_WriteEnglishChar(BMP[ad_res4%100/10+'0'],9*8,mycol);
  621. HDG12864F1_WriteEnglishChar(BMP[ad_res4%10+'0'],10*8,mycol);
  622. HDG12864F1_WriteEnglishChar(BMP['k'],11*8,mycol);
  623. HDG12864F1_WriteEnglishChar(BMP['P'],12*8,mycol);
  624. HDG12864F1_WriteEnglishChar(BMP['a'],13*8,mycol);
  625. //转动的风扇
  626. HDG12864F1_DrawPic(&pic_data1,90,0);
  627. Delayms(800);//延时显示
  628. HDG12864F1_DrawPic(&pic_data2,90,0);
  629. Delayms(700);//延时显示
  630. }
  631. }

其中,HDG12864F-1部分的程序是参考:使用Proteus模拟操作HDG12864F-1液晶屏

Proteus传感器+气体浓度检测的报警方式控制仿真的更多相关文章

  1. 第44章 MPU6050传感器—姿态检测—零死角玩转STM32-F429系列

    第44章     MPU6050传感器—姿态检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  2. 阿里 Goldeneye 四个环节落地智能监控:预测、检测、报警及定位

    阿里 Goldeneye 四个环节落地智能监控:预测.检测.报警及定位 https://www.infoq.cn/article/alibaba-goldeneye-four-links

  3. zabbix 报警方式之 微信公众号报警(5)

    一.条件 首先你得有一个微信公众号,并且是可以有发送消息的接口.然后你得有个脚本去调用微信的api. 这里感谢一下微信.使我们运维人员的报警方式多了一种... (同事们不要怪我哈.) 之后可以参考下z ...

  4. zabbix 报警方式之 邮件报警(4)

    一.为什么要自定义邮件脚本报警? 灵活,方便.可以自定义过滤信息. 下面是使用不同方式的邮件报警,一个是利用sendEmail程序来发送报警邮件,第二个是利用python脚本来发送邮件. 二.send ...

  5. vue 多种方式控制style属性

    一共用到了两种方式: 第一种:对象 第二种:数组 看代码: <!doctype html> <html lang="en"> <head> &l ...

  6. Sentinel基本使用--基于QPS流量控制(二), 采用Warm Up预热/冷启动方式控制突增流量

    Sentinel基本使用--基于QPS流量控制(二), 采用Warm Up预热/冷启动方式控制突增流量 2019年02月18日 23:52:37 xiongxianze 阅读数 398更多 分类专栏: ...

  7. CAN总线简介:如何以编程方式控制汽车

    最近,我正与Voyage公司的朋友合作研究,以实现福特Fusion空调系统(A/C)的编程控制.目前,Voyage公司正努力打造自动驾驶的终极目标:能够以低廉的价格成本和广泛的投放范围,把世界任何地方 ...

  8. P2P NAT检测和穿越方式

    一.      NAT类型 本文转自:http://www.cnblogs.com/hummersofdie/archive/2013/05/21/3090163.html  1.基本的NAT类型:只 ...

  9. 三相异步电动机过载保护及报警PLC控制

    一.项目所需设备.工具.材料 见表7-1. 表7-1  项目所需设备.工具.材料 二.  训练内容: 1.项目描述 试设计一电动机过载保护程序,要求电动机过载时能自动停止运转,同时发出10秒钟的声光报 ...

随机推荐

  1. 006-循环结构(下)-C语言笔记

    006-循环结构(下)-C语言笔记 学习目标 1.[掌握]do-while循环结构 2.[掌握]for循环结构 3.[掌握]嵌套循环 一.do-while循环结构 do-while语法:   1 2 ...

  2. stand up meeting 1/7/2016

    part 组员                今日工作              工作耗时/h 明日计划 工作耗时/h    UI 冯晓云 调研下滑条的存在问题,尝试替换方案     6 全面实行替换 ...

  3. C - Mind Control CodeForces - 1291C

    菜到家了,题意都读不懂. 题目大意: 总共有n个人和n个数字 n个人拍成一队,n个数字也是有顺序的 你排在第m个位置 按照顺序的每个人可以拿走这个序列中的第一个数字或者最后一个数字 你可以在所有人操作 ...

  4. 2. js的异步

    1. 回掉2. promise3. Generator4. Async/await

  5. 电脑Win10晚上让它更新,为何第二天开机蓝屏?

    大家好,欢迎来到<电脑讲堂>,我是主持人高帅帅.PS:没错,就是那个人见人爱,花见花开的高帅帅. 话说,在一个月黑风高的夜晚,我晚上离开实验室,离开前看到了电脑的系统更新提醒,就顺手点了一 ...

  6. tp5--相对路径和绝对路径

    首先,我们要先明白相对路径和绝对路径的理论: 绝对路径:是从盘符开始的路径,形如C:\windows\system32\cmd.exe相对路径:是从当前路径开始的路径,假如当前路径为C:\window ...

  7. Centos史上新版最详细步骤-Linux无脑命令式oracle11g静默安装

    1. 关闭selinux 1.1 sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config 1.2 或者 ...

  8. Debugging Under Unix: gdb Tutorial (https://www.cs.cmu.edu/~gilpin/tutorial/)

    //注释掉 #include <iostream.h> //替换为 #include <iostream> using namespace std; Contents Intr ...

  9. How to use QueryPerformanceCounter? (c++,不使用 .Net)

    出处:https://stackoverflow.com/questions/1739259/how-to-use-queryperformancecounter 参考:https://docs.mi ...

  10. linux uniq 命令实用手册

    Linux uniq 命令用于处理文本内容中的重复行. 这里我们只介绍其常用参数,其完整用法可参见man uniq. 例如,我们有如下文件内容: >>> cat log.txt __ ...