设计目标:
1. 单片机时钟10MHz,串口波特率115200
2. 由于波特率较高,串口必须采用中断方式接收
3. 串口接受完数据必须对数据进行解帧,即判断出帧头和帧尾,这部分放while循环里面处理
搜索了下,发现下面的代码比较符合要求
但是根据信息有几个问题
1. UART_Receive_Size在中断函数和一般函数都出现,会产生其真实值被中断后覆盖掉的问题,导致值出错(最终结果是有可能丢帧)
2. 可不可以不用UART_Receive_Size,而是定义两个指针,分别指向接收位置和处理位置,则缓冲区的满(full)
不用UART_Receive_Size进行判断,而是利用这两个指针的关系进行判断。这样子可以避免问题1?()
3. 求测试过的健壮性好的代码,谢谢
- //系统可修改参数宏定义
- #define BUFFER_SIEZ 64
- //控制命令定义
- #define COMMUNCIATE 0
- #define SET_SYSTEM_CAL_FULL 1
- #define SET_SYSTEM_CAL_MV_V 2
- #define SET_SYSTEM_OL 3
- #define SET_POWER_OFF_TIME 4 //设定系统关机时间
- #define READ_SYSTEM_DATA 5
- //变量定义
- //串口缓冲区 建立一个环形缓冲区,收发
- unsigned char xdata UART_Receive_Size=0;//串口缓冲区接收字节数
- unsigned char xdata UART_Receive_First=0;//串口缓冲区接收字节开始位置
- unsigned char xdata UART_Read_First=0;
- unsigned char xdata UART_Buffer[BUFFER_SIEZ];//串口缓冲区
- unsigned char xdata UART_Send_Byte_Ok=0;//发送一字节成功
- //中断处理
- //串口初始化根据自己的单片机写就行
- void UART0_Interrupt (void) interrupt 4
- {
- if(RI0) //如果是发中断,返回
- {
- RI0=0; //清除中断标志
- if(UART_Receive_Size<=BUFFER_SIEZ)//缓冲区未满,装载数据
- {
- UART_Buffer[UART_Receive_First++]=SBUF0;
- UART_Receive_Size++;//串口缓冲区接收字节数
- if(UART_Receive_First>=BUFFER_SIEZ)//循环装入缓冲区
- UART_Receive_First = 0;
- }
- }
- if(TI0)
- {
- TI0=0;
- UART_Send_Byte_Ok=1;
- }
- }
- //在缓冲区中读取一帧数据
- void Do_Commend()
- {
- unsigned char Buf[8]={0,0,0,0,0,0,0,0};//帧数据缓冲区
- unsigned char i=0;
- unsigned char data_packge_flag=0;
-
- if(UART_Receive_Size>=8)//缓冲区字节数大于等于一个包字节数
- {
- while(UART_Receive_Size!=0)//寻找帧数据头
- {
- if(UART_Buffer[UART_Read_First]==0xaa)
- {
- if(UART_Read_First+7<BUFFER_SIEZ)
- {
- if(UART_Buffer[UART_Read_First+7]==0x55)
- {
- data_packge_flag=1;
- break;
- }
- }
- else
- {
- if(UART_Buffer[7-(BUFFER_SIEZ-UART_Read_First)]==0x55)
- data_packge_flag=1;
- break;
- }
- }
- UART_Read_First++;
- if(UART_Read_First>=BUFFER_SIEZ)//环形 缓冲区折行
- UART_Read_First=0;
- UART_Receive_Size--;
- }
- if(data_packge_flag==1)//寻找到枕头
- {
- for(i=0;i<8;i++)//读取帧数据
- {
- Buf=UART_Buffer[UART_Read_First];
- UART_Receive_Size--;
- UART_Read_First++;
- if(UART_Read_First>=BUFFER_SIEZ)//环形 缓冲区折行
- UART_Read_First=0;
- }
- data_packge_flag=0;
- }
- if(Buf[7]==0x55&&Buf[0]==0xaa) //接收到一个正确的数据包
- {
- switch(Buf[1])
- {
- ...
- }
- }
- }
- }
复制代码
2倍够干啥的,分分钟灭趴下;我一般会计算整个程序运行的最大时间,然后根据这个时间和一帧字节去反推缓冲区多大,再加20%余量即可;
如何贴代码,不会弄啊,我本来想贴一个的;晕倒;
/**
* @brief void TFT_Scan()
* @param None
* @retval None
* @备注: TFT_Scan,主程20ms定时扫描;
按照115200bit->15200byte/s -> 15byte/ms ->
我们定义的队列长度为512, 512/15 = 34ms,近乎一半为20ms;
帧结构 : 0x55 + 帧长(1byte) + COM(1byge) + databuf(n byte) + check + 0xaa
0x55 5 [1 2 3 4 5] 6 7
*******************************************************************
**/
//TFT返回消息扫描 , 迪文屏比较二货的机制,不适合这种高密度的发描,完全是大炮大蚊子;
//非得让我在中断使用傻瓜式方法,漏帧是在所难免的!傻瓜式代码名称为TFT_ISR();
void TFT_scan(void)
{
uint8_t readlen = 0,Data_Temp = 0;
uint16_t StAddr = 0,Key_Temp = 0,QueueCounter = 0;
//1.保留指针
StAddr = Queue_GetCurRead(&tftRevQue);
memset(tftBuff,0,FRAME_BUFF_LEN);
//最小帧长不合格,数据未收全
QueueCounter = Queue_GetCounter(&tftRevQue);
if(QueueCounter < Frame_Len)
return ;
//2. 帧头和帧长
if(Queue_Peek_Mult(&tftRevQue,tftBuff,2,StAddr))
{
if((tftBuff[0] == 0xAA)&&(tftBuff[1] == 0x78))//帧头为AA 78
{
//继续侦测
readlen = Frame_Len;
if(Queue_Peek_Mult(&tftRevQue,tftBuff,readlen,StAddr))
{
if( (tftBuff[4] == 0xcc) && //帧尾正确
(tftBuff[5] == 0x33) &&
(tftBuff[6] == 0xc3) &&
(tftBuff[7] == 0x3c)
)
{
memset(tftBuff,0,sizeof(tftBuff));
Queue_Read_Mult(&tftRevQue,tftBuff,readlen);
Key_Temp = tftBuff[2];
Key_Temp*= 256;
Key_Temp += tftBuff[3];
//抛出事件
SchMsg.post(tTouch,Key_Temp);
}
else
Queue_Read_Single(&tftRevQue,&Data_Temp);//改变读指针!
}
else
Queue_Read_Single(&tftRevQue,&Data_Temp);//改变读指针!
}
else
Queue_Read_Single(&tftRevQue,&Data_Temp);//改变读指针!
}
else
Queue_Read_Single(&tftRevQue,&Data_Temp);//改变读指针!
}
一周热门 更多>