单片机串口通信协议的实现实例

单片机串口通信协议的实现

JiaLiang_825 2017-12-13 13:27:02  3998  收藏 16
分类专栏: 单片机 文章标签: 串口通信 人机交互 单片机 通信
版权
单片机上的串口是日常调试和做一些简单人机交互的一种重要的通信方式,其原理网上有一大堆,这里就不再赘述了,下面主要和大家分享一种我在实际项目中经常用到的一个简单的串口通信协议和实现方式。

下面以STM32F103这款单片机为例:

需要的片上资源:UART、TIM

协议格式:


描述:整个数据包由16个字节长度的数据组成 两位帧头 两位功能位 十位数据位 两位帧尾

实现原理:
将串口配置成中断接收,每次接受到一个8bit的数据则产生一个中断,进入中断后把串口标志位清零并对接受到的数据进行计数和存储,超过16个数据则重新计数,举个例子:

void USART1_IRQHandler(void)//中断服务函数                    
{   
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //中断标志位清零
        {
                if(UART.RxCount > 15)//计数处理
                {
                    UART.RxCount = 0;
                }
                    UART.UART_RX_BUF[UART.RxCount++] = USART_ReceiveData(USART1);// 存到数组  
    } 

1
2
3
4
5
6
7
8
9
10
11
定时器配置10ms产生一次中断,优先级低于串口中断的优先级,加入定时器的目的是检查UART.UART_RX_BUF[ ]这个数组中数据是否为目标帧格式 然后通过解析函数判断帧的的内容和功能并执行相应的功能
定时器中断服务函数举例:

void TIM3_IRQHandler(void)//定时器中断服务函数
{
    if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除标志位   
        UART_Data_Analyse();//解析函数
        UART_Process();//执行函数
    }
}
1
2
3
4
5
6
7
8
9
定时器中断服务函数中有两个函数,一个负责对指令的解析,另一个执行指令对应的动作。

void UART_Data_Analyse(void)//解析函数
{
    if(UART.UART_RX_BUF[14] + UART.UART_RX_BUF[15] == 0x82)//判定帧尾是否是“AA”
    {
        UART.Tail_Flag = 1;
        if((UART.UART_RX_BUF[0]+UART.UART_RX_BUF[1])>0x95 &&(UART.UART_RX_BUF[0]+UART.UART_RX_BUF[1])<0xA2)//帧头校验
        {
            UART.Head_Flag = 1;
        }
        else
            UART_Flush();//清空标志位和串口接受数组
    }
    else
        UART_Flush();//清空标志位和串口接受数组
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
解析函数对串口缓存中的数据进行校验,若不满足条件就清空标志位和串口的接收数组。

执行函数:

void UART_Process(void)//执行函数
{
    if(UART.Process_Flag == 1) Data_Flush(UART.UART_RX_BUF);

    if(UART.Process_Flag != 1)//注1
    {
        if(UART.Tail_Flag == 1 && UART.Tail_Flag == 1 && UART.UART_RX_BUF[3] == 0x31)
        {
            switch(UART.UART_RX_BUF[0]+UART.UART_RX_BUF[1])
            {
                case 0x96:
                                UART.Process_Flag = 1;Task1();break;
                case 0x97:
                                UART.Process_Flag = 1;Task2();break;
                case 0x98:
                                UART.Process_Flag = 1;Task3();break;
                case 0x99:
                                UART.Process_Flag = 1;Task4();break;

            }
        }
    }
}

void Task1(void)
{
    //TODO
    UART.Process_Flag = 0; //注1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
注1:提一下 UART.Procsee_Flag 这个标志位,针对上位机(如串口助手)不停的发送指令的情况下 当执行函数正在执行某一个动作的过程中突然识别到一条指令,这个时候要保证当前指令动作完成才能执行下一条指令的情况下需要加入这个标志位,这个标志位可以理解为判忙标志位,当执行对应的Task之前先将该标志位置1,执行完成之后讲标志位清零准备接收下一条指令。在执行的过程中不理会串口的指令并将其清空。

整个实现方式大致如此,在目前的项目中我经常使用这种协议去调试利用这个协议给单片机传数据或者动作指令,没有遇到过什么bug,但是这个协议还是有可以改进的空间,希望高手批评指正!
————————————————
版权声明:本文为CSDN博主「JiaLiang_825」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/JiaLiang_825/article/details/78789111

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值