找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5499|回复: 7
打印 上一主题 下一主题
收起左侧

ATmega16实现八个电位器分别同时控八个舵机,还可以更多

[复制链接]
跳转到指定楼层
楼主
  上回用了一个定时器控制三个舵机行不通,这次在次按照网上的思路,用了两个定时器,成功实现了atmega16八个电位器分别同时控八个舵机,实际还可以更多,
  通过实验发现舵机受控的周期不一定要20ms,八路舵机,每个舵机的控制周期可以延伸,例如40ms给一次脉冲,也是能控制舵机旋转至固定角度,在这里,控制舵机的应该是高电平信号持续时间,由于从20ms延长到40ms,所以单片机可以控制更多的舵机,20ms能控制8个,40ms能控制16个,但是20ms相对于40ms控制周期的舵机来说更稳定,可能是由于原本1s内,以20ms为周期的信号,可以对舵机发送50次控制信号,延长到40ms,只能对舵机发送25次控制信号,这样会导致舵机控制频率降低,从而导致相对的不稳定,这里使用的是普通舵机,数码舵机应该不会出现这种情况。
  最后贴上代码,实测可用:

  1. /**************八通道电位器控制八舵机****************
  2. *   编写:HYH
  3. *   日期:2017-6-12
  4. *   晶振:12mhz
  5. *   说明:定时/计数器0固定每2.5ms溢出中断,负责拉高对
  6. *         应端口,定时/计数器1负责在tc1中断产生后将对
  7. *         应端口的电平拉低,依次循环形成八个通道舵机
  8. *         控制pwm波
  9. *****************************************************/
  10. #include <iom16v.h>
  11. #include <macros.h>

  12. #define  uchar unsigned char
  13. #define  uint  unsigned int

  14. #define OUTPUT PORTD         //定义pd口为舵机信号输出口
  15. #define ADCN ADMUX         

  16. unsigned char output_high[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //数组控制各个io口高电平
  17. unsigned int i=0;
  18. unsigned int j=0;
  19. unsigned char ADCN_[8]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47};  //数组控制ADC通道选择
  20. unsigned int adcn_[8];     //存取八个通道的ADC值
  21. unsigned int adcn_change[8];    //存储adcn_[]经过转换成计数器1初值的值
  22.         
  23. /************延时函数***********/
  24. void delay(unsigned int ms)
  25. {
  26.         unsigned int i,j;
  27.         for(i=0;i<ms;i++)
  28.            {
  29.            for(j=0;j<1141;j++);
  30.        }
  31. }
  32. /*********端口设置函数*********/
  33. void port_init(void)
  34. {
  35.         DDRD|=0XFF;
  36.         PORTD&=0X00;        //设置舵机信号输出端口
  37.     DDRA&=0X00;   
  38.     PORTA|=0Xff;          //设置adc通道端口,带上拉输入
  39.         SREG=0X80;             //开放全局中断
  40. }
  41. void timer0_init()
  42. {
  43.         TIMSK|=(1<<TOIE0);                //是能溢出中断
  44.         TCCR0|=(1<<CS02)|(0<<CS01)|(0<<CS00); //12mhz晶振  256预分频
  45.         TCNT0=139;   
  46.                           //计数器初值,(256-139)/(12mhz/256)=2.5ms
  47. }
  48. void timer1_init()
  49. {
  50.     TCCR1A|=0X00;               //普通模式
  51.         TCCR1B|=(0<<CS12)|(0<<CS11)|(1<<CS10);     //无预分频   
  52.     TIMSK|=(1<<TOIE1);
  53. }

  54. /**********ad转换函数**********/
  55. unsigned int ADC_init()
  56. {
  57.     unsigned int addata;                        
  58.          ADCN=ADCN_[j];                                          //AVCC为基准电,设置adc通道选择
  59.          ADCSRA=0XD8;                                         //使能ADC,允许中断 11011000
  60.          ADCSRA|=BIT(ADSC);                                //开始A/D转换
  61.          while(!(ADCSRA&(BIT(ADIF))));        //等待转换完成
  62.      addata=ADCL;                                //获取ADC结果
  63.          addata=addata+ADCH*256;
  64.          return addata;                        //返回ADC值
  65. }   

  66. void main()
  67. {
  68.         timer0_init();
  69.         timer1_init();
  70.         ADC_init();
  71.         port_init();
  72. }
  73. /*********定时器0中断函数************
  74. *   说明:定时器每溢出一次,舵机通道调
  75. *         至下一个,拉高该舵机通道io口
  76. *         并把对应通道的adcn_change[]值
  77. *         赋给定时/计数器初值
  78. ************************************/
  79. #pragma interrupt_handler timer0_ovf:10
  80. void timer0_ovf()
  81. {
  82.     OUTPUT|=output_high[i];
  83.     TCNT0=139;
  84.         TCNT1=adcn_change[i];
  85.         i++;
  86.         if(i>=8)
  87.         i=0;
  88. }
  89. /************定时/计数器1中断函数********
  90. *    说明:将对应端口电平拉高
  91. ****************************************/
  92. #pragma interrupt_handler timer1_ovf:9
  93. void timer1_ovf()
  94. {   
  95.     TCNT1=0;
  96.         if(i==0)
  97.     OUTPUT&=~BIT(7);
  98.         else
  99.         OUTPUT&=~BIT(i-1);
  100. }
  101. /************ADC中断函数**************/
  102. #pragma interrupt_handler ADCN_change:15
  103. void ADCN_change()
  104. {
  105.     adcn_[j]=ADC_init();
  106.         adcn_change[j]=59536-24*adcn_[j];     //将adc值转化为定时/计数器1初值,控制高电平持续时间
  107.     j++;
  108.         if(j>=8)
  109.         j=0;
  110.         ADC_init();               //adc转换
  111. }
复制代码




全部资料下载地址:
ADC多通道.zip (537.96 KB, 下载次数: 32)



评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1 发表于 2017-6-12 15:59 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

板凳
ID:87734 发表于 2017-8-15 15:47 | 只看该作者
哇,思路清晰啊,舅服你
回复

使用道具 举报

地板
ID:87734 发表于 2017-8-15 19:58 | 只看该作者
多个数字舵机控制,楼主讲下具体思路吗?我不管小板凳已经拿来了
回复

使用道具 举报

5#
ID:76408 发表于 2018-1-31 16:23 | 只看该作者
金币不足了,先收藏了。
回复

使用道具 举报

6#
ID:76408 发表于 2018-2-25 16:08 | 只看该作者
终于可以下载到了,谢谢楼主。
回复

使用道具 举报

7#
ID:206921 发表于 2018-3-8 12:48 | 只看该作者
数字舵机区别于传统的模拟舵机,模拟舵机需要给它不停的发送PWM信号,才能让它保持在规定的位置或者让它按照某个速度转动,数字舵机则只需要发送一次PWM信号就能保持在规定的某个位置
回复

使用道具 举报

8#
ID:33897 发表于 2018-3-10 16:45 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表