STM32CubeMx启动串口调试功能Printf调试

发布者:心语如画最新更新时间:2020-06-06 来源: eefocus关键字:STM32CubeMx  串口调试功能  Printf调试 手机看文章 扫描二维码
随时随地手机看文章

## 概述

项目中往往需要调试信息,调试stm32的时候,需要标准库里面的printf函数。在keil MDK环境下重定向printf与keil C51不同,由于本人使用了STM32CubeMX生成工程模板,HAL_USART_Transmit函数即是模板里串口输出的函数。由于printf最终是调用fputc输出数据,fputc是一个弱引用(weak)函数,覆写即可重定向printf。


代码清单

/* USER CODE BEGIN Includes */

#include "FreeRTOS.h"

#include "task.h"

#include "queue.h"

#include

/* USER CODE END Includes */



/* USER CODE BEGIN PV */

/* Private variables ---------------------------------------------------------*/

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

#else

#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

#endif

PUTCHAR_PROTOTYPE

{

HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);

return ch;

}

/* USER CODE END PV */


#### 华丽的分界线


例子:

硬件平台:stm32F407Zet6


软件平台:stm32cubeMX 4.7+MDK5.14


电路连接:PA9,PA10


第一步、通过Stm32CubeMX图形界面创建Keil工程


需要配置的地方是:

stm32串口调试2

第二章配置图:

stm32PrintfDebugPic2

在这里可以修改串口工作的一下参数,软件就可以生成配置好的工程,不需要亲自去配置这些了。


第二步。打开工程,编写代码,验证

代码清单

/* USER CODE BEGIN PV */

#include "stdio.h"

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

#else

#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

#endif /* __GNUC__ */

PUTCHAR_PROTOTYPE

{

HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);

return ch;

}

/* USER CODE END PV */


这段程序为了可以使用printf()函数,对字符输出函数进行了重定向,这样我们就可以在程序中使用printf函数进行输出了,这里使用的是查询发送方式,有超时控制的。接下来来看中断方式的。


代码清单

/**

  * @brief  This function handles UART interrupt request.

  * @param  huart: pointer to a UART_HandleTypeDef structure that contains

  *                the configuration information for the specified UART module.

  * @retval None

  */

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

  uint32_t tmp1 = 0, tmp2 = 0;

 

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);

  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  

  /* UART parity error interrupt occurred ------------------------------------*/

  if((tmp1 != RESET) && (tmp2 != RESET))

  { 

    __HAL_UART_CLEAR_PEFLAG(huart);

    

    huart->ErrorCode |= HAL_UART_ERROR_PE;

  }

  

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);

  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

  /* UART frame error interrupt occurred -------------------------------------*/

  if((tmp1 != RESET) && (tmp2 != RESET))

  { 

    __HAL_UART_CLEAR_FEFLAG(huart);

    

    huart->ErrorCode |= HAL_UART_ERROR_FE;

  }

  

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);

  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

  /* UART noise error interrupt occurred -------------------------------------*/

  if((tmp1 != RESET) && (tmp2 != RESET))

  { 

    __HAL_UART_CLEAR_NEFLAG(huart);

    

    huart->ErrorCode |= HAL_UART_ERROR_NE;

  }

  

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);

  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

  /* UART Over-Run interrupt occurred ----------------------------------------*/

  if((tmp1 != RESET) && (tmp2 != RESET))

  { 

    __HAL_UART_CLEAR_OREFLAG(huart);

    

    huart->ErrorCode |= HAL_UART_ERROR_ORE;

  }

  

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);

  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);

  /* UART in mode Receiver ---------------------------------------------------*/

  if((tmp1 != RESET) && (tmp2 != RESET))

  { 

    UART_Receive_IT(huart);

  }

  

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);

  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);

  /* UART in mode Transmitter ------------------------------------------------*/

  if((tmp1 != RESET) && (tmp2 != RESET))

  {

    UART_Transmit_IT(huart);

  }

  

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);

  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);

  /* UART in mode Transmitter end --------------------------------------------*/

  if((tmp1 != RESET) && (tmp2 != RESET))

  {

    UART_EndTransmit_IT(huart);

  }

 

  if(huart->ErrorCode != HAL_UART_ERROR_NONE)

  {

    /* Set the UART state ready to be able to start again the process */

    huart->State = HAL_UART_STATE_READY;

    

    HAL_UART_ErrorCallback(huart);

  }  

}


这个函数中查询了所有可能发生的中断。用到的中断是发送完成中断,就找到了UART_EndTransmit_IT(huart);再跳进去看看:


代码清单

/**

  * @brief  Wraps up transmission in non blocking mode.

  * @param  huart: pointer to a UART_HandleTypeDef structure that contains

  *                the configuration information for the specified UART module.

  * @retval HAL status

  */

static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart)

{

  /* Disable the UART Transmit Complete Interrupt */    

  __HAL_UART_DISABLE_IT(huart, UART_IT_TC);

  

  /* Check if a receive process is ongoing or not */

  if(huart->State == HAL_UART_STATE_BUSY_TX_RX) 

  {

    huart->State = HAL_UART_STATE_BUSY_RX;

  }

  else

  {

    /* Disable the UART Parity Error Interrupt */

    __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

 

    /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */

    __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

 

    huart->State = HAL_UART_STATE_READY;

  }

  

  HAL_UART_TxCpltCallback(huart);

  

  return HAL_OK;

}


这个函数在确定中断发生了之后调用了,HAL_UART_TxCpltCallback(huart);从函数名上可以看出,这是个回调函数,就是留给上层来实现的函数,由这个函数的实现不同,来实现不同的功能。这里来实现这个函数,让它在中断发生的时候吧USART1Ready置为SET;代码修改如下:


代码清单

/* USER CODE BEGIN PV */

#include "stdio.h"

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

#else

#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

#endif /* __GNUC__ */

__IO ITStatus USART1Ready = RESET;

 

PUTCHAR_PROTOTYPE

{

HAL_UART_Transmit_IT(&huart1 , (uint8_t *)&ch, 1);

while (USART1Ready != SET)

  {

  }

USART1Ready = RESET;

return ch;

}

 

 

/* USER CODE END PV */



这是重定向函数的修改,启动发送之后,等待发送完成。重新实现的回调函数如下图所示:


/**

  * @brief  Tx Transfer completed callbacks.

  * @param  huart: pointer to a UART_HandleTypeDef structure that contains

  *                the configuration information for the specified UART module.

  * @retval None

  */

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)

{

  /* NOTE: This function Should not be modified, when the callback is needed,

           the HAL_UART_TxCpltCallback could be implemented in the user file

   */ 

USART1Ready = SET;

}



最后,编译,下载验证代码!


关键字:STM32CubeMx  串口调试功能  Printf调试 引用地址:STM32CubeMx启动串口调试功能Printf调试

上一篇:STM32F1xx HAL库中文版——USART篇
下一篇:【STM32】keil MDK下重定向printf到串口(基于STM32CubeMX)

推荐阅读最新更新时间:2024-11-16 19:57

STM32CUBEMX(7)--移植雅特力AT32F403AVGT(兼容STM32F103VGT6),DAC输出电压
概述 本篇文章主要介绍如何使用 STM32 CubeMX移植到雅特力AT32F403AVGT7,并通过 DAC 输出电压,在 芯片 中有2个12位的DAC口可以供选择。 硬件 准备 首先需要准备一个开发板,这里我准备的是雅特力AT32F403AVGT7的开发板: 述 选择芯片型号 雅特力AT32F403AVGT7兼容STM32F103系列,故选取STM32f103VG进行开发。 配置 时钟 源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示: 配置时钟树 雅特力AT32F403AVGT7最高频率到240M,但是STM32F1的最高主频到72M,同时使用不
[单片机]
<font color='red'>STM32CUBEMX</font>(7)--移植雅特力AT32F403AVGT(兼容STM32F103VGT6),DAC输出电压
stm32cubemx 多路adc采集
采用的软件是STM32CUBEMX+KEIL5 硬件为stm32F103C8T6 我与原文作者做的区别在于 External Trigger Conversion Edge,我在进行配置的时间没有None选项,我选择的是默认的Regular Conversion launched by software 原文地址: http://www.eemaker.com/stm32cubemxadc.html 实现功能:stm32cubeMX配置ADC多通道采集(非dma和中断方式) Stm32ADC的转换模式还是很灵活,很强大,模式种类很多,那么这也导致很多人使用的时候没细心研究参考手册的情况下容易混淆。不知道该用哪种方式来实
[单片机]
<font color='red'>stm32cubemx</font> 多路adc采集
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多每日新闻

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved