51单片机串口通信中需要发送数据,而一般都会使用printf这个外部函数,printf函数在<stdio.h>这个头文件中,所以要使用这个函数必须要有stdio.h这个头文件。printf函数不需要我们去定义其内部实现,可以直接使用,当然也可以自己去构造一个相似功能的函数。
在stdio.h中可以看到printf函数的第一个参数为一个字符指针其用法与c语言中的的是一样的,而printf函数的内部实现是依靠putchar这个函数来实现的,putchar这个函数在c51的库文件下有定义
源码如下
- #include <reg51.h>
- #define XON 0x11 /*串口流控制符 启动*/
- #define XOFF 0x13 /*串口流控制符 中断*/
- /*
- * putchar (full version): expands '\n' into CR LF and handles /*完整版 每次发送数据都要检查sbuf是否有中断信号 */
- * XON/XOFF (Ctrl+S/Ctrl+Q) protocol /* XON启动 XOFF中断 通信协议*/
- */
- char putchar (char c) {
- if (c == '\n') { /*判断是否是换行符的原因,是因为字符串的标准格式是末尾为\r(回车符)\n(换行符)这两个字符*/
- if (RI) { /*判断接收标识符是否为1,若为1则说明SBUF接受到了信息*/
- if (SBUF == XOFF) { /*判断SBUF中的信息是否为中断信号 是则执行以下程序*/
- do {
- RI = 0; /*将接收标识符置1 可以继续接收信息*/
- while (!RI); /*判断是否接收到了信息,是则往下循环*/
- }
- while (SBUF != XON); /*判断接收的信息是否为启动信息,是则退出循环,不是继续循环*/
- RI = 0; /*将接受标识符置1 可以继续接收信息*/
- }
- }</div><div>/*只要c是换行符,最终都要执行这里 判断发送标识符是否为1,只有为1才往下执行,这点非常重要调用printf函数时,必须将TI置1*/</div><div>while (!TI);</div><div> TI = 0; /*将TI置0 准备发送数据*/
- SBUF = 0x0d; /* output CR */ /* 发送回车符*/
- }
- if (RI) { /*下面的if函数又是判断SBUF中是否接收了中断信号与上面的一样*/
- if (SBUF == XOFF) {
- do {
- RI = 0;
- while (!RI);
- }
- while (SBUF != XON);
- RI = 0;
- <div> }</div><div>while (!TI); /*判断发送标识符是否为1*/
- TI = 0; /*将TI置0 准备发送数据*/
- return (SBUF = c); /*发送字符c*/
- }
- #if 0 // comment out versions below
- /*
- * putchar (basic version): expands '\n' into CR LF /*精简版*/
- */
- char putchar (char c) {
- if (c == '\n') { /*还是判断字符c是不是换行符*/
- while (!TI); /*判断TI是否置1 为1向下执行*/
- TI = 0;
- SBUF = 0x0d; /* output CR */ /* c是换行符先发送回车符*/
- }
- while (!TI); /*又是判断TI是否为1 为1向下执行*/
- TI = 0; /*将TI置0 准备发送数据*/
- return (SBUF = c); /*发送字符c*/
- }
- /*
- * putchar (mini version): outputs charcter only /*迷离版 少了判断字符c是否为换行符的步骤 */
- */
- char putchar (char c) {
- while (!TI); /*判断TI是否置1 为1向下执行*/
- TI = 0; /*将TI置0 准备发送数据*/
- return (SBUF = c);/*发送字符c*/
- }
- #endif
复制代码 对于上面putchar函数的实现过程以及细节我已经注释的非常清楚了,但上面的串口流控制符可能有些人有疑惑,我这里解释一下。
XON/XOFF 这两个字符就是串口流控制字符,所谓的流就是数据流,当两个串口之间进行通信时,鉴于两个设备的硬件不一样,一个设备发送的信息让另一个设备处理不过来时,接收方设备就向发送方发送一个XOFF(0X13)字符,发送方接收到这个字符以后就会中断发送,直到接收方处理完数据后又向发送方发送一个XON(0x11)字符,当发送方接收到这个字符时又开始向接收方发送数据。
接下来我们可以用printf函数来发送数据了,但发送数据前要将TI置1
- #include<reg52.h>
- #include<stdio.h>
- #include<stdlib.h>
- #include<intrins.h>
- void af(int a){
- int b,c;
- for(b=0;b<a;b++)
- for(c=0;c<110;c++);
- }
- void main(){
- TMOD=0X20;
- TH1=0Xfd;
- TL1=0xfd;
- SCON=0X50;
- SM0=0;
- SM1=1;
- TR1=1;
- EA=1;
- ES=0;
- REN=1;
- TI=1; /*初始化将TI置1*/
- while(1){
- af(1000); /*延迟1秒*/
- printf("ghjkl;lkjhgffghjklkjhgfghjk"); /*调用printf函数*/
- TI=1; /*又将TI置1 方便下车调用printf函数*/
- }
- }
复制代码 以上就是printf函数的使用方法,如果觉得这个函数不好使用,可以对putchar函数的源代码进行改动,构造出自己的输出函数这里就不做介绍了。
发送数据可以使用printf函数但如果我们想接收字符串时就需要自己构造函数,下面的接收字符串函数仅供参考
- #include<reg52.h>
- #include<stdio.h>
- char a=0; /*定义全局字符变量a并且赋值为'0' a用于接收字符函数判断串口中断是否产生 */
- char c[30]="0"; /*定义全局字符数值c初始为'0' c用于存放接收的字符串 */
- int b=0; /*定义全局整型变量b 初始b为0 b用于字符串的赋值串口每中断一次b加1 */
- void yc(int a){ /*构造延迟函数yc*/
- int b,c;
- for(b=0;b<a;b++)
- for(c=0;c<110;c++);
- }
- int scan(){ /*构造接收字符串函数scan*、/
- int af; /*定义一个整型变量af 用于返回值*/
- int ef=0; /*定义一个整型变量ef 赋值为0 用于判断*/
- if(a==1){ /*通过判断a的值来判断串口中断是否产生*/
- af=b; /*将全局变量b的值赋值给变量af*/
- yc(1); /*延迟1秒*/
- while(b!=af){ /*判断b与af是否相等 不等进入循环 否则退出循环 */
- af=b; /*又将b的值赋值给af*/
- yc(1); /*延迟1秒*/
- }
- a=0; /*将a复原为0以便下次处理*/
- c[b]='\0'; /*将第b个地址位赋值为空字符*/
- b=0; /*将b清零*/
- ef=1; /*ef赋值1 以便返回*/
- }
- return ef;
- }
- void main(){
- TMOD=0X20;
- TH1=0Xfd;
- TL1=0Xfd;
- SM0=0;
- SM1=1;
- REN=1;
- TR1=1;
- EA=1;
- ES=1;
- while(1){
- while(!scan()); /*接收到字符串就退出循环*/
- TI=1; /*TI置1 下面调用printf函数*/
- ES=0; /*串口中断置不置0其实没有多大的影响*/
- printf(c); /*用printf函数将接收到的字符串发送出去*/
- ES=1 ;
- }
- }
- void zd()interrupt 4
- {
- RI=0; /*RI置0 以便下次中断*/
- a=1; /*有中断a就为1*/
- c[b]=SBUF; /*将每次接受的字符存入c中*/
- b++; /*中断产生则b加1*/
- }
复制代码
出自 51黑电子论坛
|