参考资料:1、ST HAL库官网资料

2、https://blog.csdn.net/u014470361/article/details/79206352#comments

一、STM32CubeMX配置外部时钟

注意在进行外部时钟配置时,即“High Speed Clock”和“Low Speed Clock”需配置成“Crytal/Ceramic Resonator(低温/陶瓷谐振器)”不能配置为"BYASS Clock Source(时钟脉冲源)",否则系统起不来。

二、SWD下载接口配置

如果用HAL库不进行SWD或JTAG配置,单片机只能进行下载一次程序,要进行第二次或更多次程序下载,需要按复位键(如果你的单片机有复位按键的话),或者用镊子夹住复位线路上的电容使其短路,点击Keil下载,再松开镊子。

三、串口1(USART1)配置

四、时钟树配置(外部低速晶振32.768kHz,外部高速晶振8MHz)

五、串口DMA配置

六、软件配置

#define BUFFER_SIZE  100

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_tx;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma;

volatile uint8_t rx_len = 0;             //接收一帧数据的长度
volatile uint8_t recv_end_flag = 0;    //一帧数据接收完成标志
uint8_t rx_buffer[100]={0};   //接收数据缓存

/*
*********************************************************************************************************
*    函 数 名: MX_GPIO_Init
*    功能说明: /GPIO时钟初始化函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void MX_GPIO_Init(void)  //GPIO时钟初始化
{
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
}

/*
*********************************************************************************************************
*    函 数 名: MX_DMA_Init
*    功能说明: 串口DMA时钟初始化函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

/* DMA interrupt init */
  /* DMA2_Stream2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
  /* DMA2_Stream7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}

/*
*********************************************************************************************************
*    函 数 名: MX_USART1_UART_Init
*    功能说明: 串口功能初始化函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
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__);
  }    
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);          //使能IDLE中断

//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
    HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
}

/*
*********************************************************************************************************
*    函 数 名: HAL_UART_MspInit
*    功能说明: 串口DMA功能初始化函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  if(huart->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

/* USER CODE END USART1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
  
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* USART1 DMA Init */
    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA2_Stream7;
    hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }

__HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);

/* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA2_Stream2;
    hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }

__HAL_LINKDMA(huart,hdmarx,hdma_usart1_rx);

/* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

/* USER CODE END USART1_MspInit 1 */
  }
}

/*
*********************************************************************************************************
*    函 数 名: DMA_Usart_Send
*    功能说明: 串口发送功能函数
*    形    参: buf,len
*    返 回 值: 无
*********************************************************************************************************
*/
void DMA_Usart_Send(uint8_t *buf,uint8_t len)//串口发送封装
{
   if(HAL_UART_Transmit_DMA(&huart1, buf,len)!= HAL_OK)
        {
            Error_Handler();
        }
    /*##-3- Wait for the end of the transfer ###################################*/  
    while (UartReady != SET){}
    /* Reset transmission flag */
    UartReady = RESET;
}

/*
*********************************************************************************************************
*    函 数 名: DMA_Usart1_Read
*    功能说明: 串口接收功能函数
*    形    参: Data,len
*    返 回 值: 无
*********************************************************************************************************
*/
void DMA_Usart1_Read(uint8_t *Data,uint8_t len)//串口接收封装
{
   HAL_UART_Receive_DMA(&huart1,Data,len);//重新打开DMA接收
}

/*
*********************************************************************************************************
*    函 数 名:main
*    功能说明: main主函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  
  while (1)
  {
    if(recv_end_flag == 1)   //接收完成标志
    {
        DMA_Usart_Send(rx_buffer, rx_len);
        rx_len = 0;//清除计数
        recv_end_flag = 0;//清除接收结束标志位
        memset(rx_buffer,0,sizeof(rx_buffer));
    }    
  }
}

/*
*********************************************************************************************************
*    函 数 名:DMA2_Stream2_IRQHandler
*    功能说明: 串口DMA接收中断函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void DMA2_Stream2_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma_usart1_rx);
}

/*
*********************************************************************************************************
*    函 数 名:DMA2_Stream7_IRQHandler
*    功能说明: 串口DMA发送中断函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void DMA2_Stream7_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma_usart1_tx);
}

/*
*********************************************************************************************************
*    函 数 名:USART1_IRQHandler
*    功能说明: 串口中断函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void USART1_IRQHandler(void)    //串口中断
{
    uint32_t tmp_flag = 0;
    uint32_t temp;
    
    HAL_UART_IRQHandler(&huart1);
    if(USART1 == huart1.Instance){
        tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
            
        if((tmp_flag != RESET))//idle标志被置位
        { 
            recv_end_flag = 1;  // 接受完成标志位置1 
            __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位                     
 //           temp = UartHandle.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
//            temp = UartHandle.Instance->DR; //读取数据寄存器中的数据

HAL_UART_DMAStop(&huart1); //     
            temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数                     
            rx_len =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
               
            HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//重新打开DMA接收
        }
    }
 }

博主注明:

temp = UartHandle.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
temp = UartHandle.Instance->DR; //读取数据寄存器中的数据

这两句被屏蔽的原因是它们实现的功能和这下面串口IDLE状态寄存器SR标志位清零的宏定义实现的功能是一样的:

__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位

我们可以点击这个宏定义进去看看,它实现的功能和上面两句是一样的:

#define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)

七、串口调试助手打印

此处的IDLE中断实现的是接收1帧数据后发生一次中断,RXNE中断实现的是接收一个字节后产生中断,需要详细了解的,请自行查看其它资料,这里不做讲解。

下面链接可下载具体的源码:

https://download.csdn.net/download/euxnijuoh/10606293,代码码的不专业,请见谅!

STM32CubeMX HAL库串口+DMA数据发送不定长度数据接收相关推荐

  1. STM32 HAL库 串口DMA接收不定长数据

    STM32 HAL库 串口DMA接收不定长数据 整体思路:我是用的CUBEMX软件生成的工程,使能了两个串口,串口2用来接收不定长的数据,串口1用来发送串口2接收到的数据:串口2我找了一个UBLOX卫 ...

  2. STM32 HAL库 串口DMA(收发)和STM32串口中断接收(接收时间管理机制)+ESP8266 wifi模组通信问题

    一.HAL库 串口 DMA+ESP8266模组通信问题 用STM32 HAL库串口的DMA发送和空闲中断接收处理数据,单片机发送AT指令给ESP8266 wifi模组问题:单片机连续几次给wifi模组 ...

  3. hal库串口dma卡死_HAL库版DMA循环模式串口数据收发

    在<STM32CubeMX初识与工程创建>的基础上,首先对串口进行设置,以实现通过串口对数据的收发.STM32CubeMX生成的HAL库中,提供了三类串口数据收发的接口,分别为阻塞模式,非 ...

  4. 【STM32】HAL库——串口DMA通信(三)

    前期准备: STM32CubeMX STM32RCT6核心板 IDE Keil(MDK-ARM) 关于DMA 1. 什么是DMA? DMA(Direct Memory Access,直接存储器访问) ...

  5. hal库串口dma卡死_STM32 HAL库 串口DMA发送完成中断

    近期使用STM32驱动MAX3485进行485通信,发现STM32F103C8并不自带硬件485首发功能,需要软件上控制IO高低来驱动MAX3485进行485接收.485发送. 根据MAX3485手册 ...

  6. STM32从零到一,从标准库移植到HAL库,UART串口1以DMA模式收发不定长数据代码详解+常见问题 一文解析

    前言 本文的参考资料 感谢提供标准库版本的CSDN同学:这两篇文章至少是我看过的最详细的标准库配置DMA版本.而且代码实测稳定能用. STM32 | DMA配置和使用如此简单(超详细)_...| .. ...

  7. STM32 HAL库串口收发数据

    STM32 HAL库串口收发数据 许多传感器的使用方法是:单片机给传感器发送一帧数据,然后传感器返回单片机一帧有用数据,所以串口的收发功能十分重要. STM32cubeMX的配置 时钟和下载方式就不讲 ...

  8. STM32CubeMX | HAL库的ADC多通道数据采集(轮训、DMA、DMA+TIM)、读取内部传感器温度

    STM32CubeMX | HAL库的ADC多通道数据采集(轮训.DMA.DMA+TIM).读取内部传感器温度 目录 STM32CubeMX | HAL库的ADC多通道数据采集(轮训.DMA.DMA+ ...

  9. STM32 HAL库串口同时收发,接收卡死?

    STM32 使用 HAL库串口同时收发,使用踩坑史 = =!......by 矜辰所致 目录 前言 一. HAL 库串口收发 1.1 串口发送 1.2 串口接收 1.2.1 标准库接收 1.2.1 H ...

最新文章

  1. android.view.WindowManager$BadTokenException: Unable to add window — token null
  2. 使用application log 分析navigation target解析错误
  3. leetcode53. 最大子序和详解——pygo
  4. fluke196c系统语言,原装二手福禄克Fluke196C 电工仪表
  5. python计算凸包并绘制凸包曲线
  6. matlab 判断整除函数_判断素数函数
  7. C#中只使用Invokerequired来判断是不是UI线程可靠吗?
  8. 安卓和ios的ui设计区别_【交互设计】 也许这些才是你作品集最需要的
  9. 桌面窗口管理器和csrss导致Windows的GPU和内存占用过高而卡顿
  10. Java-Aspose实现上传Excel、Word转换为PDF并进行下载
  11. 物联网 毕业设计——方案选择
  12. modbus模拟器基本使用
  13. SDU程序设计思维Week5-作业 B-TT's Magic Cat
  14. C语言数据的表现形式及其运算
  15. 三博脑科医院:癫痫的治疗像是一场“对抗赛”
  16. 太赞了!华为工程师总结的Linux+K8S笔记,提供下载
  17. 贝叶斯课后习题(零)常用分布
  18. idea栏目字体过大,不能恢复,影响设置的解决方法
  19. excel写为字节流使用base64加解密
  20. html5中comment注释咋用,comment的用法总结大全

热门文章

  1. OpenLayers加载搜狗地图
  2. Android ListView 圆角
  3. RedHat Enterprise LInux 6.3 安装Oracle Database 11g
  4. asp.net关于kindeditor 上传图片出现服务器故障的解决办法
  5. make的常见错误信息
  6. javascript获取textarea中光标的位置 兼容
  7. 如果C++程序要调用已经被编译后的C函数,该怎么办?
  8. JavaScript 基础(十):循环语句
  9. linux系统的学习经验首篇
  10. 【Eclipse提高开发速度-插件篇】安装VJET插件,JS等提示开发插件