Board logo

标题: AVR控制20个舵机的程序 [打印本页]

作者: yuchengze    时间: 2016-10-20 14:26     标题: AVR控制20个舵机的程序

/*AVR控制20个舵机的程序*/

#include   
#include   
#include "me.h"               //自定义的通用io简化位

void timer0_init(void);   
void port_init(void);   
void init(void);   
void UART_init(void);           //串口初始化程序   
void UART_rx(void);             //串口接收中断函数   
void send_text(unsigned char *s);   //字符串发送函数   
void sendchar(unsigned char c);     //字符发送函数   
void dog_init(void);           //初始化看门狗   

unsigned char RX_data[4]={0};     //串口接收的数据   
unsigned char RX_counter=0;       //串口接收到的字节数计数器   

unsigned char pwm1,pwm2,pwm3,pwm4,pwm5,pwm6,pwm7,pwm8,pwm9,pwm10,pwm11,pwm12,pwm13,pwm14,pwm15,pwm16,pwm17,pwm18,pwm19,pwm20; //分别为20个pwm的值   
unsigned char count;           //pwm定位变量   
void main(void)   
{   
oSCCAL=0xAA;                 //系统时钟校准,不同的芯片和不同的频率   
init();   //?

  while(1)   
  {   
  WDR();                   //拼命喂狗   
    if(RX_counter==4)         //收到一个完整的命令信息   
    {   
      RX_counter=0;         //清除串口接收到的字节数计数器   

        if((RX_data[0]==''''''''S'''''''')&&(RX_data[3]==''''''''E''''''''))//判断头尾是不是符合   
        {     

          CLI();           //关闭中断,开始判断数据   
          switch(RX_data[1])   
          {   
            case 0x01:   
            pwm1=RX_data[2];   
            break;   
            case 0x02:   
            pwm2=RX_data[2];   
            break;   
            case 0x03:   
            pwm3=RX_data[2];   
            break;   
            case 0x04:   
            pwm4=RX_data[2];   
            break;   
            case 0x05:   
            pwm5=RX_data[2];   
            break;   
            case 0x06:   
            pwm6=RX_data[2];   
            break;   
            case 0x07:   
            pwm7=RX_data[2];   
            break;   
            case 0x08:   
            pwm8=RX_data[2];   
            break;   
            case 0x09:   
            pwm9=RX_data[2];            
            break;   
            case 0x0a:   
            pwm10=RX_data[2];   
            break;   
            case 0x0b:   
            pwm11=RX_data[2];   
            break;   
            case 0x0c:   
            pwm12=RX_data[2];   
            break;   
            case 0x0d:   
            pwm13=RX_data[2];   
            break;   
            case 0x0e:   
            pwm14=RX_data[2];   
            break;   
            case 0x0f:   
            pwm15=RX_data[2];   
            break;   
            case 0x10:   
            pwm16=RX_data[2];   
            break;   
            case 0x11:   
            pwm17=RX_data[2];   
            break;   
            case 0x12:   
            pwm18=RX_data[2];   
            break;   
            case 0x13:   
            pwm19=RX_data[2];   
            break;   
            case 0x14:   
            pwm20=RX_data[2];   
            break;   
            default:   
            SEI();           //错误时打开中断,以便发送错误信息   
            send_text("ER");   //范围超出20个pwm,就发出大写字母"ER"   
            break;   


          }     
          SEI();             //恢复中断允许   
          send_text("OK");     //判断处理完毕返回ok;   
        }   
    }   
  }   
}   


void init(void)   
{   
CLI(); //disable all interrupts   
port_init();   
timer0_init();   
TIMSK = 0x01; //定时器中断源   
UART_init();   
SEI(); //re-enable interrupts   
}   


void port_init(void)   
{   
PORTB = 0x00;   
DDRB = 0xFF;   
PORTC = 0x00;   
DDRC = 0x7F;   
PORTD = 0x00;   
DDRD = 0xFF;   
}   


void send_char(unsigned char c)     //发送单字符函数   
{   
  while (!(UCSRA&(1 << UDRE)));   //判断上次发送有没有完成   
  UDR = c;                 //发送数据   
}   

#pragma interrupt_handler UART_rx: iv_USART_RX //将串口接收中断,指给UART_rx   
/********************************************************   
通讯协议:S+PWM?+Volue+E   
标志说明:   S : 头标志   16进制:0x53   
标志说明: PWM? : PWM标号,?范围:0x01~0x14 指20个pwm输出   
标志说明: Volue: PWM占空比,范围0x00~0xff 关闭pwm则为0x00   
标志说明:   E : 结束标志 16进制:0x45   
其他说明: 完整一个数据占4个byte,头尾必须分别为S、E方为有效   
如果pwm位超出20个,返回字母ER;   
********************************************************/   
void UART_rx(void)                     //串口接收中断函数   
{   
  RX_data[RX_counter] = UDR;   

  if (RX_data[RX_counter]==''''''''S'''''''')         //纠正错位用,和RX_counter溢出。   
    {   
      RX_data[0]=RX_data[RX_counter];   
      RX_counter=0;   
    }   

  RX_counter++;                     //接收的字节数计数   
}   


void send_text(unsigned char *s)           //字符串发送函数   
{   
  while (*s)   
    {   
      send_char(*s);   
      s++;   
    }   
}   


void UART_init(void)                   //串口初始化程序   
{   
  UCSRB = BIT(RXCIE)| BIT(RXEN) |BIT(TXEN);   //允许串口发送和接收,并响应接收完成中断   
  UBRR = 51;                       //时钟8Mhz,波特率9600   
  UCSRC = BIT(URSEL)|BIT(UCSZ1)|BIT(UCSZ0);   //8位数据+1位stop位   
}   


/********************************************   
设计思路:舵机典型需要20mS的频率,即50Hz的频率   
为了实现8位的pwm精度,需将20mS的时间再平均分正   
256份,即78.125u秒,在一次中断的时候与目标定义   
需要的pwm占空比的值(pwm1~20)比较,判断io是否该   
输出0电平,如果不是则输出高电平   
目标中断时间: 78.125uSec (加上0.2%误差)   
实际中断时间: 78.000uSec   
如果想提高频率,只需要修改定时器的溢出时间   
如果想提高pwm的分辨率,则修改count的值   
********************************************/   
void timer0_init(void)         //定时器初始化程序   
{   
TCCR0 = 0x00;             //停止定时器   
TCNT0 = 0xB4;             //设置初始值   
TCCR0 = 0x02;             //开动定时器   
}   

#pragma interrupt_handler timer0_ovf_isr:10 //将定时器溢出中断指到timer0_ovf_isr中,好比汇编中的ORG   
void timer0_ovf_isr(void)     //定时器溢出中断程序   
{   
TCNT0 = 0xB4;             //从新调入初始值   
count++;                 //每中断一次加1   
if (count<PWM1)            判断pwm1是不是改输出高电平    {   
portc5_1;   
}else{                 //不是则输出0   
portc5_0;   
}   

if (count<PWM2)    </PWM2)   {   
portc4_1;   
}else{   
portc4_0;   
}   

if (count<PWM3)    </PWM3)   {   
portc3_1;   
}else{   
portc3_0;   
}   

if (count<PWM4)    </PWM4)   {   
portc2_1;   
}else{   
portc2_0;   
}   

if (count<PWM5)    </PWM5)   {   
portc1_1;   
}else{   
portc1_0;   
}   

if (count<PWM6)    </PWM6)   {   
portc0_1;   
}else{   
portc0_0;   
}   

if (count<PWM7)    </PWM7)   {   
portb5_1;   
}else{   
portb5_0;   
}   

if (count<PWM8)    </PWM8)   {   
portb4_1;   
}else{   
portb4_0;   
}   

if (count<PWM9)    </PWM9)   {   
portb3_1;   
}else{   
portb3_0;   
}   

if (count<PWM10)    </PWM10)   {   
portb2_1;   
}else{   
portb2_0;   
}   

if (count<PWM11)    </PWM11)   {   
portb1_1;   
}else{   
portb1_0;   
}   

if (count<PWM12)    </PWM12)   {   
portd2_1;   
}else{   
portd2_0;   
}   

if (count<PWM13)    </PWM13)   {   
portd3_1;   
}else{   
portd3_0;   
}   

if (count<PWM14)    </PWM14)   {   
portd4_1;   
}else{   
portd4_0;   
}   

if (count<PWM15)    </PWM15)   {   
portb6_1;   
}else{   
portb6_0;   
}   

if (count<PWM16)    </PWM16)   {   
portb7_1;   
}else{   
portb7_0;   
}   

if (count<PWM17)    </PWM17)   {   
portd5_1;   
}else{   
portd5_0;   
}   

if (count<PWM18)    </PWM18)   {   
portd6_1;   
}else{   
portd6_0;   
}   

if (count<PWM19)    </PWM19)   {   
portd7_1;   
}else{   
portd7_0;   
}   

if (count<PWM20)    </PWM20)   {   
portb0_1;   
}else{   
portb0_0;   
}   
}   


void dog_init(void)   //看门狗初始化   
{   
WDR();     //看门狗计数清零   
WDTCR=0x0F; //使能看门狗,并且,采用2048分频,溢出时间5V时2.1S   
}







//定时器T0中断,向8253发送控制字和数据
void T0Int() interrupt 1
{
TH0 = 0xB1;
TL0 = 0xE0;   //20ms的时钟基准
//先写入控制字,再写入计数值
SERVO0 = 0x30; //选择计数器0,写入控制字
PWM0 = BUF0L; //先写低,后写高
PWM0 = BUF0H;
SERVO1 = 0x70; //选择计数器1,写入控制字
PWM1 = BUF1L;
PWM1 = BUF1H;
SERVO2 = 0xB0; //选择计数器2,写入控制字
PWM2 = BUF2L;
PWM2 = BUF2H;
}

关键字:AVR控制2  舵机




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0