Keil重定向printf到串口UART输出

2018-06-10 11:22:18编辑:什么鱼 关键字:Keil  重定向printf  串口  UART输出

下面是我搜索到的可以借鉴的讨论+我的评述

评述:在一个芯片系统里,uart的驱动是厂商自己写好的,那他们是怎么关联printf到uart的呢?有人说,printf最终是调用了putchar,我搜索了源码,没有这个函数,估计是开发工具,像KeilC u3,里面已经集成了putchar。于是我奇怪,这个工具怎么知道厂商哪个函数时uart的,有没有命名规则要求?好像没有,看了下面的讨论,估计是通过UART的收发寄存器来关联的。我猜想应该是在某个地方,keilc关联了系统的寄存器列表,找到了串口的寄存器的地址,然后putchar操作该寄存器,就相当于操作了厂商或者开发者自定义的uart_write_byte.uart_read_byte.

所以在keilc里,别人写好的系统,可以直接调用printf输出。我觉得要弄明白,得研究下keil是怎么处理库函数和寄存器的关系的。


关于putchar函数,估计printf是通过

http://www.amobbs.com/thread-5479867-1-1.html


就是在你配置完串口的时候首先写一个数到SBUF寄存器中然后在用printf函数打印就可以,当让这个顺序是不可以变的,如果你想在追问细节为什么,我只能告诉你这应该是开发环境决定的,这一点我就理解这么多,如果有大侠给出更好的解释我也一起共勉。


其实也不用首先写一个数据到SBUF寄存器,只需在串口初始化后,加上一句TI=1;即可。原因是printf函数事实上是调用putchar输出字符的。之所以能输出到串口上,就是因为putchar函数把字符通过串口输出。
这是keil中putchar最简单的版本,其他版本也一样,看函数就明白为什么要先让TI=1;了,楼主写的那个SBUF=0,原理是相同的,写入了数据,那么TI就等于1了,然后就可以使用putchar函数和printf函数了。
putchar函数的源码在{keil安装目录下}\C51\LIB文件夹里的PUTCHAR.C文件里,另外在keil的帮助文档里有说明

char putchar (char c)  {

  while (!TI);

  TI = 0;

  return (SBUF = c);

}

从下面这篇文章中,我好像找到答案了

评述:我在某个CortextM3的源码里的debug.c找到了fputc。应该说,某些系统是通过fputc建立联系,而不是putchar的。如下:


void fputc_hook(char ch)  

{  

    if (DebugType == 0)  

    {  

        UARTWriteByte(ch, 1000);  

    }  

    else  

    {  

        VirtualUartWrite(ch);  

    }  

}  

  

int fputc(int ch, FILE *f)  

{  

    uint8 dgbBuffer[DEBUG_TIME_LEN];  

    uint32 tmpcnt, i;  

  

    if (ch == '\n')  

    {          

        tmpcnt = SysTickCounter;  

        for (i = 0; i < DEBUG_TIME_LEN; i++)  

        {  

            dgbBuffer[i] = tmpcnt % 10;  

            tmpcnt = tmpcnt / 10;  

        }  

          

        fputc_hook('\r');  

        fputc_hook('\n');  

        fputc_hook('[');  

        for (i = 0; i < DEBUG_TIME_LEN; i++)  

        {  

            fputc_hook(dgbBuffer[DEBUG_TIME_LEN - 1 -i]+0x30);  

            if (DEBUG_TIME_LEN - 1 -i == 2)  

            {  

                fputc_hook('.');  

            }  

        }  

        fputc_hook(']');  

          

        return OK;  

    }  

      

    fputc_hook(ch);  

  

    return OK;  

}  

下面是参考文章的转载:
http://blog.chinaunix.net/uid-27631233-id-3345008.html


    在实际工作中,遇到了这么一个问题,需要向不同的串口传输ASCII码,无疑使用printf函数是最方便的。然而printf打印出的信息无法选择出口。在网上搜到的程序,printf要调用fputc函数发送字符。该函数如下:


int fputc(int ch, FILE *f)
{
  /* 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函数输出到stdout,而fprintf可以指定字符到达的文件。可FILE结构体中,没有一个是与串口相关的。

typedef struct {
  char *fpos; /* Current position of file pointer (absolute address) */
  void *base; /* Pointer to the base of the file */
  unsigned short handle; /* File handle */
  short flags; /* Flags (see FileFlags) */
  short unget; /* 1-byte buffer for ungetc (b15=1 if non-empty) */
  unsigned long alloc; /* Number of currently allocated bytes for the file */
  unsigned short buffincrement; /* Number of bytes allocated at once */
} FILE;

    该如何重定向呢?不知道。但有一个弥补的方法。
    自己定义n个FILE*指针,并任意赋值。在fputc中利用if..else来做判断,代码如下:

FILE* FileUart1 = (FILE*)0x19;
FILE* FileUart2 = (FILE*)0x28;
int fputc(int ch, FILE *f) {
  if ( f == FileUart1 ) {
    USART_SendData(COM_USART[0], (uint8_t) ch);
    while (USART_GetFlagStatus(COM_USART[0], USART_FLAG_TC) == RESET){}
  }
  else if ( f == FileUart2 ) {
    USART_SendData(COM_USART[1], (uint8_t) ch);
    while (USART_GetFlagStatus(COM_USART[1], USART_FLAG_TC) == RESET){}
  }
}

    这样,fprintf(FileUart1,...)和fprintf(FileUart2,...)便能向不同的串口发送数据。哈哈,虽然没有真正做到重定向,只是用了个歪招,但最初的目的还是达到了。


关键字:Keil  重定向printf  串口  UART输出

来源: eefocus 引用地址:http://www.eeworld.com.cn/mcu/article_2018061039720.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32F103程序串口调用printf打印数据
下一篇:STM32串口打印printf发送中文乱码问题

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

keil环境下stm32f030R8环境配置

的映射。     存取区一般不需要设置,除非用于IAP或APP需要调整区域空间;3、生成hex文件,即烧录文件。是在keil中编写程序并编译连接成可以下载到开发板的  .hex 文件,然后用jlink仿真器下载;2,是在uboot APP中编写编译代码,生成的是 .bin 文件,可以用uboot 下载。4、用于生成bin文件,如果不需要则可以略过这一步。C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe  --bin -o  E:\bootloader_030test\OBJ\bootloader_030.bin E
发表于 2018-07-11 20:27:28

keil环境下stm32f030程序运行的说明

我们先来看看STM32 正常的程序运行流程:STM32 的内部闪存(FLASH)地址起始于0x08000000,一般情况下,程序文件就从此地址开始写入。此外STM32 是基于Cortex-M3 内核的微控制器,其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是0x08000004,当中断来临,STM32 的内部硬件机制亦会自动将PC 指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。环境配置:map文件中断向量表:SRAM堆栈分配:程序占用空间:FLASH所占用空间:Code +RO +RW = 1.41K;
发表于 2018-07-11 20:21:48

keil环境下stm32f030R8 APP程序中断向量的重映射

1、理论基础:        Stm32f030R8 有64KFlash + 8KSram      Stm32f0系列MCU中断矢量表的定位跟STM32其它系列相比有点差异,即M0系列没有像其它M3/M4/M0+系列所具备的中断矢量表重定位寄存器,其中断矢量表不能借助矢量重定位寄存器简单修改实现。所以Stm32f0 IAP的过程会跟其它系列的STM32芯片的IAP动作有所不同。我们知道,做IAP往往需要两部分代码,一部分是用来升级的IAP程序,一部分用来运行用户实际应用功能的应用程序APP代码。IAP程序及自身的中断向量表放在内部FLASH的
发表于 2018-07-10 21:57:40

STM32f030 boot iap升级时keil配置注意事项

最近使用了一款Cortex-M0内核的芯片STM32F030CC,发现它中断向量表的重映射方法与STM32F10x系列的有所区别,在这里记录与分享一下。由于需要通过IAP进行固件升级,所以芯片的FLASH里面要烧录两份代码:一个Boot loader, 一个用户应用程序。理所当然的,在用户应用程序中,必须得重新映射中断向量表。可是在ST提供的固件库里,我却没有发现类似于stm32f10x固件库中的voidNVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)接口。     浏览了一下Cortex-M0的Programmingman
发表于 2018-07-10 21:33:26
STM32f030 boot iap升级时keil配置注意事项

keil C51使用串口时程序跑死的问题

在使用STC51单片机的串口时,有时候会进入一种很奇怪的情况,就是程序进入了一下子跑死了,初始化代码如下:void UsartConfiguration(unsigned int bps){ SCON = 0X50; //设置为工作方式1 10位异步收发器 TL2 = RCAP2L = bps; //set auto reload value TH2 = RCAP2H = bps>>8; T2CON = 0x34;//0011 0100  timer2 sart run ES = 1;//打开串口中断,注意打开开一定要写串口中断函数 EA = 1;//打开总中断}经过程序模拟DEBUG可以发现程序跑死在发送
发表于 2018-07-06 23:56:17

STM32 PWM的输出与Keil软件仿真

 Main函数int main(){        RCC_Config();        GPIO_Config();        TIM_Config();        while(1)        {                ;        }}接下来,我们讲解一下,在Keil里面看我
发表于 2018-06-29 21:09:23

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2018 EEWORLD.com.cn, Inc. All rights reserved