新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 第49节:利用DS18B20做一个温控器

第49节:利用DS18B20做一个温控器

作者:时间:2016-11-22来源:网络收藏
开场白:
DS18B20是一款常用的温度传感器芯片,它只占用单片机一根IO口,使用起来也特别方便。需要特别注意的是,正因为它只用一根IO口跟单片机通讯,因此读取一次温度值的通讯时间比较长,而且时序要求严格,在通讯期间不允许被单片机其它的中断干扰,因此在实际项目中,系统一旦选用了这款传感器芯片,就千万不要选用动态扫描数码管的显示方式。否则在关闭中断读取温度的时候,数码管的显示会有略微的“闪烁”现象。
DS18B20的测温范围是-55度至125度。在-10度至85度的温度范围内误差是+-0.5度,能满足大部分常用的测温要求。
这一节要教会大家三个知识点:
第一个:大概了解一下DS18B20的驱动程序。
第二个:做温控设备的时候,为了避免继电器在临界温度附近频繁跳动切换,应该设置一个缓冲温差。本程序的缓冲温差是2度。
第三个:继续加深了解按键,显示,传感器它们三者是如何紧密关联起来的程序框架。

具体内容,请看源代码讲解。

(1) 硬件平台.
基于朱兆祺51单片机学习板

(2)实现功能:
本程序只有1个窗口。这个窗口有2个局部显示。
第1个局部是第7,6,5位数码管,显示设定的温度。
第2个局部是第4,3,2,1位数码管,显示实际环境温度。其中第4位数码管显示正负符号位。
S1按键是加键,S5按键是减键。通过它们可以直接设置“设定温度”。
一个LED灯用来模拟工控的继电器。
当实际温度低于或者等于设定温度2度以下时,模拟继电器的LED灯亮。
当实际温度等于或者大于设定温度时,模拟继电器的LED灯灭。
当实际温度处于设定温度和设定温度减去2度的范围内,模拟继电器的LED维持现状,这个2度范围用来做缓冲温差,避免继电器在临界温度附近频繁跳动切换。

(3)源代码讲解如下:
  1. #include "REG52.H"
  2. #define const_voice_short40 //蜂鸣器短叫的持续时间
  3. #define const_key_time120 //按键去抖动延时的时间
  4. #define const_key_time220 //按键去抖动延时的时间
  5. #define const_ds18b20_sampling_time 180 //累计主循环次数的时间,每次刷新采样时钟芯片的时间
  6. void initial_myself(void);
  7. void initial_peripheral(void);
  8. void delay_short(unsigned int uiDelayShort);
  9. void delay_long(unsigned int uiDelaylong);
  10. //驱动数码管的74HC595
  11. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
  12. void display_drive(void); //显示数码管字模的驱动函数
  13. void display_service(void); //显示的窗口菜单服务程序
  14. //驱动LED的74HC595
  15. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
  16. void T0_time(void);//定时中断函数
  17. void key_service(void); //按键服务的应用程序
  18. void key_scan(void);//按键扫描函数 放在定时中断里
  19. void temper_control_service(void); //温控程序
  20. void ds18b20_sampling(void); //ds18b20采样程序
  21. void ds18b20_reset(); //复位ds18b20的时序
  22. unsigned char ds_read_byte(void ); //读一字节
  23. void ds_write_byte(unsigned char dat); //写一个字节
  24. unsigned int get_temper();//读取一次没有经过换算的温度数值
  25. sbit dq_dr_sr=P2^6; //ds18b20的数据驱动线
  26. sbit key_sr1=P0^0; //对应朱兆祺学习板的S1键
  27. sbit key_sr2=P0^1; //对应朱兆祺学习板的S5键
  28. sbit led_dr=P3^5;//LED灯,模拟工控中的继电器
  29. sbit key_gnd_dr=P0^4; //模拟独立按键的地GND,因此必须一直输出低电平
  30. sbit beep_dr=P2^7; //蜂鸣器的驱动IO口
  31. sbit dig_hc595_sh_dr=P2^0; //数码管的74HC595程序
  32. sbit dig_hc595_st_dr=P2^1;
  33. sbit dig_hc595_ds_dr=P2^2;
  34. sbit hc595_sh_dr=P2^3; //LED灯的74HC595程序
  35. sbit hc595_st_dr=P2^4;
  36. sbit hc595_ds_dr=P2^5;
  37. unsigned int uiSampingCnt=0; //采集Ds1302的计时器,每秒钟更新采集一次
  38. unsigned char ucSignFlag=0; //正负符号。0代表正数,1代表负数,表示零下多少度。
  39. unsigned long ulCurrentTemper=33; //实际温度
  40. unsigned long ulSetTemper=26; //设定温度
  41. unsigned int uiTemperTemp=0; //中间变量
  42. unsigned char ucKeySec=0; //被触发的按键编号
  43. unsigned intuiKeyTimeCnt1=0; //按键去抖动延时计数器
  44. unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志
  45. unsigned intuiKeyTimeCnt2=0; //按键去抖动延时计数器
  46. unsigned char ucKeyLock2=0; //按键触发后自锁的变量标志
  47. unsigned intuiVoiceCnt=0;//蜂鸣器鸣叫的持续时间计数器
  48. unsigned charucVoiceLock=0;//蜂鸣器鸣叫的原子锁
  49. unsigned char ucDigShow8;//第8位数码管要显示的内容
  50. unsigned char ucDigShow7;//第7位数码管要显示的内容
  51. unsigned char ucDigShow6;//第6位数码管要显示的内容
  52. unsigned char ucDigShow5;//第5位数码管要显示的内容
  53. unsigned char ucDigShow4;//第4位数码管要显示的内容
  54. unsigned char ucDigShow3;//第3位数码管要显示的内容
  55. unsigned char ucDigShow2;//第2位数码管要显示的内容
  56. unsigned char ucDigShow1;//第1位数码管要显示的内容
  57. unsigned char ucDigDot8;//数码管8的小数点是否显示的标志
  58. unsigned char ucDigDot7;//数码管7的小数点是否显示的标志
  59. unsigned char ucDigDot6;//数码管6的小数点是否显示的标志
  60. unsigned char ucDigDot5;//数码管5的小数点是否显示的标志
  61. unsigned char ucDigDot4;//数码管4的小数点是否显示的标志
  62. unsigned char ucDigDot3;//数码管3的小数点是否显示的标志
  63. unsigned char ucDigDot2;//数码管2的小数点是否显示的标志
  64. unsigned char ucDigDot1;//数码管1的小数点是否显示的标志
  65. unsigned char ucDigShowTemp=0; //临时中间变量
  66. unsigned char ucDisplayDriveStep=1;//动态扫描数码管的步骤变量
  67. unsigned char ucWd=1;//因为本程序只有1个窗口,在实际项目中,此处的ucWd也可以省略不要
  68. unsigned char ucWd1Part1Update=1;//在窗口1中,局部1的更新显示标志
  69. unsigned char ucWd1Part2Update=1; //在窗口1中,局部2的更新显示标志
  70. unsigned char ucTemp1=0;//中间过渡变量
  71. unsigned char ucTemp2=0;//中间过渡变量
  72. unsigned char ucTemp3=0;//中间过渡变量
  73. unsigned char ucTemp4=0;//中间过渡变量
  74. unsigned char ucTemp5=0;//中间过渡变量
  75. unsigned char ucTemp6=0;//中间过渡变量
  76. unsigned char ucTemp7=0;//中间过渡变量
  77. unsigned char ucTemp8=0;//中间过渡变量
  78. //根据原理图得出的共阴数码管字模表
  79. code unsigned char dig_table[]=
  80. {
  81. 0x3f,//0 序号0
  82. 0x06,//1 序号1
  83. 0x5b,//2 序号2
  84. 0x4f,//3 序号3
  85. 0x66,//4 序号4
  86. 0x6d,//5 序号5
  87. 0x7d,//6 序号6
  88. 0x07,//7 序号7
  89. 0x7f,//8 序号8
  90. 0x6f,//9 序号9
  91. 0x00,//无 序号10
  92. 0x40,//- 序号11
  93. 0x73,//P 序号12
  94. };
  95. void main()
  96. {
  97. initial_myself();
  98. delay_long(100);
  99. initial_peripheral();
  100. while(1)
  101. {
  102. key_service(); //按键服务的应用程序
  103. ds18b20_sampling(); //ds18b20采样程序
  104. temper_control_service(); //温控程序
  105. display_service(); //显示的窗口菜单服务程序
  106. }
  107. }
  108. /* 注释一:
  109. * 做温控设备的时候,为了避免继电器在临界温度附近频繁跳动切换,应该设置一个
  110. * 缓冲温差。本程序的缓冲温差是2度。
  111. */
  112. void temper_control_service(void) //温控程序
  113. {
  114. if(ucSignFlag==0) //是正数的前提下
  115. {
  116. if(ulCurrentTemper>=ulSetTemper)//当实际温度大于等于设定温度时
  117. {
  118. led_dr=0; //模拟继电器的LED灯熄灭
  119. }
  120. else if(ulCurrentTemper<=(ulSetTemper-2))//当实际温度小于等于设定温度2读以下时,这里的2是缓冲温差2度
  121. {
  122. led_dr=1; //模拟继电器的LED灯点亮
  123. }
  124. }
  125. else//是负数,说明是零下多少度的情况下
  126. {
  127. led_dr=1; //模拟继电器的LED灯点亮
  128. }
  129. }
  130. void ds18b20_sampling(void) //ds18b20采样程序
  131. {
  132. ++uiSampingCnt;//累计主循环次数的时间
  133. if(uiSampingCnt>const_ds18b20_sampling_time)//每隔一段时间就更新采集一次Ds18b20数据
  134. {
  135. uiSampingCnt=0;
  136. ET0=0;//禁止定时中断
  137. uiTemperTemp=get_temper();//读取一次没有经过换算的温度数值
  138. ET0=1; //开启定时中断
  139. if((uiTemperTemp&0xf800)==0xf800) //是负号
  140. {
  141. ucSignFlag=1;
  142. uiTemperTemp=~uiTemperTemp;//求补码
  143. uiTemperTemp=uiTemperTemp+1;
  144. }
  145. else //是正号
  146. {
  147. ucSignFlag=0;
  148. }
  149. ulCurrentTemper=0; //把int数据类型赋给long类型之前要先清零
  150. ulCurrentTemper=uiTemperTemp;
  151. ulCurrentTemper=ulCurrentTemper*10; //为了先保留一位小数点,所以放大10倍,
  152. ulCurrentTemper=ulCurrentTemper>>4;//往右边移动4位,相当于乘以0.0625. 此时保留了1位小数点,
  153. ulCurrentTemper=ulCurrentTemper+5;//四舍五入
  154. ulCurrentTemper=ulCurrentTemper/10; //四舍五入后,去掉小数点
  155. ucWd1Part2Update=1; //局部2更新显示实时温度
  156. }
  157. }
  158. //ds18b20驱动程序
  159. unsigned int get_temper()//读取一次没有经过换算的温度数值
  160. {
  161. unsigned char temper_H;
  162. unsigned char temper_L;
  163. unsigned int ds18b20_data=0;
  164. ds18b20_reset(); //复位ds18b20的时序
  165. ds_write_byte(0xCC);
  166. ds_write_byte(0x44);
  167. ds18b20_reset(); //复位ds18b20的时序
  168. ds_write_byte(0xCC);
  169. ds_write_byte(0xBE);
  170. temper_L=ds_read_byte();
  171. temper_H=ds_read_byte();
  172. ds18b20_data=temper_H; //把两个字节合并成一个int数据类型
  173. ds18b20_data=ds18b20_data<<8;
  174. ds18b20_data=ds18b20_data|temper_L;
  175. return ds18b20_data;
  176. }
  177. void ds18b20_reset() //复位ds18b20的时序
  178. {
  179. unsigned char x;
  180. dq_dr_sr=1;
  181. delay_short(8);
  182. dq_dr_sr=0;
  183. delay_short(80);
  184. dq_dr_sr=1;
  185. delay_short(14);
  186. x=dq_dr_sr;
  187. delay_short(20);
  188. }
  189. void ds_write_byte(unsigned char date) //写一个字节
  190. {
  191. unsigned chari;
  192. for(i=0;i<8;i++)
  193. {
  194. dq_dr_sr=0;
  195. dq_dr_sr=date&0x01;
  196. delay_short(5);
  197. dq_dr_sr=1;
  198. date=date>>1;
  199. }
  200. }
  201. unsigned char ds_read_byte(void ) //读一字节
  202. {
  203. unsigned char i;
  204. unsigned char date=0;
  205. for(i=0;i<8;i++)
  206. {
  207. dq_dr_sr=0;
  208. date=date>>1;
  209. dq_dr_sr=1;
  210. if(dq_dr_sr)
  211. {
  212. date=date|0x80;
  213. }
  214. delay_short(5);
  215. }
  216. return (date);
  217. }
  218. void display_service(void) //显示的窗口菜单服务程序
  219. {
  220. switch(ucWd)//因为本程序只有1个窗口,在实际项目中,此处的ucWd也可以省略不要
  221. {
  222. case 1:
  223. if(ucWd1Part1Update==1)//局部设定温度更新显示
  224. {
  225. ucWd1Part1Update=0;
  226. ucTemp8=10; //显示空
  227. if(ulSetTemper>=100)
  228. {
  229. ucTemp7=ulSetTemper%1000/100; //显示设定温度的百位
  230. }
  231. else
  232. {
  233. ucTemp7=10; //显示空
  234. }
  235. if(ulSetTemper>=10)
  236. {
  237. ucTemp6=ulSetTemper%100/10; //显示设定温度的十位
  238. }
  239. else
  240. {
  241. ucTemp6=10; //显示空
  242. }
  243. ucTemp5=ulSetTemper%10; //显示设定温度的个位
  244. ucDigShow8=ucTemp8; //数码管显示实际内容
  245. ucDigShow7=ucTemp7;
  246. ucDigShow6=ucTemp6;
  247. ucDigShow5=ucTemp5;
  248. }
  249. if(ucWd1Part2Update==1)//局部实际温度更新显示
  250. {
  251. if(ucSignFlag==0)//正数
  252. {
  253. ucTemp4=10; //显示空
  254. }
  255. else//负数,说明是零下多少度的情况下
  256. {
  257. ucTemp4=11; //显示负号-
  258. }
  259. if(ulCurrentTemper>=100)
  260. {
  261. ucTemp3=ulCurrentTemper%100/100; //显示实际温度的百位
  262. }
  263. else
  264. {
  265. ucTemp3=10; //显示空
  266. }
  267. if(ulCurrentTemper>=10)
  268. {
  269. ucTemp2=ulCurrentTemper%100/10;//显示实际温度的十位
  270. }
  271. else
  272. {
  273. ucTemp2=10;//显示空
  274. }
  275. ucTemp1=ulCurrentTemper%10; //显示实际温度的个数位
  276. ucDigShow4=ucTemp4; //数码管显示实际内容
  277. ucDigShow3=ucTemp3;
  278. ucDigShow2=ucTemp2;
  279. ucDigShow1=ucTemp1;
  280. }
  281. break;
  282. }
  283. }
  284. void key_scan(void)//按键扫描函数 放在定时中断里
  285. {
  286. if(key_sr1==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  287. {
  288. ucKeyLock1=0; //按键自锁标志清零
  289. uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
  290. }
  291. else if(ucKeyLock1==0)//有按键按下,且是第一次被按下
  292. {
  293. uiKeyTimeCnt1++; //累加定时中断次数
  294. if(uiKeyTimeCnt1>const_key_time1)
  295. {
  296. uiKeyTimeCnt1=0;
  297. ucKeyLock1=1;//自锁按键置位,避免一直触发
  298. ucKeySec=1; //触发1号键
  299. }
  300. }
  301. if(key_sr2==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  302. {
  303. ucKeyLock2=0; //按键自锁标志清零
  304. uiKeyTimeCnt2=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
  305. }
  306. else if(ucKeyLock2==0)//有按键按下,且是第一次被按下
  307. {
  308. uiKeyTimeCnt2++; //累加定时中断次数
  309. if(uiKeyTimeCnt2>const_key_time2)
  310. {
  311. uiKeyTimeCnt2=0;
  312. ucKeyLock2=1;//自锁按键置位,避免一直触发
  313. ucKeySec=2; //触发2号键
  314. }
  315. }
  316. }
  317. void key_service(void) //按键服务的应用程序
  318. {
  319. switch(ucKeySec) //按键服务状态切换
  320. {
  321. case 1:// 加按键 对应朱兆祺学习板的S1键
  322. switch(ucWd) //因为本程序只有1个窗口,在实际项目中,此处的ucWd也可以省略不要
  323. {
  324. case 1: //在窗口1下设置设定温度
  325. ulSetTemper++;
  326. if(ulSetTemper>125)
  327. {
  328. ulSetTemper=125;
  329. }
  330. ucWd1Part1Update=1; //更新显示设定温度
  331. break;
  332. }
  333. ucVoiceLock=1;//原子锁加锁,保护主函数与中断函数的共享变量uiVoiceCnt
  334. uiVoiceCnt=const_voice_short; //按键声音触发,滴一声就停。
  335. ucVoiceLock=0;//原子锁解锁,保护主函数与中断函数的共享变量uiVoiceCnt
  336. ucKeySec=0;//响应按键服务处理程序后,按键编号清零,避免一致触发
  337. break;
  338. case 2:// 减按键 对应朱兆祺学习板的S5键
  339. switch(ucWd) //因为本程序只有1个窗口,在实际项目中,此处的ucWd也可以省略不要
  340. {
  341. case 1: //在窗口1下设置设定温度
  342. if(ulSetTemper>2)//由于缓冲温差是2度,所以我人为规定最小允许设定的温度不能低于2度
  343. {
  344. ulSetTemper--;
  345. }
  346. ucWd1Part1Update=1; //更新显示设定温度
  347. break;
  348. }
  349. ucVoiceLock=1;//原子锁加锁,保护主函数与中断函数的共享变量uiVoiceCnt
  350. uiVoiceCnt=const_voice_short; //按键声音触发,滴一声就停。
  351. ucVoiceLock=0;//原子锁解锁,保护主函数与中断函数的共享变量uiVoiceCnt
  352. ucKeySec=0;//响应按键服务处理程序后,按键编号清零,避免一致触发
  353. break;
  354. }
  355. }
  356. void display_drive(void)
  357. {
  358. //以下程序,如果加一些数组和移位的元素,还可以压缩容量。但是鸿哥追求的不是容量,而是清晰的讲解思路
  359. switch(ucDisplayDriveStep)
  360. {
  361. case 1://显示第1位
  362. ucDigShowTemp=dig_table[ucDigShow1];
  363. if(ucDigDot1==1)
  364. {
  365. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  366. }
  367. dig_hc595_drive(ucDigShowTemp,0xfe);
  368. break;
  369. case 2://显示第2位
  370. ucDigShowTemp=dig_table[ucDigShow2];
  371. if(ucDigDot2==1)
  372. {
  373. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  374. }
  375. dig_hc595_drive(ucDigShowTemp,0xfd);
  376. break;
  377. case 3://显示第3位
  378. ucDigShowTemp=dig_table[ucDigShow3];
  379. if(ucDigDot3==1)
  380. {
  381. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  382. }
  383. dig_hc595_drive(ucDigShowTemp,0xfb);
  384. break;
  385. case 4://显示第4位
  386. ucDigShowTemp=dig_table[ucDigShow4];
  387. if(ucDigDot4==1)
  388. {
  389. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  390. }
  391. dig_hc595_drive(ucDigShowTemp,0xf7);
  392. break;
  393. case 5://显示第5位
  394. ucDigShowTemp=dig_table[ucDigShow5];
  395. if(ucDigDot5==1)
  396. {
  397. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  398. }
  399. dig_hc595_drive(ucDigShowTemp,0xef);
  400. break;
  401. case 6://显示第6位
  402. ucDigShowTemp=dig_table[ucDigShow6];
  403. if(ucDigDot6==1)
  404. {
  405. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  406. }
  407. dig_hc595_drive(ucDigShowTemp,0xdf);
  408. break;
  409. case 7://显示第7位
  410. ucDigShowTemp=dig_table[ucDigShow7];
  411. if(ucDigDot7==1)
  412. {
  413. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  414. }
  415. dig_hc595_drive(ucDigShowTemp,0xbf);
  416. break;
  417. case 8://显示第8位
  418. ucDigShowTemp=dig_table[ucDigShow8];
  419. if(ucDigDot8==1)
  420. {
  421. ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点
  422. }
  423. dig_hc595_drive(ucDigShowTemp,0x7f);
  424. break;
  425. }
  426. ucDisplayDriveStep++;
  427. if(ucDisplayDriveStep>8)//扫描完8个数码管后,重新从第一个开始扫描
  428. {
  429. ucDisplayDriveStep=1;
  430. }
  431. }
  432. //数码管的74HC595驱动函数
  433. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
  434. {
  435. unsigned char i;
  436. unsigned char ucTempData;
  437. dig_hc595_sh_dr=0;
  438. dig_hc595_st_dr=0;
  439. ucTempData=ucDigStatusTemp16_09;//先送高8位
  440. for(i=0;i<8;i++)
  441. {
  442. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
  443. else dig_hc595_ds_dr=0;
  444. dig_hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器
  445. delay_short(1);
  446. dig_hc595_sh_dr=1;
  447. delay_short(1);
  448. ucTempData=ucTempData<<1;
  449. }
  450. ucTempData=ucDigStatusTemp08_01;//再先送低8位
  451. for(i=0;i<8;i++)
  452. {
  453. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
  454. else dig_hc595_ds_dr=0;
  455. dig_hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器
  456. delay_short(1);
  457. dig_hc595_sh_dr=1;
  458. delay_short(1);
  459. ucTempData=ucTempData<<1;
  460. }
  461. dig_hc595_st_dr=0;//ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来
  462. delay_short(1);
  463. dig_hc595_st_dr=1;
  464. delay_short(1);
  465. dig_hc595_sh_dr=0; //拉低,抗干扰就增强
  466. dig_hc595_st_dr=0;
  467. dig_hc595_ds_dr=0;
  468. }
  469. //LED灯的74HC595驱动函数
  470. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
  471. {
  472. unsigned char i;
  473. unsigned char ucTempData;
  474. hc595_sh_dr=0;
  475. hc595_st_dr=0;
  476. ucTempData=ucLedStatusTemp16_09;//先送高8位
  477. for(i=0;i<8;i++)
  478. {
  479. if(ucTempData>=0x80)hc595_ds_dr=1;
  480. else hc595_ds_dr=0;
  481. hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器
  482. delay_short(1);
  483. hc595_sh_dr=1;
  484. delay_short(1);
  485. ucTempData=ucTempData<<1;
  486. }
  487. ucTempData=ucLedStatusTemp08_01;//再先送低8位
  488. for(i=0;i<8;i++)
  489. {
  490. if(ucTempData>=0x80)hc595_ds_dr=1;
  491. else hc595_ds_dr=0;
  492. hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器
  493. delay_short(1);
  494. hc595_sh_dr=1;
  495. delay_short(1);
  496. ucTempData=ucTempData<<1;
  497. }
  498. hc595_st_dr=0;//ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来
  499. delay_short(1);
  500. hc595_st_dr=1;
  501. delay_short(1);
  502. hc595_sh_dr=0; //拉低,抗干扰就增强
  503. hc595_st_dr=0;
  504. hc595_ds_dr=0;
  505. }
  506. void T0_time(void) interrupt 1 //定时中断
  507. {
  508. TF0=0;//清除中断标志
  509. TR0=0; //关中断
  510. if(ucVoiceLock==0) //原子锁判断
  511. {
  512. if(uiVoiceCnt!=0)
  513. {
  514. uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫
  515. beep_dr=0;//蜂鸣器是PNP三极管控制,低电平就开始鸣叫。
  516. }
  517. else
  518. {
  519. ; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。
  520. beep_dr=1;//蜂鸣器是PNP三极管控制,高电平就停止鸣叫。
  521. }
  522. }
  523. key_scan(); //按键扫描函数
  524. display_drive();//数码管字模的驱动函数
  525. TH0=0xfe; //重装初始值(65535-500)=65035=0xfe0b
  526. TL0=0x0b;
  527. TR0=1;//开中断
  528. }
  529. void delay_short(unsigned int uiDelayShort)
  530. {
  531. unsigned int i;
  532. for(i=0;i
  533. {
  534. ; //一个分号相当于执行一条空语句
  535. }
  536. }
  537. void delay_long(unsigned int uiDelayLong)
  538. {
  539. unsigned int i;
  540. unsigned int j;
  541. for(i=0;i
  542. {
  543. for(j=0;j<500;j++)//内嵌循环的空指令数量
  544. {
  545. ; //一个分号相当于执行一条空语句
  546. }
  547. }
  548. }
  549. void initial_myself(void)//第一区 初始化单片机
  550. {
  551. led_dr=0;//此处的LED灯模拟工控中的继电器
  552. key_gnd_dr=0; //模拟独立按键的地GND,因此必须一直输出低电平
  553. beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。
  554. hc595_drive(0x00,0x00);//关闭所有经过另外两个74HC595驱动的LED灯
  555. TMOD=0x01;//设置定时器0为工作方式1
  556. TH0=0xfe; //重装初始值(65535-500)=65035=0xfe0b
  557. TL0=0x0b;
  558. }
  559. void initial_peripheral(void) //第二区 初始化外围
  560. {
  561. ucDigDot8=0; //小数点全部不显示
  562. ucDigDot7=0;
  563. ucDigDot6=0;
  564. ucDigDot5=0;
  565. ucDigDot4=0;
  566. ucDigDot3=0;
  567. ucDigDot2=0;
  568. ucDigDot1=0;
  569. EA=1; //开总中断
  570. ET0=1; //允许定时中断
  571. TR0=1; //启动定时中断
  572. }

总结陈词:
下一节开始讲单片机采集模拟信号的内容,欲知详情,请听下回分解-----利用ADC0832采集电压的模拟信号。


关键词: DS18B20温控

评论


技术专区

关闭