舵机光敏电阻实现一维光源追踪

来源:互联网 发布:淘宝主图要求规范 编辑:程序博客网 时间:2024/06/11 17:11
学习430已经有几天了,一直以来就是熟悉各个模块。从最开始的点亮一个发光二级管,再做流水灯,再通过按键来控制发光二极管的亮灭,再到后来的1602、定时器做频率计,AD,再到今天的舵机控制以及光源跟踪。期间遇到了不少的问题,不过通过同学和老师还有你们的帮助,都将困难克服。但是前进的路还有很长,我们一起学习,一起努力,共同进步。下面先说说舵机。

用单片机控制舵机我还是第一次。以前在航模上用过舵机,不过那都是买的现成的遥控器之类的。刚拿到舵机的时候,我就是在想如何让舵机转动。我在网上查找资料,觉得跟步进电机很相似,但舵机只有三根线,其中有根线是用来输入PWM的。初步查找了资料以后,我用函数信号发生器给它输入周期为20ms的方波,发现如果占空比不变的话,舵机是不会动的。如果将占空比改变,在改变的时候,舵机会转动。我再次查找资料,发现要让舵机动起来,就是不断的调节占空比,但是PWM的周期是20ms固定的。高电平的时间范围是0.5ms~2.5ms。这下就简单多了,用定时器产生PWM,CCR0设置周期,CCR1设置可调的占空比。CCR1=LMAX+(unsigned int)(angle*_angle),这样,就可以通过改变angle的值来调节CCR1了。很多人应该都知道这些,不好意思哈,只是想把这一过程都写出来,让不是很清楚的人都有个比较好的了解,能达到一起学习的效果就好。


舵机的问题搞定了,然后就是传感器的问题。首先就选了光敏电阻,它便宜,而且这里备用的比较多。用了两个光敏电阻。(注意刚开始的时候用一个很长的黑色的套筒将光敏电阻罩住了,光敏电阻的阻值很大,这样就出现了一个问题。就是在分压的时候必须要用很大的电阻去分压。如果输入到AD去采样的话,就出现电路简图
2012-7-21 11:27:14 上传
下载附件(17.44 KB)
电路简图
很大的问题
看看这张图,就是我采用的比较简单的电路图。如果R3比较大的话,有电流流入点A,那么点A的电压就会很高,从而改变了取样点A的电压值。这就是使用msp430中ADC10的时候要注意的一个问题。如果将光敏电阻的套筒变短一点,那么光敏电阻R1的值就会降低一些,R2和R3的电阻就能相应的减小,A点的电压就不会有太大的影响了。用在其他地方的时候也要注意这个问题,不然会很麻烦。AD是使用双通道的,有不明白的可以看我前几天发的帖子http://www.9mcu.com/9mcubbs/forum.php?mod=viewthread&tid=960789&extra=page%3D1。这个系统就是把AD,舵机,定时器的程序揉和在一起了。下面上程序,图片还有视频。东西做的不好,见笑了~~~
//**********************************************
//***********一维光源跟踪系统*******************
//          --------------------------------
//     -->|P1.0(A0)        P1.2(PWM)|-->
//     -->|P1.1(A1)         P1.6(lcdrs)|-->
//         |                     P1.7(lcden)|-->
//         |                              lcdrw|----
//         |                                      |   \|/
//         |       msp430g2553           |
//**********************************************
#include<msp430g2553.h>
#include<1602.h>
#include<duoji.h>
#define uint unsigned int
#define uchar unsigned char
uchar table_num[]={"0123456789"};
uint a[8],b[2],c,d,c_ge,c_shi,c_bai,c_qian,d_ge,d_shi,d_bai,d_qian;
uint i,j,num_1,num_0,diff;
uchar Direction=0;
float k;
void adc()
{
    ADC10CTL0&=~ENC;//关闭采样使能
    while(ADC10CTL1&BUSY);//检测AD是否繁忙
    ADC10CTL0|=ENC+ADC10SC;//启动ADC
    ADC10SA=(unsigned int)a;//获取a[]的首地址。首先对A1、A0采样,放入a[0]和a[1]中。再对A1、A0采样,放入a[2]和a[3]中,如此循环下去。
    _BIS_SR(GIE);//低功耗模式0,开中断
     for(i=0;i<2;i++)
    {
      b=0;
      for(j=0;j<4;j++)
        b+=a[i+j*2];
    }
    for(i=0;i<2;i++)
    {  
      b=b/4;
    }
    num_1=(int)(b[0]*1.08);//根据需要,可以更改这里的数值,将量程调到0~1024
    num_0=(int)(b[1]*1.08);//根据需要,可以更改这里的数值,将量程调到0~1024
    num_1=num_1-num_1%10;
    num_0=num_0-num_0%10;
    if(num_0>num_1)
      diff=num_0-num_1;
    else if(num_0<num_1)
      diff=num_1-num_0;
    else diff=0;
}
void display()
{
  delay_Nms(50);
  
  c=(int)(num_1*3.3);//转换为电压值
  c_ge=c/1000;
  c_shi=c%1000/100;
  c_bai=c%100/10;
  c_qian=c%10;
  
  d=(int)(num_0*3.3);//转换为电压值
  d_ge=d/1000;
  d_shi=d%1000/100;
  d_bai=d%100/10;
  d_qian=d%10;
  
  write_com(0x80);
  write_data(table_num[num_1/1000]);
  write_data(table_num[num_1%1000/100]);
  write_data(table_num[num_1%100/10]);
  write_data(table_num[num_1%10]);
  write_data('=');
  write_data(table_num[c_ge]);
  write_data('.');
  write_data(table_num[c_shi]);
  write_data(table_num[c_bai]);
  write_data(table_num[c_qian]);
  write_data('V');  
  write_com(0x80+0x40);
  write_data(table_num[num_0/1000]);
  write_data(table_num[num_0%1000/100]);
  write_data(table_num[num_0%100/10]);
  write_data(table_num[num_0%10]);
  write_data('=');
  write_data(table_num[d_ge]);
  write_data('.');
  write_data(table_num[d_shi]);
  write_data(table_num[d_bai]);
  write_data(table_num[d_qian]);
  write_data('V');
}
void main()
{
  WDTCTL=WDTPW+WDTHOLD;//关看门狗
  
  P2SEL=0x00;//P2为I/O模式
  P2DIR|=0xff;//P2为LCD输出
  P1DIR|=BIT6+BIT7;//P1.6和P1.7为LCD的输出
  P1SEL|=BIT1+BIT0;//P1.1和P1.2设置为ADC功能A1和A0
  P1DIR&=0xfc;
  
  ADC10CTL1|=CONSEQ_3+INCH_1;//序列通道单次转换+最大通道为A1
  ADC10CTL0|=ADC10SHT_2+MSC+ADC10ON+ADC10IE;
  ADC10DTC1|=0x08;//一共采样8次
  ADC10AE0|=BIT0+BIT1;//打开A0和A1的模拟输入通道
  
  init_clock();//时钟初始化
  motor();//舵机初始化
  init_lcd();//lcd初始化
  
  _BIS_SR(GIE);//开中断
  TACTL|=MC_1+TASSEL_2;//增计数模式+SMCLK
  k=80;//让舵机从中间位置开始转动
  
  
  
  while(1)
  {
    adc();
    display();//lcd显示
    set_angle(k);
    delay_Nms(25);//更改延时,可以调节舵机转动的快慢
////////////////////////////////   
    if(diff>30)//当两值相差大于50的时候,转动
    {
      if((num_0)>(num_1))
        Direction=0;
      else if(num_0<num_1)
        Direction=1;
      else Direction=2;
    }
    else Direction=2;
//////////////////////////////////
    if(Direction==0)//逆时针转动
        k=k+1.5;       //逆时针转动
    else if(Direction==1)   //顺时针转动
        k=k-1.5;       //顺时针转动
    else k=k;
///////////////////////////////////////
    if(k>160)
      Direction=1;     //换为减
    if(k<20)
      Direction=0;     //换为加
   
  }
}
#pragma vector=ADC10_VECTOR
__interrupt void ADC(void)
{
     LPM0_EXIT;//退出低功耗模式
}


原创粉丝点击