【经验分享】C51单片机中如何实现printf输出log?

【经验分享】C51单片机中如何实现printf输出log?

你在真实的项目工程开发中,有考虑过在C51单片机中实现printf输出log吗?本文给出一种参考实现。

文章目录

  • 1 需求说明
  • 2 源码实现
    • 2.1 函数申明
    • 2.2 功能实现
  • 3 源码测试
  • 4 小小总结
  • 5 更多分享

1 需求说明

这个需求比较简单,就是要在C51单片机中实现printf函数,并使用它来打印输出常用的几种类型的数据,比如整型数据,字符串数据等等。

2 源码实现

2.1 函数申明

通过查看man帮助,我们可以知道printf函数的功能及其简要申明。


NAME
       printf - format and print data

SYNOPSIS
       printf FORMAT [ARGUMENT]...
       printf OPTION

DESCRIPTION
       Print ARGUMENT(s) according to FORMAT, or execute according to OPTION:

       --help display this help and exit

       --version
              output version information and exit

       FORMAT controls the output as in C printf.  Interpreted sequences are:

       \"     double quote

       \\     backslash

       \a     alert (BEL)

       \b     backspace

       \c     produce no further output

       \e     escape

       \f     form feed

       \n     new line

       \r     carriage return

       \t     horizontal tab

       \v     vertical tab

       \NNN   byte with octal value NNN (1 to 3 digits)

       \xHH   byte with hexadecimal value HH (1 to 2 digits)

       \uHHHH Unicode (ISO/IEC 10646) character with hex value HHHH (4 digits)

       \UHHHHHHHH
              Unicode character with hex value HHHHHHHH (8 digits)

       %%     a single %

       %b     ARGUMENT as a string with '\' escapes interpreted, except that octal escapes are of the form \0 or \0NNN

       %q     ARGUMENT is printed in a format that can be reused as shell input, escaping non-printable characters with the proposed POSIX $'' syntax.

       and all C format specifications ending with one of diouxXfeEgGcs, with ARGUMENTs converted to proper type first.  Variable widths are handled.

       NOTE:  your  shell  may have its own version of printf, which usually supersedes the version described here.  Please refer to your shell's documentation for details about the
       options it supports.

2.2 功能实现

以下是我的一个简单实现源码,仅供参考:

#include 
#include "log.h"
#include "stdarg.h"
#include "types.h"

static  xdata char  Simple_Prn_Buf[6]; 
uchar Align_Bit = 0;

void Dark_Fill_String(void)
{
    unsigned char i, j;

    j = 4;
    for(i=0;i<5;i++)
    {
        if (Simple_Prn_Buf[i] != '0')
        {
            j = i;
            break;
        }
    }

    if (j != 0)
    {
        for (i=j;i<6;i++)
            Simple_Prn_Buf[i-j] = Simple_Prn_Buf[i];
    }
    
    j = strlen(Simple_Prn_Buf);

    if (Align_Bit>j)
    {
        for (i=0;i<j+1;i++)
            Simple_Prn_Buf[Align_Bit-i] = Simple_Prn_Buf[j-i];

        for (i=0;i<Align_Bit-j;i++)
            Simple_Prn_Buf[i] = '0';
    }
}

void IntToStr(int Int_Data)
{
    unsigned char i;
    int Shang, Div_Data;

    Shang = Int_Data;
    Div_Data = 10000;

    for(i=0;i<5;i++)
    {
        Simple_Prn_Buf[i] = Shang / Div_Data + '0';
        Shang = Shang % Div_Data;
        Div_Data /= 10;
    }
    Simple_Prn_Buf[5] = '\0';
    Dark_Fill_String();
}

void HexToStr(int Int_Data, unsigned char x)
{
    unsigned char i;

    if (Int_Data == 0) {
        if (Align_Bit == 0) {
            Align_Bit = 1;
        } 
        memset(Simple_Prn_Buf, '0', Align_Bit);
        Simple_Prn_Buf[Align_Bit] = '\0';
        return;
    }

    x = (x) ? 'A' : 'a';

    for (i=0;i<4;i++)
    {
        Simple_Prn_Buf[i] = ((Int_Data >> (3-i)*4)) & 0x000F;

        if (Simple_Prn_Buf[i] > 9)
            Simple_Prn_Buf[i] += (x - 10);
        else
            Simple_Prn_Buf[i] += '0';
    }

    Simple_Prn_Buf[4] = '\0';
    Dark_Fill_String(); 
}

int xprintf(char *fmt, ...)
{
    char *Str;
    int  Int_Data;
    uchar Fill_Flag = 0;

    va_list ap;
    va_start(ap, fmt);

    while(*fmt)
    {
        if ((*fmt != '%') && (Fill_Flag == 0))
        {
            Push_To_TX_Buffer(*fmt++);
            continue;
        }

        if (*fmt == '%')
        {
            fmt++;
            Align_Bit = 0;
            Fill_Flag = 1;
        }
        
        switch(*fmt)
        {
            case 's':
                 Str = va_arg(ap, char *);
                 for (; *Str; Str++)
                    Push_To_TX_Buffer(*Str);
                 Fill_Flag = 0;
                 Align_Bit = 0;
                 break;

            case 'd':
                 Int_Data = va_arg(ap, int);
                 IntToStr(Int_Data);
                 for (Str=Simple_Prn_Buf; *Str; Str++) {
                    Push_To_TX_Buffer(*Str);
                 }
                 Fill_Flag = 0;
                 Align_Bit = 0;
                 break;

            case 'x':
                 Int_Data = va_arg(ap, int);
                 HexToStr(Int_Data, 0); //小写
                 for (Str=Simple_Prn_Buf; *Str; Str++) {
                    Push_To_TX_Buffer(*Str);
                 }
                 Fill_Flag = 0;
                 Align_Bit = 0;
                 break;

            case 'X':
                 Int_Data = va_arg(ap, int);
                 HexToStr(Int_Data, 1); //大写
                 for (Str=Simple_Prn_Buf; *Str; Str++) {
                    Push_To_TX_Buffer(*Str);
                 }
                 Fill_Flag = 0;
                 Align_Bit = 0;
                 break;

            default:
                 //Push_To_TX_Buffer(*fmt);
                 Align_Bit = *fmt - '0';
                 if (Align_Bit > 9)
                    Align_Bit = 9;
                 break;
        }
        fmt++;
    }
    va_end(ap);

    return 0;
}

3 源码测试

简单的测试代码如下:

#include 
#include 
#include 

extern int xprintf(const char* format, ...);

#define LOG(fmt, arg...)	xprintf(fmt, ##arg)

int main(int argc, const char *argv[])
{
	//uart_init();
    
#if 1
	puts("Hello World\r\n");/*
	unsigned int size1 = sizeof(char *);
	unsigned int size2 = sizeof(int *);
	unsigned int size3 = sizeof(int);
	unsigned int size4 = sizeof(short int);
	size = sizeof(int);
	printf("sizeof int = %d\r\n", size);
	size = sizeof(short int);
	printf("sizeof short int = %d\r\n", size);*/
	uart2_send_string("Hello World\r\n");	
	uart1_send_string("\r\n\r\n");
	uart1_send_string("\r\n\r\n");
	LOG("1Test log\r\n");
	LOG("2Test log %c\r\n", '=');
	LOG("3Test log %s %s\r\n", "123", "098");
	LOG("4--Test log %d\r\n", -456);
	LOG("4Test log %d\r\n", 456);
	LOG("5Test log %u\r\n", 789);
	LOG("6Test log %x\r\n", 0x12);
	LOG("6Test log %x\r\n", 0x1A);
	LOG("6Test log %x\r\n", 0x1A);
	LOG("6Test log %x\r\n", 0x1B);
	LOG("6Test log %x\r\n", 0xab);
	LOG("6Test log %x\r\n", 0xAB);
	LOG("6Test log %x\r\n", 0x01);
	LOG("6Test log %2x\r\n", 0x01);
	LOG("6Test log %x\r\n", 0x00);
	LOG("6Test log %2x\r\n", 0x00);
#endif

	return 0;
}

感兴趣的朋友可以把这段测试代码,在C51平台上编译运行下,相信它会给你惊喜的!

4 小小总结

printf函数看似很常用,但是真正到了要自己去实现它的时候,你又会发现其实还是蛮多东西需要考虑的。

同时,即便是本文中的实现,还是有些类型的数据是不支持输出的,比如 long int 类型这种,就比较难输出;还有 float类型这种数据,也是没法输出的。

看到这里,你是否还有更好的实现方案呢?

5 更多分享

架构师李肯

架构师李肯全网同名),一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验,深耕IoT领域多年,熟知IoT领域的业务发展,深度掌握IoT领域的相关技术栈,包括但不限于主流RTOS内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、主流IoT云平台的对接、嵌入式IoT系统的架构设计等等。拥有多项IoT领域的发明专利,热衷于技术分享,有多年撰写技术博客的经验积累,连续多月获得RT-Thread官方技术社区原创技术博文优秀奖,荣获CSDN博客专家、CSDN物联网领域优质创作者、2021年度CSDN&RT-Thread技术社区之星、2022年RT-Thread全球技术大会讲师、RT-Thread官方嵌入式开源社区认证专家、RT-Thread 2021年度论坛之星TOP4、华为云云享专家(嵌入式物联网架构设计师)等荣誉。坚信【知识改变命运,技术改变世界】!

你可能感兴趣的:(单片机,经验分享,c语言,51单片机,printf)