赞助论坛
  • 8635阅读
  • 0回复

AVR控制20个舵机的程序 [复制链接]

楼层直达
发帖
13
精华
0
金币
25
威望
2
贡献
1
好评
1
注册
2008-10-25
楼主    ☆天宇☆ 发表于: 2008-10-25 18:04:17 
#include <iom8v.h>  
#include <macros.h>  
#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)  
{  
portc4_1;  
}else{  
portc4_0;  
}  
 
if (count<pwm3)  
{  
portc3_1;  
}else{  
portc3_0;  
}  
 
if (count<pwm4)  
{  
portc2_1;  
}else{  
portc2_0;  
}  
 
if (count<pwm5)  
{  
portc1_1;  
}else{  
portc1_0;  
}  
 
if (count<pwm6)  
{  
portc0_1;  
}else{  
portc0_0;  
}  
 
if (count<pwm7)  
{  
portb5_1;  
}else{  
portb5_0;  
}  
 
if (count<pwm8)  
{  
portb4_1;  
}else{  
portb4_0;  
}  
 
if (count<pwm9)  
{  
portb3_1;  
}else{  
portb3_0;  
}  
 
if (count<pwm10)  
{  
portb2_1;  
}else{  
portb2_0;  
}  
 
if (count<pwm11)  
{  
portb1_1;  
}else{  
portb1_0;  
}  
 
if (count<pwm12)  
{  
portd2_1;  
}else{  
portd2_0;  
}  
 
if (count<pwm13)  
{  
portd3_1;  
}else{  
portd3_0;  
}  
 
if (count<pwm14)  
{  
portd4_1;  
}else{  
portd4_0;  
}  
 
if (count<pwm15)  
{  
portb6_1;  
}else{  
portb6_0;  
}  
 
if (count<pwm16)  
{  
portb7_1;  
}else{  
portb7_0;  
}  
 
if (count<pwm17)  
{  
portd5_1;  
}else{  
portd5_0;  
}  
 
if (count<pwm18)  
{  
portd6_1;  
}else{  
portd6_0;  
}  
 
if (count<pwm19)  
{  
portd7_1;  
}else{  
portd7_0;  
}  
 
if (count<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;
}
  [font=宋体]文字[/font]
本帖最近评分记录: 1 条评分