先说一下我想要实现的功能:
通过PC的串口助手发送一帧数据给STM32设备,STM32设备解析出某一位,若是1就点亮1个LED灯,若是0就把该LED灯熄灭。
自定义的通信协议如下:
AA 01 01 02 BB
AA —— 帧头
01 —— 地址
01 —— 控制字(是01就点亮LED,是00就熄灭LED)
02 —— 校验和(地址+控制字)
BB —— 帧尾
今天我们主要是讨论一下自定义协议的问题,在这里我就默认你的STM32设备已经可以和电脑的串口助手可以通信上了。如果还没有实现这一功能,建议参考STM32FX开发指南(库函数版),下方我也会提供出源代码供大家参考。
因为我硬件采用的是STM32F407,大家可以根据自己的实际情况进行移植;
你准备好了吗?接下来跟着我的节奏开始.......
第一步:替换中断服务函数;
把原来的中断服务函数用下面的函数代替(函数可以在usart.c文件中找到)
- void USART1_IRQHandler(void)
- {
- u8 Res;//临时变量,存放串口接收的数据
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
- {
- Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
- if(rx_stack.head_flag==1)//收到了帧头
- {
- if(Res==0xBB)//判断当前值是不是帧尾
- {
- rx_stack.finish_flag = 1;
- rx_stack.tail_flag=1;
- rx_stack.head_flag=0;
- }
- else
- {
- rx_stack.recevie_data[rx_stack.data_pt] = Res;
- rx_stack.data_pt++;
- if(rx_stack.data_pt > 9)
- {
- rx_stack.data_pt = 0;
- }
- }
- }
- else//没有收到帧头
- {
- if(Res==rx_stack.head)
- rx_stack.head_flag=1;
- else
- {
- CommClr();
- return;
- }
- }
- }
- USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志
- }
复制代码 到这里你会发现,运行之后会出现很多错误,别慌别慌,问题不大,那是因为我的中断服务函数里面定义了一些原来没有的变量和函数;接着往下看.......
第二步:添加自定义的函数
- void rx_stack_init()
- {
- rx_stack.head = 0xAA; //协议栈头,起始位
- rx_stack.addr=0x01; //从机地址
- memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
- rx_stack.tail = 0xBB; //协议栈尾,结束位
- rx_stack.head_flag = 0;
- rx_stack.tail_flag = 0;
- rx_stack.finish_flag = 0;
- // rx_stack.lock_flag = 0;
- rx_stack.data_pt = 0;
- }
- struct receive_stack rx_stack;
- void CommClr(void)
- {
- rx_stack.head_flag = 0;
- rx_stack.tail_flag = 0;
- rx_stack.finish_flag = 0;
- rx_stack.data_pt = 0;
-
- memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
- rx_stack.commPack_OK_flag=0;
- }
复制代码
把这两个函数放到中断服务函数前面。什么还会报错??当然了,因为我们定义的函数都没有声明,接着来......
第三步:自定义函数的声明(可以在usart.h文件中进行声明)
声明自定义的结构体变量:
- struct receive_stack
- {
- u8 head;//帧头
- u8 addr;//从机地址
- u8 recevie_data[10];//数据
- u8 check;//校验
- u8 tail;//帧尾
- u8 head_flag;//接收到帧头标志位
- u8 tail_flag;//接收到帧尾标志位
- u8 finish_flag;//接收完成标志位
- u8 data_pt;//已接收的字节数
- u8 commPack_OK_flag;//数据解包完成标志
- };
- extern struct receive_stack rx_stack;
复制代码
声明上文中自定义的两个函数:
- void rx_stack_init(void);
- void CommClr(void);
复制代码
现在是不是就没有错误了,但是可能还有几个警告。如果还有错误的话应该是因为_sys_exit(int x) 这个函数,把他改成void _sys_exit(int x) 再试一试,错误应该就没有了吧。那警告怎么去呢?出现告警可能是因为我们使用了memset()这个函数,我们只需要在usart.c中包含#include <string.h>头文件就可以了。现在理论上应该是没有任何报警了,你的是不是这样的?
第四步:验证是不是能正确返回数据
仿照第二步在usart.c中添加串口发送函数
- void usart_send(u8 byte)
- {
- USART_SendData(USART1,byte);
- while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);//发送完成标志位
- }
复制代码
别忘记声明这个函数;
第五步:写主函数
- int main(void)
- {
-
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
- delay_init(168); //延时初始化
- uart_init(9600); //串口初始化波特率为115200
- LED_Init(); //初始化与LED连接的硬件接口
- while(1)
- {
- u8 i;
- u8 SendBuf[5];
- if(rx_stack.finish_flag ==1)//数据接收完成
- {
- SendBuf[0]=0x7B;
- SendBuf[1]=rx_stack.recevie_data[0];
- SendBuf[2]=rx_stack.recevie_data[1];
- SendBuf[3]=rx_stack.recevie_data[2];
- SendBuf[4]=0x7D;
- for(i=0;i<5;i++)
- {
- usart_send(SendBuf[i]);
- }
- }
- }
- }
复制代码
编译一下,把程序下载到板子里面试一试,当你用电脑的串口助手发送AA 01 01 02 BB 给你的目标板,它能把发的数据原样传回来吗?坛友们一块讨论一下。
|