打印
[应用方案]

printf重定向到串口

[复制链接]
1612|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 | 只看该作者
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     retarget.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
* [url=home.php?mod=space&uid=247401]@brief[/url]    M480 Series Debug Port and Semihost Setting Source File
*
* SPDX-License-Identifier: Apache-2.0
* [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/


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

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

#if defined(DEBUG_ENABLE_SEMIHOST)
    #ifndef DISABLE_UART
        #define DISABLE_UART
    #endif
#endif

#define DEBUG_PORT   UART0
/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/
#if !(defined(__ICCARM__) && (__VER__ >= 6010000))
# if (__ARMCC_VERSION < 6040000)
struct __FILE
{
    int handle; /* Add whatever you need here */
};
# endif
#elif(__VER__ >= 8000000)
struct __FILE
{
    int handle; /* Add whatever you need here */
};
#endif
FILE __stdout;
FILE __stdin;


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

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

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

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



/*---------------------------------------------------------------------------------------------------------*/
/* Routine to write a char                                                                                 */
/*---------------------------------------------------------------------------------------------------------*/

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

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

# elif defined(__ICCARM__)      // IAR

void SH_End(void)
{
    asm("MOVS   R0,#1 \n"        /*; Set return value to 1 */
        "BX     lr    \n"        /*; Return */
       );
}

void SH_ICE(void)
{
  asm("CMP   R2,#0   \n"
      "BEQ   SH_End  \n"
      "STR   R0,[R2] \n"       /*; Save the return value to *pn32Out_R0 */
     );
}

/**
*
* @brief      The function to process semihosted command
* @param[in]  n32In_R0  : semihost register 0
* @param[in]  n32In_R1  : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval     0: No ICE debug
* @retval     1: ICE debug
*
*/
int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
    asm("BKPT   0xAB   \n"       /*; This instruction will cause ICE trap or system HardFault */
        "B      SH_ICE \n"
        "SH_HardFault: \n"       /*; Captured by HardFault */
        "MOVS   R0,#0  \n"       /*; Set return value to 0 */
        "BX     lr     \n"       /*; Return */
        );

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

/**
* @brief       Get LR value and branch to Hard_Fault_Handler function
* @param       None
* @return      None
* @details     This function is use to get LR value and branch to Hard_Fault_Handler function.
*/
void Get_LR_and_Branch(void)
{
    asm("MOV     R1, LR               \n" /*; LR current value */
        "B       Hard_Fault_Handler   \n"
       );
}

/**
* @brief       Get MSP value and branch to Get_LR_and_Branch function
* @param       None
* @return      None
* @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
*/
void Stack_Use_MSP(void)
{
    asm("MRS     R0, MSP           \n" /*; read MSP */
        "B       Get_LR_and_Branch \n"
       );
}

/**
* @brief       Get stack pointer value and branch to Get_LR_and_Branch function
* @param       None
* @return      None
* @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
*/
void HardFault_Handler_Ret(void)
{
    asm("MOVS    r0, #4                        \n"
        "MOV     r1, LR                        \n"
        "TST     r0, r1                        \n" /*; check LR bit 2 */
        "BEQ     Stack_Use_MSP                 \n" /*; stack use MSP */
        "MRS     R0, PSP                       \n" /*; stack use PSP, read PSP */
        "B       Get_LR_and_Branch             \n"
       );
}

/**
* @brief    This function is implemented to support semihost
* @param    None
* @returns  None
* @details  This function is implement to support semihost message print.
*
*/
void SP_Read_Ready(void)
{
    asm("LDR     R1, [R0, #24] \n"        /*; Get previous PC */
        "LDRH    R3, [R1]      \n"        /*; Get instruction */
        "LDR     R2, [pc, #8]  \n"        /*; The special BKPT instruction */
        "CMP     R3, R2        \n"        /*; Test if the instruction at previous PC is BKPT */
        "BNE     HardFault_Handler_Ret \n" /*; Not BKPT */
        "ADDS    R1, #4        \n"        /*; Skip BKPT and next line */
        "STR     R1, [R0, #24] \n"        /*; Save previous PC */
        "BX      lr            \n"        /*; Return */
        "DCD     0xBEAB        \n"        /*; BKPT instruction code */
        "B       HardFault_Handler_Ret \n"
       );
}

/**
* @brief       Get stack pointer value and branch to Get_LR_and_Branch function
* @param       None
* @return      None
* @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
*/
void SP_is_PSP(void)
{
    asm(
        "MRS     R0, PSP       \n"      /*; stack use PSP, read PSP */
        "B       Get_LR_and_Branch    \n"

       );
}

/**
* @brief    This HardFault handler is implemented to support semihost
*
* @param    None
*
* @returns  None
*
* @details  This function is implement to support semihost message print.
*
*/
void HardFault_Handler (void)
{
    asm("MOV     R0, lr        \n"
        "LSLS    R0, #29       \n"        /*; Check bit 2 */
        "BMI     SP_is_PSP     \n"        /*; previous stack is PSP */
        "MRS     R0, MSP       \n"        /*; previous stack is MSP, read MSP */
        "B       SP_Read_Ready \n"
       );

    while(1);
}

# else

/**
* @brief    This HardFault handler is implemented to support semihost
* @param    None
* @returns  None
* @details  This function is implement to support semihost message print.
*
*/
__asm int32_t HardFault_Handler(void)
{
    MOV     R0, LR
    LSLS    R0, #29               /*; Check bit 2 */
    BMI     SP_is_PSP             /*; previous stack is PSP */
    MRS     R0, MSP               /*; previous stack is MSP, read MSP */
    B       SP_Read_Ready
SP_is_PSP
    MRS     R0, PSP               /*; Read PSP */

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

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

    BX      LR                    /*; Return */
HardFault_Handler_Ret

    /* TODO: Implement your own hard fault handler here. */
    MOVS    r0, #4
    MOV     r1, LR
    TST     r0, r1                          /*; check LR bit 2 */
    BEQ     Stack_Use_MSP                   /*; stack use MSP */
    MRS     R0, PSP ;stack use PSP          /*; stack use PSP, read PSP */
    B       Get_LR_and_Branch
Stack_Use_MSP
    MRS     R0, MSP ; stack use MSP         /*; read MSP */
Get_LR_and_Branch
    MOV     R1, LR ; LR current value       /*; LR current value */
    LDR     R2,=__cpp(Hard_Fault_Handler)   /*; branch to Hard_Fault_Handler */
    BX      R2

    B       .

    ALIGN
}

/**
*
* @brief      The function to process semihosted command
* @param[in]  n32In_R0  : semihost register 0
* @param[in]  n32In_R1  : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval     0: No ICE debug
* @retval     1: ICE debug
*
*/
__asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
    BKPT   0xAB          /*; Wait ICE or HardFault */
    /*; ICE will step over BKPT directly
      ; HardFault will step BKPT and the next line */
    B      SH_ICE

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

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

SH_End
    MOVS   R0, #1        /*; Set return value to 1 */
    BX     lr            /*; Return */
}
#endif

#else   // ndef DEBUG_ENABLE_SEMIHOST

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

/**
* @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param    None
*
* @returns  None
*
* @details  This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
*
*/
void HardFault_Handler(void)
{
    asm("MOVS    r0, #4                        \n"
        "MOV     r1, LR                        \n"
        "TST     r0, r1                        \n" /*; check LR bit 2 */
        "BEQ     1f                            \n" /*; stack use MSP */
        "MRS     R0, PSP                       \n" /*; stack use PSP, read PSP */
        "MOV     R1, LR                        \n" /*; LR current value */
        "B       Hard_Fault_Handler            \n"
        "1:                                    \n"
        "MRS     R0, MSP                       \n" /*; LR current value */
        "B       Hard_Fault_Handler            \n"   
        ::[Hard_Fault_Handler] "r" (Hard_Fault_Handler) // input
    );
    while(1);
}

# elif defined(__ICCARM__)

void Get_LR_and_Branch(void)
{
    asm("MOV     R1, LR                  \n" /*; LR current value */
        "B       Hard_Fault_Handler      \n"
       );
}

void Stack_Use_MSP(void)
{
    asm("MRS     R0, MSP           \n" /*; read MSP */
        "B       Get_LR_and_Branch \n"
       );
}

/**
* @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param    None
*
* @returns  None
*
* @details  This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
*
*/
void HardFault_Handler(void)
{
    asm("MOVS    r0, #4                        \n"
        "MOV     r1, LR                        \n"
        "TST     r0, r1                        \n" /*; check LR bit 2 */
        "BEQ     Stack_Use_MSP                 \n" /*; stack use MSP */
        "MRS     R0, PSP                       \n" /*; stack use PSP, read PSP */
        "B       Get_LR_and_Branch             \n"
       );

    while(1);
}

# else

/**
* @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param    None
*
* @return   None
*
* @details  The function extracts the location of stack frame and passes it to Hard_Fault_Handler function as a pointer
*
*/
__asm int32_t HardFault_Handler(void)
{
    MOVS    r0, #4
    MOV     r1, LR
    TST     r0, r1          /*; check LR bit 2 */
    BEQ     Stack_Use_MSP   /*; stack use MSP */
    MRS     R0, PSP         /*; stack use PSP, read PSP */
    B       Get_LR_and_Branch
Stack_Use_MSP
    MRS     R0, MSP         /*; read MSP */
Get_LR_and_Branch
    MOV     R1, LR          /*; LR current value */
    LDR     R2,=__cpp(Hard_Fault_Handler) /*; branch to Hard_Fault_Handler */
    BX      R2
}

#endif

#endif

#ifndef DISABLE_UART
/**
* @brief       Routine to send a char
*
* @param[in]   ch Character to send to debug port.
*
* @returns     Send value from UART debug port
*
* @details     Send a target char to UART debug port .
*/
#ifndef NONBLOCK_PRINTF
static void SendChar_ToUART(int ch)
{
    while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);

    if(ch == '\n')
    {
        DEBUG_PORT->DAT = '\r';
        while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
    }
    DEBUG_PORT->DAT = ch;
}

#else
/* Non-block implement of send char */
#define BUF_SIZE    2048
static void SendChar_ToUART(int ch)
{
    static uint8_t u8Buf[BUF_SIZE] = {0};
    static int32_t i32Head = 0;
    static int32_t i32Tail = 0;
    int32_t i32Tmp;

    /* Only flush the data in buffer to UART when ch == 0 */
    if(ch)
    {
        /* Push char */
        if(ch == '\n')
        {
            i32Tmp = i32Head+1;
            if(i32Tmp > BUF_SIZE) i32Tmp = 0;
            if(i32Tmp != i32Tail)
            {
                u8Buf[i32Head] = '\r';
                i32Head = i32Tmp;
            }
        }

        i32Tmp = i32Head+1;
        if(i32Tmp > BUF_SIZE) i32Tmp = 0;
        if(i32Tmp != i32Tail)
        {
            u8Buf[i32Head] = ch;
            i32Head = i32Tmp;
        }
    }
    else
    {
        if(i32Tail == i32Head)
            return;
    }

    /* pop char */
    do
    {
        i32Tmp = i32Tail + 1;
        if(i32Tmp > BUF_SIZE) i32Tmp = 0;

        if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) == 0)
        {
            DEBUG_PORT->DAT = u8Buf[i32Tail];
            i32Tail = i32Tmp;
        }
        else
            break; /* FIFO full */
    }while(i32Tail != i32Head);
}
#endif   /* else for NONBLOCK_PRINTF */

#endif   /* if not def DISABLE_UART */

/**
* @brief       Routine to send a char
*
* @param[in]   ch Character to send to debug port.
*
* @returns     Send value from UART debug port or semihost
*
* @details     Send a target char to UART debug port or semihost.
*/
static void SendChar(int ch)
{
#if defined(DEBUG_ENABLE_SEMIHOST)
    g_buf[g_buf_len++] = ch;
    g_buf[g_buf_len] = '\0';
    if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
    {
        /* Send the char */
        if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
        {
            g_buf_len = 0;
            return;
        }
        else
        {
#ifndef DISABLE_UART
            int i;

            for(i = 0; i < g_buf_len; i++)
                SendChar_ToUART(g_buf[i]);
#endif
            g_buf_len = 0;
        }
    }
#else
#ifndef DISABLE_UART
    SendChar_ToUART(ch);
#endif
#endif
}

/**
* @brief    Routine to get a char
*
* @param    None
*
* @returns  Get value from UART debug port or semihost
*
* @details  Wait UART debug port or semihost to input a char.
*/
static char GetChar(void)
{
#ifdef DEBUG_ENABLE_SEMIHOST
# if defined (__CC_ARM)
    int nRet;
    while(SH_DoCommand(0x101, 0, &nRet) != 0)
    {
        if(nRet != 0)
        {
            SH_DoCommand(0x07, 0, &nRet);
            return (char)nRet;
        }
    }
# else
    int nRet;
    while(SH_DoCommand(0x7, 0, &nRet) != 0)
    {
        if(nRet != 0)
            return (char)nRet;
    }
# endif
    return (0);
#else
#ifndef DISABLE_UART
    while(1)
    {
        if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
        {
            return (DEBUG_PORT->DAT);
        }
    }
#else
    return 0;
#endif
#endif
}

/**
* @brief    Check any char input from UART
*
* @param    None
*
* @retval   1: No any char input
* @retval   0: Have some char input
*
* @details  Check UART RSR RX EMPTY or not to determine if any char input from UART
*/

int kbhit(void)
{
#ifndef DISABLE_UART
    return !((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0);
#else
    return 0;
#endif
}
/**
* @brief    Check if debug message finished
*
* @param    None
*
* @retval   1: Message is finished
* @retval   0: Message is transmitting.
*
* @details  Check if message finished (FIFO empty of debug port)
*/

int IsDebugFifoEmpty(void)
{
#ifndef DISABLE_UART
    return ((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) != 0);
#else
    return 1;
#endif
}

/**
* @brief       C library retargetting
*
* @param[in]   ch Character to send to debug port.
*
* @returns     None
*
* @details     Check if message finished (FIFO empty of debug port)
*/

void _ttywrch(int ch)
{
    SendChar(ch);
    return;
}


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

int fputc(int ch, FILE *stream)
{
    SendChar(ch);
    return ch;
}

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

int _write (int fd, char *ptr, int len)
{
    int i = len;

    while(i--)
    {
        while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);

        if(*ptr == '\n')
        {
            DEBUG_PORT->DAT = '\r';
            while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
        }

        DEBUG_PORT->DAT = *ptr++;

    }
    return len;
}

int _read (int fd, char *ptr, int len)
{

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


}

#else
/**
* @brief      Get character from UART debug port or semihosting input
*
* @param[in]  stream   Pointer to a FILE object that identifies the stream on which the operation is to be performed.
*
* @returns    The character read from UART debug port or semihosting
*
* @details    For get message from debug port or semihosting.
*
*/

int fgetc(FILE *stream)
{
    return (GetChar());
}

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

int ferror(FILE *stream)
{
    return EOF;
}
#endif
#ifdef DEBUG_ENABLE_SEMIHOST
# ifdef __ICCARM__
void __exit(int return_code)
{

    /* Check if link with ICE */
    if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
    {
        /* Make sure all message is print out */
        while(IsDebugFifoEmpty() == 0);
    }
label:
    goto label;  /* endless loop */
}
# else
void _sys_exit(int return_code)
{

    /* Check if link with ICE */
    if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
    {
        /* Make sure all message is print out */
        while(IsDebugFifoEmpty() == 0);
    }
label:
    goto label;  /* endless loop */
}
# endif
#endif

使用特权

评论回复
地板
sdlls| | 2024-8-5 10:01 | 只看该作者
新唐单片机(Nuvoton)上的printf函数重定向到串口的方法与其他单片机类似。

使用特权

评论回复
5
mattlincoln| | 2024-8-5 11:40 | 只看该作者
配置串口相关的寄存器,设置波特率、数据位、停止位等参数,使其能够正常工作。

使用特权

评论回复
6
iyoum| | 2024-8-5 12:35 | 只看该作者
stdio.h:标准输入输出头文件,包含printf函数的声明。
serial.h:如果串口功能是通过特定的库实现的,则需要包含相应的头文件。对于新唐单片机,可能需要包含NuMicro.h或其他与串口相关的头文件。

使用特权

评论回复
7
plsbackup| | 2024-8-5 16:33 | 只看该作者
需要定义一个新的函数,比如fputc_redirect,这个函数将被用作fputc的替代。在这个函数中,你将写入一个字符到串口。

使用特权

评论回复
8
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;
}

使用特权

评论回复
9
10299823| | 2024-8-5 19:51 | 只看该作者
需要包含标准的输入输出库以及其他必要的头文件,比如串口通信的头文件。

使用特权

评论回复
10
benjaminka| | 2024-8-5 21:38 | 只看该作者
需要包含必要的头文件,并声明一个用于串口初始化的函数。

使用特权

评论回复
11
lzmm| | 2024-8-6 10:19 | 只看该作者
使用的是Keil MDK或者其他集成开发环境,你可能需要在项目的选项设置中启用微库(MicroLib),因为它包含了优化的标准C库函数,更适合嵌入式系统,并且支持printf的重定向。

使用特权

评论回复
12
药无尘| | 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;
}

使用特权

评论回复
13
backlugin| | 2024-8-6 11:55 | 只看该作者
需要调整缓冲区大小以适应特定的应用需求。

使用特权

评论回复
14
i1mcu| | 2024-8-6 13:29 | 只看该作者
在Keil MDK中,你可以在“Project -> Options for Target -> Target”中找到“Use MicroLIB”选项并勾选它。

使用特权

评论回复
15
minzisc| | 2024-8-6 15:09 | 只看该作者
重定向通常是通过一个简单的库函数来实现的,它会在程序开始时初始化串口,并在调用printf时将输出发送到串口。

使用特权

评论回复
16
albertaabbot| | 2024-8-6 16:47 | 只看该作者
// 重定向fputc函数到串口
int fputc(int ch, FILE *stream) {
    // 发送字符到串口
    Uart_PutChar(UART0, (char)ch);
    return ch;
}

使用特权

评论回复
17
updownq| | 2024-8-6 18:22 | 只看该作者
需要重新定义标准输入/输出(I/O)函数,特别是fputc函数,以便它将字符发送到串口而不是控制台。

使用特权

评论回复
18
jimmhu| | 2024-8-6 20:02 | 只看该作者
需要实现一个串口通信接口,并将标准I/O库中的fputc函数重定向到串口。

使用特权

评论回复
19
saservice| | 2024-8-6 21:45 | 只看该作者
可以像平常一样使用printf函数,它会自动将输出重定向到串口。

使用特权

评论回复
20
uytyu| | 2024-8-8 09:26 | 只看该作者
典型的嵌入式C开发环境              

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

1373

帖子

0

粉丝