cubeMX STM32 HAL库Uart串口通讯以及printf重定向使用方法

STM32 HAL库Uart串口通讯以及printf重定向

介绍

是串口通讯有着简单可靠,跨平台应用,可拓展性强,使用范围也很普及等优点,使得它成为开发者最常用的通讯协议之一,配合串口调试助手使用也是开发者的调试好帮手。本文不过多讲述串口协议的底层原理,直接阐述基于cubeMX配置HAL库STM32的uart和printf重定向使用方法

UART通信

下面是USART1,USART2,USART3的通讯示例

cubeMX配置

点击Connectivity下拉菜单的USART1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
按上图步骤配置好串口后,点击生成代码,cubeMX配置步骤就已完成
在这里插入图片描述
建议也可以把这个勾选上,可以对每个模块独立生成.c 和.h文件,使main.c文件看起来没那么臃肿。

Uart程序

cubxMX配置好的初始化等程序这里不再过多赘述直接看需要更改的程序
下面cubeMX后main.c主要内容

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

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "myuart.h"
#include "stm32f1xx_hal.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

//myuart.h上定义的接收结构体
RX_struct RX={0};
RX_struct RX2={0};
RX_struct RX3={0};


/* 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)
{
  
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */

  /* 启动串口接收 */
  HAL_UART_Receive_IT(&huart1, &RX.rx_temp, 1);
	HAL_UART_Receive_IT(&huart2, &RX2.rx_temp, 1);
	HAL_UART_Receive_IT(&huart3, &RX3.rx_temp, 1);
	/*测试串口程序*/
	Myuart_sent_string(&huart1,"\r\nuart1 is ok !!\r\n");
	Myuart_sent_string(&huart2,"\r\nuart2 is ok !!\r\n");
	Myuart_sent_string(&huart3,"\r\nuart3 is ok !!\r\n");
	
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

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

myuart.c:
HAL_UART_RxCpltCallback函数可以根据自己需求更改

#include "myuart.h"
#include "usart.h"

extern RX_struct RX;
extern RX_struct RX2;
extern RX_struct RX3;

/**
  * @brief  发送一个字节
  * @param 	uart指针
	* @param 	要发送的字节数据
  * @retval	None
  */
void Myuart_sent_byte(UART_HandleTypeDef *huart,uint8_t ch)
{
	HAL_UART_Transmit(huart,&ch,1,0xFFFF);
}


/**
  * @brief  发送一个字符串
  * @param 	uart指针
	* @param 	要发送的字符串指针
  * @retval	None
  */
void Myuart_sent_string(UART_HandleTypeDef *huart,char *ch)
{
  
	for(int ptr=0;ch[ptr]!='\0';ptr++)
	{
		char temp =ch[ptr];
		Myuart_sent_byte(huart,(uint8_t)temp);
	}
}


/**
  * @brief  发送len个字节的数据
  * @param 	uart指针
	* @param 	数据长度
	* @param 	数据指针
  * @retval	None
  */
void Myuart_sent_lenarray(UART_HandleTypeDef *huart,uint8_t len,uint8_t *ch)
{
	for(int i=0;i<len;i++)
	{
		HAL_UART_Transmit(huart,&ch[i],1,0xFFFF);
	}
}


/**
  * @brief  发送一个字节数据,用16进制串口显示
  * @param 	uart指针
	* @param 	要展示的数据
  * @retval	None
  */
void Myuart_sent_uint8(UART_HandleTypeDef *huart,uint8_t x)
{
	Myuart_sent_string(huart," 0X");
	for(int i=1;i>=0;i--){
	if(((x>>(4*i))&0x000f)<10){uint8_t temp='0'+((x>>(4*i))&0x000f);Myuart_sent_byte(huart,temp);}
	else if(((x>>(4*i))&0x000f)==10){uint8_t temp='A';Myuart_sent_byte(huart,temp);}
	else if(((x>>(4*i))&0x000f)==11){uint8_t temp='B';Myuart_sent_byte(huart,temp);}
	else if(((x>>(4*i))&0x000f)==12){uint8_t temp='C';Myuart_sent_byte(huart,temp);}
	else if(((x>>(4*i))&0x000f)==13){uint8_t temp='D';Myuart_sent_byte(huart,temp);}
	else if(((x>>(4*i))&0x000f)==14){uint8_t temp='E';Myuart_sent_byte(huart,temp);}
	else if(((x>>(4*i))&0x000f)==15){uint8_t temp='F';Myuart_sent_byte(huart,temp);}
	}
}



/**
  * @brief  发送len个字节数据,用16进制串口显示
  * @param 	uart指针
	* @param 	数据长度
	* @param 	数据指针
  * @retval	None
  */
void Myuart_sent_lenuint8(UART_HandleTypeDef *huart,uint8_t len,uint8_t *ch)
{
	for(int i=0;i<len;i++)
	{
		Myuart_sent_uint8(huart,ch[i]);
	}
}


/**
  * @brief  串口接收中断回调函数
  * @param 	uart指针
  * @retval	None
  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    /* 判断是否是当前使用的串口 */
    if (huart == &huart1) {
			
        RX.rx_dat[RX.rx_ptr++]=RX.rx_temp;
		//	Myuart_sent_byte(&huart1,RX.rx_temp);
			HAL_UART_Receive_IT(&huart1, &RX.rx_temp, 1);
			
			if(RX.rx_ptr>=4){
				RX.rx_ptr=0;
				Myuart_sent_string(&huart1,"\r\n");
				Myuart_sent_lenarray(&huart1,4,RX.rx_dat);
				Myuart_sent_string(&huart1,"\r\n");
        }
			}
		
	 if (huart == &huart2) 
		{
			 RX2.rx_dat[RX2.rx_ptr++]=RX2.rx_temp;
			Myuart_sent_uint8(&huart1,RX2.rx_temp);
			HAL_UART_Receive_IT(&huart2, &RX2.rx_temp, 1);
			if(RX2.rx_ptr>=8){
				RX2.rx_ptr=0;
				Myuart_sent_string(&huart1,"\r\nthe data is :  ");
				Myuart_sent_lenarray(&huart1,8,RX2.rx_dat);
				Myuart_sent_string(&huart1,"\r\n");
        }
		}
		
		if (huart == &huart3) 
		{
			 RX3.rx_dat[RX3.rx_ptr++]=RX3.rx_temp;
			//Myuart_sent_uint8(&huart1,RX3.rx_temp);
			HAL_UART_Receive_IT(&huart3, &RX3.rx_temp, 1);
			if(RX3.rx_ptr>=8){
				RX3.rx_ptr=0;
				Myuart_sent_string(&huart1,"\r\nthe data is :  ");
				Myuart_sent_lenuint8(&huart1,8,RX3.rx_dat);
				Myuart_sent_string(&huart1,"\r\n");
        }
		}
}


myuart.h

#ifndef _MYUART_H_
#define	_MYUART_H_

#include "main.h"

typedef struct
{
	uint8_t rx_dat[30];
	uint8_t rx_ptr;
	uint8_t rx_temp;
	
}RX_struct;

extern  void Myuart_sent_byte(UART_HandleTypeDef *huart,uint8_t ch);
extern void Myuart_sent_string(UART_HandleTypeDef *huart,char *ch);
extern void Myuart_sent_lenarray(UART_HandleTypeDef *huart,uint8_t len,uint8_t *ch);
extern void Myuart_sent_uint8(UART_HandleTypeDef *huart,uint8_t x);
extern void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
extern void Myuart_sent_lenuint8(UART_HandleTypeDef *huart,uint8_t len,uint8_t *ch);

#endif

以上完成了串口通讯的代码,printf重定向后串口调试将更加的方便

printf 重定向

方法一

第一步:勾选MicroLib
在这里插入图片描述
第二步:在myuart文件下添加下面函数 。 *注意得包含头文件stdio.h。

int fputc (int ch, FILE *f)

{

 (void)HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);

  return ch;

} 

之后就可以愉快的使用printf函数输出调试了

方法二

在myuart文件下添加下列函数即可

//重定向printf1至uart1的demo
void printf1(const char *fmt,...)
{
  char buf[50] = {0};
  va_list arg;
  
  va_start(arg,fmt);
  vsnprintf(buf,sizeof(buf),fmt,arg);
  va_end(arg);
  
  HAL_UART_Transmit(&huart1, (uint8_t*)buf, strlen(buf), 5000);
}

需要注意的是,此函数需要引用头文件**#include ”stdarg.h“** 和 #include “string.h”
此方法不需要勾选MicroLib,而且可以很方便的自定义多个printf函数。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用STM32 HAL库的时候,我们可以使用DMA方式进行串口数据发送,同时也可以通过重定向printf输出到串口。下面给出一种实现方式: 首先,在初始化串口时,需要开启DMA传输模式。例如: ```c // 初始化串口 huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } // 开启DMA传输模式 __HAL_UART_ENABLE_DMA(&huart2, UART_DMA_TX); ``` 接着,我们需要在代码中实现重定向printf输出到串口的功能。可以通过重写标准输出流中的`_write`函数来实现。例如: ```c int _write(int file, char *ptr, int len) { if (file == STDOUT_FILENO || file == STDERR_FILENO) { // 确保DMA传输完成 while (HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX) ; // 启动DMA传输 HAL_UART_Transmit_DMA(&huart2, (uint8_t *)ptr, len); return len; } errno = EIO; return -1; } ``` 这里我们判断输出流是标准输出流或标准错误输出流时,才进行串口DMA传输。同时,为了避免重复启动DMA传输,需要等待之前的传输完成。 最后,我们就可以在代码中使用printf输出到串口了,例如: ```c printf("Hello, world!\r\n"); ``` 这样,我们就实现了STM32 HAL库串口DMA发送并与printf重定向的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值