文章目录

  • 前言
  • STM32CUBE配置
  • 配置串口
  • 代码分析与修改
  • 实验结果

前言

本文主要介绍 串口实验 的通过STM32CUBE形式和直接编程模式的不同。 本文可以参考博客<STM32F429第十四篇之串口实验详解>。

两种方式实验的效果完全相同:

  • 在程序启动时,会发送信息 hello,zhy!
  • 在程序运行时,LED等闪烁。
  • 向串口1 发送数据,其会返回相同的数据。

该实验源代码下载https://github.com/zhenhaiyang/STM32CUBE

本文主要参考资料:

  • 正点原子.STM32F429开发指南-HAL库版本_V1.1

STM32CUBE配置

关于LED灯的配置部分,可以参考博客<STM32CubeMX第二篇之跑马灯>。本文不再重复介绍。

配置串口

  1. 配置Pinout。本实验使用的是PA9和PA10。首先配置为串口功能,如下图所示:

STM32cubemx配置usart_ARM

  1. 配置configuration。在此处经常需要配置GPIO,NVIC,RCC,USART等。本例程主要演示USART,如下所示:

STM32cubemx配置usart_UART_02

配置串口的参数。

STM32cubemx配置usart_stm32_03

配置串口的中断

STM32cubemx配置usart_ARM_04

配置串口的GPIO

STM32cubemx配置usart_串口_05

配置完成后,点击确定。

  1. 配置中断。

STM32cubemx配置usart_stm32_06

STM32cubemx配置usart_UART_07

最后,可以按照之前博客<STM32CubeMX第二篇之跑马灯>中介绍的方法生成代码。此处不再介绍。

代码分析与修改

1. 添加代码

添加三部分代码:

  1. 对列相关
  2. 延时相关
  3. 系统相关

其中,前两个部分与博客<STM32F429第十五篇之串口实验详解二>中介绍的完全相同。因为系统初始化还有串口部分都可以自动生成,所以,对系统相关的文件需要修改如下:

头文件与上述博客内容也是一致,如上所示:

/**
  ******************************************************************************
  * @file    sys.h
  * @author  zhy
  * @version 1.0
  * @date    2021-01-22
  * @brief   系统初始化相关的头文件
  ******************************************************************************
  */

#ifndef _SYS_H
#define _SYS_H
#include <stdint.h>

/* 位带操作 */
typedef struct
{
    unsigned int bit0 : 1;
    unsigned int bit1 : 1;
    unsigned int bit2 : 1;
    unsigned int bit3 : 1;
    unsigned int bit4 : 1;
    unsigned int bit5 : 1;
    unsigned int bit6 : 1;
    unsigned int bit7 : 1;
    unsigned int bit8 : 1;
    unsigned int bit9 : 1;
    unsigned int bit10 : 1;
    unsigned int bit11 : 1;
    unsigned int bit12 : 1;
    unsigned int bit13 : 1;
    unsigned int bit14 : 1;
    unsigned int bit15 : 1;
    unsigned int rsv : 16;

} BitBand __attribute__((bitband));

extern BitBand PAin;
extern BitBand PBin;
extern BitBand PCin;
extern BitBand PDin;
extern BitBand PEin;
extern BitBand PFin;
extern BitBand PGin;
extern BitBand PHin;
extern BitBand PIin;

extern BitBand PAout;
extern BitBand PBout;
extern BitBand PCout;
extern BitBand PDout;
extern BitBand PEout;
extern BitBand PFout;
extern BitBand PGout;
extern BitBand PHout;
extern BitBand PIout;

#endif

C文件

/**
  ******************************************************************************
  * @file    sys.c
  * @author  zhy
  * @version 1.0
  * @date    2021-01-22
  * @brief   系统初始化相关,配置RCC时钟,中断分组
  ******************************************************************************
  */
#include "sys.h"
#include "stm32f4xx.h"

/* 全局变量 */
BitBand PAin __attribute__((at(GPIOA_BASE + 16)));
BitBand PBin __attribute__((at(GPIOB_BASE + 16)));
BitBand PCin __attribute__((at(GPIOC_BASE + 16)));
BitBand PDin __attribute__((at(GPIOD_BASE + 16)));
BitBand PEin __attribute__((at(GPIOE_BASE + 16)));
BitBand PFin __attribute__((at(GPIOF_BASE + 16)));
BitBand PGin __attribute__((at(GPIOG_BASE + 16)));
BitBand PHin __attribute__((at(GPIOH_BASE + 16)));
BitBand PIin __attribute__((at(GPIOI_BASE + 16)));


BitBand PAout __attribute__((at(GPIOA_BASE + 20)));
BitBand PBout __attribute__((at(GPIOB_BASE + 20)));
BitBand PCout __attribute__((at(GPIOC_BASE + 20)));
BitBand PDout __attribute__((at(GPIOD_BASE + 20)));
BitBand PEout __attribute__((at(GPIOE_BASE + 20)));
BitBand PFout __attribute__((at(GPIOF_BASE + 20)));
BitBand PGout __attribute__((at(GPIOG_BASE + 20)));
BitBand PHout __attribute__((at(GPIOH_BASE + 20)));
BitBand PIout __attribute__((at(GPIOI_BASE + 20)));



/** 
 * @brief 重构函数 
 * @note 在printf中自动调用
 * @param {int} ch  发送的数据
 * @param {FILE} *f 此处用不到
 * @retval 当前发送值
 */
int fputc(int ch, FILE *f)
{
    while ((USART1->SR & USART_SR_TXE) == 0)
        ;                     //判断是否发送完成
    USART1->DR = (uint8_t)ch; //发送数据
    return ch;
}

去掉了系统初始化相关内容,将printf相关内容加入其中,这样,附加的内容就添加完毕。

我们所有的配置生成的代码和需要修改的代码都在该文件夹中,如下图所示:

STM32cubemx配置usart_ARM_08

在本例程中,除了上述分析的自己添加的文档三个文档,STM32CUBE自动生成的代码有:

  • stm32f4xx_hal_msp.c——底层初始化相关
  • main.c——主程序
  • stm32f4xx_it.c——中断响应相关

2.底层初始化

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * Initializes the Global MSP.
  */
void HAL_MspInit(void)
{
  /* USER CODE BEGIN MspInit 0 */

  /* USER CODE END MspInit 0 */

  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);

  /* System interrupt init*/
  /* MemoryManagement_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
  /* BusFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
  /* UsageFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
  /* DebugMonitor_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

  /* USER CODE BEGIN MspInit 1 */

  /* USER CODE END MspInit 1 */
}

该函数被函数UAL_Init()函数最后调用。通过该函数设置了中断优先组为2。

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);

    /* Peripheral interrupt init */
    HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }

}

该函数被HAL_UART_MspInit()函数调用。主要设置了串口相关的GPIO设置方法,以及串口对应的中断。

3.中断服务函数

/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

与本实验有关的串口中断服务函数原有定义为上文。但是,为了执行效率,不需要这么复杂。结合博客<STM32F429第十五篇之串口实验详解二>中的案例,将该函数修改为:

/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
    /* USER CODE BEGIN USART1_IRQn 0 */

    /* USER CODE END USART1_IRQn 0 */
    if ((USART1->SR & USART_SR_RXNE) && (USART1->CR1 & USART_CR1_RXNEIE)) //当接收中断置位且有中断标记
    {
        InQueue(&queueRx, USART1->DR); //将接收的内容放入队列,读取寄存器,自动清除中断标记位
    }
    /* USER CODE BEGIN USART1_IRQn 1 */

    /* USER CODE END USART1_IRQn 1 */
}

为了程序可以顺利执行还需要在该文档头部增加内容:

STM32cubemx配置usart_串口_09

至此,中断服务部分修改完毕。

4. 主文档

一、添加头文件:

#include "stm32f4xx_hal.h"
#include "queue.h"
#include "sys.h"
#include "delay.h"

添加外部全局变量引用:

extern Queue QueueRx;

总体如下:

STM32cubemx配置usart_串口_10

二、修改串口初始化

void MX_USART1_UART_Init(void)
{
    UART_HandleTypeDef huart1; //将全局变量添加到此
    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;
    HAL_UART_Init(&huart1);

    __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //开启接收中断
}

最后一行为我添加的使能接收中断。

至此程序完成。

int main(void)
{

    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration----------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* Configure the system clock */
    SystemClock_Config();

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();

    /* USER CODE BEGIN 2 */
    InitQueue(&queueRx);
    printf("hello, world!\n");
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        uint8_t temp = 0;
        /* USER CODE END WHILE */
        while (DeQueue(&queueRx, &temp))
        {
            while ((USART1->SR & USART_SR_TXE) == 0)
                ;
            USART1->DR = temp;
        }
        PBout.bit0=0;
        PBout.bit1=1;
        delay_ms(20);
        PBout.bit0=1;
        PBout.bit1=0;
        delay_ms(20);

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

主程序和原来大致一致。

实验结果

STM32cubemx配置usart_UART_11