1、定义需要用到的变量
typedef struct {
u8 RxPacket[256]; //数据接收缓存区 :接收到的数据存放在这里
u8 pRxPacket; //数组下标 :每接收一个数据,下标加一
u8 RxFlag; //接受完成标志位 :当数据接收完时置位,否则清零
u8 RxState; //数据接收状态机 :什么状态接收什么数据,滤掉不要的数据,对数据初步处理
u8 RxTimer; //数据接收定时器 :软件定时器,基于定时器的定时器。接收数据就打开,接收完成
// 就关闭
u8 RxCount; //数据接收计数器 :数据接收定时器一打开就开始数数,
// 接收到数据就重新数即清零,数到定的时间还不清零就认为这一
// 包数据接收完了
}reseive_t;
enum {
Close = 0,//
Open = 1
};
2、定时器中断处理
定时器时间取决于 波特率:即1秒能接收的字节数
如 115200 波特率 1 秒是 115200个字节
而发来的每个字节的数据有 1 起始位, 1 停止位,8 数据位,即 10位
因此接收每个字节所需要的时间为 10/115200 秒
1 秒等于 1000 000 微秒,则接收每个字节需要 1000 000 * 10/115200 微秒,约86微秒
因此每过来一个数据便打开定时器开始计时,并且每来一个数据重新开始计时
若没有数据过来,就一直计时,直到超过某个时间(一定要大于接收每个字节的时间)
便判定这一包数据接收完毕(一个数据包的数据每个字节的发送时间不会差太多的)
我这里使用的波特率为115200,不妨设 这个时间 为100微秒,超过100微秒则认为这一包数据接收完毕
基于定时器的定时器 :单片机的定时器每10us进入中断,我的“数据接收定时器”要数10个数才能进去执行内容
进入定时器中断之后,首先判断我的“数据接收定时器”打开了没(在接收中断中打开,且有数据过来才能打开)
如果打开了,说明有数据来了,那么我就开始计数,不妨假设计数超过了10,那么判定数据接收完毕
关闭该“数据接收定时器”,计数值清零,给 数据缓存区数组【数组下标】 = '\0',设为字符串到这结束
把数组下标清零 注:先给 数据缓存区末位='\0'再清零,数组也要清空,但是不在这里清,我们要把数据处理完再清
接收完成标志位置位,告诉单片坤数据接收完成
if(reseive.RxTimer == Open)//如果接收定时器打开了
{
reseive.RxCount++;//开始计数
if(reseive.RxCount >= RxMaxTime_100us)//超过100us认为数据接收完成
{
reseive.RxTimer = Close;//关闭“数据接收定时器”
reseive.RxCount = 0;//计数值清零
reseive.RxPacket[reseive.pRxPacket] = '\0';
reseive.pRxPacket = 0;//数组下表清零
reseive.RxFlag = 1;//接收完成标志位置位,接收完成
}
}
3、串口中断处理
这里我是把发过来的数据照单全收,并没有用到 reseive.Status 这个变量
先对结构体初始化,全部清零
数据过来进入中断,定义一个变量接收数据
如果用状态机的话可以先判断数据是不是想要的,比如帧头、回车换行、帧尾什么的
是的话进入下一个状态接收数据,不是的话就放弃接收,清空数组、复位数组下标重新接收什么的,当然这里没有用到
那么接着往下看,数据来了就打开 “数据接收计时器” 开始计时
把数据接收到数组里面,数组下标自增,以便保存下一个数据
最后把计数值清零,因为对于连续接收的数据我们认为他们是在同一个数据包,
并认为发过来的每个字节间隔时间超过100us便不在同一个数据包,至于为啥这么认为,
以及不是同一个数据包怎么办、我已经在定时器中断那里阐述过了
所以给他清零,告诉单片坤是同一个数据包。
reseive_t reseive = {{0},0,0,0,0,0};
void USART1_IRQHandler()
{
if(USART_GetFlagStatus(USART1,USART_IT_RXNE) != RESET)
{
u8 RxData = USART_ReceiveData(USART1);
reseive.RxTimer = Open;//打开定时计数器
reseive.RxPacket[reseive.pRxPacket] = RxData;//开始接收
reseive.pRxPacket++;
reseive.RxCount = 0; //接收到一字节数据,计数值清零
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
4、主函数处理
在主函数里对接收的数据进行处理,若有其他需求可把数据处理封装成函数,塞到其他地方
首先要判断数据接收完了没,即数据 接收完成标志位 有没有置位,至于有没有置位是在定时器中断里操作的
若是接收完成标志位置位了,就把接收到的一串玩意打印出来
因为我是对发来的数据照单全收的,所以没有进一步处理
处理思路就是判断这个数据是不是自己想要的
比如 if( strcmp( 数据名,"字符串" ) == 0) strcmp函数是字符串匹配,如果数组里的字符串与你给的字符串一毛一样
那么就是我要接收的数据了,据此进行下一步操作。如若使用,记得加上<string.h>头文件。当然了我这里没有这么做
我这里是把接收的字符串全部打印出来,看看是不是我发的数据
接下来,既然对数据处理完了,当然要把接收完成标志位清零了啦,顺手也把数组也清空一下~~~~~~~~~~~~~~~~
if(reseive.RxFlag == 1)
{
printf("%s\n", reseive.RxPacket);
reseive.RxFlag = 0;//接收完成标志位清零
memset(reseive.RxPacket, 0, sizeof(reseive.RxPacket));//清空数组
//这个也需要<string.h>头文件
}