本次帖子主要是对STM32CubeMX生成的串口通信框架进行分析。 一、硬件分析。 1. 对于STM32F412来说一共有USART1,USART2,USART3,USART6四个同步异步通信接口,接口引脚定义如下: 因为串口1和串口3默认已经被使用,因此本次使用串口6进行通信实验。首先打开上一次新建的STM32CubeMX的工程。使能USART6模块。如下图所示: 时钟设置上一次评测也已经详细分析过,这里不做介绍。 串口参数设置:115200波特率,8数据位,1停止位,无校验。 开启串口6全局中断。 NVIC中断向量控制器设置:设置串口6的抢占优先级和次优先级都为0. 把上次评测写好的SYSTICK延时函数添加到现有工程中来,编译之后没有错误,下面是生成的框架结构。
二、生成的代码框架分析。 1. 重要结构体说明:首先对HAL中关于串口的主要结构体变量进行说明。首先对UART_HandleTypeDef这个结构体。其中的红框中的qian2两个主要是这次初始化时的重点之处。 Instance处主要存放的是寄存器基地址参数,类似于Windows编程中的实例句柄。当定义了UART_HandleTypeDef结构体变量,并对其中的Instance赋值某一个串口之后,以后对该串口的操作都可以通过对定义的UART_HandleTypeDef结构体变量进行操作来实现。 UART_InitTypeDef结构体主要是对串口进行初始化的相关参数设置,其中就包括我们经常设置的波特率,起始位停止位之类的。 2. 框架分析。 STM32CubeMX生成的函数中重要的一个函数是 MX_USART6_UART_Init();该函数主要是对串口的参数进行设置。下面是这个函数的主要内容。 该函数中的参数设置与我们之前使用STM32CubeMX生成代码时选择的设置是一样的。这里面主要重要的是这个函数: HAL_UART_Init(&huart6);进入该函数查看,其中有这样一句话: If中的判断语句主要是判断相关串口是否已经被初始化。如果没有被初始化就会执行if语句中的代码。 If语句中的函数HAL_UART_MspInit(huart);也是由STM32CubeMX生成的代码。如下图所示,这个函数主要是初始化与串口使用的硬件相关的GPIO口,这样写的好处是便于以后进行移植。 到此处就已经把串口相关的参数就已经初始化完成了。下面来看看中断响应函数如何对中断进行响应。 在STM32CubeMX生成的文件中,stm32f4xx_it.c文件中就定义了串口6的中断响应函数。 函数内部执行的函数 HAL_UART_IRQHandler(&huart6);主要是对发生的中断类别进行分辨,这样就确定调用哪一个中断相应函数。对于此我们比较关注的是UART_Receive_IT(huart);这个函数,用来进行中断接收响应的。 最终会执行我们自己写的HAL_UART_RxCpltCallback(huart);用来对接收中断进行处理。 3. 代码框架移植:为了提高代码的移植性,下面对整体生成的框架进行移植。代码移植之后主要添加了bsp_usart.c,bsp_usart.h文件,代码如下所示。 - //bsp_usart.h文件内容
- //串口初始化说明
- #ifndef __USART__
- #define __USART__
- /* 包含头文件 ----------------------------------------------------------------*/
- #include "stm32f4xx_hal.h"
- extern UART_HandleTypeDef huart6;//存放串口6相关的参数
- extern uint8_t rxbuf;//用于存放串口接收的数据
- //对于想使能串口接收中断使用函数 HAL_UART_Receive_IT()即可
- void MX_USART6_UART_Init(void);//串口6的初始化函数声明
- #endif
[color=rgb(51, 102, 153) !important]复制代码
- //bsp_usart.c文件内容
- #include "bsp_usart.h"
- UART_HandleTypeDef huart6;//存放串口1相关的参数
- uint8_t rxbuf;//用于存放串口接收的数据
- /* USART6 init function */
- void MX_USART6_UART_Init(void)
- {
- huart6.Instance = USART6;
- huart6.Init.BaudRate = 115200;
- huart6.Init.WordLength = UART_WORDLENGTH_8B;
- huart6.Init.StopBits = UART_STOPBITS_1;
- huart6.Init.Parity = UART_PARITY_NONE;
- huart6.Init.Mode = UART_MODE_TX_RX;
- huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
- huart6.Init.OverSampling = UART_OVERSAMPLING_16;
- HAL_UART_Init(&huart6);
- }
- //串口相关GPIO口初始化操作 该函数是弱函数不需要进行声明
- void HAL_UART_MspInit(UART_HandleTypeDef* huart)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- if(huart->Instance==USART6)
- {
- /* USER CODE BEGIN USART6_MspInit 0 */
- /* USER CODE END USART6_MspInit 0 */
- /* Peripheral clock enable */
- __HAL_RCC_USART6_CLK_ENABLE();
- /**USART6 GPIO Configuration
- PC6 ------> USART6_TX
- PC7 ------> USART6_RX
- */
- GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
- /* Peripheral interrupt init */
- HAL_NVIC_SetPriority(USART6_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(USART6_IRQn);
- /* USER CODE BEGIN USART6_MspInit 1 */
- /* USER CODE END USART6_MspInit 1 */
- }
- }
- /**
- * 函数功能: 串口硬件反初始化配置
- * 输入参数: huart:串口句柄类型指针
- * 返 回 值: 无
- * 说 明: 该函数被HAL库内部调用
- */
- void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
- {
- if(huart->Instance==USART6)
- {
- /* USER CODE BEGIN USART6_MspDeInit 0 */
- /* USER CODE END USART6_MspDeInit 0 */
- /* Peripheral clock disable */
- __HAL_RCC_USART6_CLK_DISABLE();
- /**USART6 GPIO Configuration
- PC6 ------> USART6_TX
- PC7 ------> USART6_RX
- */
- HAL_GPIO_DeInit(GPIOC, GPIO_PIN_6|GPIO_PIN_7);
- /* Peripheral interrupt DeInit*/
- HAL_NVIC_DisableIRQ(USART6_IRQn);
- }
- /* USER CODE BEGIN USART6_MspDeInit 1 */
- /* USER CODE END USART6_MspDeInit 1 */
- }
- //中断响应回调函数的定义
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- {
- if(huart->Instance==USART6)//串口6的接收中断
- {
- HAL_UART_Transmit(&huart6,&rxbuf,1,0);
- HAL_UART_Receive_IT(&huart6,&rxbuf,1);
- }
- }
[color=rgb(51, 102, 153) !important]复制代码
主函数代码: - int main(void)
- {
- /* USER CODE BEGIN 1 */
- uint8_t txbuf[50];
- /* 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_USART6_UART_Init();
- /* USER CODE BEGIN 2 */
- delay_init(100);
- memcpy(txbuf,"串口中断接收返回的通信实验",100);
- HAL_UART_Transmit(&huart6,txbuf,strlen((char *)txbuf),1000);
- /* 使能接收,进入中断回调函数 */
- HAL_UART_Receive_IT(&huart6,&rxbuf,1);
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);
- HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET);
- delay_ms(500);
- // HAL_Delay(200);
- HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET);
- HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET);
- // HAL_Delay(200);
- delay_ms(500);
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
[color=rgb(51, 102, 153) !important]复制代码
三、通信实验 2. 因为串口6是直接引出来的,其中没有串口转USB接口,因此我就用手头的一块 开发板做转接。硬件图如下所示: 连接关系一一对应即可。 3. 实际开发板连接图。 4. 通信测试。 开发板上电之后,串口接收到数据。跟发送的数据是一样的。 因为这个软件不是很好用,下面更换为我自己写的软件,并将端口号改为COM2。 接收情况如下: 程序能够正常运行。 四、总结 本次主要对生成的串口框架进行了分析,并将相关函数进行了移植,重新写了相关函数,下载到 单片机中后能够很好的实现相应的功能。
|