51單片機串口通信使用類似printf函數的兩種辦法
本文引用地址:http://www.104case.com/article/201611/318584.htm今天就簡單來說說怎么在51單片機中使用"printf"函數:包括使用自帶的printf函數和自己動手寫一個printf函數,再貼代碼之前先介紹幾個相關的知識,主要用于自己寫printf函數。
①C語言函數:vsprintf,
其原型為int vsprintf(char *string, char *format, va_list param);,作用為將param按格式format寫入字符串string中,因此他可以用于將任何格式數據轉化為字符串數據,比如把整數97轉化為ASCII碼的97的程序就像下面這樣vsprintf(string,"%d",97),當然還有一點需要注意:在keil里面使用sprintf需要包含stdio.h這個頭文件(當然這里也可以使用sprintf,作用完全差不多,只需要稍加修改即可,不多介紹)。說到這里,再來說說另一個函數itoa吧,其實他比vsprintf更簡單,其原型為char *itoa(int value, char *string, int radix),作用為將value按radix進制寫入到string字符串中,使用時需要包含頭文件stdlib.h,可是在keil里面卻無法使用,頭文件里面不包含itoa,即使把VC里面的進來貌似還是不行,,目前不知道原因。
②可變參數函數
具體來說就是stdarg.h里面的這幾個函數va_start,va_arg,va_list,va_end,這幾個參數用于開辟一段內存區域,可以配合vsprintf使用,但是對內存使用較大,需要單片機具備一定的RAM,否則程序就算能編譯通過也是無法運行的,用法見這里http://blog.csdn.net/googlemi/article/details/8988567
③內部拓展RAM
定義:集成在單片機內部的數據存儲器,在物理上是內部,但邏輯上是外部,訪問時需要使用MOVX或者xdata訪問,具體可以看STC8051手冊,如下所示
:內部RAM(256byte)包括三部分:低128byte,高128byte和特殊功能寄存器區,特別注意和51不同,他的特殊功能寄存器和高128byte地址重疊,但是物理上是分開的,所有內部可用的RAM有256byte,所以到此為止可以得到內部RAM大小總共有:256byte+1024byte=1280byte
說了這么多,下面不多說,直接上程序
《一》直接使用系統自帶的printf函數:特別注意需要置位TI=1,否則是無法發送的,程序如下:
//此程序主要用于uart發送(proteus終端不能顯示漢字,但串口助手可以),輸入換行符n換行#include//stdio.h,string.h用于printf函數原型#include void delay(unsigned int z);void uart_init(void);//串行口初始化int main(void){int a=99;char *string="abde";uart_init();while(1){printf("%d %x %c %s %pn",a,a,(char)a,string,string);delay(1000);}return 0;}void uart_init(void){TMOD=0x20;//即0010 0000,定時器/計數器1,工作方式2TH1=0xfd;//設置波特率為9600TL1=0xfd;TR1=1;//啟動定時器/計數器1SCON=0x50; //0101 0000.串口工作方式1,允許串行控制PCON=0x00;//設置SMOD=0IE=0x90; //CPU允許中斷,串行允許中斷TI=1;//直接使用printf必須加入此句才能實現發送}void delay(unsigned int z){unsigned int x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);} 《二》自己動手寫一個類似printf的函數:uart_printf
但是這種情況占用RAM較多,因為需要開辟大數組,所以需要使用拓展型的51單片機,普通的AT89C51和STC89C52之類的會造成內存不夠用、堆棧溢出等等問題,所以以下程序都是基于STC12C5A60S2的,因為它含有內部拓展的1024byte的RAM,可以用來存儲大數組
//此程序主要用于uart發送(proteus不能仿真,但實際是可以運行的),輸入換行符n換行#include//stdio.h,stdarg.h用于vsprintf函數原型#include #include void delay(unsigned int z);void uart_init(void);//串行口初始化void sendbyte(unsigned char c);void sendstring(unsigned char *string);void uart_printf(const char *fmt,...);int main(void){int a=99;uart_init();while(1){uart_printf("10進制:%d 16進制:%x 字符格式:%cn",a,a,a);delay(1000);}return 0;}void uart_init(void){TMOD=0x20;//即0010 0000,定時器/計數器1,工作方式2TH1=0xf3;//設置波特率為2400TL1=0xf3;TR1=1;//啟動定時器/計數器1SCON=0x50; //0101 0000.串口工作方式1,允許串行控制PCON=0x00;//設置SMOD=0IE=0x00; //由于是查詢方式,故需要禁止中斷,CPU不允許中斷,串行不允許中斷}void delay(unsigned int z){unsigned int x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void sendbyte(unsigned char c){if(c==n)//如果遇到n就換行{//發送CR(carriage return)SBUF=0x0D; while(!TI);//等待發送完成TI=0;//發送 LF(NL line feed,new line)SBUF=0x0A; while(!TI);//等待發送完成TI=0; }else{SBUF=c;while(!TI);//等待發送完成TI=0;}}void sendstring(unsigned char *string)//此處*string相當于數組{while(*string!= 主站蜘蛛池模板: 连江县| 北川| 大名县| 抚松县| 玉龙| 巨鹿县| 稻城县| 民和| 奎屯市| 安徽省| 湖口县| 太和县| 广昌县| 苍溪县| 潼南县| 西城区| 泾源县| 昌都县| 平江县| 晋江市| 武川县| 喀什市| 马山县| 霍林郭勒市| 金坛市| 苗栗市| 新野县| 皮山县| 电白县| 丹阳市| 普定县| 高平市| 柳江县| 白河县| 永定县| 六枝特区| 宁波市| 峡江县| 济源市| 贵港市| 冷水江市|