今天要做一个串口取数据然后叠加OSD的项目,串口发过来的数据一次8个字节,0x5A开头,最后一个字节校验和,大约100ms发一次,波特率115200。
然后就想直接在原子哥的串口教程里改改,先把串口收数据这一块搞定。但发现每次进中断,读到的数据都只是0x5A,后边的7个数据数据都读不出来了。苦思冥想了一会,再加上这边帖子里的灵感
http://www.openedv.com/posts/list/41525.htm
我也觉得在高波特率下,在串口接收中断函数里做过多处理的话,有可能会把字头后边的数据漏掉,造成混乱。所以,
个人建议,中断服务程序我们只做存储数据就好,处理数据尽量去main里面处理,这样不容易产生混乱。
USART_RX_BUF和seri_count都是全局变量。
然后在main函数中处理数据,核心问题是如果传输过程中出现乱码该怎么办。我的思路是:
若数组USART_RX_BUF中的数据超过8字节,则开始找帧头,若找不到,丢掉数据,重新从USART_RX_BUF[0]开始写数据。 若找到帧头,则从帧头开始,检查和校验,校验通过就可以刷新数据,校验不通过的话,丢掉该组数据。如果帧头在数据的中间,也是一样处理。这样即使有乱码过来,程序也能很快找到帧头。
[mw_shl_code=c,true]
[/mw_shl_code]
[mw_shl_code=c,true]#if EN_USART1_RX //如果使能了接收
void USART1_IRQHandler(void) //串口1中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
USART_RX_BUF[seri_count]=USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
LED1=!LED1;
seri_count++;
}
}
#endif [/mw_shl_code]
[mw_shl_code=c,true][/mw_shl_code]
[mw_shl_code=c,true]
[mw_shl_code=c,true]#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "stdio.h"
//ALIENTEK Mini STM32开发板范例代码11
//TFTLCD显示实验
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司
typedef struct osd_Data
{
int16_t roll; // 滚转角,高八位在前,第八位在后,,除以10得到角度值,精度为0.1度
int16_t pitch; // 俯仰角,高八位在前,第八位在后,除以10得到角度值,精度为0.1度
u16 V_bat; // 电池电压,除以10得到电压值,精度为0.1V
} OSD_Data;
OSD_Data OSD_250;
int main(void)
{
u8 x=0;
u8 sum_check=0;
// u8 UART_RX_Mid[10];
u8 lcd_id[12]; //存放LCD ID字符串
seri_count=0; //串口缓冲区数组个数,初始化为0
delay_init(); //延时函数初始化
uart_init(115200); //串口初始化为115200
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init();
NVIC_Configuration();// 设置中断优先级分组
POINT_COLOR=RED;
sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将LCD ID打印到lcd_id数组。
LCD_Clear(GRAY);
LCD_ShowString(30,40,200,24,24,"Mini STM32 ^_^");
LCD_ShowString(30,70,200,16,16,"TFTLCD TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,lcd_id); //显示LCD ID
LCD_ShowString(30,130,200,12,12,"2014/3/7");
while(1)
{
if(seri_count>=Data_Length) //如果已经接收到超过字符串长度的字符
{
u8 i=0;
while(USART_RX_BUF!=0x5A) //找字头
{
i++;
if(i>(Data_Length-1))
{ i=0; //如果在一个字符串的长度范围内,都没有接收到字头,则重新开始
seri_count=0;
}
}
if(i==0)
{
for(x=0;x<Data_Length-1;x++) //将校验和之前的字符串相加
{
sum_check=sum_check+USART_RX_BUF[x];
}
if(sum_check==USART_RX_BUF[Data_Length-1]) //判断校验和
{
seri_count=0; //为下一次进中断做好准备
sum_check=0; //校验和清零,准备下一次校验
OSD_250.roll=((u16)USART_RX_BUF[1])<<8 |USART_RX_BUF[2];
OSD_250.pitch=((u16)USART_RX_BUF[3])<<8|USART_RX_BUF[4];
OSD_250.V_bat=((u16)USART_RX_BUF[5])<<8|USART_RX_BUF[6];
LCD_Fill(30,150,300,210,GRAY); //填充单色,刷掉显示区域
sprintf((char*)lcd_id, "Roll:%-04.1f",(float)OSD_250.roll/10.0); //将数据打印到data数组。
LCD_ShowString(30,150,200,16,16,lcd_id);
sprintf((char*)lcd_id,"pitch:%-04.1f",(float)OSD_250.pitch/10.0);//将数据打印到data数组。
LCD_ShowString(30,170,200,16,16,lcd_id);
sprintf((char*)lcd_id,"votalge:%-04.1f",(float)OSD_250.V_bat/100.0);//将数据打印到data数组。
LCD_ShowString(30,190,200,16,16,lcd_id);
}
else
{seri_count=0; //校验和不正确,则可能发生帧错误,重新开始
sum_check=0;
}
}
else
{
for(x=0;x<Data_Length-1;x++) //将校验和之前的字符串相加个数据相加
{
sum_check=sum_check+USART_RX_BUF[x+i];
}
if(sum_check==USART_RX_BUF[i+Data_Length-1])
{
seri_count=0; // 为下一次进中断做好准备
sum_check=0; //校验和清零,准备下一次校验
OSD_250.roll=((u16)USART_RX_BUF[i+1])<<8 |USART_RX_BUF[i+2];
OSD_250.pitch=((u16)USART_RX_BUF[i+3])<<8|USART_RX_BUF[i+4];
OSD_250.V_bat=((u16)USART_RX_BUF[i+5])<<8|USART_RX_BUF[i+6];
LCD_Fill(30,150,300,210,GRAY); //填充单色,刷掉显示区域
sprintf((char*)lcd_id, "Roll:%-04.1f",(float)OSD_250.roll/10.0); //将数据打印到data数组。
LCD_ShowString(30,150,200,16,16,lcd_id);
sprintf((char*)lcd_id,"pitch:%-04.1f",(float)OSD_250.pitch/10.0);//将数据打印到data数组。
LCD_ShowString(30,170,200,16,16,lcd_id);
sprintf((char*)lcd_id,"votalge:%-04.1f",(float)OSD_250.V_bat/100.0);//将数据打印到data数组。
LCD_ShowString(30,190,200,16,16,lcd_id);
}
else //校验和不正确,则可能发生帧错误,重新开始
{seri_count=0;
sum_check=0;
}
}
}
x++;
if(x==12)x=0;
LED0=!LED0;
delay_ms(1000);
}
}
[/mw_shl_code]
[/mw_shl_code]
|