[应用方案] printf重定向到串口

[复制链接]
2829|26
 楼主| maudlu 发表于 2024-7-25 20:36 | 显示全部楼层 |阅读模式
在mdk 中用printf,需要同时重定义fputc函数和避免使用semihosting(半主机模式),
标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数.
例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下:
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
因printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法运行,以下是解决方法:
方法1.使用微库,因为使用微库的话,不会使用半主机模式.
方法2.仍然使用标准库,在主程序添加下面代码:
#pragma import(__use_no_semihosting)  
_sys_exit(int x)  
{  
x = x;  
}  
struct __FILE  
{  
int handle;  
/* Whatever you require here. If the only file you are using is */  
/* standard output using printf() for debugging, no file handling */  
/* is required. */  
};  
/* FILE is typedef’ d in stdio.h. */  
FILE __stdout;
如果使用的是MDK,请在工程属性的“Target“-》”Code Generation“中勾选”Use MicroLIB;今天参考了一下论坛,使用微库可以很好的解决这个问题。
2.另一种方法:(其实大同小异)   
需要添加以下代码  
(论坛里应该有完整介绍这个的帖子,但是我没搜到,也许是沉了。)
#pragma import(__use_no_semihosting)   
/******************************************************************************   
*标准库需要的支持函数   
******************************************************************************/   
struct __FILE   
{   
int handle;   
/* Whatever you require here. If the only file you are using is */   
/* standard output using printf() for debugging, no file handling */   
/* is required. */   
};   
/* FILE is typedef’ d in stdio.h. */   
FILE __stdout;  
///
  
/// 定义_sys_exit()以避免使用半主机模式   
///
  
///   
///   
_sys_exit(int x)   
{   
x = x;   
}  

int fputc(int ch, FILE *f)  
{  
    //USART_SendData(USART1, (u8) ch);  
    USART1->DR = (u8) ch;  

    /* Loop until the end of transmission */  
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {  
    }
    return ch;  
}  

jiekou001 发表于 2024-7-25 22:17 | 显示全部楼层
新唐一般会帮你实现这个。
jiekou001 发表于 2024-7-25 22:18 | 显示全部楼层
  1. /**************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     retarget.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]    M480 Series Debug Port and Semihost Setting Source File
  5. *
  6. * SPDX-License-Identifier: Apache-2.0
  7. * [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
  8. ******************************************************************************/


  9. #include <stdio.h>
  10. #include "NuMicro.h"

  11. #if defined ( __CC_ARM   )
  12. #if (__ARMCC_VERSION < 400000)
  13. #else
  14. /* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
  15. #pragma import _printf_widthprec
  16. #endif
  17. #endif
  18. /* Uncomment this line to disable all printf and getchar. getchar() will always return 0x00*/
  19. /* #define DISABLE_UART */

  20. #if defined(DEBUG_ENABLE_SEMIHOST)
  21.     #ifndef DISABLE_UART
  22.         #define DISABLE_UART
  23.     #endif
  24. #endif

  25. #define DEBUG_PORT   UART0
  26. /*---------------------------------------------------------------------------------------------------------*/
  27. /* Global variables                                                                                        */
  28. /*---------------------------------------------------------------------------------------------------------*/
  29. #if !(defined(__ICCARM__) && (__VER__ >= 6010000))
  30. # if (__ARMCC_VERSION < 6040000)
  31. struct __FILE
  32. {
  33.     int handle; /* Add whatever you need here */
  34. };
  35. # endif
  36. #elif(__VER__ >= 8000000)
  37. struct __FILE
  38. {
  39.     int handle; /* Add whatever you need here */
  40. };
  41. #endif
  42. FILE __stdout;
  43. FILE __stdin;


  44. enum { r0, r1, r2, r3, r12, lr, pc, psr};

  45. /**
  46. * @brief       Helper function to dump register while hard fault occurred
  47. * @param[in]   stack pointer points to the dumped registers in SRAM
  48. * [url=home.php?mod=space&uid=266161]@return[/url]      None
  49. * [url=home.php?mod=space&uid=1543424]@Details[/url]     This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr
  50. */
  51. static void stackDump(uint32_t stack[])
  52. {
  53.     printf("r0  = 0x%x\n", stack[r0]);
  54.     printf("r1  = 0x%x\n", stack[r1]);
  55.     printf("r2  = 0x%x\n", stack[r2]);
  56.     printf("r3  = 0x%x\n", stack[r3]);
  57.     printf("r12 = 0x%x\n", stack[r12]);
  58.     printf("lr  = 0x%x\n", stack[lr]);
  59.     printf("pc  = 0x%x\n", stack[pc]);
  60.     printf("psr = 0x%x\n", stack[psr]);
  61. }

  62. /**
  63. * @brief       Hard fault handler
  64. * @param[in]   stack pointer points to the dumped registers in SRAM
  65. * @return      None
  66. * @details     Replace while(1) at the end of this function with chip reset if WDT is not enabled for end product
  67. */
  68. void Hard_Fault_Handler(uint32_t stack[])
  69. {
  70.     printf("In Hard Fault Handler\n");

  71.     stackDump(stack);
  72.     /* Replace while(1) with chip reset if WDT is not enabled for end product */
  73.     while(1);
  74.     /* SYS->IPRST0 = SYS_IPRST0_CHIPRST_Msk; */
  75. }



  76. /*---------------------------------------------------------------------------------------------------------*/
  77. /* Routine to write a char                                                                                 */
  78. /*---------------------------------------------------------------------------------------------------------*/

  79. #if defined(DEBUG_ENABLE_SEMIHOST)
  80. /* The static buffer is used to speed up the semihost    */
  81. static char g_buf[16];
  82. static char g_buf_len = 0;

  83. /* Make sure won't goes here only because --gnu is defined , so
  84.    add !__CC_ARM and !__ICCARM__ checking */
  85. # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)

  86. # elif defined(__ICCARM__)      // IAR

  87. void SH_End(void)
  88. {
  89.     asm("MOVS   R0,#1 \n"        /*; Set return value to 1 */
  90.         "BX     lr    \n"        /*; Return */
  91.        );
  92. }

  93. void SH_ICE(void)
  94. {
  95.   asm("CMP   R2,#0   \n"
  96.       "BEQ   SH_End  \n"
  97.       "STR   R0,[R2] \n"       /*; Save the return value to *pn32Out_R0 */
  98.      );
  99. }

  100. /**
  101. *
  102. * @brief      The function to process semihosted command
  103. * @param[in]  n32In_R0  : semihost register 0
  104. * @param[in]  n32In_R1  : semihost register 1
  105. * @param[out] pn32Out_R0: semihost register 0
  106. * @retval     0: No ICE debug
  107. * @retval     1: ICE debug
  108. *
  109. */
  110. int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
  111. {
  112.     asm("BKPT   0xAB   \n"       /*; This instruction will cause ICE trap or system HardFault */
  113.         "B      SH_ICE \n"
  114.         "SH_HardFault: \n"       /*; Captured by HardFault */
  115.         "MOVS   R0,#0  \n"       /*; Set return value to 0 */
  116.         "BX     lr     \n"       /*; Return */
  117.         );

  118.     return 1;                    /*; Return 1 when it is trap by ICE */
  119. }

  120. /**
  121. * @brief       Get LR value and branch to Hard_Fault_Handler function
  122. * @param       None
  123. * @return      None
  124. * @details     This function is use to get LR value and branch to Hard_Fault_Handler function.
  125. */
  126. void Get_LR_and_Branch(void)
  127. {
  128.     asm("MOV     R1, LR               \n" /*; LR current value */
  129.         "B       Hard_Fault_Handler   \n"
  130.        );
  131. }

  132. /**
  133. * @brief       Get MSP value and branch to Get_LR_and_Branch function
  134. * @param       None
  135. * @return      None
  136. * @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
  137. */
  138. void Stack_Use_MSP(void)
  139. {
  140.     asm("MRS     R0, MSP           \n" /*; read MSP */
  141.         "B       Get_LR_and_Branch \n"
  142.        );
  143. }

  144. /**
  145. * @brief       Get stack pointer value and branch to Get_LR_and_Branch function
  146. * @param       None
  147. * @return      None
  148. * @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
  149. */
  150. void HardFault_Handler_Ret(void)
  151. {
  152.     asm("MOVS    r0, #4                        \n"
  153.         "MOV     r1, LR                        \n"
  154.         "TST     r0, r1                        \n" /*; check LR bit 2 */
  155.         "BEQ     Stack_Use_MSP                 \n" /*; stack use MSP */
  156.         "MRS     R0, PSP                       \n" /*; stack use PSP, read PSP */
  157.         "B       Get_LR_and_Branch             \n"
  158.        );
  159. }

  160. /**
  161. * @brief    This function is implemented to support semihost
  162. * @param    None
  163. * @returns  None
  164. * @details  This function is implement to support semihost message print.
  165. *
  166. */
  167. void SP_Read_Ready(void)
  168. {
  169.     asm("LDR     R1, [R0, #24] \n"        /*; Get previous PC */
  170.         "LDRH    R3, [R1]      \n"        /*; Get instruction */
  171.         "LDR     R2, [pc, #8]  \n"        /*; The special BKPT instruction */
  172.         "CMP     R3, R2        \n"        /*; Test if the instruction at previous PC is BKPT */
  173.         "BNE     HardFault_Handler_Ret \n" /*; Not BKPT */
  174.         "ADDS    R1, #4        \n"        /*; Skip BKPT and next line */
  175.         "STR     R1, [R0, #24] \n"        /*; Save previous PC */
  176.         "BX      lr            \n"        /*; Return */
  177.         "DCD     0xBEAB        \n"        /*; BKPT instruction code */
  178.         "B       HardFault_Handler_Ret \n"
  179.        );
  180. }

  181. /**
  182. * @brief       Get stack pointer value and branch to Get_LR_and_Branch function
  183. * @param       None
  184. * @return      None
  185. * @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
  186. */
  187. void SP_is_PSP(void)
  188. {
  189.     asm(
  190.         "MRS     R0, PSP       \n"      /*; stack use PSP, read PSP */
  191.         "B       Get_LR_and_Branch    \n"

  192.        );
  193. }

  194. /**
  195. * @brief    This HardFault handler is implemented to support semihost
  196. *
  197. * @param    None
  198. *
  199. * @returns  None
  200. *
  201. * @details  This function is implement to support semihost message print.
  202. *
  203. */
  204. void HardFault_Handler (void)
  205. {
  206.     asm("MOV     R0, lr        \n"
  207.         "LSLS    R0, #29       \n"        /*; Check bit 2 */
  208.         "BMI     SP_is_PSP     \n"        /*; previous stack is PSP */
  209.         "MRS     R0, MSP       \n"        /*; previous stack is MSP, read MSP */
  210.         "B       SP_Read_Ready \n"
  211.        );

  212.     while(1);
  213. }

  214. # else

  215. /**
  216. * @brief    This HardFault handler is implemented to support semihost
  217. * @param    None
  218. * @returns  None
  219. * @details  This function is implement to support semihost message print.
  220. *
  221. */
  222. __asm int32_t HardFault_Handler(void)
  223. {
  224.     MOV     R0, LR
  225.     LSLS    R0, #29               /*; Check bit 2 */
  226.     BMI     SP_is_PSP             /*; previous stack is PSP */
  227.     MRS     R0, MSP               /*; previous stack is MSP, read MSP */
  228.     B       SP_Read_Ready
  229. SP_is_PSP
  230.     MRS     R0, PSP               /*; Read PSP */

  231. SP_Read_Ready
  232.     LDR     R1, [R0, #24]         /*; Get previous PC */
  233.     LDRH    R3, [R1]              /*; Get instruction */
  234.     LDR     R2, =0xBEAB           /*; The special BKPT instruction */
  235.     CMP     R3, R2                /*; Test if the instruction at previous PC is BKPT */
  236.     BNE     HardFault_Handler_Ret /*; Not BKPT */

  237.     ADDS    R1, #4                /*; Skip BKPT and next line */
  238.     STR     R1, [R0, #24]         /*; Save previous PC */

  239.     BX      LR                    /*; Return */
  240. HardFault_Handler_Ret

  241.     /* TODO: Implement your own hard fault handler here. */
  242.     MOVS    r0, #4
  243.     MOV     r1, LR
  244.     TST     r0, r1                          /*; check LR bit 2 */
  245.     BEQ     Stack_Use_MSP                   /*; stack use MSP */
  246.     MRS     R0, PSP ;stack use PSP          /*; stack use PSP, read PSP */
  247.     B       Get_LR_and_Branch
  248. Stack_Use_MSP
  249.     MRS     R0, MSP ; stack use MSP         /*; read MSP */
  250. Get_LR_and_Branch
  251.     MOV     R1, LR ; LR current value       /*; LR current value */
  252.     LDR     R2,=__cpp(Hard_Fault_Handler)   /*; branch to Hard_Fault_Handler */
  253.     BX      R2

  254.     B       .

  255.     ALIGN
  256. }

  257. /**
  258. *
  259. * @brief      The function to process semihosted command
  260. * @param[in]  n32In_R0  : semihost register 0
  261. * @param[in]  n32In_R1  : semihost register 1
  262. * @param[out] pn32Out_R0: semihost register 0
  263. * @retval     0: No ICE debug
  264. * @retval     1: ICE debug
  265. *
  266. */
  267. __asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
  268. {
  269.     BKPT   0xAB          /*; Wait ICE or HardFault */
  270.     /*; ICE will step over BKPT directly
  271.       ; HardFault will step BKPT and the next line */
  272.     B      SH_ICE

  273. SH_HardFault             /*; Captured by HardFault */
  274.     MOVS   R0, #0        /*; Set return value to 0 */
  275.     BX     lr            /*; Return */

  276. SH_ICE                   /*; Captured by ICE */
  277.     /*; Save return value */
  278.     CMP    R2, #0
  279.     BEQ    SH_End
  280.     STR    R0, [R2]      /*; Save the return value to *pn32Out_R0 */

  281. SH_End
  282.     MOVS   R0, #1        /*; Set return value to 1 */
  283.     BX     lr            /*; Return */
  284. }
  285. #endif

  286. #else   // ndef DEBUG_ENABLE_SEMIHOST

  287. /* Make sure won't goes here only because --gnu is defined , so
  288.    add !__CC_ARM and !__ICCARM__ checking */
  289. # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)

  290. /**
  291. * @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
  292. *
  293. * @param    None
  294. *
  295. * @returns  None
  296. *
  297. * @details  This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
  298. *
  299. */
  300. void HardFault_Handler(void)
  301. {
  302.     asm("MOVS    r0, #4                        \n"
  303.         "MOV     r1, LR                        \n"
  304.         "TST     r0, r1                        \n" /*; check LR bit 2 */
  305.         "BEQ     1f                            \n" /*; stack use MSP */
  306.         "MRS     R0, PSP                       \n" /*; stack use PSP, read PSP */
  307.         "MOV     R1, LR                        \n" /*; LR current value */
  308.         "B       Hard_Fault_Handler            \n"
  309.         "1:                                    \n"
  310.         "MRS     R0, MSP                       \n" /*; LR current value */
  311.         "B       Hard_Fault_Handler            \n"   
  312.         ::[Hard_Fault_Handler] "r" (Hard_Fault_Handler) // input
  313.     );
  314.     while(1);
  315. }

  316. # elif defined(__ICCARM__)

  317. void Get_LR_and_Branch(void)
  318. {
  319.     asm("MOV     R1, LR                  \n" /*; LR current value */
  320.         "B       Hard_Fault_Handler      \n"
  321.        );
  322. }

  323. void Stack_Use_MSP(void)
  324. {
  325.     asm("MRS     R0, MSP           \n" /*; read MSP */
  326.         "B       Get_LR_and_Branch \n"
  327.        );
  328. }

  329. /**
  330. * @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
  331. *
  332. * @param    None
  333. *
  334. * @returns  None
  335. *
  336. * @details  This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
  337. *
  338. */
  339. void HardFault_Handler(void)
  340. {
  341.     asm("MOVS    r0, #4                        \n"
  342.         "MOV     r1, LR                        \n"
  343.         "TST     r0, r1                        \n" /*; check LR bit 2 */
  344.         "BEQ     Stack_Use_MSP                 \n" /*; stack use MSP */
  345.         "MRS     R0, PSP                       \n" /*; stack use PSP, read PSP */
  346.         "B       Get_LR_and_Branch             \n"
  347.        );

  348.     while(1);
  349. }

  350. # else

  351. /**
  352. * @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
  353. *
  354. * @param    None
  355. *
  356. * @return   None
  357. *
  358. * @details  The function extracts the location of stack frame and passes it to Hard_Fault_Handler function as a pointer
  359. *
  360. */
  361. __asm int32_t HardFault_Handler(void)
  362. {
  363.     MOVS    r0, #4
  364.     MOV     r1, LR
  365.     TST     r0, r1          /*; check LR bit 2 */
  366.     BEQ     Stack_Use_MSP   /*; stack use MSP */
  367.     MRS     R0, PSP         /*; stack use PSP, read PSP */
  368.     B       Get_LR_and_Branch
  369. Stack_Use_MSP
  370.     MRS     R0, MSP         /*; read MSP */
  371. Get_LR_and_Branch
  372.     MOV     R1, LR          /*; LR current value */
  373.     LDR     R2,=__cpp(Hard_Fault_Handler) /*; branch to Hard_Fault_Handler */
  374.     BX      R2
  375. }

  376. #endif

  377. #endif

  378. #ifndef DISABLE_UART
  379. /**
  380. * @brief       Routine to send a char
  381. *
  382. * @param[in]   ch Character to send to debug port.
  383. *
  384. * @returns     Send value from UART debug port
  385. *
  386. * @details     Send a target char to UART debug port .
  387. */
  388. #ifndef NONBLOCK_PRINTF
  389. static void SendChar_ToUART(int ch)
  390. {
  391.     while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);

  392.     if(ch == '\n')
  393.     {
  394.         DEBUG_PORT->DAT = '\r';
  395.         while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
  396.     }
  397.     DEBUG_PORT->DAT = ch;
  398. }

  399. #else
  400. /* Non-block implement of send char */
  401. #define BUF_SIZE    2048
  402. static void SendChar_ToUART(int ch)
  403. {
  404.     static uint8_t u8Buf[BUF_SIZE] = {0};
  405.     static int32_t i32Head = 0;
  406.     static int32_t i32Tail = 0;
  407.     int32_t i32Tmp;

  408.     /* Only flush the data in buffer to UART when ch == 0 */
  409.     if(ch)
  410.     {
  411.         /* Push char */
  412.         if(ch == '\n')
  413.         {
  414.             i32Tmp = i32Head+1;
  415.             if(i32Tmp > BUF_SIZE) i32Tmp = 0;
  416.             if(i32Tmp != i32Tail)
  417.             {
  418.                 u8Buf[i32Head] = '\r';
  419.                 i32Head = i32Tmp;
  420.             }
  421.         }

  422.         i32Tmp = i32Head+1;
  423.         if(i32Tmp > BUF_SIZE) i32Tmp = 0;
  424.         if(i32Tmp != i32Tail)
  425.         {
  426.             u8Buf[i32Head] = ch;
  427.             i32Head = i32Tmp;
  428.         }
  429.     }
  430.     else
  431.     {
  432.         if(i32Tail == i32Head)
  433.             return;
  434.     }

  435.     /* pop char */
  436.     do
  437.     {
  438.         i32Tmp = i32Tail + 1;
  439.         if(i32Tmp > BUF_SIZE) i32Tmp = 0;

  440.         if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) == 0)
  441.         {
  442.             DEBUG_PORT->DAT = u8Buf[i32Tail];
  443.             i32Tail = i32Tmp;
  444.         }
  445.         else
  446.             break; /* FIFO full */
  447.     }while(i32Tail != i32Head);
  448. }
  449. #endif   /* else for NONBLOCK_PRINTF */

  450. #endif   /* if not def DISABLE_UART */

  451. /**
  452. * @brief       Routine to send a char
  453. *
  454. * @param[in]   ch Character to send to debug port.
  455. *
  456. * @returns     Send value from UART debug port or semihost
  457. *
  458. * @details     Send a target char to UART debug port or semihost.
  459. */
  460. static void SendChar(int ch)
  461. {
  462. #if defined(DEBUG_ENABLE_SEMIHOST)
  463.     g_buf[g_buf_len++] = ch;
  464.     g_buf[g_buf_len] = '\0';
  465.     if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
  466.     {
  467.         /* Send the char */
  468.         if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
  469.         {
  470.             g_buf_len = 0;
  471.             return;
  472.         }
  473.         else
  474.         {
  475. #ifndef DISABLE_UART
  476.             int i;

  477.             for(i = 0; i < g_buf_len; i++)
  478.                 SendChar_ToUART(g_buf[i]);
  479. #endif
  480.             g_buf_len = 0;
  481.         }
  482.     }
  483. #else
  484. #ifndef DISABLE_UART
  485.     SendChar_ToUART(ch);
  486. #endif
  487. #endif
  488. }

  489. /**
  490. * @brief    Routine to get a char
  491. *
  492. * @param    None
  493. *
  494. * @returns  Get value from UART debug port or semihost
  495. *
  496. * @details  Wait UART debug port or semihost to input a char.
  497. */
  498. static char GetChar(void)
  499. {
  500. #ifdef DEBUG_ENABLE_SEMIHOST
  501. # if defined (__CC_ARM)
  502.     int nRet;
  503.     while(SH_DoCommand(0x101, 0, &nRet) != 0)
  504.     {
  505.         if(nRet != 0)
  506.         {
  507.             SH_DoCommand(0x07, 0, &nRet);
  508.             return (char)nRet;
  509.         }
  510.     }
  511. # else
  512.     int nRet;
  513.     while(SH_DoCommand(0x7, 0, &nRet) != 0)
  514.     {
  515.         if(nRet != 0)
  516.             return (char)nRet;
  517.     }
  518. # endif
  519.     return (0);
  520. #else
  521. #ifndef DISABLE_UART
  522.     while(1)
  523.     {
  524.         if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
  525.         {
  526.             return (DEBUG_PORT->DAT);
  527.         }
  528.     }
  529. #else
  530.     return 0;
  531. #endif
  532. #endif
  533. }

  534. /**
  535. * @brief    Check any char input from UART
  536. *
  537. * @param    None
  538. *
  539. * @retval   1: No any char input
  540. * @retval   0: Have some char input
  541. *
  542. * @details  Check UART RSR RX EMPTY or not to determine if any char input from UART
  543. */

  544. int kbhit(void)
  545. {
  546. #ifndef DISABLE_UART
  547.     return !((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0);
  548. #else
  549.     return 0;
  550. #endif
  551. }
  552. /**
  553. * @brief    Check if debug message finished
  554. *
  555. * @param    None
  556. *
  557. * @retval   1: Message is finished
  558. * @retval   0: Message is transmitting.
  559. *
  560. * @details  Check if message finished (FIFO empty of debug port)
  561. */

  562. int IsDebugFifoEmpty(void)
  563. {
  564. #ifndef DISABLE_UART
  565.     return ((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) != 0);
  566. #else
  567.     return 1;
  568. #endif
  569. }

  570. /**
  571. * @brief       C library retargetting
  572. *
  573. * @param[in]   ch Character to send to debug port.
  574. *
  575. * @returns     None
  576. *
  577. * @details     Check if message finished (FIFO empty of debug port)
  578. */

  579. void _ttywrch(int ch)
  580. {
  581.     SendChar(ch);
  582.     return;
  583. }


  584. /**
  585. * @brief      Write character to stream
  586. *
  587. * @param[in]  ch       Character to be written. The character is passed as its int promotion.
  588. * @param[in]  stream   Pointer to a FILE object that identifies the stream where the character is to be written.
  589. *
  590. * @returns    If there are no errors, the same character that has been written is returned.
  591. *             If an error occurs, EOF is returned and the error indicator is set (see ferror).
  592. *
  593. * @details    Writes a character to the stream and advances the position indicator.\n
  594. *             The character is written at the current position of the stream as indicated \n
  595. *             by the internal position indicator, which is then advanced one character.
  596. *
  597. * [url=home.php?mod=space&uid=536309]@NOTE[/url]       The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/fputc/.
  598. *
  599. *
  600. */

  601. int fputc(int ch, FILE *stream)
  602. {
  603.     SendChar(ch);
  604.     return ch;
  605. }

  606. #if defined (__GNUC__) && !defined(__ARMCC_VERSION)

  607. int _write (int fd, char *ptr, int len)
  608. {
  609.     int i = len;

  610.     while(i--)
  611.     {
  612.         while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);

  613.         if(*ptr == '\n')
  614.         {
  615.             DEBUG_PORT->DAT = '\r';
  616.             while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
  617.         }

  618.         DEBUG_PORT->DAT = *ptr++;

  619.     }
  620.     return len;
  621. }

  622. int _read (int fd, char *ptr, int len)
  623. {

  624.     while((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) != 0);
  625.     *ptr = DEBUG_PORT->DAT;
  626.     return 1;


  627. }

  628. #else
  629. /**
  630. * @brief      Get character from UART debug port or semihosting input
  631. *
  632. * @param[in]  stream   Pointer to a FILE object that identifies the stream on which the operation is to be performed.
  633. *
  634. * @returns    The character read from UART debug port or semihosting
  635. *
  636. * @details    For get message from debug port or semihosting.
  637. *
  638. */

  639. int fgetc(FILE *stream)
  640. {
  641.     return (GetChar());
  642. }

  643. /**
  644. * @brief      Check error indicator
  645. *
  646. * @param[in]  stream   Pointer to a FILE object that identifies the stream.
  647. *
  648. * @returns    If the error indicator associated with the stream was set, the function returns a nonzero value.
  649. *             Otherwise, it returns a zero value.
  650. *
  651. * @details    Checks if the error indicator associated with stream is set, returning a value different
  652. *             from zero if it is. This indicator is generally set by a previous operation on the stream that failed.
  653. *
  654. * @note       The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/ferror/.
  655. *
  656. */

  657. int ferror(FILE *stream)
  658. {
  659.     return EOF;
  660. }
  661. #endif
  662. #ifdef DEBUG_ENABLE_SEMIHOST
  663. # ifdef __ICCARM__
  664. void __exit(int return_code)
  665. {

  666.     /* Check if link with ICE */
  667.     if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
  668.     {
  669.         /* Make sure all message is print out */
  670.         while(IsDebugFifoEmpty() == 0);
  671.     }
  672. label:
  673.     goto label;  /* endless loop */
  674. }
  675. # else
  676. void _sys_exit(int return_code)
  677. {

  678.     /* Check if link with ICE */
  679.     if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
  680.     {
  681.         /* Make sure all message is print out */
  682.         while(IsDebugFifoEmpty() == 0);
  683.     }
  684. label:
  685.     goto label;  /* endless loop */
  686. }
  687. # endif
  688. #endif
sdlls 发表于 2024-8-5 10:01 | 显示全部楼层
新唐单片机(Nuvoton)上的printf函数重定向到串口的方法与其他单片机类似。
mattlincoln 发表于 2024-8-5 11:40 | 显示全部楼层
配置串口相关的寄存器,设置波特率、数据位、停止位等参数,使其能够正常工作。
iyoum 发表于 2024-8-5 12:35 | 显示全部楼层
stdio.h:标准输入输出头文件,包含printf函数的声明。
serial.h:如果串口功能是通过特定的库实现的,则需要包含相应的头文件。对于新唐单片机,可能需要包含NuMicro.h或其他与串口相关的头文件。
plsbackup 发表于 2024-8-5 16:33 | 显示全部楼层
需要定义一个新的函数,比如fputc_redirect,这个函数将被用作fputc的替代。在这个函数中,你将写入一个字符到串口。
ccook11 发表于 2024-8-5 18:01 | 显示全部楼层
#include <stdio.h>
#include <stdarg.h>

// 串口发送字符的函数
void UART_SendChar(unsigned char c) {
    // 在此处添加将字符发送到串口的代码
}

// `printf` 重定向函数
int fputc(int ch, FILE *f) {
    UART_SendChar((unsigned char)ch);
    return ch;
}
10299823 发表于 2024-8-5 19:51 | 显示全部楼层
需要包含标准的输入输出库以及其他必要的头文件,比如串口通信的头文件。
benjaminka 发表于 2024-8-5 21:38 | 显示全部楼层
需要包含必要的头文件,并声明一个用于串口初始化的函数。
lzmm 发表于 2024-8-6 10:19 | 显示全部楼层
使用的是Keil MDK或者其他集成开发环境,你可能需要在项目的选项设置中启用微库(MicroLib),因为它包含了优化的标准C库函数,更适合嵌入式系统,并且支持printf的重定向。
药无尘 发表于 2024-8-6 11:44 | 显示全部楼层
/ 串口发送字符的函数
void UART_SendChar(unsigned char c) {
    // 在此处添加将字符发送到串口的代码
}

// `printf` 重定向函数
int fputc(int ch, FILE *f) {
    UART_SendChar((unsigned char)ch);
    return ch;
}
backlugin 发表于 2024-8-6 11:55 | 显示全部楼层
需要调整缓冲区大小以适应特定的应用需求。
i1mcu 发表于 2024-8-6 13:29 | 显示全部楼层
在Keil MDK中,你可以在“Project -> Options for Target -> Target”中找到“Use MicroLIB”选项并勾选它。
minzisc 发表于 2024-8-6 15:09 | 显示全部楼层
重定向通常是通过一个简单的库函数来实现的,它会在程序开始时初始化串口,并在调用printf时将输出发送到串口。
albertaabbot 发表于 2024-8-6 16:47 | 显示全部楼层
// 重定向fputc函数到串口
int fputc(int ch, FILE *stream) {
    // 发送字符到串口
    Uart_PutChar(UART0, (char)ch);
    return ch;
}
updownq 发表于 2024-8-6 18:22 | 显示全部楼层
需要重新定义标准输入/输出(I/O)函数,特别是fputc函数,以便它将字符发送到串口而不是控制台。
jimmhu 发表于 2024-8-6 20:02 | 显示全部楼层
需要实现一个串口通信接口,并将标准I/O库中的fputc函数重定向到串口。
saservice 发表于 2024-8-6 21:45 | 显示全部楼层
可以像平常一样使用printf函数,它会自动将输出重定向到串口。
uytyu 发表于 2024-8-8 09:26 | 显示全部楼层
典型的嵌入式C开发环境              
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

1693

帖子

0

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