|
本帖最后由 天星1979379768 于 2016-8-20 13:55 编辑
我想用单片机控制多个舵机的转速(不用延时的办法,因为我用同时控制多个舵机的运转,加延时只能控制一个舵机的转速了),同时让舵机来回转动,想法是用IO口输出简单可变PWM脉宽,通过细分PWM脉宽值的方法控制舵机转速(即把一个大的预期角度分成几个小的角度,舵机每转一个小的角度需20ms的时间,5个小的角度就是100ms了),但是遇到个问题:舵机在完成一个预定角度的转动时需要一定的时间,我想要在舵机转完上一个预定的角度后马上改变PWM值让舵机从当前位置转到下一个预期角度,该怎么做?AVR mega32的芯片。下面是想法,延时语句(红色字体部分)是想让舵机转完预期角度,但是舵机在转动过程中有一定的停顿时间(延时的时间是算好的,将预定脉宽值细分成5份,每份执行时间20ms,总共100ms),请问该怎么改?
#include <mega32.h>
#include <delay.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define SERVO PORTA.1 //PWM信号输出端口
#define CENTER 30 //舵机归中数值
uint pwm,cpwm,lpwm; //预期pwm值,上一个pwm值,当前pwm值
int num=0,sdate=0; //sdate为脉宽增量值,num用做定时器计数
interrupt [TIM1_OVF] void timer1_ovf_isr(void)//定时器中断溢出函数
{
TCNT1H=(65536-800)/256; //定时器1每隔50us溢出一次
TCNT1L=(65536-800)%256;
num++;
sdate=(pwm-lpwm)/5; //得到pwm脉宽微小增量值,将预定pwm脉宽细分,增加转动时间
if(num<cpwm)
{
SERVO=1; //IO口电平反转,产生舵机控制信号
}
else
{
SERVO=0;
}
if(num==400) //产生周期为20ms舵机控制信号
{
num=0;
if(cpwm!=pwm)
{
cpwm=cpwm+sdate; //将当前脉宽值增加微小增量,产生新的PWM脉宽控制信号
}
}
}
void main(void)
{
DDRA=0xff; //端口初始化
TCCR1B=0x01; //16MHz时钟频率
TCNT1H=(65536-800)/256; //定时器1寄存器初始化
TCNT1L=(65536-800)%256; //定时器每隔50us溢出一次
TIMSK=0x04;
#asm("sei") //全局中断使能
cpwm=CENTER; //当前脉宽值初始化
lpwm=CENTER; //上一次脉宽值初始化
while (1)
{
pwm=30; //第一个预定PWM脉宽值,舵机位置归中
delay_ms(110); //等待舵机缓慢转动预定位置
lpwm=pwm; //记录上一PWM脉宽值,从而让舵机从当前位置缓慢转到下一个位置
pwm=40; //第二个预定PWM脉宽值,舵机从归中位置转到+45度方向
delay_ms(110); //等待舵机缓慢转动预定位置
lpwm=pwm; //记录上一PWM脉宽值,从而让舵机从当前位置缓慢转到下一个位置
pwm=50; //第三个预定PWM脉宽值,舵机从归中位置转到+90度方向
delay_ms(110); //等待舵机缓慢转动预定位置
lpwm=pwm; //记录上一PWM脉宽值,从而让舵机从当前位置缓慢转到下一个位置
}
}
下面是我的一个尝试的思路,用标志位,但是还是不起作用
#include <mega32.h>
#include <delay.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define LED PORTA.0
#define SERVO PORTA.1 //PWM信号输出端口
#define CENTER 30 //舵机归中数值
uchar flag=0; //舵机执行下一个动作标志位
uint pwm,cpwm,lpwm; //预期pwm值,上一个pwm值,当前pwm值
int num=0,sdate=0; //sdate为脉宽增量值,num用做定时器计数
interrupt [TIM1_OVF] void timer1_ovf_isr(void)//定时器中断溢出函数
{
TCNT1H=(65536-800)/256; //定时器1每隔50us溢出一次
TCNT1L=(65536-800)%256;
num++;
sdate=(pwm-lpwm)/5; //得到pwm脉宽微小增量值,将预定pwm脉宽细分,增加转动时间
if(num<cpwm)
{
SERVO=1; //IO口电平反转,产生舵机控制信号
}
else
{
SERVO=0;
}
if(num==400) //产生周期为20ms舵机控制信号
{
num=0;
if(cpwm!=pwm)
{
cpwm=cpwm+sdate; //将当前脉宽值增加微小增量,产生新的PWM脉宽控制信号
}
else
{
flag++; //表明当前角度已经转完,准备转下一个角度
lpwm=pwm;//记录上一PWM脉宽值,从而让舵机从当前位置缓慢转到下一个位置
if(flag>=3)
{
flag=0;
}
}
}
}
void main(void)
{
DDRA=0xff; //端口初始化
TCCR1B=0x01; //16MHz时钟频率
TCNT1H=(65536-800)/256; //定时器1寄存器初始化
TCNT1L=(65536-800)%256; //定时器每隔50us溢出一次
TIMSK=0x04;
cpwm=CENTER; //当前脉宽值初始化
lpwm=CENTER; //上一次脉宽值初始化
#asm("sei") //全局中断使能
while (1)
{
switch(flag)
{
case 0: pwm=50; //第一个预定PWM脉宽值,舵机位置归中
LED=1;
break;
case 1: LED=0;
pwm=30; //第二个预定PWM脉宽值,舵机从归中位置转到+45度向
break;
case 2:
pwm=40; //第三个预定PWM脉宽值,舵机从归中位置转到+90度方向
break;
default: break;
}
}
}
|
|