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

发布者:Tiger8最新更新时间:2019-12-04 来源: eefocus关键字:STM8  单片机空间太小  printf  串口打印 手机看文章 扫描二维码
随时随地手机看文章

概述:


在使用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位单片机处理浮点数,是通过编译器来软实现,故对浮点数处理可能每增加一次浮点数处理,代码就会增加几十上百个字节,我这边的整型数和浮点数处理后的编译代码大小可以看看,浮点数处理和整型数处理代码空间的差异。

关键字:STM8  单片机空间太小  printf  串口打印 引用地址:解决STM8类型单片机空间太小,使用不了printf串口打印问题

上一篇:基于STM8的IIC协议--协议篇
下一篇:基美电子新型表面贴装MLCC满足小型化的广泛需求

推荐阅读最新更新时间:2024-11-04 16:20

不用串口,如何打印STM32单片机log
本文主要介绍在嵌入式开发中用来输出log的方法。 最常用的是通过串口输出uart log,这种方法实现简单,大部分嵌入式芯片都有串口功能。但是这样简单的功能有时候却不是那么好用,比如: 一款新拿到的芯片,没有串口驱动时如何打印log 某些应用下对时序要求比较高,串口输出log占用时间太长怎么办?比如USB枚举。 某些bug正常运行时会出现,当打开串口log时又不再复现怎么办 一些封装中没有串口,或者串口已经被用作其他用途,要如何输出log 下文来讨论这些问题。 1输出log信息到SRAM 准确来说这里并不是输出log,而是以一种方式不使用串口就可以看到log。在芯片开发阶段都可以连接仿真器调试,可以使用打断点的方法调试,但是有
[单片机]
不用<font color='red'>串口</font>,如何<font color='red'>打印</font>STM32<font color='red'>单片机</font>log
IAR for STM8重定向printf
#include stdio.h int fputc(int ch, FILE *f)//STM8S105,printf函数重定向 { while (!(UART2- SR&0x80)); UART2- DR=ch; return ch; } 同时需要修改IAR的Projec t- Options - General Options - Library Configuration中的Library 项由 Normal 改为 Full 。
[单片机]
STM8 16位高级控制定时器(TIM1)
16位高级控制定时器(TIM1)简介 STM8S的TIM1由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。 本章中使用i来代表1、2、3、4,分别对应于四个不同的捕获/比较通道。 高级控制定时器适用于许多不同的用途: 基本的定时 测量输入信号的脉冲宽度(输入捕获) 产生输出波形(输出比较,PWM和单脉冲模式) 对应与不同事件(捕获,比较,溢出,刹车,触发)的中断 与TIM5/TIM6或者外部信号(外部时钟,复位信号,触发和使能信号)同步 高级控制定时器广泛的适用于各种控制应用中,包括那些需要中间对齐模式PWM的应用,该模式支持互补输出和死区时间控制。 高级控制定时器的时钟源可以是内部时钟,也可以
[单片机]
<font color='red'>STM8</font> 16位高级控制定时器(TIM1)
STM8-利用外部中断编写一个按键控制灯的亮灭
目的:熟悉外部中断的使用。(一个按键控制灯的亮灭) #include stm8s.h #include stm8s_exti.h #define uchar unsigned char #define uint unsigned int #define ulong unsigned long void delay(uint i) { while(i--); } void main() { GPIO_DeInit(GPIOD); GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST);//输出 GPIO_DeInit(GPIOB); GPIO_Init
[单片机]
STM32 printf重定向
STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK) 在STM32串口通信程序中使用printf发送数据,非常的方便。可在刚开始使用的时候总是遇到问题,常见的是硬件访真时无法进入main主函数,其实只要简单的配置一下就可以了。 下面就说一下使用printf需要做哪些配置。 有两种配置方法: 一、对工程属性进行配置,详细步骤如下 1、首先要在你的main 文件中 包含“stdio.h” (标准输入输出头文件)。 2、在main文件中重定义 fputc 函数 如下: // 发送数据 int fputc(int ch, FILE *f) { USART_SendData(
[单片机]
STM8不用手动复位进入自带Bootloader方法(串口下载)
除非STM8片子的空的,如果复位运行的是自带Bootloader,而且要通过串口下载程序的话,必须在1s内点击上位机,要不然就运行用户程序了。 这一步很麻烦,所以想把它给省掉。 后来发现上位机Flash Loader Demonstrator在启动画面点击Next后,会先从串口的DTR、RTS输出一个大概100多毫秒的脉冲,TTL电平就是负脉冲了,之后才会和单片机通信。 所以只要按照下面的图接线,如果单片机复位运行的是自带Bootloader,只要在Flash Loader Demonstrator启动画面点击Next,软件就会复位单片机,不用自己手动复位再点击Next就可以和单片机通信了。 还有就是下载STM8S或STM8
[单片机]
<font color='red'>STM8</font>不用手动复位进入自带Bootloader方法(<font color='red'>串口</font>下载)
STM8 复位
STM8S共有9个复位源: NRST引脚产生的外部复位 上电复位(POR) 掉电复位(BOR) 独立看门狗复位 窗口看门狗复位 软件复位 SWIM复位 非法操作码复位 EMS复位:当一些关键的寄存器被破坏或错误加载时产生的复位 所有的复位源最终都作用于NRST管脚,并在复位过程中保持低电平。复位入口向量在内存映射中位于固定的地址6000h。 复位电路 复位引脚NRST内部集成了弱上拉电阻RPU,即可作为输入,也可作为开漏输出。 一个在复位引脚上宽度最小为500ns的低电平脉冲即可产生一个外部复位。对于复位的检测是异步进行的,因此即使MCU处于停机(Halt)模式,也有可能进入复位状态。 复位引脚也可以作为开漏输
[单片机]
<font color='red'>STM8</font> 复位
S3C2440在MDK4.22下使用printf串口打印调试
背景知识: 串口的基本知识已经在上一篇讲过了。这里重点讲解如何在MDK4.22下使用printf函数,这样的话就可以很方便的打印调试信息,追踪。 这个知识来源于MDK自带的帮助手册。有现成的代码提供。 实现方式有2种,使用标准C库下裁剪合适的函数,使用微库C下裁剪合适的函数。 微库下的情况,在魔术棒那里要勾选上使用微库。然后需要定义如下结构和改写如下函数--FILE stdout fputc ferror。 标准库的情况,也是需要关注FILE stdout fputc ferror。注意网上很多文章说,在标准库下,需要关掉半主机模式,我尝试过,关掉后,需要定义_sys_exit函数,可以达到效果,但是如果不关掉半主机模式,和
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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