第二节和第三节介绍了如何使用C语言编程单片机,制作 LED 闪烁小灯,以及 LED “呼吸灯”。上一节介绍了利用 DHT11 温湿度传感器测量室内温度和湿度的方法,本节将把它们结合,制作一些更加“有意思”的小玩意儿。
温湿度报警器
温湿度传感器的很多实际应用的场景都是检测一个“阈值”——例如,如果环境温度在 40 摄氏度以下则一切正常,一旦环境温度超过 40 摄氏度,就会有报警信息,通常以“声光”的形式(铃声、警报灯等)给出。
参照实际应用,我们可以使用C语言编程单片机,用缓和的 LED “呼吸灯”表示正常温湿度情况。而一旦出现温度超过阈值的情况,则可以用急促的 LED 闪烁小灯表示。
先来看看上一节获取室内温湿度的单片机 C语言程序代码:
void main() { char dat[5] = {0}; int cks; init_uart(9600); set_timer0(10); // 10us prints("init...\r\n"); delay_10us(50000);delay_10us(50000); delay_10us(50000);delay_10us(50000); prints("program start...\r\n"); while(1){ dht11_start(); dht11_read_once(dat); cks = 0; cks += dat[0]; cks += dat[1]; cks += dat[2]; cks += dat[3]; if((char)cks == dat[4]){ prints("RH: ");printn(dat[0]);prints(".");printn(dat[1]);prints(" "); prints("TM: ");printn(dat[2]);prints(".");printn(dat[3]);prints("\r\n"); }else{ prints("capture failed\r\n"); } delay_10us(50000);delay_10us(50000); } }
乍一看,要实现上面的设计好像很简单,只需要判断一下温度值,再决定使用哪一套 LED 小灯的控制程序(“呼吸灯”程序,或者“闪烁”程序)就可以了。
但是 DHT11 传感器需要的 delay_10us(50000); 语句会破坏 LED 小灯的控制程序,因为在这 500ms 期间,单片机处于等待状态,无法控制 LED 小灯闪烁或者“呼吸”。那么,没有办法解决这个问题吗?也不是,请看 LED 小灯“闪烁”的核心C语言程序:
while(1){ P20 = 0; delay(10); P20 = 1; delay(10); }
以及 LED 的“呼吸灯”的核心C语言程序:
void twinkle_once(unsigned char darkTime) { P20 = 0; delay(100-darkTime); P20 = 1; delay(darkTime); }
仔细思考一下,应该能明白无论是 LED “闪烁”程序,还是“呼吸”程序,其实都依赖“延时”。那思路就有了,直接使用 LED 小灯的控制程序代替 delay_10us(50000); 不就可以了吗?的确如此,请继续往下看。
编写C语言程序,制作自己的警报器
先在上一节 C语言代码的基础上氨气报警器,实现更大尺度的 5ms 延时函数:
void delay_5ms(unsigned int n) { while(n--) delay_10us(5); }
使用 delay_5m() 函数替换之前定义的“不精确”延时函数 delay() 函数甲烷报警器,这样我们就能知道较为精确的 LED 小灯的控制程序执行时间,也就能更加方便的替换 delay_10us(50000); 语句。
现在写出“呼吸”1 秒的 LED “呼吸灯”C语言程序就不难了,请看:
void led_breath_1s() { static int cnt = 0; static char dark_time = 0, dir = 1 ; while(1){ twinkle_once(dark_time); if( 0==((cnt++)%4) ){ if(dir) dark_time += 1; else dark_time -= 1; if(dark_time >= 100) dir = 0; if(dark_time <= 60) dir = 1; } if(cnt > 200){ cnt = 0; break; } } }
twinkle_once() 执行一次需要 5ms 的时间,cnt 计数到 200 次就恰好是 1 秒,另外,if( 0==((cnt++)%4) ) 语句仍然能够控制 LED 小灯的“呼吸”频率。其他部分的代码与之前介绍的就没什么不同了。
类似的,闪烁 1 秒的 LED “闪烁”C语言程序可以如下实现:
void led_twinkle_1s() { char cnt = 5; while(cnt--){ P21 = 1; delay_10us(10000); P21 = 0; delay_10us(10000); } }
闪烁一次需要 200 ms 的时间,那么闪烁 5 次就是 1秒了。现在使用 led_breath_1s() 和 led_twinkle_1s() 函数替换delay_10us(50000); 语句就可以了。请看:
void main() { char dat[5] = {0}; int cks; init_uart(9600); set_timer0(10); // 10us prints("init...\r\n"); // delay_10us(50000);delay_10us(50000); // delay_10us(50000);delay_10us(50000); led_breath_1s(); led_breath_1s(); prints("program start...\r\n"); while(1){ dht11_start(); dht11_read_once(dat); cks = 0; cks += dat[0]; cks += dat[1]; cks += dat[2]; cks += dat[3]; if((char)cks == dat[4]){ prints("RH: ");printn(dat[0]);prints(".");printn(dat[1]);prints(" "); prints("TM: ");printn(dat[2]);prints(".");printn(dat[3]);prints("\r\n"); }else{ prints("capture failed\r\n"); } if(dat[2] > 15) led_twinkle_1s(); else led_breath_1s(); //delay_10us(50000);delay_10us(50000); } }
初始化时,使用了 led_breath_1s(); 代替了 DHT11 传感器需要的延时,每次获取温湿度值的时候,则判断了温度值,如果温度大于 15 摄氏度,使用LED的“闪烁”程序代替延时 1秒,否则使用 LED 的“呼吸灯”程序代替。
现在编译C语言程序,烧写到单片机,可以得到如下结果:
一开始,DHT11 探测到的温度较低,所以LED指示灯是“呼吸”状态的温湿度探测,然后使用手捏住 DHT11,温度升高超过“阈值”后,LED 小灯就变成“闪烁”状态了。
还有问题吗?
上面的控制程序还不是很完美,相信细心的朋友应该看出来了,LED小灯处于“呼吸”状态时,总是会有一次闪烁。这是因为我们采集 DHT11 传回来的温湿度信息时,也有几十毫秒的延时,在这段时间内,单片机是无法控制 LED 小灯的温湿度探测,所以小灯会一直处于最近一次的亮暗状态,查看 led_twinkle_1s() 函数的C语言代码就知道,LED 小灯最后的状态是亮的状态,这就解释了我们遇到的问题。
这其实也是单片机编程的一个特点温湿度探测,若单片机内部没有运行操作系统,则编写并行的程序几乎是不可能的,所以串行的阻塞延时应该尽量避免,否则就会出现类似上面的问题。那么,上面这种问题不借助于操作系统也能解决吗?当然可以,借助于单片机的中断系统就很好解决,限于篇幅,以后再说了。
欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。
腾元达编辑,转载请注明出处
- 2023-09-17
什么环境需要安装氧气检测仪?有什么作用? - 2023-09-10
垃圾填埋场有毒有害气体如何防范? - 2023-09-10
常见有毒有害气体以及如何防范? - 2023-09-10
固定式可燃气体探测器一般用什么气体标定 - 2023-08-19
密闭空间如何选择气体检测仪? - 2021-09-08
二氧化氮探测器 二氧化氮NO2传感器 - 2021-09-08
pm2.5检测仪 欢迎##简阳PM2.5扬尘监测系统环境检测仪##集团 - 2021-09-08
在线式二氧化碳检测仪 - 2021-09-08
噪音检测仪 噪声检测仪哪个品牌好? - 2021-09-08
pm2.5检测仪 云南玉溪 扬尘监测PM10监测PM2.5监测TSP检测仪扬尘监测仪