最近重温经典喜剧电影时,发现下面这么一幕:
达文西发明了一个“古怪手电筒”,“在有光的时候就会亮,在没有光的情况下绝对不会亮!”
这种手电筒是怎么制作的呢,我们能否自己制作一个类似的手电筒呢?当然可以,情继续往下看。
设计“古怪手电筒”
这里计划仍然使用C语言编程 51 单片机完成这种设计,那么,51 单片机就是“古怪手电筒”的大脑,它决定“古怪手电筒”是否发光。而为了实现“有光才亮,无光不亮”的机制,51 单片机还需要一只“眼睛”,用于观察“古怪手电筒”所处环境是否有光。
光敏电阻恰好可以作为 51 单片机的“眼睛”,它能够感知环境光照的变化。当照射在光敏电阻上的光亮度改变时,光敏电阻的阻值也会变化:
加上适当的电路(例如简单将光敏电阻与定电阻和电源串联),很容易将这样的电阻值变化,转变为电压值变化,而 51 单片机的 ADC 模块恰恰可以采集电压值。
如此一来,“古怪手电筒”的设计思路就有了:先将光敏电阻和定电阻与电源串联起来,如下图,然后使用 51 单片机的 P1.0 口(ADC的通道 0)连接检测点:
再使用51 单片机的 ADC 模块检测电压,记录有光时的电压 Vb 和无光时的电压 Vd。之后,当 51 单片机检测到 Vb 附近的电压时,就控制“手电筒”发光,检测到 Vd 附近的电压时则关闭“手电筒”。
C语言编程单片机,实现“古怪手电筒”的设计
因为要使用到 51 单片机的 ADC 模块,所以首先要实现 ADC 的C语言代码,请看:
void adc_init(){ P1ASF = 0xff; // 8 个通道都开 ADC_RES = 0; ADC_CONTR = ADC_POWER|ADC_SPEEDLL; delay_about_100ms(2);}
这里将 P1ASF 赋值为 0xff,表示 P1 的 8 个 IO 口都可以作为 ADC 采样口。然后延时一段时间,等待 ADC 模块初始化。获取一次 ADC 采样值的 C语言代码可以如下写:
// 获取高 8 位的 adc 值BYTE get_adc_h8bit(BYTE ch){ ADC_CONTR = ADC_POWER|ADC_SPEEDLL|ADC_START|ch; _nop_();_nop_();_nop_();_nop_(); // 等待转换完成 while(!(ADC_CONTR & ADC_FLAG)); ADC_CONTR &= ~ADC_FLAG; return ADC_RES;}// 获取 10 位 adcWORD get_adc_res(BYTE ch){ WORD res = 0; res = get_adc_h8bit(ch); res <<= 2; res |= ADC_LOW2; return res;}
这里的 ADC 代码比较简要,详细的说明可参考第 9 节文章。现在将 51 单片机测量的电压值发送到串口,C语言代码可以如下写:
void main(){ float vol; adc_init(); init_uart(9600); while(1){ vol = 5.0*((float)get_adc_res(0))/1024.0; delay_about_100ms(2); printf("voltage: %0.2fV