TI Driverlib 标准输出完整重定向的改进方案

电子说

1.4w人已加入

描述

MCU:MSPM0G3507

前段时间在课内做实验的时候碰到了比较丰富的交互需求,遂打开UART,#include "stdio.h",然后开始重定向。虽然网上有广为流传的重定向方案,但是常年玩STM32的我有点迷惑:为什么TI Driverlib的重定向需要定义三个函数呢?

Trial

按照 STM32 重定向的方法,先对fputc进行重定向:

int fputc(int _c, FILE *_fp) {
    while((UART0 - > STAT & UART_STAT_TXFF_MASK));
    UART0 - > TXDATA = _c;
    return _c;
}

观察到,在这种重定向的方案下,printf函数可以输出常字符串,但是无法进行变量的格式化输出。

根据网络上的方案,补充fputsputs函数,稍作修改:

int fputs(const char *restrict s, FILE *restrict stream) {
    uint16_t i, len;
    len = strlen(s);
    for (i = 0; i < len; i++) {
        fputc(s[i], stream);
    }
    return len;
}

int puts(const char *s) {
    int count = fputs(s, stdout);
    count += fputs("n", stdout);
    return count;
}

在这种重定向方法下,printf成功实现了完整的重定向,可以进行变量的格式化输出——但是,sprintf依然无法工作,为什么呢?

观察三个函数的输入参数,其中两个都包含了一个FILE*输入变量,但是我们在使用的时候却完全没用到。找到FILE的定义:

struct __sFILE {
    int fd;                    /* File descriptor */
    unsigned char* buf;        /* Pointer to start of buffer */
    unsigned char* pos;        /* Position in buffer */
    unsigned char* bufend;     /* Pointer to end of buffer */
    unsigned char* buff_stop;  /* Pointer to last read char in buffer */
    unsigned int   flags;      /* File status flags (see below) */
};

typedef struct __sFILE FILE;

可见,在TI的库中, FILE类型并没有被简单地改为简单的存储指针,而是依然保留了“数据流”的形式 。再结合debug中端点的触发情况,以及函数之间的调用关系,尝试对FILE*指针进行写入。若调用了puts,认为上层的标准输出走的是printf(),就向下传递空指针,将输出导向 UART。如果stream不是自己设定的空指针,就去编辑stream指向的缓冲区。

Result

对重定向的三个函数进行如下修改:

int fputc(int _c, FILE *_fp) {
    if(!(_fp)) {
        while((UART0 - > STAT & UART_STAT_TXFF_MASK));
        UART0 - > TXDATA = _c;
    }
    else
        *(_fp- >pos) = _c;
    return _c;
}

int fputs(const char* restrict s, FILE* restrict stream) {
    uint16_t i, len;
    len = strlen(s);
    for(unsigned int i=0; i < len; i++) {
        fputc(s[i], stream);
        if(stream) stream- >pos++;
    }
    return len;
}

int puts(const char *_ptr) {
    int count = fputs(_ptr,NULL);
    count += fputs("n",NULL);
    return count;
}

重定向成功,sprintfprintf均可以正常工作!

More…

那个结构体我还没用完,估计在重定向输入流的时候会用到更多的元素。但是知道这些已经足够了,可以搞点花招,比如把UARTx → TXDATA直接丢到stream里面去,当然FIFO只有一个入口,不需要地址偏移,这么看也是有点麻烦;或者直接把自己的指定buffer设为默认输出区域,等等,虽然更复杂了,但是相对于仅仅把FILE作为一个独立指针,还是更加灵活有趣的!

实力尚浅,还请多多指教!

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分