查看: 2408|回复: 0

[原创] 串口打印输出的实现方式

[复制链接]

该用户从未签到

656

主题

6312

帖子

0

超级版主

Rank: 8Rank: 8

积分
20017
最后登录
2024-4-25
发表于 2021-3-24 11:03:40 | 显示全部楼层 |阅读模式
本帖最后由 小恩GG 于 2021-3-24 13:57 编辑

概要
在MCU开发过程中,经常会用串口打印输出各类信息,如寄存器,变量,标记符的值,各种调试信息等,方便开发者探知软件的实现结果,功能错误原因等。
在本篇分享中,小编会以MCUXpresso IDE和MIMXRT1050-EVK为例,介绍如何在SDK 软件库中实现三种串口打印的实现方式,好的,我们开始吧。

PRINTF打印
PRINTF是SDK 软件库自身定义的指向Printf功能函数的宏,代码细节如下所示,而为了使能PRINTF打印功能,需要设置SDK_DEBUGCONSOLE = 1(Project -> Properties -> C/C++ Build -> Setting -> Preprocessor,如下图1所示)在预编译阶段选择串口输出的目标函数:SDK DbgConsole_Printf()。
  1. #elif SDK_DEBUGCONSOLE == DEBUGCONSOLE_REDIRECT_TO_SDK /* Select printf, scanf, putchar, getchar of SDK version. */
  2. #define PRINTF  DbgConsole_Printf
  3. #define SCANF   DbgConsole_Scanf
  4. #define PUTCHAR DbgConsole_Putchar
  5. #define GETCHAR DbgConsole_Getchar
复制代码
2021-03-23_16-41-25.jpg

图 1

printf打印
printf是C标准库提供的打印函数,在使用它之前需定义__MCUXPRESSO和SDK_DEBUGCONSOLE_UART宏(Project -> Properties -> C/C++ Build -> Setting -> Preprocessor,如下图2所示),这样的话,C标准库中的printf和scanf函数的底层实现会指向fsl_debug_console.c中的_write和_read函数(如下所示)。
2021-03-23_16-54-01.jpg
图 2
  1. #if ((defined(__GNUC__) && (!defined(__MCUXPRESSO)) && (defined(SDK_DEBUGCONSOLE_UART))) || \
  2.      (defined(__MCUXPRESSO) && (defined(SDK_DEBUGCONSOLE_UART))))
  3. int __attribute__((weak)) _write(int handle, char *buffer, int size);
  4. int __attribute__((weak)) _write(int handle, char *buffer, int size)
  5. {
  6.     if (buffer == NULL)
  7.     {
  8.         /* return -1 if error. */
  9.         return -1;
  10.     }

  11.     /* This function only writes to "standard out" and "standard err" for all other file handles it returns failure. */
  12.     if ((handle != 1) && (handle != 2))
  13.     {
  14.         return -1;
  15.     }

  16.     /* Send data. */
  17.     (void)DbgConsole_SendDataReliable((uint8_t *)buffer, (size_t)size);

  18.     return size;
  19. }

  20. int __attribute__((weak)) _read(int handle, char *buffer, int size);
  21. int __attribute__((weak)) _read(int handle, char *buffer, int size)
  22. {
  23.     uint8_t ch     = 0U;
  24.     int actualSize = 0;

  25.     /* This function only reads from "standard in", for all other file handles it returns failure. */
  26.     if (handle != 0)
  27.     {
  28.         return -1;
  29.     }

  30.     /* Receive data. */
  31.     for (; size > 0; size--)
  32.     {
  33.         if (DbgConsole_ReadCharacter(&ch) < 0)
  34.         {
  35.             break;
  36.         }

  37.         *buffer++ = (char)ch;
  38.         actualSize++;

  39.         if ((ch == 0U) || (ch == (uint8_t)'\n') || (ch == (uint8_t)'\r'))
  40.         {
  41.             break;
  42.         }
  43.     }

  44.     return (actualSize > 0) ? actualSize : -1;
  45. }
  46. #endif
复制代码


std::cout输出
std::cout是C++标准库提供的输出流功能,所以要使用它的前提是创建的工程是基于C++,或者按照小编先前的分享:《MCUXPresso C++工程变成C工程》,将C工程改造C++工程。
预编译设置跟printf打印实现一样,将C++标准库提供的输出和输入流功能的底层实现同样指向fsl_debug_console.c中的_write和_read函数。
注意:
虽然上面介绍的都是串口打印输出的实现步骤,但输出的实现也代表了输入功能也被同样使能了

测试
测试代码(请查看附件)是基于SDK软件库创建的C++工程,按照如上介绍,在project -> Properties -> C/C++ Build -> Setting -> Preprocessor中设置相应的宏,将以上三种打印输出方式全都使能,并用他们打印对应的信息,具体代码如下:
  1. #include <stdio.h>
  2. #include "board.h"
  3. #include "peripherals.h"
  4. #include "pin_mux.h"
  5. #include "clock_config.h"
  6. #include "MIMXRT1052.h"
  7. #include "fsl_debug_console.h"
  8. #include<cstdint>
  9. #include <iostream>
  10. /* TODO: insert other include files here. */
  11. using namespace std;
  12. /* TODO: insert other definitions and declarations here. */

  13. /*
  14. * @brief   Application entry point.
  15. *
  16. */



  17. int main(void) {

  18.     /* Init board hardware. */
  19.     BOARD_InitBootPins();
  20.     BOARD_InitBootClocks();
  21.     BOARD_InitBootPeripherals();
  22.     /* Init FSL debug console. */
  23.     BOARD_InitDebugConsole();



  24.     PRINTF("PRINT method of print output\n");
  25.     printf("print method of print output\n");
  26.     cout<< "std::cout method of print output\n" <<endl;


  27.     /* Force the counter to be placed into memory. */
  28.     volatile static int i = 0 ;
  29.     /* Enter an infinite loop, just incrementing a counter. */
  30.     while(1) {
  31.         i++ ;
  32.         /* 'Dummy' NOP to allow source level single stepping of
  33.             tight while() loop */
  34.         __asm volatile ("nop");
  35.     }
  36.     return 0 ;
  37. }
复制代码
MIMXRT1052 C Project.zip (781.17 KB, 下载次数: 7)
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /4 下一条

Archiver|手机版|小黑屋|恩智浦技术社区

GMT+8, 2024-4-26 05:28 , Processed in 0.105462 second(s), 19 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表