单片机很好玩11,制作达文西的“古怪手电筒”

最近重温经典喜剧电影时,发现下面这么一幕:

达文西发明了一个“古怪手电筒”,“在有光的时候就会亮,在没有光的情况下绝对不会亮!”,这种手电筒是怎么制作的呢,我们能否自己制作一个类似的手电筒呢?当然可以,情继续往下看。

设计“古怪手电筒”

这里计划仍然使用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 位 adc
WORD 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\r\n", vol);
    }
}

编译C语言程序,烧写到单片机,在电脑端打开串口调试工具:

这是我开着灯时, 51单片机采集到的电压值,可以看出是大于 4.4V 的。现在关灯,观察 51 单片机传来的电压值:

此时电压值基本在 2 V 附近,低于 3V。现在用 LED 小灯模拟“手电筒”,控制代码可以如下写:

void main()
{
    float vol;
    adc_init();

    while(1){
        vol = 5.0*((float)get_adc_res(0))/1024.0;
        if(vol < 3.00)
            P20 = 1;
        else
            P20 = 0;
    }
}

上面的C语言代码很简单,就是认为电压小于 3V 时是关灯,此时单片机关闭“古怪手电筒”。否则认为开着灯,此时单片机控制“古怪手电筒”发光。编译C语言程序,烧写到单片机,测试发现我们成功的仿制出了达文西的“古怪手电筒”,“在有光的时候就会亮,在没有光的情况下绝对不会亮!”:

其实稍微修改一下C语言控制代码,就可以把“古怪手电筒”改成真正的“智能手电筒”:

        if(vol < 3.00)
            P20 = 0;
        else
            P20 = 1;

编译C语言程序,烧写到单片机,再测试之,发现“手电筒”在没光的时候自动亮起来,有光的时候则自动关闭:

思考

可以说,目前所谓的“信息化”社会,其实就是“电信号”的社会,从手机到计算机,再到集群服务器,本质上都是基于数字电路的计算机器。看了这两节内容的朋友,应该发现单片机的 ADC 模块的强大之处了,ADC 能够将模拟信号“数字化”,而没有数字化的信号,“信息化”也无从谈起。

“智能”机器则可以认为是能够对外界环境做出反应的机器。例如上一节介绍的温度警报器在某种程度上就属于一种智能机器,它能够检测环境温度,并在温度超过设定值后发出警报。本节最后介绍的“智能手电筒”也属于智能机器。

阅读更多:   单片机
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif