51單片機串口通信中需要發(fā)送數(shù)據(jù),而一般都會使用printf這個外部函數(shù),printf函數(shù)在<stdio.h>這個頭文件中,所以要使用這個函數(shù)必須要有stdio.h這個頭文件。printf函數(shù)不需要我們?nèi)ザx其內(nèi)部實現(xiàn),可以直接使用,當然也可以自己去構造一個相似功能的函數(shù)。
在stdio.h中可以看到printf函數(shù)的第一個參數(shù)為一個字符指針其用法與c語言中的的是一樣的,而printf函數(shù)的內(nèi)部實現(xiàn)是依靠putchar這個函數(shù)來實現(xiàn)的,putchar這個函數(shù)在c51的庫文件下有定義
源碼如下
- #include <reg51.h>
- #define XON 0x11 /*串口流控制符 啟動*/
- #define XOFF 0x13 /*串口流控制符 中斷*/
- /*
- * putchar (full version): expands '\n' into CR LF and handles /*完整版 每次發(fā)送數(shù)據(jù)都要檢查sbuf是否有中斷信號 */
- * XON/XOFF (Ctrl+S/Ctrl+Q) protocol /* XON啟動 XOFF中斷 通信協(xié)議*/
- */
- char putchar (char c) {
- if (c == '\n') { /*判斷是否是換行符的原因,是因為字符串的標準格式是末尾為\r(回車符)\n(換行符)這兩個字符*/
- if (RI) { /*判斷接收標識符是否為1,若為1則說明SBUF接受到了信息*/
- if (SBUF == XOFF) { /*判斷SBUF中的信息是否為中斷信號 是則執(zhí)行以下程序*/
- do {
- RI = 0; /*將接收標識符置1 可以繼續(xù)接收信息*/
- while (!RI); /*判斷是否接收到了信息,是則往下循環(huán)*/
- }
- while (SBUF != XON); /*判斷接收的信息是否為啟動信息,是則退出循環(huán),不是繼續(xù)循環(huán)*/
- RI = 0; /*將接受標識符置1 可以繼續(xù)接收信息*/
- }
- }</div><div>/*只要c是換行符,最終都要執(zhí)行這里 判斷發(fā)送標識符是否為1,只有為1才往下執(zhí)行,這點非常重要調(diào)用printf函數(shù)時,必須將TI置1*/</div><div>while (!TI);</div><div> TI = 0; /*將TI置0 準備發(fā)送數(shù)據(jù)*/
- SBUF = 0x0d; /* output CR */ /* 發(fā)送回車符*/
- }
- if (RI) { /*下面的if函數(shù)又是判斷SBUF中是否接收了中斷信號與上面的一樣*/
- if (SBUF == XOFF) {
- do {
- RI = 0;
- while (!RI);
- }
- while (SBUF != XON);
- RI = 0;
- <div> }</div><div>while (!TI); /*判斷發(fā)送標識符是否為1*/
- TI = 0; /*將TI置0 準備發(fā)送數(shù)據(jù)*/
- return (SBUF = c); /*發(fā)送字符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向下執(zhí)行*/
- TI = 0;
- SBUF = 0x0d; /* output CR */ /* c是換行符先發(fā)送回車符*/
- }
- while (!TI); /*又是判斷TI是否為1 為1向下執(zhí)行*/
- TI = 0; /*將TI置0 準備發(fā)送數(shù)據(jù)*/
- return (SBUF = c); /*發(fā)送字符c*/
- }
- /*
- * putchar (mini version): outputs charcter only /*迷離版 少了判斷字符c是否為換行符的步驟 */
- */
- char putchar (char c) {
- while (!TI); /*判斷TI是否置1 為1向下執(zhí)行*/
- TI = 0; /*將TI置0 準備發(fā)送數(shù)據(jù)*/
- return (SBUF = c);/*發(fā)送字符c*/
- }
- #endif
復制代碼 對于上面putchar函數(shù)的實現(xiàn)過程以及細節(jié)我已經(jīng)注釋的非常清楚了,但上面的串口流控制符可能有些人有疑惑,我這里解釋一下。
XON/XOFF 這兩個字符就是串口流控制字符,所謂的流就是數(shù)據(jù)流,當兩個串口之間進行通信時,鑒于兩個設備的硬件不一樣,一個設備發(fā)送的信息讓另一個設備處理不過來時,接收方設備就向發(fā)送方發(fā)送一個XOFF(0X13)字符,發(fā)送方接收到這個字符以后就會中斷發(fā)送,直到接收方處理完數(shù)據(jù)后又向發(fā)送方發(fā)送一個XON(0x11)字符,當發(fā)送方接收到這個字符時又開始向接收方發(fā)送數(shù)據(jù)。
接下來我們可以用printf函數(shù)來發(fā)送數(shù)據(jù)了,但發(fā)送數(shù)據(jù)前要將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"); /*調(diào)用printf函數(shù)*/
- TI=1; /*又將TI置1 方便下車調(diào)用printf函數(shù)*/
- }
- }
復制代碼 以上就是printf函數(shù)的使用方法,如果覺得這個函數(shù)不好使用,可以對putchar函數(shù)的源代碼進行改動,構造出自己的輸出函數(shù)這里就不做介紹了。
發(fā)送數(shù)據(jù)可以使用printf函數(shù)但如果我們想接收字符串時就需要自己構造函數(shù),下面的接收字符串函數(shù)僅供參考
- #include<reg52.h>
- #include<stdio.h>
- char a=0; /*定義全局字符變量a并且賦值為'0' a用于接收字符函數(shù)判斷串口中斷是否產(chǎn)生 */
- char c[30]="0"; /*定義全局字符數(shù)值c初始為'0' c用于存放接收的字符串 */
- int b=0; /*定義全局整型變量b 初始b為0 b用于字符串的賦值串口每中斷一次b加1 */
- void yc(int a){ /*構造延遲函數(shù)yc*/
- int b,c;
- for(b=0;b<a;b++)
- for(c=0;c<110;c++);
- }
- int scan(){ /*構造接收字符串函數(shù)scan*、/
- int af; /*定義一個整型變量af 用于返回值*/
- int ef=0; /*定義一個整型變量ef 賦值為0 用于判斷*/
- if(a==1){ /*通過判斷a的值來判斷串口中斷是否產(chǎn)生*/
- af=b; /*將全局變量b的值賦值給變量af*/
- yc(1); /*延遲1秒*/
- while(b!=af){ /*判斷b與af是否相等 不等進入循環(huán) 否則退出循環(huán) */
- 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()); /*接收到字符串就退出循環(huán)*/
- TI=1; /*TI置1 下面調(diào)用printf函數(shù)*/
- ES=0; /*串口中斷置不置0其實沒有多大的影響*/
- printf(c); /*用printf函數(shù)將接收到的字符串發(fā)送出去*/
- ES=1 ;
- }
- }
- void zd()interrupt 4
- {
- RI=0; /*RI置0 以便下次中斷*/
- a=1; /*有中斷a就為1*/
- c[b]=SBUF; /*將每次接受的字符存入c中*/
- b++; /*中斷產(chǎn)生則b加1*/
- }
復制代碼
出自 51黑電子論壇
|