大锤子 发表于 2024-1-10 01:05:40

【SDCC】如何使用printf函数发送串口数据

本帖最后由 大锤子 于 2024-1-10 01:18 编辑

背景
相信大家一定都有使用串口助手通过串口跟单片机交互的经历。在学习瑞生大佬的STC8G学习机的时候,有个例程是使用eeprom来记录最后的按键。然后单片机重新上电后从eeprom中读出,再通过串口发送出去,然后使用串口助手接收。除此之外在很多调试的场景也都可以将关键步骤的信息通过串口发送到串口助手。比如这个例子中串口的初始化,和发送数据函数:void UartInit(void)
{
    SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
      AUXR |= 0x04;                //定时器时钟1T模式
      T2L = 0xB4;                        //设置定时初始值
      T2H = 0xFF;                        //设置定时初始值
      AUXR |= 0x10;                //定时器2开始计时
}

void Uart_Send_Byte(unsigned char dat)
{
      SBUF = dat;

      while (!TI);
      TI = 0;
      
}SDCC 中使用printf
       在简单的使用场景中可以直接使用上边的简单方法来发送单字节数据。但是如果我们希望发送字符串呢,比如优化成"the last press key is: 03" 再使用这种方式就比较难实现了。 大家肯定也都想得到,可以将printf函数重定向到串口;确实是可以的。而且sdcc 也是支持的。只是有所不同;
       在sdcc用户手册中找到了下边的一段话:


      意思是说标准库中的getchar和putchar这两个函数再嵌入式开发中需要用户自己来实现,因为SDCC不知道他们具体是通过什么通信的。因此如果我们是通过串口UART通信那就重写它。 下边也给出了示例;
按照示例程序改写成下边的代码:
看效果:      
       如果到这里就完了其实也没啥,大家大概也是都知道的。当继续看用户手册时,手册给出了一些最佳实践及数据对比,恰好对比使用的MCU是mcs51的:





      这里强调了几点,printf 在printf_large.c 这个源文件中实现,并且默认是不支持float的。而且printf这个函数占用的存储很大,建议在使用的时候将存储模式设置成model-large。 因此对于存储空间不大,且在应用中对存储较为关注时最好不要使用printf。 而且也提供了更加合适的方法比如:printf_small, 这个函数我已经验证过了这里就不贴代码了。
      下边分别在model-large模式下分别使用printf和prinf_small 编译的结果:


















大锤子 发表于 2024-1-10 01:19:05

哎这个编辑工具啊, 真糟心{:4_238:}

Snapdragon 发表于 2024-1-10 20:47:52

SDCC用过一段时间,和keil比还是差很多。完整的printf比keil效率、代码体积差得远。不过float计算的精度比keil高。

大锤子 发表于 2024-1-10 21:11:17

Snapdragon 发表于 2024-1-10 20:47
SDCC用过一段时间,和keil比还是差很多。完整的printf比keil效率、代码体积差得远。不过float计算的精度比k ...

{:4_250:}

清风迎明月 发表于 2024-5-4 10:59:57

如果用串口2,串口3,如何用printf

大锤子 发表于 2024-5-4 13:28:58

清风迎明月 发表于 2024-5-4 10:59
如果用串口2,串口3,如何用printf

类似的重写putchar函数, ti和buff 改成串口2,3对应的寄存器就可以了。
页: [1]
查看完整版本: 【SDCC】如何使用printf函数发送串口数据