历史上的今天
返回首页

历史上的今天

今天是:2024年12月04日(星期三)

正在发生

2019年12月04日 | 解决STM8类型单片机空间太小,使用不了printf串口打印问题

2019-12-04 来源:eefocus

概述:


在使用STM8L101F3这款单片机时,由于它只有8K的flash,空间非常小,只要调用C库函数printf编译后整个文件很大,直接程序溢出。这也就意味着我们实现printf串口打印调试就没办法进行。既然使用不了库函数,那么我们就可以自己动手封装类似printf的函数,这样我们就可以实现数据串口打印啦。这里就直接放上我的STM8L101F3的部分源码了,希望可以给你一些参考。


源码:


#include "stdarg.h"

#include "stm8l10x.h"

 

void USART_Config(void)

{

    /*Set the USART RX and USART TX at high level*/

    GPIO_ExternalPullUpConfig(GPIOC,GPIO_Pin_3|GPIO_Pin_4, ENABLE);

    /* Enable USART clock */

    CLK_PeripheralClockConfig(CLK_Peripheral_USART, ENABLE);

    USART_DeInit();

    USART_Init((uint32_t)9600, USART_WordLength_8D, USART_StopBits_1,

                USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Rx | USART_Mode_Tx));

    USART_Cmd(DISABLE);

    enableInterrupts();

    USART_Cmd(ENABLE);    

}

 

/*发送串口数据*/

void send_uart_data(uint8_t data)

{

  while (USART_GetFlagStatus(USART_FLAG_TXE) == RESET);

  USART_SendData8(data);

}

 

/*

  功能:将int型数据转为2,8,10,16进制字符串

  参数:value --- 输入的int整型数

        str --- 存储转换的字符串

        radix --- 进制类型选择

  注意:8位单片机int字节只占2个字节

*/

char *sky_itoa(int value, char *str, unsigned int radix)

{

  char list[] = "0123456789ABCDEF";

  unsigned int tmp_value;

  int i = 0, j, k = 0;

  if (NULL == str) {

    return NULL;

  }

  if (2 != radix && 8 != radix && 10 != radix && 16 != radix) {

    return NULL;

  }

  if (radix == 10 && value < 0) {

    //十进制且为负数

    tmp_value = (unsigned int)(0 - value);

    str[i++] = '-';

    k = 1;

  } else {

    tmp_value = (unsigned int)value;

  }

  //数据转换为字符串,逆序存储

  do {

    str[i ++] = list[tmp_value%radix];

    tmp_value /= radix;

  } while(tmp_value);

  str[i] = '';

  //将逆序字符串转换为正序

  char tmp;

  for (j = k; j < (i+k)/2; j++) {

    tmp = str[j];

    str[j] = str[i-j-1+k];

    str[i-j-1+k] = tmp;

  }

  return str;

}

 

/*

  功能:将double型数据转为字符串

  参数:value --- 输入的double浮点数

        str --- 存储转换的字符串

        eps --- 保留小数位选择,至少保留一个小数位,至多保留4个小数位

  注意:8位单片机int字节只占2个字节

*/

void sky_ftoa(double value, char *str, unsigned int eps)

{

  unsigned int integer;

  double decimal;

  char list[] = "0123456789";

  int i = 0, j, k = 0;

  //将整数及小数部分提取出来

  if (value < 0) {

    decimal = (double)(((int)value) - value);

    integer = (unsigned int)(0 - value);

    str[i ++] = '-';

    k = 1;

  } else {

    integer = (unsigned int)(value);

    decimal = (double)(value - integer);

  }

  //整数部分数据转换为字符串,逆序存储

  do {

    str[i ++] = list[integer%10];

    integer /= 10;

  } while(integer);

  str[i] = '';

  //将逆序字符串转换为正序

  char tmp;

  for (j = k; j < (i+k)/2; j++) {

    tmp = str[j];

    str[j] = str[i-j-1+k];

    str[i-j-1+k] = tmp;

  }

  //处理小数部分

  if (eps < 1 || eps > 4) {

    eps = 4;

  }

  

  //精度问题,防止输入1.2输出1.19等情况

  double pp = 0.1;

  for (j = 0; j <= eps; j++) {

    pp *= 0.1;

  }

  decimal += pp;

  while (eps) {

    decimal *= 10;

    eps --;

  }

  int tmp_decimal = (int)decimal;

  str[i ++] = '.';

  k = i;

  //整数部分数据转换为字符串,逆序存储

  do {

    str[i ++] = list[tmp_decimal%10];

    tmp_decimal /= 10;

  } while(tmp_decimal);

  str[i] = '';

  //将逆序字符串转换为正序

  for (j = k; j < (i+k)/2; j++) {

    tmp = str[j];

    str[j] = str[i-j-1+k];

    str[i-j-1+k] = tmp;

  }

  str[i] = '';

}

 

 

void mprintf(char * Data, ...)

{

  const char *s;

  int d;   

  char buf[16];

  uint8_t txdata;

  va_list ap;

  va_start(ap, Data);

  while ( * Data != 0 ) {                          

    if ( * Data == 0x5c )  {  

      switch ( *++Data ) {

        case 'r':          

          txdata = 0x0d;

          send_uart_data(txdata);

          Data ++;

          break;

        case 'n':          

          txdata = 0x0a;

          send_uart_data(txdata);

          Data ++;

          break;

        default:

          Data ++;

          break;

      }  

    } else if ( * Data == '%') {  

      switch ( *++Data ) {

      case 's':  

        s = va_arg(ap, const char *);

        for ( ; *s; s++) {

          send_uart_data(*((uint8_t *)s));

        }

        Data++;

        break;

      case 'd':

        d = va_arg(ap, int);

        sky_itoa(d, buf, 10);

        for (s = buf; *s; s++) {

          send_uart_data(*((uint8_t *)s));

        }

        Data++;

        break;

      case 'x': {

        d = va_arg(ap, int);

        sky_itoa(d, buf, 16);

        for (s = buf; *s; s++) {

          send_uart_data(*((uint8_t *)s));

        }

        Data++;

        break;

      }

      case 'f': {

        double num = va_arg(ap, double);

        sky_ftoa(num, buf, 4);

        for (s = buf; *s; s++) {

          send_uart_data(*((uint8_t *)s));

        }

        Data++;

        break;

      }

      default:

        Data++;

        break;

      }  

    } else {

        send_uart_data(*((uint8_t *)Data));

        Data++;

    }

  }

}

 

void main(void)

{

    USART_Config();

    mprintf("STM8L start...rn");

    mprintf("%f %f %frn", 1.2, 12.36, -1.2364568);

    mprintf("%x %x %xrn", 0x1035, 0x0830, 0x2018);

    mprintf("%d %d %drn", 12, -12345, 2);

    mprintf("STM8L end...rn");

    while (1) {

        

    }

}

执行串口打印结果:

注意事项:


如果你不需要打印浮点数,那么就把浮点数打印部分代码注释掉。由于像这种8位单片机处理浮点数,是通过编译器来软实现,故对浮点数处理可能每增加一次浮点数处理,代码就会增加几十上百个字节,我这边的整型数和浮点数处理后的编译代码大小可以看看,浮点数处理和整型数处理代码空间的差异。

推荐阅读

史海拾趣

Ericsson公司的发展小趣事

随着通信技术的不断发展和市场竞争的加剧,Ericsson也面临着前所未有的挑战。为了应对这些挑战,Ericsson积极进行转型升级。一方面,公司加大了对研发的投入力度,不断推出具有创新性和竞争力的产品和服务;另一方面,Ericsson也通过收购、兼并等方式拓展业务领域和市场份额。此外,公司还注重与合作伙伴建立紧密的合作关系共同推动行业发展。

驰芯微(CHIPWISE)公司的发展小趣事

驰芯微公司自2014年成立以来,就立志于打破国外芯片厂商在车规级芯片领域的垄断。初创时期,公司面临着资金短缺、技术壁垒高和市场竞争激烈的挑战。然而,驰芯微团队凭借对技术的执着追求和对市场的敏锐洞察,成功研发出了一系列车规级智能传感和控制芯片,并逐渐在行业中崭露头角。经过数年的努力,驰芯微已经成为国内车规级芯片领域的领军者,其产品广泛应用于各类前装量产车型。

Dino-Lite公司的发展小趣事

Dino-Lite公司在发展过程中,始终注重市场拓展和合作伙伴关系的建立。公司与多家知名企业建立了长期稳定的合作关系,共同开拓市场、分享资源。通过与合作伙伴的紧密合作,Dino-Lite公司的产品得以快速进入各个行业领域,并获得了良好的口碑和市场份额。

此外,Dino-Lite公司还积极参与国际展览和交流活动,展示公司的最新技术和产品。这些活动不仅提高了公司的知名度,也为公司带来了更多的商业机会和合作伙伴。

Bivar公司的发展小趣事

随着技术的不断发展和市场的日益扩大,Bivar公司意识到国内市场的局限性,开始积极拓展国际市场。公司派遣专业团队前往海外进行市场调研,了解当地需求和竞争态势。通过定制化的产品和灵活的销售策略,Bivar成功打入多个海外市场,并获得了可观的收益。

Goldentech Discrete Semiconductor Inc公司的发展小趣事

在20世纪90年代末,Goldentech Discrete Semiconductor Inc.(以下简称“Goldentech”)由一群来自顶尖学术机构的半导体专家创立。公司从成立之初就专注于研发高性能的离散半导体器件,特别是针对当时迅速发展的移动通信市场。Goldentech的创新团队成功开发出了一种新型的低功耗、高频率的晶体管,这一技术突破迅速吸引了多家手机制造商的注意。凭借这一技术优势,Goldentech在短时间内成为移动通信领域离散半导体器件的主要供应商之一,推动了公司业务的快速增长。

CETC公司的发展小趣事

CETC深知人才是企业发展的根本。因此,公司一直注重人才培养和团队建设。公司设立了完善的培训体系,为员工提供各种学习和发展的机会。同时,CETC还积极引进国内外优秀人才,打造了一支高素质、专业化的团队。这支团队在公司的各个领域都发挥着重要作用,为公司的持续创新和发展提供了有力保障。

问答坊 | AI 解惑

三星2440芯片

三星2440芯片结构…

查看全部问答>

求低成本电子体温计方案

不能用那种什么都集成好的直接输出驱动数码管的,因为我需要拿到数字信号有其它用途,DS18B20 满足技术上的要求,不过我想要精度更高一点的,能做到0.3以内最好 谢谢!…

查看全部问答>

求rt2880f的资料

求rt2880f数据手册 如果有daemon板的原理图更好 在网上找了不少时间都没有找到,以前好像都可以下的,但是现在下不到了 求各位大哥大姐,学弟学妹有的分享一下 先谢过各位了 …

查看全部问答>

从第四个起隔一个丢一个,困扰两天了

以下程序段的功能是:     以2400bps从计算机发送任一字节数据,当单片机收到该数据后, 在此数据前加上一序号然后连同此数据一起发送至计算机 出现的问题:     当发送abcdefgh时,收到的是1a2b3c4e5g    &nbs ...…

查看全部问答>

44b0x的中断优先级问题

44b0x的I_PSLV寄存器设置中断优先级,比如sGA (EINT0),是00最高,还是11最高?谢谢!…

查看全部问答>

一个CAN接口卡,两个SJA1000

我是搞单片机软件开发的,有一个问题,想问大家:一个CAN接口卡,两个SJA1000怎么协调工作?怎么工作的?能给解释以下吗?谢谢了!!…

查看全部问答>

有关LINUX移植的理解问题

书上有这么一段话: 众所周知,处理器只能执行存放在主存中的软件,而操作系统作为一种比较大的软件,在通常情况下,它只能存放在磁盘里。因此,就必须想办法在系统上电之后把它自磁盘提取出来并装入主存。       现在有块S3C ...…

查看全部问答>

stm32103xx请教DMA(DMA_Mode)使用问题!

DMA的正常(Normal)模式:采集到DMA_BufferSize 的个数后,DMA停止。DMA的循环模式:采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。 …

查看全部问答>

鼎阳SDS1102DL拆机图

近日在网上看到用户对鼎阳SDS1102DL的拆机图,给大家分享下,以后如考虑鼎阳示波器这也是个参考资料。 1,包装箱 2,型号,序列号标贴 3,软件版本 4,打开包装箱 内部摆设 5,配件大全 6,裸机观察 背部 CE标贴,接口,电源参数 QC、QA ...…

查看全部问答>