C语言单片机等待询问_单片机很好玩8,温度太高就报警,制作一个智能室内温度湿度计...

第二节和第三节介绍了如何使用C语言编程单片机,制作 LED 闪烁小灯,以及 LED “呼吸灯”。上一节介绍了利用 DHT11 温湿度传感器测量室内温度和湿度的方法,本节将把它们结合,制作一些更加“有意思”的小玩意儿。

f0fa49ec932905da5d06fa8c527a0690.png

温湿度报警器

温湿度传感器的很多实际应用的场景都是检测一个“阈值”——例如,如果环境温度在 40 摄氏度以下则一切正常,一旦环境温度超过 40 摄氏度,就会有报警信息,通常以“声光”的形式(铃声、警报灯等)给出。

参照实际应用,我们可以使用C语言编程单片机,用缓和的 LED “呼吸灯”表示正常温湿度情况。而一旦出现温度超过阈值的情况,则可以用急促的 LED 闪烁小灯表示。

3c07f17595f34ba2c730b63416f0acb7.gif

先来看看上一节获取室内温湿度的单片机 C语言程序代码:

void main(){ char dat[5] = {0}; int cks; init_uart(9600); set_timer0(10); // 10us prints("init..."); delay_10us(50000);delay_10us(50000); delay_10us(50000);delay_10us(50000); prints("program start..."); 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(""); }else{ prints("capture failed"); } delay_10us(50000);delay_10us(50000); }}
73935d766673f34fb931eaa9a09b3253.png

乍一看,要实现上面的设计好像很简单,只需要判断一下温度值,再决定使用哪一套 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); 不就可以了吗?的确如此,请继续往下看。

5cc7fb99ea7307704b34fe530995af76.gif

编写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; } }}
cee9e2a30dcdf7a8436948bf7695a0ef.png

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...");// delay_10us(50000);delay_10us(50000);// delay_10us(50000);delay_10us(50000); led_breath_1s(); led_breath_1s();  prints("program start..."); 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(""); }else{ prints("capture failed"); } if(dat[2] > 15) led_twinkle_1s(); else led_breath_1s(); //delay_10us(50000);delay_10us(50000); }}
e8077ce408bade4adc8748ac25b1c897.png

初始化时,使用了 led_breath_1s(); 代替了 DHT11 传感器需要的延时,每次获取温湿度值的时候,则判断了温度值,如果温度大于 15 摄氏度,使用LED的“闪烁”程序代替延时 1秒,否则使用 LED 的“呼吸灯”程序代替。

现在编译C语言程序,烧写到单片机,可以得到如下结果:

6e7c0f3b3e8fd82f521d9584e116dcc0.gif

一开始,DHT11 探测到的温度较低,所以LED指示灯是“呼吸”状态的,然后使用手捏住 DHT11,温度升高超过“阈值”后,LED 小灯就变成“闪烁”状态了。

还有问题吗?

上面的控制程序还不是很完美,相信细心的朋友应该看出来了,LED小灯处于“呼吸”状态时,总是会有一次闪烁。这是因为我们采集 DHT11 传回来的温湿度信息时,也有几十毫秒的延时,在这段时间内,单片机是无法控制 LED 小灯的,所以小灯会一直处于最近一次的亮暗状态,查看 led_twinkle_1s() 函数的C语言代码就知道,LED 小灯最后的状态是亮的状态,这就解释了我们遇到的问题。

2214a7b9ff2d49741f9c4da434ea4c2d.png

这其实也是单片机编程的一个特点,若单片机内部没有运行操作系统,则编写并行的程序几乎是不可能的,所以串行的阻塞延时应该尽量避免,否则就会出现类似上面的问题。那么,上面这种问题不借助于操作系统也能解决吗?当然可以,借助于单片机的中断系统就很好解决,限于篇幅,以后再说了。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值