找回密码
 立即注册

QQ登录

只需一步,快速开始

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

avr单片机m16用一个定时器实现一个多个电位器控制多个舵机

[复制链接]
跳转到指定楼层
楼主
ID:206921 发表于 2017-6-1 23:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近在研究多个舵机的控制,上网找了很多资料,编写了一个程序,用三个电位器分别控制三个舵机,只用tc0定时计数器,最后无法实现,原理是对的,不知道哪里出了问题,程序如下:
#include <iom16v.h>
#include <macros.h>
#include "1602LCD_drive.h"
//unsigned char line1_data[]={"ADC1:"};     //
//unsigned char line2_data[]={"ADC3:"};          
//unsigned char line3_data[]={"ADC2:"};                     
#define  uchar unsigned char
#define  uint  unsigned int
#define OUTPUT PORTC
#define SER0 0x01
#define SER1 0x02
#define SER2 0x04
#define ADCN ADMUX
#define ADC0 0x40
#define ADC1 0x41
#define ADC2 0x42
char Counter=1;
char num=0;
char time=0;
       

/************延时函数***********/
void delay(unsigned int ms)
{
        unsigned int i,j;
        for(i=0;i<ms;i++)
           {
           for(j=0;j<1141;j++);
       }
}
/*********端口设置函数*********/
void port_init(void)
{
     PORTB=0XFF;                        //设置1602端口的
     DDRB=0XFF;
    DDRD=0XFF;       
    PORTD=0Xff;       
    DDRC=0XFF;               //设置pc口为舵机pwm输出
    PORTC|=0X00;
    DDRA&=0X00;                     //adc口设为输入,带上啦电阻
    PORTA|=0Xff;
}
void timer0_init()
{
        SREG=0X80;
        TIMSK|=(1<<TOIE0);                //是能溢出中断
        TCCR0|=(0<<CS02)|(0<<CS01)|(1<<CS00); //12mhz晶振  无预分频60/12m=5us
        TCNT0=0;                          //计数器初值
}

/**********ad转换函数**********/
unsigned int adc_()
{
         unsigned int addata;                                
         ADMUX=0X40;                                          //AVCC为基准电,AD0为输入通道 01000010
         ADCSRA=0XC0;                                         //使能ADC,自动连续转换 11000000
         ADCSRA|=BIT(ADSC);                                //开始A/D转换
         while(!(ADCSRA&(BIT(ADIF))));        //等待转换完成
         addata=ADCL;                                //获取ADC结果
         addata=addata+ADCH*256;
         return addata;                        //返回ADC值
}   

/**ADC通道转换函数**/
uint adc_change()
{
     unsigned int ada, adcx;
         ada=adc_();
         adcx=ada/2.5+100;
         return adcx;
}


/********************主函数**********************/
void main()
{
        port_init();
        adc_();
        timer0_init();
       
        adc_change();
}

#pragma interrupt_handler timer0_ovf:10
void timer0_ovf()
{   
         TCNT0=196;            //重新赋值256-196=60,溢出一次等于5us
         adc_change();           //adc值转换成counter计数值最大值
     Counter++;
         time++;            
         if(num==0&&Counter<=1)          //这里
         {
             ADCN=ADC0;                                 //设置adc通道为adc0
             OUTPUT|=SER0;                                  //输出口为PC0
                 //k[0]=adc_change()/100;
             //k[1]=(adc_change()%100)/10;
             //LCD_write_char(14,1,k[0]+0x30);
             //LCD_write_char(15,1,k[1]+0x30);
                 
         }
                 
         if(num==1&&Counter<=1)
         {
             ADCN=ADC1;                 //adc通道为adc1
             OUTPUT|=SER1;           //修改输出口为pc1
                 //k[0]=adc_change()/100;
             //k[1]=(adc_change()%100)/10;
             //LCD_write_char(5,1,k[0]+0x30);
             //LCD_write_char(6,1,k[1]+0x30);
               
         }
if(num==2&&Counter<=1)
         {
             ADCN=ADC2;           //adc通道为adc2
             OUTPUT|=SER2;            //输出口为pc2
         }
if(Counter>=adc_change())          //如果计数值大于adc转换值
         {     
                 OUTPUT&=0X00;                   //所有输出口拉低
                 num=num+1;                     //num+1
                 Counter=0;                      //重新计数
                  if(num>=3)                       //num大于三所有c口拉低
                 OUTPUT&=0X00;
         }
       
         if(time>=4000)                //计数达到4000?4000*5us=20000us=20ms为舵机周期
        {
                 num=0;                     //全部重新赋值                       
                 time=0;
                  Counter=0;   
    }
}

小白一个,求大神指教!








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

使用道具 举报

沙发
ID:207004 发表于 2017-6-2 10:49 | 只看该作者
你可以用pmw波控制舵机

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

板凳
ID:207029 发表于 2017-6-2 11:44 | 只看该作者
你的问题很笼统!具体怎么无法实现?有哪些错误?体现在哪里?原理图可否晒出来,否则怎么帮助你?单片机这个东西定制性很强,你单单拿出个程序我想神仙也帮不了你!

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

地板
ID:206921 发表于 2017-6-2 13:07 | 只看该作者
jlqiu 发表于 2017-6-2 10:50
你可以用pmw波控制舵机

那个我会,现在要实现的是多个电位器分别控制多个舵机,采用的是模拟pwm波形,而不是用定时器的快速pwm

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

5#
ID:206921 发表于 2017-6-2 14:05 | 只看该作者
zt2017 发表于 2017-6-2 11:44
你的问题很笼统!具体怎么无法实现?有哪些错误?体现在哪里?原理图可否晒出来,否则怎么帮助你?单片机这 ...

你说的对,具体如下
m16芯片,12mhz晶振,电位器3个,舵机三个,
单片机的PA0~PA2口作为ADC输入通道,分别接三个电位器,采用单端接入法,
PC0~PC2为舵机信号输出脚,分别链接三个舵机的信号线
程序思路是这样
设置定时器溢出中断,使能ADC转换,把得到的ADC值0~1000,通过adc_change()函数转化成100~500,100*5us=0.5ms,500*5us=2.5ms,就是一个舵机的脉冲周期,
例如第一次转换是ADC0,舵机通道SER0(pc0)电平拉高,得到的adc_change()的值为200(相当于脉冲周期200*5us=1ms),赋给Counter,定时器TCNT0初值为196,经过200次溢出,Counter的值达到200,
执行Counter清零,ADCN(ADC输入通道选择)重新赋值为ADC1,舵机通道SER1(pc1)拉高,
此时读取ADC1的值,赋给Counter,再执行如上指令,直到第三通道的舵机脉冲完成,num大于3,所有pc口拉低
程序中每次计数器溢出,time+1,溢出4000次(4000*5us=20ms),为一个舵机控制周期,超过4000,次,time,Counter等清0,重新计数。

程序最后测试结果为,pc0端口保持高点平,pc1,pc2保持低电平,舵机就没反应,电位器都检查了,电路连接良好。可能是程序出错。

评分

参与人数 1黑币 +40 收起 理由
admin + 40 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

6#
ID:207004 发表于 2017-6-5 15:52 | 只看该作者
HYH520 发表于 2017-6-2 13:07
那个我会,现在要实现的是多个电位器分别控制多个舵机,采用的是模拟pwm波形,而不是用定时器的快速pwm

用仿真软件调试过吗?输出方波符合舵机波形吗?
回复

使用道具 举报

7#
ID:206921 发表于 2017-6-12 12:26 | 只看该作者
已实现八个电位器分别同时控制八个舵机,请看新帖
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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