[STM8] 解决STM8类型单片机空间太小,使用不了printf串口打印问题

[复制链接]
1323|2
 楼主| 花间一壶酒sd 发表于 2024-3-30 11:10 | 显示全部楼层 |阅读模式
概述:
     在使用STM8L101F3这款单片机时,由于它只有8K的flash,空间非常小,只要调用C库函数printf编译后整个文件很大,直接程序溢出。这也就意味着我们实现printf串口打印调试就没办法进行。既然使用不了库函数,那么我们就可以自己动手封装类似printf的函数,这样我们就可以实现数据串口打印啦。这里就直接放上我的STM8L101F3的部分源码了,希望可以给你一些参考。

源码:

  1. #include "stdarg.h"
  2. #include "stm8l10x.h"

  3. void USART_Config(void)
  4. {
  5.     /*Set the USART RX and USART TX at high level*/
  6.     GPIO_ExternalPullUpConfig(GPIOC,GPIO_Pin_3|GPIO_Pin_4, ENABLE);
  7.     /* Enable USART clock */
  8.     CLK_PeripheralClockConfig(CLK_Peripheral_USART, ENABLE);
  9.     USART_DeInit();
  10.     USART_Init((uint32_t)9600, USART_WordLength_8D, USART_StopBits_1,
  11.                 USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Rx | USART_Mode_Tx));
  12.     USART_Cmd(DISABLE);
  13.     enableInterrupts();
  14.     USART_Cmd(ENABLE);   
  15. }

  16. /*发送串口数据*/
  17. void send_uart_data(uint8_t data)
  18. {
  19.   while (USART_GetFlagStatus(USART_FLAG_TXE) == RESET);
  20.   USART_SendData8(data);
  21. }

  22. /*
  23.   功能:将int型数据转为2,8,10,16进制字符串
  24.   参数:value --- 输入的int整型数
  25.         str --- 存储转换的字符串
  26.         radix --- 进制类型选择
  27.   注意:8位单片机int字节只占2个字节
  28. */
  29. char *sky_itoa(int value, char *str, unsigned int radix)
  30. {
  31.   char list[] = "0123456789ABCDEF";
  32.   unsigned int tmp_value;
  33.   int i = 0, j, k = 0;
  34.   if (NULL == str) {
  35.     return NULL;
  36.   }
  37.   if (2 != radix && 8 != radix && 10 != radix && 16 != radix) {
  38.     return NULL;
  39.   }
  40.   if (radix == 10 && value < 0) {
  41.     //十进制且为负数
  42.     tmp_value = (unsigned int)(0 - value);
  43.     str[i++] = '-';
  44.     k = 1;
  45.   } else {
  46.     tmp_value = (unsigned int)value;
  47.   }
  48.   //数据转换为字符串,逆序存储
  49.   do {
  50.     str[i ++] = list[tmp_value%radix];
  51.     tmp_value /= radix;
  52.   } while(tmp_value);
  53.   str[i] = '\0';
  54.   //将逆序字符串转换为正序
  55.   char tmp;
  56.   for (j = k; j < (i+k)/2; j++) {
  57.     tmp = str[j];
  58.     str[j] = str[i-j-1+k];
  59.     str[i-j-1+k] = tmp;
  60.   }
  61.   return str;
  62. }

  63. /*
  64.   功能:将double型数据转为字符串
  65.   参数:value --- 输入的double浮点数
  66.         str --- 存储转换的字符串
  67.         eps --- 保留小数位选择,至少保留一个小数位,至多保留4个小数位
  68.   注意:8位单片机int字节只占2个字节
  69. */
  70. void sky_ftoa(double value, char *str, unsigned int eps)
  71. {
  72.   unsigned int integer;
  73.   double decimal;
  74.   char list[] = "0123456789";
  75.   int i = 0, j, k = 0;
  76.   //将整数及小数部分提取出来
  77.   if (value < 0) {
  78.     decimal = (double)(((int)value) - value);
  79.     integer = (unsigned int)(0 - value);
  80.     str[i ++] = '-';
  81.     k = 1;
  82.   } else {
  83.     integer = (unsigned int)(value);
  84.     decimal = (double)(value - integer);
  85.   }
  86.   //整数部分数据转换为字符串,逆序存储
  87.   do {
  88.     str[i ++] = list[integer%10];
  89.     integer /= 10;
  90.   } while(integer);
  91.   str[i] = '\0';
  92.   //将逆序字符串转换为正序
  93.   char tmp;
  94.   for (j = k; j < (i+k)/2; j++) {
  95.     tmp = str[j];
  96.     str[j] = str[i-j-1+k];
  97.     str[i-j-1+k] = tmp;
  98.   }
  99.   //处理小数部分
  100.   if (eps < 1 || eps > 4) {
  101.     eps = 4;
  102.   }
  103.   
  104.   //精度问题,防止输入1.2输出1.19等情况
  105.   double pp = 0.1;
  106.   for (j = 0; j <= eps; j++) {
  107.     pp *= 0.1;
  108.   }
  109.   decimal += pp;
  110.   while (eps) {
  111.     decimal *= 10;
  112.     eps --;
  113.   }
  114.   int tmp_decimal = (int)decimal;
  115.   str[i ++] = '.';
  116.   k = i;
  117.   //整数部分数据转换为字符串,逆序存储
  118.   do {
  119.     str[i ++] = list[tmp_decimal%10];
  120.     tmp_decimal /= 10;
  121.   } while(tmp_decimal);
  122.   str[i] = '\0';
  123.   //将逆序字符串转换为正序
  124.   for (j = k; j < (i+k)/2; j++) {
  125.     tmp = str[j];
  126.     str[j] = str[i-j-1+k];
  127.     str[i-j-1+k] = tmp;
  128.   }
  129.   str[i] = '\0';
  130. }


  131. void mprintf(char * Data, ...)
  132. {
  133.   const char *s;
  134.   int d;   
  135.   char buf[16];
  136.   uint8_t txdata;
  137.   va_list ap;
  138.   va_start(ap, Data);
  139.   while ( * Data != 0 ) {                                                          
  140.     if ( * Data == 0x5c )  {                                                                          
  141.       switch ( *++Data ) {
  142.         case 'r':                                                                  
  143.           txdata = 0x0d;
  144.           send_uart_data(txdata);
  145.           Data ++;
  146.           break;
  147.         case 'n':                                                                  
  148.           txdata = 0x0a;
  149.           send_uart_data(txdata);
  150.           Data ++;
  151.           break;
  152.         default:
  153.           Data ++;
  154.           break;
  155.       }                         
  156.     } else if ( * Data == '%') {                                                                          
  157.       switch ( *++Data ) {                               
  158.       case 's':                                                                                 
  159.         s = va_arg(ap, const char *);
  160.         for ( ; *s; s++) {
  161.           send_uart_data(*((uint8_t *)s));
  162.         }                               
  163.         Data++;                               
  164.         break;
  165.       case 'd':                       
  166.         d = va_arg(ap, int);                                       
  167.         sky_itoa(d, buf, 10);                                       
  168.         for (s = buf; *s; s++) {
  169.           send_uart_data(*((uint8_t *)s));
  170.         }                                       
  171.         Data++;                               
  172.         break;
  173.       case 'x': {
  174.         d = va_arg(ap, int);                                       
  175.         sky_itoa(d, buf, 16);                                       
  176.         for (s = buf; *s; s++) {
  177.           send_uart_data(*((uint8_t *)s));
  178.         }                                       
  179.         Data++;                       
  180.         break;
  181.       }
  182.       case 'f': {
  183.         double num = va_arg(ap, double);                                       
  184.         sky_ftoa(num, buf, 4);
  185.         for (s = buf; *s; s++) {
  186.           send_uart_data(*((uint8_t *)s));
  187.         }                                       
  188.         Data++;                       
  189.         break;
  190.       }
  191.       default:
  192.         Data++;                               
  193.         break;                               
  194.       }                 
  195.     } else {
  196.         send_uart_data(*((uint8_t *)Data));
  197.         Data++;
  198.     }
  199.   }
  200. }

  201. void main(void)
  202. {
  203.     USART_Config();
  204.     mprintf("STM8L start...\r\n");
  205.     mprintf("%f %f %f\r\n", 1.2, 12.36, -1.2364568);
  206.     mprintf("%x %x %x\r\n", 0x1035, 0x0830, 0x2018);
  207.     mprintf("%d %d %d\r\n", 12, -12345, 2);
  208.     mprintf("STM8L end...\r\n");
  209.     while (1) {
  210.         
  211.     }
  212. }


 楼主| 花间一壶酒sd 发表于 2024-3-30 11:10 | 显示全部楼层
执行串口打印结果:

47004660782a051056.png
 楼主| 花间一壶酒sd 发表于 2024-3-30 11:10 | 显示全部楼层
注意事项:
      如果你不需要打印浮点数,那么就把浮点数打印部分代码注释掉。由于像这种8位单片机处理浮点数,是通过编译器来软实现,故对浮点数处理可能每增加一次浮点数处理,代码就会增加几十上百个字节,我这边的整型数和浮点数处理后的编译代码大小可以看看,浮点数处理和整型数处理代码空间的差异。

27480660782ad9fa32.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则

101

主题

1219

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部