解决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-18 07:14

STM8 关闭PWM输出后的电平输出问题解决
STM系列的单片机PWM输出如果被关断比如用TIM1_CtrlPWMOutputs进行停止输出后,电平的高低处于不确定的状态。 他取决于: 1.GPIO初始化的特性 2.关断那一刻时的电平 3.CCMR1的寄存器设置 因此要实现PWM关断后的输出确定比如输出高电平必须: 1. GPIO的设置为推挽输出或开漏外接上拉 2.执行TIM1_ForcedOCxConfig(TIM1_FORCEDACTION_ACTIVE) TIM1_CtrlPWMOutputs((FunctionalState)0); TIM1_ForcedOC1Config(TIM1_FORCEDACTION_ACTIVE);
[单片机]
STM8 PWM例程
在单片机应用系统中,也常常会用到PWM 信号输出,例如电机转速的控制。现在很多高档的单片机 也都集成了PWM 功能模块,方便用户的应用。 对于PWM 信号,主要涉及到两个概念,一个就是PWM 信号的周期或频率,另一个就是PWM 信号的 占空比。例如一个频率为1KHZ,占空比为30%,有效信号为1 的PWM 信号,在用示波器测量时, 就是高电平的时间为300uS,低电平的时间为700uS 的周期波形。 在单片机中实现PWM 信号的功能模块,实际上就是带比较器的计数器模块。首先该计数器循环计数, 例如从0 到N,那么这个N 就决定了PWM 的周期,PWM 周期=(N+1)*计数器时钟的周期。在计数 器模块中一定还有一个比
[单片机]
STM8 中关于PWM1 和 PWM2的区别
STM8中PWM1和PWM2模式是时钟输出PWM波形控制的一个必选参数,使用库函数原型如下: void TIMx_OC2Init(TIM2_OCMode_TypeDef TIM2_OCMode, TIM2_OutputState_TypeDef TIM2_OutputState, uint16_t TIM2_Pulse, TIM2_OCPolarity_TypeDef TIM2_OCPolarity) 函数中的第一个参数TIM2_OCMode_TypeDef就是指定当前的 PWM波形模式是PWM1或PWM2,关于这两者的区别通俗点讲就是: PWM1中空控
[单片机]
STM32学习记录——printf函数重定位
功能: 重定位printf函数,使printf作为串口打印输出函数。代替usart_send_string()函数 步骤: usart.c中包含USART初始化函数 1、USART初始化(使能时钟、使能GPIO、GPIO和USART初始化) 2、打开USART 3、在usart.c中加入如下代码 #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker- Libraries- Small printf set to 'Yes') calls __io_putchar() */ #define PUT
[单片机]
STM32L152RC 在keil4中使用printf()和scanf() 函数
1、在keil中配置使用Micro LIB,如下图 2、配置USART模块 void SYS_USARTInit(void) { static USART_InitTypeDef USART_InitStructure; static GPIO_InitTypeDef GPIO_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_
[单片机]
STM32L152RC 在keil4中使用<font color='red'>printf</font>()和scanf() 函数
STM8学习总结三:TIM1定时器使用
本文主要总结关于STM8在库函数开发时,各条语句的含义。 (1)TIM1初始化配置函数 函数主要作用:对计数器的参数,工作模式进行设定,并使能; void Tim1_Init(void) { TIM1_TimeBaseInit(16,TIM1_COUNTERMODE_UP,1000,0); //(定时器频率:16分频即系统频率的1/16,为1M,向上计数,定时器溢出值,重装载计数从0开始) TIM1_ITConfig(TIM1_IT_UPDATE , ENABLE);//中断配置与使能函数 TIM1_ARRPreloadConfig(ENABLE);//使能数值自动重装载功能 TIM1_Cmd(E
[单片机]
IAR FOR STM8 简单使用教程
一、创建工程 1.先创建一个workplace.选择File New Workplace 2.创建一个新的工程,选择Project Creat New Project,如果用的是IAR FOR STM8 就默认无需更改。保存并输入Project名字,在workplace窗口中显示如下 3.在添加文件到工程之前,先保存Workplace。并输入保存的名字,Workplace的扩展名是eww。 4.添加文件到工程. (1)右击工程名 ADD ADD FILES添加 .c文件 (2)添加头文件文件夹路径:右击工程名 Options C/++compiler PreProcessor中加入头文件所在文件夹的路径 例如: $
[单片机]
IAR FOR <font color='red'>STM8</font> 简单使用教程
STM8 CAN总线的IdMask模式的讲解
前言 在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时根据标识符的值决定软件是否需要该报文;如果需要,就拷贝到RAM里;如果不需要,报文就被丢弃且无需软件的干预。为满足这一需求,BeCAN为应用程序提供了个可配置的、位宽可变的6个(0-5)过滤器组,用于只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件进行过滤,从而占用一定的CPU资源。 一、IdMask模式 首先,需要明白IdMask的作用: 举个例子吧,过滤器长度为32位,模式为屏蔽模式,假如我要发送的标示符为0x1314;那过滤器设置如下 1、过滤器完全无
[单片机]
<font color='red'>STM8</font> CAN总线的IdMask模式的讲解
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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