STM32F4_HAL库_串口阻塞/中断/DMA三种方式发送数据的配置

1、串口阻塞发送

串口阻塞发送的意思就是,发送一段数据,在没有发送完所有数据之前,一直停留在此发送函数(可设定阻塞时间),这个过程中会阻塞别的程序运行;

1.1、配置

HAL库的配置分为两个层次,一个是HAL库内部调用的、与MCU硬件相关的初始化xxx_MspInit,一个是我们外部调用的初始化xxx_Init;

这两个初始化函数配置完,就可以进行阻塞式的串口发送了,很简单。

1.1.1、HAL_UART_MspInit 

HAL_UART_MspInit,MCU硬件初始化,需要开启RCC串口时钟、RCC的GPIO端口时钟、配置GPIO的模式;

(还有个反初始化HAL_UART_MspDeInit,这里就不说了)

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	if(huart->Instance==DEBUG_USARTx){
		/* 时钟使能 */
		DEBUG_USART_RCC_CLK_ENABLE();
		DEBUG_USARTx_GPIO_ClK_ENABLE(); 
		  
		/* 串口外设功能GPIO配置 */
		GPIO_InitStruct.Pin = DEBUG_USARTx_Tx_GPIO_PIN;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
		GPIO_InitStruct.Alternate = DEBUG_USARTx_AFx;
		HAL_GPIO_Init(DEBUG_USARTx_Tx_GPIO, &GPIO_InitStruct);

		GPIO_InitStruct.Pin = DEBUG_USARTx_Rx_GPIO_PIN;  
		HAL_GPIO_Init(DEBUG_USARTx_Tx_GPIO, &GPIO_InitStruct);       
	}  
}

1.1.2、MX_DEBUG_USART_Init

MX_DEBUG_USART_Init,串口协议初始化,波特率、数据宽度、停止位、串口模式的配置;

void MX_DEBUG_USART_Init(void)
{
	husart_debug.Instance = DEBUG_USARTx;
	husart_debug.Init.BaudRate = DEBUG_USARTx_BAUDRATE;
	husart_debug.Init.WordLength = UART_WORDLENGTH_8B;
	husart_debug.Init.StopBits = UART_STOPBITS_1;
	husart_debug.Init.Parity = UART_PARITY_NONE;
	husart_debug.Init.Mode = UART_MODE_TX_RX;
	husart_debug.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	husart_debug.Init.OverSampling = UART_OVERSAMPLING_16;
	HAL_UART_Init(&husart_debug);
}

1.2、调用

外部调用的初始化就是MX_DEBUG_USART_Init,然后就可以使用HAL_UART_Transmit函数来发送数据了。

static uint8_t uart1_tx_buf[]="123456789";
int main(void)
{
    HAL_Init();            //复位所有外设,初始化Flash接口和系统滴答定时器
    SystemClock_Config();  //配置系统时钟
    LED_GPIO_Init();	    
    MX_DEBUG_USART_Init(); //串口初始化

    while (1){
        LED1_ON;     HAL_Delay(1000);
        LED1_OFF;    HAL_Delay(1000);	  
        HAL_UART_Transmit(&husart_debug,uart1_tx_buf,8,1000);
    }
}

2、串口中断发送

串口中断发送的意思就是,发送数据的过程在中断中进行,这个中断实际上是发送数据寄存器空的中断。

比如说你要发送10个字节的数据,那么肯定这10个字节不会一次性发送完吧,只能是一个一个字节地发送。每发送一个字节,发送数据寄存器就会有一个为空的标志,以提示可以发送下一个字节了,这样在发送数据的过程中CPU不会一直在等待,而是用中断来提示需要进行发送的时候再发送。

2.1、配置

在1的基础上,HAL_UART_MspInit 函数的末尾增加串口中断配置,如下:

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	if(huart->Instance==DEBUG_USARTx){
        //这部分配置不变......  

		/* USART1 interrupt Init */
		HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
		HAL_NVIC_EnableIRQ(USART1_IRQn);   
	}  
}

 增加串口1的中断服务函数,具体的功能不用我们写;

void USART1_IRQHandler(void){
	HAL_UART_IRQHandler(&husart_debug);
}

2.2、调用

和1的外部调用的初始化是一样的,发送函数使用HAL_UART_Transmit_IT;

3、串口DMA发送

3.1、配置

注:必须增加串口的中断配置(如2的配置),否则会出现只能发送一次的尴尬局面,3.1.2中的DMA中断也必须配置,否则也是只能发送一次,不过这一处的配置应该不会漏就是了;

3.1.1、HAL_UART_MspInit

在2的基础上,增加有关DMA的配置,数据流、通道、传输方向、地址自增与否等等;(可以用CubeMX勾勾选选生成配置代码,然后再移植到自己的代码上)

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	if(huart->Instance==DEBUG_USARTx){
		//这部分配置不变...... 

		/* USART1 DMA 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_LOW;
		hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
		HAL_DMA_Init(&hdma_usart1_tx);

		__HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);

		/* USART1 interrupt Init */
		HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
		HAL_NVIC_EnableIRQ(USART1_IRQn);  
	}  
}

3.1.2、UART1_DMA_Init

UART1_DMA_Init,这里面就是开启DMA时钟,配置DMA的优先级;

DMA流的中断服务函数也是只写到这就OK了;

void UART1_DMA_Init(void)
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

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

void DMA2_Stream7_IRQHandler(void){
	HAL_DMA_IRQHandler(&hdma_usart1_tx);	
}

3.2、调用

要先调用DMA初始化,再调用串口初始化;

因为串口初始化中有配置DMA的参数等操作,所以在这之前DMA需要初始化;

static uint8_t uart1_tx_buf[]="123456789";
int main(void)
{
    HAL_Init();            //复位所有外设,初始化Flash接口和系统滴答定时器
    SystemClock_Config();  //配置系统时钟
    LED_GPIO_Init();
    UART1_DMA_Init();      //串口DMA初始化	    
    MX_DEBUG_USART_Init(); //串口初始化

    while (1){
        LED1_ON;     HAL_Delay(1000);
        LED1_OFF;    HAL_Delay(1000);	  
        HAL_UART_Transmit_DMA(&husart_debug,uart1_tx_buf,8);
    }
}
### STM32F4 UART Redirection Using HAL Library Implementation For implementing UART redirection on the STM32F4 series microcontroller with the Hardware Abstraction Layer (HAL) library, configuring standard output to be redirected through a serial interface is essential. This allows printf statements or other console outputs to appear over UART instead of being lost as they would normally when running embedded code without such configuration. To achieve this functionality, initialization of the UART peripheral must occur first by setting up parameters like baud rate, word length, stop bits, parity control, hardware flow control, and mode (transmitter/receiver)[^1]. Following proper setup, `stdout` should then point towards the desired UART instance so that any calls made to functions like printf will send data out via the specified port rather than attempting to use non-existent system-level I/O facilities found within desktop operating systems. Below demonstrates how one might go about performing these tasks: #### Initialization Code Example ```c #include "stm32f4xx_hal.h" UART_HandleTypeDef huart1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); int __io_putchar(int ch); /* Required for redirecting putchar */ int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); while(1){ // Your application logic here. } } /* Function used to initialize USART1 */ static void MX_USART1_UART_Init(void){ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; // Set Baud Rate value according to your needs huart1.Init.WordLength = UART_WORDLENGTH_8B;// Configure Word Length parameter huart1.Init.StopBits = UART_STOPBITS_1; // Choose number of Stop Bits huart1.Init.Parity = UART_PARITY_NONE; // Select Parity Control method huart1.Init.Mode = UART_MODE_TX_RX; // Enable Transmitter & Receiver modes huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; // Disable HW Flow Control huart1.Init.OverSampling = UART_OVERSAMPLING_16; if(HAL_UART_Init(&huart1)!= HAL_OK){ // Initialize UART Peripheral Error_Handler(); // Handle errors appropriately } } ``` The above example initializes USART1 at a baudrate of 115200 bps configured for asynchronous communication where no hardware handshaking takes place between devices connected across TX/RX lines. The next step involves overriding `_write()` function which gets called internally whenever characters are sent from high level APIs including but not limited to printf(). By doing so, every character intended originally for display purposes now goes directly into transmit buffer associated with chosen UART channel before getting transmitted physically outside MCU pins. #### Redirect Putchar Definition ```c // Overriding weak symbol provided by newlib nano spec __attribute__((weak)) int _write(int fd, char *ptr, int len){ uint8_t i=0; for(i=0;i<len;i++){ ITM_SendChar(*ptr++); } return len; } ``` Alternatively, another approach could involve redefining `putchar()`. However, using `_write()` ensures compatibility even when different C libraries come into play during project development phases since most implementations rely upon it under-the-hood anyway. In conclusion, after completing both steps mentioned earlier—initializing relevant peripherals alongside altering default behavior tied specifically around sending bytes meant initially for terminal emulation—one achieves successful redirection capabilities allowing easier debugging sessions especially useful throughout early stages involved in firmware creation processes targeting ARM Cortex-M based platforms similar to those belonging inside STMicroelectronics' popular STM32 family members.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值