接之前的HAL库串口篇:https://blog.csdn.net/u010779035/article/details/103764852
目录
前言
在某次实践中,使用HAL库中断接收,会出现不少毛病,查了硬件软件看起来都没问题,考虑了一下可能是HAL库函数的操作耗时过长等原因。无奈之下,尝试使用了LL库,问题不再复现。LL库的使用其实就相当于直接操作寄存器,没有过多的自定义状态变量使用。另外,MX中,可以为多个串口分别选配HAL库和LL库驱动。
一、MX配置
串口参数
使能全局中断
选择LL库
二、生成的代码
由于我同时选择了LL库的GPIO,所以GPIO的配置同样也使用了LL库。
在初始化函数中,已经配置好串口1、中断向量表、使能串口1。接下来需要用户自己使能中断。
三、用户代码
1、<usart.h> 自定义接收缓存
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
#define USART_REC_LEN 200 //定义最大接收字节数 200
extern uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲
/* USER CODE END Private defines */
/* USER CODE BEGIN Prototypes */
void Uart1_SendStr(char*SendBuf);
void uart1_revice_my_data(void);
/* USER CODE END Prototypes */
2、<usart.c> 实现printf、字符串发送、消息头接收
/* USER CODE BEGIN 0 */
uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲
uint8_t flag;
uint8_t state;
uint8_t recv_cnt;
uint16_t header;
uint8_t pkt_len;
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
//HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
LL_USART_TransmitData8(USART1,(uint8_t)ch);
return ch;
}
//#define USR_USE_HAL
#ifdef USR_USE_HAL
void Uart1_SendStr(char*SendBuf)//串口1发送字符串
{
while(*SendBuf)
{
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=1);//等待发送完成
HAL_UART_Transmit(&huart1,(uint8_t*)SendBuf,1,1000);//发送数据
SendBuf++;
}
}
#else
void Uart1_SendStr(char*SendBuf)//串口1发送字符串
{
while(*SendBuf)
{
while(LL_USART_IsActiveFlag_TC(USART1)!=1);//等待发送完成
LL_USART_TransmitData8(USART1,(uint8_t)(*SendBuf & (uint8_t)0xff));//发送数据
SendBuf++;
}
}
#endif
void uart1_revice_my_data(void)
{
uint8_t Res = LL_USART_ReceiveData8(USART1);
if(flag!=1)
{
if(state==0)
{//未收到包头
if(Res == 0xfc)
{
header = 0x00fc;
}
else if(Res ==0xfe)
{
header=(header<<8)|Res;
if(header==0xfcfe)
{//收到包头
state=1;
USART_RX_BUF[0]=0xfc;
USART_RX_BUF[1]=0xfe;
recv_cnt=2;
}
}
else
{
header=0;
}
}
else if(state==1)
{//收到包头未收到长度
pkt_len=Res;
USART_RX_BUF[recv_cnt++]=pkt_len;
state=2;
}
else if(state==2)
{//收到包头且收到长度
USART_RX_BUF[recv_cnt++]=Res;
if(recv_cnt==pkt_len)
{
flag=1;
state=0;
recv_cnt=0;
}
}
}
}
/* USER CODE END 1 */
3、<stm32f1xx_it.c> 串口中断响应
/* USER CODE BEGIN Includes */
#include "usart.h"
/* USER CODE END Includes */
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
/* USER CODE BEGIN USART1_IRQn 1 */
uart1_revice_my_data();//在此加入这段函数,分析接收到的数据
/* USER CODE END USART1_IRQn 1 */
}
4、<main.c> 使能接收中断、分析接收到的数据
int main(void)
{
...
LL_USART_EnableIT_RXNE(USART1);//使能串口接收中断
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(flag == 1)
{
massage_analysis();//自定义协议分析
flag = 0;
}
}
/* USER CODE END 3 */
}
小结
发送数据:LL_USART_TransmitData8(USART1,(uint8_t)ch);
接收数据:uint8_t Res = LL_USART_ReceiveData8(USART1);//阻塞模式和中断模式或者DMA都适用
开启接收中断:LL_USART_EnableIT_RXNE(USART1);
判断发送完成:LL_USART_IsActiveFlag_TC(USART1) //返回值1为完成,0为未完成。
使能串口:LL_USART_Enable(USART1);
使能串口中断:NVIC_EnableIRQ(USART1_IRQn);