我要努力工作,加油!

STC12C5A60S2 单片机,光敏电阻,步进电机,制作寻光器,始终指向光源

单片机 向日葵智能 102℃ 0评论

光纤传感专业的我转行做了嵌入式软件,可是心系光学专业啊。下班回来发现个 stc 的 51 单片机最小系统,是我之前做的,好久没碰了。正好手边有两个光敏电阻,结合着步进电机,琢磨着做一个寻光器玩玩,让箭头始终指向光源。

总体思路

因为要寻找光源,所以需要一个能感知外界光线的器件,这里选择了光敏电阻。一般,正对着光源才会接收到最强的光源,所以为了寻找到光源方向,仅仅能够探测到光纤还不够,还需要探测光的强度,这个工作就交给了 STC12C5A60S2 单片机的 ADC。当然,在使用 ADC 之前,需要设计电路,将光敏电阻的信息转换为电压信息。得到光源方向后,还需要一个能够转向光源的器件,这里选择了步进电机。所以要做的工作如下:

  • 设计电路,将对光功率变化敏感的电阻信息转换为电压信息
  • 设计单片机程序,驱动 STC12C5A60S2 的 AD 模块采集光敏电压信息
  • 设计程序,驱动步进电机转动
  • 设计算法,使步进电机时钟指向光源

将光敏电阻信息转换为光敏电压信息

这里直接使用了最简单的电路,如下图,就是一个可调电阻和光敏电阻串联,可调电阻的大小要与光敏电阻的常态接近。

STC12C5A60S2 的 AD 驱动程序

这个程序可参考:STC12C5A60S2 单片机的A/D转换c语言实例

步进电机驱动程序

我使用的是 28BYJ-48 步进电机,驱动程序非常简单,采用了单片机的 P0 口的低 4 位驱动。


\#include "reg51.h" char motorIndex = 0; unsigned char code beatCode[8] = {0xe,0xc,0xd,0x9,0xb,0x3,0x7,0x6}; void Delay2ms(unsigned int cnt) { unsigned int i = 2000; while(cnt--) while(i--); } void MotorTurn(unsigned int rounds) { while(rounds--){ P0 = beatCode[motorIndex]; motorIndex ++; motorIndex = motorIndex&0x07; Delay2ms(1); } } void MotorTurnBack(unsigned int rounds) // 反转 { while(rounds--){ P0 = beatCode[motorIndex]; if(motorIndex > 0) motorIndex --; else motorIndex = 7; Delay2ms(1); } }

寻光算法

算法也是考虑了很久,最后决定使用两个光敏电阻,两个光敏电阻的电路是相同的,都是上面介绍的电路。只不过,将两个电阻之间用隔光纸板隔开了,如下图

如果光源在左边,则左边的电阻接收光强比右边的大。如果光源在右边,则反之。如此一来,寻光算法就非常简单了,就是判断两边光强,那边强往哪边转。在实验之前,调节两个光敏电阻电路中的可调电阻,使两个光敏电阻在相同光强下,尽量输出接近的电压值。最后,总体程序如下:


void main() { WORD res0 = 0, res1 = 0; InitUart(); InitADC(); while(1){ //Delay2ms(2); res0 = GetADCRes(0); res1 = GetADCRes(1); printf("res: %d - %d\n", (int)res0, (int)res1); if(res0-20 > res1) MotorTurnBack(100); else if(res1-20 > res0) MotorTurn(100); } }

可以看出,非常简单。单片机的 ADC 通道 0 和 通道 1 分别探测两个光敏电阻电路输出的电压值,只要两个电压值差值大于阈值,则驱动步进电机步进100个角度。

最终,寻光器的工作效果如下:

转载请注明:xrk智能 » STC12C5A60S2 单片机,光敏电阻,步进电机,制作寻光器,始终指向光源

喜欢 (1)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址