[STM32C0] 【STM32C092RC 测评】+关于usart2_printf的相关修正

[复制链接]
3433|19
 楼主| yinxiangxv 发表于 2025-5-5 11:14 | 显示全部楼层 |阅读模式
本帖最后由 yinxiangxv 于 2025-5-26 22:31 编辑

之前在运行例程中的printf重定向函数的时候,总是输出乱码?
经过一番折腾,今天终于能正常输出字符了?看图,其中最关键的应该还是时钟和波特率的配置了。
usart2_rcc.jpg


看时钟树的配置:
usart2_tree.jpg


这里选择的是12M的时钟PCLK
根据这个对波特率进行重新计算:
  1. 波特率 (Baud Rate): 指串口每秒传输的位数 (bits per second, bps)。通信双方必须使用相同的波特率才能正确解码数据。
  2. USART 时钟 (f_CK): 输入到 USART 外设的时钟频率。根据我们之前的分析,你的 USART2 时钟 (PCLK) 是 12 MHz (12,000,000 Hz)。
  3. 波特率寄存器 (USART_BRR): STM32 内部有一个寄存器,你需要写入一个特定的值 (USARTDIV),这个值是根据 f_CK 和目标波特率计算出来的,用于分频 f_CK 以产生实际的位时钟。
  4. 过采样 (Oversampling): USART 可以配置为过采样 16 次 (OVER8=0) 或 8 次 (OVER8=1)。这会影响波特率计算公式和精度。通常推荐使用过采样 16 次,除非需要非常高的波特率或有特殊功耗要求。
  5. 计算方法 :
  6. 计算写入 BRR 寄存器的值 (USARTDIV) 的基本公式:
  7. 过采样 16 次 (OVER8 = 0):
  8. USARTDIV = f_CK / Desired_BaudRate
  9. 过采样 8 次 (OVER8 = 1):
  10. USARTDIV = (2 * f_CK) / Desired_BaudRate
在配上修改后的代码:
  1. /* USER CODE BEGIN Header */
  2. /**
  3.   ******************************************************************************
  4.   * [url=home.php?mod=space&uid=288409]@file[/url]    UART/UART_Printf/Src/main.c
  5.   * [url=home.php?mod=space&uid=187600]@author[/url]  MCD Application Team
  6.   * [url=home.php?mod=space&uid=247401]@brief[/url]   This example shows how to retarget the C library printf function
  7.   *          to the UART.
  8.   ******************************************************************************
  9.   * @attention
  10.   *
  11.   * Copyright (c) 2024 STMicroelectronics.
  12.   * All rights reserved.
  13.   *
  14.   * This software is licensed under terms that can be found in the LICENSE file
  15.   * in the root directory of this software component.
  16.   * If no LICENSE file comes with this software, it is provided AS-IS.
  17.   *
  18.   ******************************************************************************
  19.   */
  20. /* USER CODE END Header */
  21. /* Includes ------------------------------------------------------------------*/
  22. #include "main.h"

  23. /* Private includes ----------------------------------------------------------*/
  24. /* USER CODE BEGIN Includes */
  25. /* USER CODE END Includes */

  26. /* Private typedef -----------------------------------------------------------*/
  27. /* USER CODE BEGIN PTD */

  28. /* USER CODE END PTD */

  29. /* Private define ------------------------------------------------------------*/
  30. /* USER CODE BEGIN PD */

  31. /* USER CODE END PD */

  32. /* Private macro -------------------------------------------------------------*/
  33. /* USER CODE BEGIN PM */

  34. /* USER CODE END PM */

  35. /* Private variables ---------------------------------------------------------*/

  36. UART_HandleTypeDef huart2;

  37. /* USER CODE BEGIN PV */
  38. /* USER CODE END PV */

  39. /* Private function prototypes -----------------------------------------------*/
  40. void SystemClock_Config(void);
  41. static void MX_GPIO_Init(void);
  42. static void MX_USART2_UART_Init(void);
  43. /* USER CODE BEGIN PFP */
  44. #if defined(__ICCARM__)
  45. __ATTRIBUTES size_t __write(int, const unsigned char *, size_t);
  46. #endif /* __ICCARM__ */

  47. #if defined(__ICCARM__)
  48. /* New definition from EWARM V9, compatible with EWARM8 */
  49. int iar_fputc(int ch);
  50. #define PUTCHAR_PROTOTYPE int iar_fputc(int ch)
  51. #elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION)
  52. /* ARM Compiler 5/6*/
  53. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  54. #elif defined(__GNUC__)
  55. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  56. #endif /* __ICCARM__ */
  57. /* USER CODE END PFP */

  58. /* Private user code ---------------------------------------------------------*/
  59. /* USER CODE BEGIN 0 */

  60. /* USER CODE END 0 */

  61. /**
  62.   * [url=home.php?mod=space&uid=247401]@brief[/url]  The application entry point.
  63.   * @retval int
  64.   */
  65. int main(void)
  66. {

  67.   /* USER CODE BEGIN 1 */

  68.   /* STM32C0xx HAL library initialization:
  69.        - Configure the Flash prefetch
  70.        - Systick timer is configured by default as source of time base, but user
  71.          can eventually implement his proper time base source (a general purpose
  72.          timer for example or other time source), keeping in mind that Time base
  73.          duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
  74.          handled in milliseconds basis.
  75.        - Low Level Initialization
  76.      */
  77.   /* USER CODE END 1 */

  78.   /* MCU Configuration--------------------------------------------------------*/

  79.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  80.   HAL_Init();

  81.   /* USER CODE BEGIN Init */

  82.   /* USER CODE END Init */

  83.   /* Configure the system clock */
  84.   SystemClock_Config();

  85.   /* USER CODE BEGIN SysInit */
  86.   /* Initialize BSP Led for LED2 */
  87.   BSP_LED_Init(LED2);
  88.   /* USER CODE END SysInit */

  89.   /* Initialize all configured peripherals */
  90.   MX_GPIO_Init();
  91.   MX_USART2_UART_Init();
  92.   /* USER CODE BEGIN 2 */

  93.   /* Output a message on Hyperterminal using printf function */
  94.   printf("\n\r UART Printf Example: retarget the C library printf function to the UART\n\r");
  95.   printf("** Test finished successfully. ** \n\r");
  96.   /* USER CODE END 2 */

  97.   /* Infinite loop */
  98.   /* USER CODE BEGIN WHILE */
  99.   while (1)
  100.   {
  101.                 printf("** Test finished successfully. ** \n\r");
  102.                 uint8_t test[] = {0x55, 0xAA, 'A', 'B', 'C'};  // 十六进制+ASCII混合数据
  103.                 HAL_UART_Transmit(&huart2, test, sizeof(test), 100);
  104.     /* USER CODE END WHILE */

  105.     /* USER CODE BEGIN 3 */

  106.   }
  107.   /* USER CODE END 3 */
  108. }

  109. /**
  110.   * [url=home.php?mod=space&uid=247401]@brief[/url] System Clock Configuration
  111.   * @retval None
  112.   */
  113. void SystemClock_Config(void)
  114. {
  115.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  116.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  117.   __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_0);

  118.   /** Initializes the RCC Oscillators according to the specified parameters
  119.   * in the RCC_OscInitTypeDef structure.
  120.   */
  121.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  122.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  123.   RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV4;
  124.   RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  125.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  126.   {
  127.     Error_Handler();
  128.   }

  129.   /** Initializes the CPU, AHB and APB buses clocks
  130.   */
  131.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  132.                               |RCC_CLOCKTYPE_PCLK1;
  133.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  134.   RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV4;
  135.   RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
  136.   RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;

  137.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  138.   {
  139.     Error_Handler();
  140.   }
  141. }

  142. /**
  143.   * [url=home.php?mod=space&uid=247401]@brief[/url] USART2 Initialization Function
  144.   * @param None
  145.   * @retval None
  146.   */
  147. static void MX_USART2_UART_Init(void)
  148. {

  149.   /* USER CODE BEGIN USART2_Init 0 */

  150.   /* USER CODE END USART2_Init 0 */

  151.   /* USER CODE BEGIN USART2_Init 1 */

  152.   /* USER CODE END USART2_Init 1 */
  153.   huart2.Instance = USART2;
  154.   huart2.Init.BaudRate = 9600;
  155.   huart2.Init.WordLength = UART_WORDLENGTH_8B;
  156.   huart2.Init.StopBits = UART_STOPBITS_1;
  157.   huart2.Init.Parity = UART_PARITY_NONE;
  158.   huart2.Init.Mode = UART_MODE_TX_RX;
  159.   huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  160.   huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  161.   huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  162.   huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  163.   huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  164.   if (HAL_UART_Init(&huart2) != HAL_OK)
  165.   {
  166.     Error_Handler();
  167.   }
  168.   /* USER CODE BEGIN USART2_Init 2 */

  169.   /* USER CODE END USART2_Init 2 */

  170. }

  171. /**
  172.   * [url=home.php?mod=space&uid=247401]@brief[/url] GPIO Initialization Function
  173.   * @param None
  174.   * @retval None
  175.   */
  176. static void MX_GPIO_Init(void)
  177. {
  178.   /* USER CODE BEGIN MX_GPIO_Init_1 */
  179.   /* USER CODE END MX_GPIO_Init_1 */

  180.   /* GPIO Ports Clock Enable */
  181.   __HAL_RCC_GPIOF_CLK_ENABLE();
  182.   __HAL_RCC_GPIOA_CLK_ENABLE();

  183.   /* USER CODE BEGIN MX_GPIO_Init_2 */
  184.   /* USER CODE END MX_GPIO_Init_2 */
  185. }

  186. /* USER CODE BEGIN 4 */
  187. /**
  188.   * @brief  Retargets the C library printf function to the USART.
  189.   * @param  None
  190.   * @retval None
  191.   */
  192. PUTCHAR_PROTOTYPE
  193. {
  194.   /* Place your implementation of fputc here */
  195.   /* e.g. write a character to the USART2 and Loop until the end of transmission */
  196.   HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);

  197.   return ch;
  198. }

  199. #if defined(__ICCARM__)
  200. size_t __write(int file, unsigned char const *ptr, size_t len)
  201. {
  202.   size_t idx;
  203.   unsigned char const *pdata = ptr;

  204.   for (idx = 0; idx < len; idx++)
  205.   {
  206.     iar_fputc((int)*pdata);
  207.     pdata++;
  208.   }
  209.   return len;
  210. }
  211. #endif /* __ICCARM__ */



  212. void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
  213.     if(huart->Instance == USART4) {
  214.         printf("UART Error: 0x%lX\n", huart->ErrorCode);
  215.     }
  216. }

  217. /* USER CODE END 4 */

  218. /**
  219.   * @brief  This function is executed in case of error occurrence.
  220.   * @retval None
  221.   */
  222. void Error_Handler(void)
  223. {
  224.   /* USER CODE BEGIN Error_Handler_Debug */
  225.   /* User can add his own implementation to report the HAL error return state */
  226.   /* Turn LED2 on */
  227.   BSP_LED_On(LED2);
  228.   while (1);
  229.   /* USER CODE END Error_Handler_Debug */
  230. }

  231. #ifdef  USE_FULL_ASSERT
  232. /**
  233.   * @brief  Reports the name of the source file and the source line number
  234.   *         where the assert_param error has occurred.
  235.   * @param  file: pointer to the source file name
  236.   * @param  line: assert_param error line source number
  237.   * @retval None
  238.   */
  239. void assert_failed(uint8_t *file, uint32_t line)
  240. {
  241.   /* USER CODE BEGIN 6 */
  242.   /* User can add his own implementation to report the file name and line number,
  243.     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  244.   /* Infinite loop */
  245.   while (1)
  246.   {
  247.   }
  248.   /* USER CODE END 6 */
  249. }
  250. #endif /* USE_FULL_ASSERT */
最后终于看到正常的输出了:
usart2_9600.jpg


最近先折腾到这里,以后有板子还是要积极参与。



   
AdaMaYun 发表于 2025-6-8 20:14 | 显示全部楼层
usart2_printf还是有必要的
yiyigirl2014 发表于 2025-6-10 17:37 | 显示全部楼层
这个主要就是重定向的映射问题吧。
fengm 发表于 2025-7-3 15:25 | 显示全部楼层
重定向printf函数到USART2。
wwppd 发表于 2025-7-4 19:37 | 显示全部楼层
使用轻量级的snprintf替代标准printf。
febgxu 发表于 2025-7-5 21:07 | 显示全部楼层
STM32C092RC微控制器的USART2和printf函数的使用,这对于开发者来说是一个非常具体和实用的主题。
ingramward 发表于 2025-7-6 11:42 | 显示全部楼层
printf函数重定向的方法              
qiufengsd 发表于 2025-7-6 15:17 | 显示全部楼层
printf重定向优化              
wengh2016 发表于 2025-7-12 10:17 | 显示全部楼层
在发送和接收过程中加入超时机制,防止因硬件故障或通信异常导致程序卡死。
janewood 发表于 2025-7-12 13:21 | 显示全部楼层
记得在项目设置中勾选“Use MicroLIB”选项
mmbs 发表于 2025-7-12 14:48 | 显示全部楼层
建议改用环形缓冲区或FIFO存储数据
cemaj 发表于 2025-7-12 16:00 | 显示全部楼层
printf函数是C语言中常用的输出函数
ccook11 发表于 2025-7-12 22:24 | 显示全部楼层
标准库printf功能过于庞大              
hilahope 发表于 2025-7-18 09:33 | 显示全部楼层
如何在实际项目中使用USART2串口与PC进行交互
maqianqu 发表于 2025-7-18 13:28 | 显示全部楼层
USART2是微控制器中用于串行通信的重要外设
rosemoore 发表于 2025-7-18 17:05 | 显示全部楼层
考虑实现环形缓冲区来管理发送和接收的数据,避免溢出或丢失数据。
earlmax 发表于 2025-7-19 11:40 | 显示全部楼层
#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(&huart2, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
    return ch;
}
benjaminka 发表于 2025-7-19 12:25 | 显示全部楼层
在Keil中勾选Use MicroLIB,直接重写fputc,减少代码体积。
benjaminka 发表于 2025-7-19 18:58 | 显示全部楼层
int fputc(int ch, FILE *f) {
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF); // 使用HAL库发送一个字符
    return ch;
}
i1mcu 发表于 2025-7-19 19:58 | 显示全部楼层
通过重写 __io_putchar(GNU 工具链)或 fputc(其他工具链)函数
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

348

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部