(三)STM32F407 cubemx串口中断通讯

(三)STM32F407 cubemx串口中断通讯

这篇文章主要是个人的学习经验,想分享出来供大家提供思路,如果其中有不足之处请批评指正哈。

废话不多说直接开始主题,本人是基于STM32F407VET6芯片,但是意在你看懂这篇文章后,不管是F1,F4,H7等一系列系统串口通讯配置都能明白如何通过参考手册去学习配置。而不是Ctrl c,Ctrl v。
串口通讯其实cubemx已经把步骤精简的不能再精简了,但是秉持着不断学习的理念,有必要去大概学习一下串口协议,以及cubemx是如何根据参考手册封装的。

(三)STM32F407 cubemx串口中断通讯_第1张图片以上是串口协议比较重要的几个点,跟着参考手册一个一个点的讲解,了解串口协议的重点。首先串口主要有3根线TX、RX、GND。根据以上的几个点知一个串口数据包主要由1.起始位 2.数据字 3.停止位构成其他的寄存器都是围绕它们为它们服务。

(三)STM32F407 cubemx串口中断通讯_第2张图片接下来我将参照串口助手一步步讲解。
(三)STM32F407 cubemx串口中断通讯_第3张图片
1)波特率
发送和接收由一共用的波特率发生器驱动,当发送器和接收器的使能位分别置位时,分别为其产生时钟。波特率从某种意义上来说,它就是时钟的一种表现形式,115200意思是1秒内产生115200个高低电平变化。一个8位字长的串口数据=8字长+1起始位+1停止位=10;也就是1秒钟能发送115200/10=11520个数据,也就是1/11520=86us平均86us发一个‘A’(数据)。

(三)STM32F407 cubemx串口中断通讯_第4张图片2)停止位
USART支持多种停止位的配置:0.5、1、1.5和2个停止位。
1.1个停止位:停止位位数的默认值。
2.2个停止位:可用于常规USART模式、单线模式以及调制解调器模式
3. 0.5个停止位:在智能卡模式下接收数据时使用。
4.1.5个停止位:在智能卡模式下发送和接收数据时使用。空闲帧包括了停止位
(三)STM32F407 cubemx串口中断通讯_第5张图片停止位是通讯双方需要一致的,通常情况都是默认为1。在USART__CR2中编程停止位的位数。
若停止位需要更改长度
方一cubemx自动配置(三)STM32F407 cubemx串口中断通讯_第6张图片
方二代码hal库代码调用
(三)STM32F407 cubemx串口中断通讯_第7张图片在这里插入图片描述hal库只提供了两种一个停止位,和两个停止位的定义

3)起始位中断信号产生
在USART中,如果辨认出一个特殊的采样序列,那么就认为侦测到一个起始位。该序列为:1110X0X0X0000
(三)STM32F407 cubemx串口中断通讯_第8张图片
起始位的开始标志是1110低电平下降沿,当下降沿触发时它会间隔采样,X就是它采样的信号是不确定的,但是若需要进入串口中断必须每一次采样的X(采样点为3,5,7,8,9,10)都为0才可确认收到起始位,这时设置RXNE标志位,如果RXNEIE=1,则产生中断。若其中采样X为1不管什么原因,返回空闲状态等待下降沿。

4)数据位
USART可以根据USART_CR1的M位接收8位或9位的数据字
8位数据的信号是和ASCLL码表一一对应的比如‘A’=65=0x41=01000001 8位传输的数据就是低高低低低低低高
(三)STM32F407 cubemx串口中断通讯_第9张图片
5)奇偶校验
设置USART_CR1寄存器上的PCE位,可以使能奇偶控制(发送时生成一个奇偶位,接收时进行奇偶校验)。根据M位定义的帧长度,可能的USART帧格式列在下表中。
(三)STM32F407 cubemx串口中断通讯_第10张图片偶校验:校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为偶数。
例如:数据=00110101,有4个1’,如果选择偶校验(在USART_CR1中的PS=0),校验位将是’0’。4个1凑个偶数,校验位为0
奇校验:此校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为奇数。
例如:数据=00110101,有4个’1’,如果选择奇校验(在USART_CR1中的PS=1),校验位将是’1’。4个1凑个奇数,还需一个1,校验位为1
这是参考手册的例子很清楚,但是可能是自己才疏学浅本人并不知道校验位有什么很大的作用,有大佬的话可以评论区指导一下。
(三)STM32F407 cubemx串口中断通讯_第11张图片

我们默认使用的是第一种00
在这里插入图片描述

0x0000u这样的常数一律默认为int型0,不是什么字节。

关键内容讲完了开始cubemx配置实现功能

基础时钟配置等请见:http://t.csdnimg.cn/XQ0L6
(三)STM32F407 cubemx串口中断通讯_第12张图片中断勾上
(三)STM32F407 cubemx串口中断通讯_第13张图片(三)STM32F407 cubemx串口中断通讯_第14张图片(三)STM32F407 cubemx串口中断通讯_第15张图片(三)STM32F407 cubemx串口中断通讯_第16张图片
(三)STM32F407 cubemx串口中断通讯_第17张图片
keil5处点击魔术棒,给红框处打上勾。

(三)STM32F407 cubemx串口中断通讯_第18张图片
dubug处我用的下载器是DAP可能和你们的不一样,勾上重新下载程序后复位功能。

  uint8_t AA='A';
  HAL_UART_Transmit(&huart1,&AA,1,10000);

HAL_UART_Transmit函数语法很简单,只要配置串口号,内容,内容长度,发送时间即可
主函数

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	uint8_t AA='A';
  HAL_UART_Transmit(&huart1,&AA,1,10000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

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

考虑到重定义函数printf只有一个串口可用,本人给大家提供了printf转译其他串口也可使用printf
主函数部分

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include 
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern UART_HandleTypeDef huart1;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern uint8_t uart1_rxbuf[10];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
  * @brief  The application entry point.
  * @retval int
  */
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();
  /* USER CODE BEGIN Init */
  /* USER CODE END Init */
  /* Configure the system clock */
  SystemClock_Config();
  /* USER CODE BEGIN SysInit */
  /* USER CODE END SysInit */
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	uint8_t AA='A';
  HAL_UART_Transmit(&huart1,&AA,1,10000);
	u1_printf("您的身高:%.0f cm\r\n",2);
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

usart.h

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
#include 
#include "main.h"
#include "stdarg.h"		//包含需要的头文件 
#include "string.h"     //包含需要的头文件
/* USER CODE END Includes */
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN Private defines */
#define USART1_RX_ENABLE     0      //是否开启接收功能  1:开启  0:关闭
#define USART1_TXBUFF_SIZE   256    //定义串口1 发送缓冲区大小 256字节
#define USART1_RXBUFF_SIZE   256               //定义串口1 接收缓冲区大小 256字节
/* USER CODE END Private defines */
void MX_USART1_UART_Init(void);
/* USER CODE BEGIN Prototypes */
void u3_printf(char* fmt,...) ;
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */

usart.c

/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  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();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_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_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* 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 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
__align(8) char Usart1_TxBuff[USART1_TXBUFF_SIZE];  
void u1_printf(char* fmt,...) 
{  
	unsigned int i,length;
	va_list ap;
	va_start(ap,fmt);
	vsprintf(Usart1_TxBuff,fmt,ap);
	va_end(ap);	
	
	length=strlen((const char*)Usart1_TxBuff);		
	while((USART1->SR&0X40)==0);
	for(i = 0;i < length;i ++)
	{			
		USART1->DR = Usart1_TxBuff[i];
		while((USART1->SR&0X40)==0);	
	}	
}
/* USER CODE END 1 */

实验效果
(三)STM32F407 cubemx串口中断通讯_第19张图片
串口发送中断主函数

	HAL_UART_Receive_IT(&huart1,&Data, sizeof(Data));//开启中断接收数据
	uint8_t IT_SEND[]="IT_SEND";
	HAL_UART_Transmit_IT(&huart1,IT_SEND, sizeof(IT_SEND)/sizeof(IT_SEND[0]));
	u1_printf("\r\n");

只需要在主函数处添加这一部分代码。
效果图
(三)STM32F407 cubemx串口中断通讯_第20张图片串口中断接收本人采用的方式是结束位为0x5c串口接收结束,长度不可大于15个字节,实例代码如下

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == &huart1)
	{
		  if(recv_end_flag_1==1)
			{
				 for(int i=0;i<sizeof(rx_buffer1)/sizeof(rx_buffer1[0]);i++)
				{
					 rx_buffer1[i]=0;
				}
				recv_end_flag_1 = 0;          //数据清空
			}
			rx_buffer1[Cnt]=Data;
			Cnt++;
			if(rx_buffer1[Cnt-1] == 0x5C)//判断是否为'\'结尾
			{
				//rx_buffer1[Cnt-1] = 0x0a; 
				u1_printf("\n接收到的数据为:\n");
				HAL_UART_Transmit(&huart1,rx_buffer1,Cnt,10000);//显示在串口助手
				Cnt = 0;
				recv_end_flag_1 = 1;          //数据接收完成
				for(int i=0;i<sizeof(rx_buffer1)/sizeof(rx_buffer1[0]);i++)
				{
					 rx_buffer1[i]=0;
				}
			}
		HAL_UART_Receive_IT(&huart1,&Data,1);//继续接收数据
	}
} 

(三)STM32F407 cubemx串口中断通讯_第21张图片显示效果如图。

整体的所有代码以及数据手册链接:
链接:https://pan.baidu.com/s/1xmEUNd82dunSmh_NyI09fg?pwd=6dqr
提取码:6dqr
希望这篇文章对你有所帮助。

你可能感兴趣的:(stm32,单片机,嵌入式硬件)