前言
之前的一篇文章中我为了可以实现USART接收任意长度的数据,对HAL的库进行了修改,可以实现接收以0x0a结尾的任意长度数据,即认为接收到0x0a时接收结束,见链接:HAL USART接收任意长度。
然而,上述这种方法并不合适,原则上HAL库一般不去修改,不便于其他人移植程序,降低了程序中库的适用性,这是很不好的习惯,所以这种方法并不可取。
后查资料得知STM32中还可以利用DMA的方式实现串口的任意长度数据的接收,故开始学习DMA+串口接收任意长度的数据这种方式。
cubeMX软件配置过程
首先,第一步都是进行时钟树的配置,配置好系统的时钟,不同的芯片配置不同的时钟频率,如图。
接着,配置USART1,选择异步asynchronous,软件自动配置了PA9和PA10管脚。
然后,继续添加USART1的发送和接收DMA,其余默认即可。
接着,勾选上USART1的中断使能。
最后,生成MDK-ARM V5版本环境的程序。
UASRT串口程序修改
//添加变量,为什么用关键字volatile见链接:[链接](http://blog.csdn.net/u014470361/article/details/78830147)
volatile uint8_t rx_len=0;
volatile uint8_t recv_end_flag=0;
uint8_t rx_buffer[200];
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
//上面的usart配置代码为cubemx自动生成的,在下方添加使能idle中断和打开串口DMA接收语句
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能idle中断
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//打开DMA接收,数据存入rx_buffer数组中。
}
接下来修改串口中断函数。
void USART1_IRQHandler(void)
{
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
if((tmp_flag != RESET))//idle标志被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
temp = huart1.Instance->SR; //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
temp = huart1.Instance->DR; //读取数据寄存器中的数据
HAL_UART_DMAStop(&huart1); //
temp = hdma_usart1_rx.Instance->NDTR;// 获取DMA中未传输的数据个数,NDTR寄存器分析见下面
rx_len = BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
recv_end_flag = 1; // 接受完成标志位置1
}
HAL_UART_IRQHandler(&huart1);
}
DMA通道结构体中定义了NDTR寄存器,那为什么是未传输的数据数呢,STM32的中文手册给出了该寄存器的具体说明。
typedef struct
{
__IO uint32_t CR; /*!< DMA stream x configuration register */
__IO uint32_t NDTR; /*!< DMA stream x **number of data register** */
__IO uint32_t PAR; /*!< DMA stream x peripheral address register */
__IO uint32_t M0AR; /*!< DMA stream x memory 0 address register */
__IO uint32_t M1AR; /*!< DMA stream x memory 1 address register */
__IO uint32_t FCR; /*!< DMA stream x FIFO control register */
} DMA_Stream_TypeDef;
接着,编写主函数中串口中断的处理函数。
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
while (1)
{
if(recv_end_flag ==1)
{
printf("rx_len=%d\r\n",rx_len);//打印接收长度
HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);接收数据打印出来
for(uint8_t i=0;i { rx_buffer[i]=0;//清接收缓存 } rx_len=0;//清除计数 recv_end_flag=0;//清除接收结束标志位 } HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//重新打开DMA接收 } } 程序的运行效果如下图所示 ,输入任意长度数据,串口打印出接收的数据长度并打印出接收的数据。本程序设置的接收长度最大BUFFER_SIZE是200,若想接收更长的数据,也可以把BUFFER_SIZE和数组长度改大。
上一篇:STM32—DMA使用
下一篇:STM32—printf函数重定义
推荐阅读最新更新时间:2024-03-16 16:23