#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 { portc5_1; }else{ //不是则输出0 portc5_0; } if (count { portc4_1; }else{ portc4_0; } if (count { portc3_1; }else{ portc3_0; } if (count { portc2_1; }else{ portc2_0; } if (count { portc1_1; }else{ portc1_0; } if (count { portc0_1; }else{ portc0_0; } if (count { portb5_1; }else{ portb5_0; } if (count { portb4_1; }else{ portb4_0; } if (count { portb3_1; }else{ portb3_0; } if (count { portb2_1; }else{ portb2_0; } if (count { portb1_1; }else{ portb1_0; } if (count { portd2_1; }else{ portd2_0; } if (count { portd3_1; }else{ portd3_0; } if (count { portd4_1; }else{ portd4_0; } if (count { portb6_1; }else{ portb6_0; } if (count { portb7_1; }else{ portb7_0; } if (count { portd5_1; }else{ portd5_0; } if (count { portd6_1; }else{ portd6_0; } if (count { portd7_1; }else{ portd7_0; } if (count { 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绝对定位面面观
下一篇:AVR单片机端口操作
推荐阅读最新更新时间:2024-03-16 15:16