串口实现不定长数据收发(接收中断)
1头文件
#include "uart1.h"
#include "string.h"
#include "stdio.h"
#include "sys.h"
#define UART1_RX_BUF_SIZE 128 //接收
#define UART1_TX_BUF_SIZE 64 //发送 发送可以小一些看使用的场景
//宏定义错误代码
#define UART_EOK 0
#define UART_ERROR 1
#define UART_ETIMEOUT 2 //数据超时
#define UART_EINVAL 3 //非法字符
void uart1_init(uint32_t baudrate);
void uart1_receiv_test(void);
//接收来的数据保存到数组里面
uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE];
uint16_t uart1_rx_len = 0;//数组长度
uint16_t uart1_cnt = 0,uart1_cntPre = 0;//会正常一些 需要判断计数器有无变化
2初始化函数
UART_HandleTypeDef uart1_handle = {0};
//初始化
void uart1_init(uint32_t baudrate)
{
uart1_handle.Instance = USART1; //选择通用异步收发器
uart1_handle.Init.BaudRate = baudrate; //波特率
uart1_handle.Init.WordLength= UART_WORDLENGTH_8B;//字长参数列表用的8位
uart1_handle.Init.StopBits = UART_STOPBITS_1; //停止位的数量
uart1_handle.Init.Parity = UART_PARITY_NONE //奇偶校验,不准确一般不用,故不设置
uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;//流控制?
uart1_handle.Init.Mode = UART_MODE_TX_RX; //我们的需要时既要收又要发
HAL_UART_Init(&uart1_handle);
}
3msp公用的一个函数这里有三个串口,都会调用msp先进行一个判断
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
判断是否为USART1
if(huart->Instance == USART1)
{
//使能USART1,GPIO时钟
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio_initstruct;
//配置TX
gpio_initstruct.Pin = GPIO_PIN_9;//数据手册
gpio_initstruct.Mode = GPIO_MODE_AF_PP;//数据手册要求
gpio_initstruct.Pull = GPIO_PULLUP;//随意
gpio_initstruct.Speed= GPIO_SPEED_FREQ_HIGH;//随意
HAL_GPIO_Init(GPIOA,&gpio_initstruct);
//配置RX
gpio_initstruct.Pin = GPIO_PIN_10;
gpio_initstruct.Mode = GPIO_MODE_AF_INPUT;//复用推完输入和输入模式一样
//NVIC
HAL_NVIC_EnableIRQ(USART1_IRQn); //使能NVIC中断
HAL_NVIC_SetPriority(USART1_IRQn,2,2);//设置中断优先级
//确定RXNE被置为1 __HAL_UART_ENABLE_IT()
__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE);
}
}
4中断服务函数--数据收发
void UASRT1_IRQHandler(void)
{
uint8_t receive data = 0;
//判断什么时候数据的收发 如何判断是否收到数据 看RXNE RDR接收数据寄存器内不为空 就会触发一个
//中断就可以进行一个操作
//判断是否为RXNE触发的中断
if(__HAL_UART_GET_FLAG(&uart1_handle,UART_FLAG_RXNE) != RESER)//被置1不为RESET
{
//需要判断数组是否接收完,防止缓冲区被刷爆
if(uart1_cnt >= sizeof(uart1_rx_buf))
uart1_cnt = 0;
//进行接收
//接收的位置,接收的数据,接受的长度,超时时间
HAL_UART_Receive(&uart1_handle,&receive_data,1,1,1000);
//接收到的数据保存到数组中
uart1_rx_buf[uart1_cnt++] = receive_data;
}
}
5重定向到串口1中SR ? DR? ch 将fputc 定向到printf中
int fputc(int ch,FILE *f)??
{
while((USART1->SR & 0x40) == 0);//一直卡住 判断是否为1
USART1->DR = (uint8_t)ch;//将dr的值赋到ch中,要勾选魔术棒中的Micro
return ch;
}
6需要判断数组是否接收完
uint8_t uart1_wait_receive(void)
{
if(uart1_cnt == 0)
return UART_ERROR;
if(uart_cnt == uart1_cntPre)//数据接收完毕 计数器无变化
return UART_EOK;
//以上条件都不满足
uart1_cntPre = uart1_cnt;
return UART_ERROR;
}
7将BUF清空以便于下一次的接收,如果上一次的数据在里面会造成不必要的问题
void uart1_rx_clear(void)
{
//对接收寄存器进行清空
memset(&uart1_rx_buf,0,sizeof(uart1_rx_buf));
uart1_rx_len = 0;
}
8测试函数
void uart1_receiv_test(void)
{
//在while中一直调用该函数
//数据接收完整就打印出来
//重定向fputc
if(uart1_wait_receive() == UART_EOK)
{
printf("recv: %s\r\n", uart1_rx_buf);
uart1_rx_clear();
}
}
9 main函数
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9);/* 设置时钟, 72Mhz */
uart1_init(115200); /* LED初始化 */
while(1)
{
uart1_receiv_test();
delay_ms(10)
}
}
10 运行结果