单片机学习小组
直播中

许佳

8年用户 213经验值
私信 关注

ATmega16实现八通道电位器控制八舵机程序

   上回用了一个定时器控制三个舵机行不通,这次在次按照网上的思路,用了两个定时器,成功实现了atmega16八个电位器分别同时控八个舵机,实际还可以更多,
   通过实验发现舵机受控的周期不一定要20ms,八路舵机,每个舵机的控制周期可以延伸,例如40ms给一次脉冲,也是能控制舵机旋转至固定角度,在这里,控制舵机的应该是高电平信号持续时间,由于从20ms延长到40ms,所以单片机可以控制更多的舵机,20ms能控制8个,40ms能控制16个,但是20ms相对于40ms控制周期的舵机来说更稳定,可能是由于原本1s内,以20ms为周期的信号,可以对舵机发送50次控制信号,延长到40ms,只能对舵机发送25次控制信号,这样会导致舵机控制频率降低,从而导致相对的不稳定,这里使用的是普通舵机,数码舵机应该不会出现这种情况。
   最后贴上代码,实测可用:
  • /**************八通道电位器控制八舵机****************
  • *   编写:HYH
  • *   日期:2017-6-12
  • *   晶振:12mhz
  • *   说明:定时/计数器0固定每2.5ms溢出中断,负责拉高对
  • *         应端口,定时/计数器1负责在tc1中断产生后将对
  • *         应端口的电平拉低,依次循环形成八个通道舵机
  • *         控制pwm波
  • *****************************************************/
  • #include
  • #include
  • #define  uchar unsigned char
  • #define  uint  unsigned int
  • #define OUTPUT PORTD         //定义pd口为舵机信号输出口
  • #define ADCN ADMUX
  • unsigned char output_high[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //数组控制各个io口高电平
  • unsigned int i=0;
  • unsigned int j=0;
  • unsigned char ADCN_[8]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47};  //数组控制ADC通道选择
  • unsigned int adcn_[8];     //存取八个通道的ADC值
  • unsigned int adcn_change[8];    //存储adcn_[]经过转换成计数器1初值的值
  • /************延时函数***********/
  • void delay(unsigned int ms)
  • {
  •         unsigned int i,j;
  •         for(i=0;i           {
  •            for(j=0;j<1141;j++);
  •        }
  • }
  • /*********端口设置函数*********/
  • void port_init(void)
  • {
  •         DDRD|=0XFF;
  •         PORTD&=0X00;        //设置舵机信号输出端口
  •     DDRA&=0X00;
  •     PORTA|=0Xff;          //设置adc通道端口,带上拉输入
  •         SREG=0X80;             //开放全局中断
  • }
  • void timer0_init()
  • {
  •         TIMSK|=(1<        TCCR0|=(1<        TCNT0=139;
  •                           //计数器初值,(256-139)/(12mhz/256)=2.5ms
  • }
  • void timer1_init()
  • {
  •     TCCR1A|=0X00;               //普通模式
  •         TCCR1B|=(0<    TIMSK|=(1<}
  • /**********ad转换函数**********/
  • unsigned int ADC_init()
  • {
  •     unsigned int addata;
  •          ADCN=ADCN_[j];                                          //AVCC为基准电,设置adc通道选择
  •          ADCSRA=0XD8;                                         //使能ADC,允许中断 11011000
  •          ADCSRA|=BIT(ADSC);                                //开始A/D转换
  •          while(!(ADCSRA&(BIT(ADIF))));        //等待转换完成
  •      addata=ADCL;                                //获取ADC结果
  •          addata=addata+ADCH*256;
  •          return addata;                        //返回ADC值
  • }
  • void main()
  • {
  •         timer0_init();
  •         timer1_init();
  •         ADC_init();
  •         port_init();
  • }
  • /*********定时器0中断函数************
  • *   说明:定时器每溢出一次,舵机通道调
  • *         至下一个,拉高该舵机通道io口
  • *         并把对应通道的adcn_change[]值
  • *         赋给定时/计数器初值
  • ************************************/
  • #pragma interrupt_handler timer0_ovf:10
  • void timer0_ovf()
  • {
  •     OUTPUT|=output_high;
  •     TCNT0=139;
  •         TCNT1=adcn_change;
  •         i++;
  •         if(i>=8)
  •         i=0;
  • }
  • /************定时/计数器1中断函数********
  • *    说明:将对应端口电平拉高
  • ****************************************/
  • #pragma interrupt_handler timer1_ovf:9
  • void timer1_ovf()
  • {   
  •     TCNT1=0;
  •         if(i==0)
  •     OUTPUT&=~BIT(7);
  •         else
  •         OUTPUT&=~BIT(i-1);
  • }
  • /************ADC中断函数**************/
  • #pragma interrupt_handler ADCN_change:15
  • void ADCN_change()
  • {
  •     adcn_[j]=ADC_init();
  •         adcn_change[j]=59536-24*adcn_[j];     //将adc值转化为定时/计数器1初值,控制高电平持续时间
  •     j++;
  •         if(j>=8)
  •         j=0;
  •         ADC_init();               //adc转换
  • }





  


全部资料下载地址:
    ADC多通道.zip  




更多回帖

发帖
×
20
完善资料,
赚取积分