单片机C语言实现printf.docx

上传人:b****2 文档编号:1954360 上传时间:2022-10-25 格式:DOCX 页数:10 大小:76.49KB
下载 相关 举报
单片机C语言实现printf.docx_第1页
第1页 / 共10页
单片机C语言实现printf.docx_第2页
第2页 / 共10页
单片机C语言实现printf.docx_第3页
第3页 / 共10页
单片机C语言实现printf.docx_第4页
第4页 / 共10页
单片机C语言实现printf.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

单片机C语言实现printf.docx

《单片机C语言实现printf.docx》由会员分享,可在线阅读,更多相关《单片机C语言实现printf.docx(10页珍藏版)》请在冰豆网上搜索。

单片机C语言实现printf.docx

单片机C语言实现printf

单片机串口实现printf函数

背景叙述:

在初学C语言时,利用printf函数向屏幕上输出字符,非常的好用和方便。

学会单片机以后,尤其在学会串口通信之后,通过单片机的串口向PC机发送数据,怎么实现printf函数的功能。

对于学习单片机来说,如果没有仿真器,出错误的时候不好找,只能用最笨的办法,使用printf函数,可是在KEIL里面使用printf却不像VC里面那么简单,因为其发送和硬件是有关系的。

所以今天就简单来说说怎么在51单片机中使用"printf"函数:

包括使用自带的printf函数和自己动手写一个printf函数功能描述:

通过printf函数向串口发送数据,显示在终端或者串口助手上Proteus中串口终端的介绍

2、串口的配置

尤其注意配置的波特率一定要和程序代码中所写的一样(否则会造成

无法显示字符)

数据位

停止位

奇偶校验位

极性(这些属性基本上是默认的配置)

3、串口终端的使用

proteusvirtualterminal使用注意事项

a.virtualterminal默认显示字符,如果单片机发送的是非显示字符,则虚拟终端不会显示,会导致用户认为通讯未通。

运行程序,在虚拟终端窗口里面点击右键,在弹出菜单里面:

选HEXDISPLAYMODEU显示按十六进制显示,能显示所有字符。

b.virtualterminal默认情况下不显示回显字符,

运行程序,在虚拟终端窗口里面点击右键,在弹出菜单里面:

选EchoTypedCharacters显示回显字符

c.virtualterminal和模拟物理串口COMPIM不能同时使用,同时使用

会发生相互影响。

d.启动仿真后可以右键单击终端,最后一栏打开和关闭串口显示终

直接使用系统自带的printf函数:

特别注意需要置位TI=1,否则是无法发送的,程序如下(此程序在proteus终端上不能显示汉字,但在串口调试助手上可以)

/******decription

******************

利用printf函数向串口打印信息

51单片机晶振频率11.0592MHZ

串口通信波特率9600bps

**********************************『

#include

#include

#include

#include

#defineucharunsignedchar

#defineuintunsignedint

voiddelay_1ms(uintz)

{

uintx,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--);

}

voiduart_init(void)

TMOD=0x20;〃定时计数器1,工作方式2

TH1=0xFD;〃设置波特率9600

TL1=0xFD;

TR1=1;

SCON=0x50;

PCON=0x00;

EA=1;

ES=1;

TI=1;〃若利用printf函数则TI初始值必须置1

voidmain()

uart_init();

while

(1)

//SBUF='H';

//while(TI==0);

//TI=0;

printf("iamherro!

\n\r");

delay_1ms(1000);

ff=0;

printf("%c",num);

voidser_interrupt()interrupt4

if(RI==1)

ES=0;

RI=0;

num=SBUF;

ES=1;

ff=1;

4.编写自己的printf函数(这个函数不能再proteus中仿真,但实际中

可以使用)

a.预备知识

①C语言函数:

vsprintf,

其原型为intvsprintf(char*string,char*format,va_listparam);,作用为将param按格式format写入字符串string中,因此他可以用于将任何格式数据转化为字符串数据,比如把整数97转化为ASCII码的97的

程序就像下面这样vsprintf(string,"%d",97),当然还有一点需要注意:

在keil里面使用sprintf需要包含stdio.h这个头文件(当然这里也可以使用sprintf,作用完全差不多,只需要稍加修改即可,不多介绍)。

到这里,再来说说另一个函数itoa吧,其实他比vsprintf更简单,其原型为char*itoa(intvalue,char*string,intradix),作用为将value按radix进制写入到string字符串中,使用时需要包含头文件stdlib.h,

可是在keil里面却无法使用,头文件里面不包含itoa,即使把VC里

面的复制进来貌似还是不行,呵呵,目前不知道原因。

②可变参数函数

具体来说就是stdarg.h里面的这几个函数va_start,va_arg,va_list,va_end这几个参数用于开辟一段内存区域,可以配合vsprintf使用,但是对内存使用较大,需要单片机具备一定的RAM,否则程序就算能编译通过也是无法运行的。

函数形参列表中的变量在内存中的位置是顺次排列的。

头文件Stdarg.h里的几个宏定义就是利用了这么一点,顺次获取多个参数Keil中上述函数的定义如下

typedefchar*va_list;//va_list即为字符指针类型

#defineva_start(ap,v)ap=(va_list)&v+sizeof(v)

#defineva_arg(ap,t)(((int*)ap)++[0])

#defineva_end(ap)//keil中什么也没有做

每个平台下面的Stdarg头文件的定义都是不相同的。

就拿keil那里的来入手。

先看一个最简单的可变参数列表的函数:

voidmytest(inta,...)

{

intb;

va_listap;

va_start(ap,a);

b=va_arg(ap,int);

va_end(ap);

printf("%d,%d",a,b);

}

i.首先定义一个va_list型的变量ap,也就是char*。

ii.va_start(ap,a彦替换之后就是ap=(va_list)&a+sizeof(a);

首先取a的地址,即第一个固定参数的地址,然后强制类型转换为va_list,接着后移a的内存大小,把当前这个地址值赋给ap。

很明显,就是第一个参数a后面的那个地方,按照上面说的,也就是第一个可变参数。

即现在把ap指向第一个可变参数。

iii.b=va_arg(ap,int宏替换为b=((int*)ap)++[0];

自加在后,因此是获取第一个参数的值赋给b,然后ap后移一个

类型的位置,即指向下一个元素的地址。

iiii.va_end(ap),这里什么都没有做,在ADS那个版本里是将ap指向

NULL防止误操作。

具体内容详见

③内部拓展RAM

定义:

集成在单片机内部的数据存储器,在物理上是内部,但逻辑上

是外部,访问时需要使用MOVX或者xdata访问,具体可以看STC8051手册。

89C52单片机内含有1024byte=1Kbyte的内部拓展RAM,在访问的时候,使用C语言的时候,需要加上xdata才可以访问,使用汇编的时候需要用MOVX指令访问。

xdata:

访问内部RAM数据

源程序

/******decription

******************

利用printf函数向串口打印信息

51单片机晶振频率11.0592MHZ

串口通信波特率9600bps

利用系统自带printf函数TI初始值必须置1

***********************************

*******

includesfile

*************

 

#include

#include

〃用于vsprintf函数原型

#include#include

#defineucharunsignedchar

#defineuintunsignedint

voiddelay_1ms(uintz);

voiduart_init(void);

voidsendbyte(ucharc);

voidsendstring(uchar*string);

可变参数列表函数

voiduart_printf(constchar*fmt,...

voidmain(void)

{

inta=99;

uart_init();

while

(1)

uart_printf("10进制%d16进制%x字符格式%c",a,a,a);

delay_1ms(1000);

voiddelay_1ms(uintz)

{

uintx,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--);

voiduart_init(void)

{

TMOD=0x20;〃定时计数器1,工作方式2

TH1=0xFD;〃设置波特率9600

TL1=0xFD;

TR1=1;

SCON=0x50;

PCON=0x00;

EA=1;

ES=1;

)voidsendbyte(unsignedcharc)

if(c=='\n')

SBUF=0X0D;

while(TI==0);

TI=0;

SBUF=0X0A;

while(TI==0);

TI=0;

}

else

SBUF=c;

while(TI==0);

TI=0;

}

}

voidsendstring(unsignedchar*string)

while(*string!

='\0')//判断是否到字符串的尾端

sendbyte(*string);

string++;

voiduart_printf(constchar*fmt,...)

va_listap;

charxdatastring[1024];〃访问内部RAM

va_start(ap,fmt);

vsprintf(string,fmt,ap);

sendstring(string);

va_end(ap);

voiduart_interrupt()interrupt4

if(RI==1)

ES=0;

/*添加处理代码*/

ES=1;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 行政公文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1