51單片機實現scanf和printf函數

2020-12-13 電子產品世界

最開始學習C語言時,使用printf和scanf進行格式化輸入輸出十分方便。

學習單片機有很長時間了,之前要再屏幕上顯示一個變量或者通過串口傳出一些變量值觀測的話,需要進行一系列的取餘取整運算,很是麻煩。

本文引用地址:http://www.eepw.com.cn/article/201611/318359.htm

最近又研究了一下keil中針對printf和scanf的實現機理,做了一些改動,實現了標準格式化輸入輸出,共大家參考。

1.printf函數在格式化輸出時,向下調用了char putchar(char c);這個函數,在「stdio.h」裡可以發現有這個函數,所以我們需要自己構造一個這樣的函數,即通過串口putchar(),代碼如下:

char putchar(char c){hal_uart_putchar(c);return c;}

其中hal_uart_putchar(c);函數是我們比較熟悉的了,是51單片機通過串口發送一個字節的函數,具體代碼如下:

void hal_uart_putchar(char i){ES = 0;TI = 0; //清空發送完中斷請求標誌位SBUF = i;  //將數據放入寄存器發送while(TI == 0);//等待發送完畢,發送完畢 TI == 1TI = 0; //清空發送完中斷請求標誌位ES = 1;}

有了這兩個函數,在單片機啟動後,首先進行串口初始化,接著就可以使用printf了……是不是很簡單……

-------------------------------------------------------------------------------------------------------------------------------------

2.下面再看scanf的具體實現方法:

scanf函數在格式化輸入時,向下掉用了char getkey(void);這個函數,在「stdio.h」裡可以發現有這個函數,所以我們需要自己構造一個這樣的函數,即通過串口getkey(),代碼如下:

char _getkey (void)  {return hal_uart_getchar();}

其中hal_uart_getchar();稍稍複雜,但也很好理解,代碼如下:

char hal_uart_getchar(void){uchar ch;//Wait until a character is available:while(uart_rx_cnt == 0);ES = 0;ch = uart_rx[uart_rx_rp];uart_rx_rp = (uart_rx_rp + 1) % UART_BUF_SIZE;uart_rx_cnt--;ES = 1;return ch;}

這個函數是從串口接收隊列中取出隊尾的一個字節。uart_rx_cnt表示現在串口隊列中的已有字節數,uart_rx_rp指向隊尾。

最後要介紹的一個函數是串口接收中斷函數,代碼如下:

void UART1InterruptReceive(void) interrupt 4{ES=0;//關串行口中斷if(RI){RI=0;//接收中斷信號清零,表示將繼續接收if(uart_rx_cnt < UART_BUF_SIZE){uart_rx[uart_rx_wp] = SBUF;uart_rx_wp = (uart_rx_wp + 1) % UART_BUF_SIZE;uart_rx_cnt++;}} ES=1;//開串行口中斷 }

該函數實現了串口的中斷接收,收到的新的字節存放在隊首,即uart_rx_wp指向隊列的首地址,每次收到一個新的字節,uart_rx_cnt增1。

至此,scanf函數也可以實現了。

測試截圖:


註:串口接收的隊列沒有溢出檢測……

這篇文章裡實現的是對於串口的格式化輸入輸出,實際上,我們同樣可以對hal_uart_getchar();和hal_uart_putchar(c);函數進行更改,實現在屏幕上的格式化輸出等,思路都是一樣的……


相關焦點

  • arm串口實現 printf 和scanf函數
    問題描述:arm串口實現scanf和printf函數實現輸入一串十進位數字換成十六進位輸出功能,但是我的板子測試就是出不來#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) 作用是_ismask這個函數對輸入的參數進行一個unsigned char轉化到int類型的。#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) !
  • 單片機使用printf函數的兩種辦法
    今天就簡單來說說怎麼在51單片機中使用"printf"函數:包括使用自帶的printf函數和自己動手寫一個printf函數,再貼代碼之前先介紹幾個相關的知識,主要用於自己寫printf函數。②可變參數函數具體來說就是stdarg.h裡面的這幾個函數va_start,va_arg,va_list,va_end,這幾個參數用於開闢一段內存區域,可以配合vsprintf使用,但是對內存使用較大,需要單片機具備一定的RAM,否則程序就算能編譯通過也是無法運行的,用法見這裡http://blog.csdn.net/googlemi/article/details/8988567
  • 關於printf和scanf函數的一些問題(含拓展)
    printf 函數和scanf 函數一樣,都被聲明在頭文件stdio.h裡。(特殊IDE除外)如果在開頭沒有加stdio.h,你如果不用輸入輸出語句是沒有一點問題的,代碼為證:調用scanf函數時,需要傳入變量的地址作為參數,scanf函數會等待標準輸入設備(比如鍵盤)輸入數據,並且將輸入的數據賦值給地址對應的變量1.簡單用法* 運行程序,執行完第1行代碼,控制臺會輸出一句提示信息:
  • ios從入門到放棄之C基礎鞏固-----printf函數、scanf函數、scanf函數實現原理
    printf函數:繼續IOS的C基礎之旅,對於printf函數來說應該都非常之熟了,除了C有這個函數外,像Koltin也是有它,這裡還是對它進行一個梳理
  • 3.2 C++scanf和printf
    C++的scanf輸入函數和printf輸出函數學過C語言的讀者,對scanf函數和printf函數應該都不陌生,在C語言中最常見的輸入輸出就是用的這兩個函數,同樣在C++中也可以使用這兩個函數進行輸入和輸出,但是在C++中,普遍使用的是cin和cout函數。
  • C語言中的scanf與printf
    為實現這樣的操作,C語言提供了scanf與printf兩個函數,使用它們之前,一般需要包含stdio.h頭文件。語法是: #include 1. 使用scanf函數的注意事項。2)輸出兩個整型值分別給變量a,b可以使用兩條scanf函數語句來實現:scanf(「%d」,&a); scanf(「%d」,&b);這種寫法主要的缺點就是繁瑣,幾個變量就需要寫幾篇scanf,輸入數據時,兩次數據間用空格或回車分隔都可以。
  • 單片機使用printf函數進行串口列印輸出
    以前在使用keil編寫51單片機程序的時候,經常使用printf函數列印輸出一些關鍵的過程數據到電腦,方便監控程序的運行狀況。最近使用IAR for MSP430 調試 MSP430G2553 程序的時候,發現了一些小問題,MSP430G2553單片機並沒有按照我的預期輸出數據到電腦。帶著疑惑我查看了keil的幫助文件裡面的printf函數說明,原來printf函數最終是調用putchar函數來實現列印輸出字符的。
  • printf()函數重定向到STM32串口輸出
    /html/1573.htmlC語言中使用printf()函數輸出是非常方便功能非常強大的,如果能將printf()函數使用到串口上,能實現非常多的強大輸出功能,極大方便我們使用串口輸出功能。/article_2017110735665.html 推薦閱讀 單片機修改底層函數putchar()實現printf()在LCD上輸出 單片機源程序如下:#include <reg51.h>
  • scanf和printf格式化輸入輸出中非常實用的小技巧
    C提供的輸入輸出函數除了具有必須的輸入輸出功能外,還有一些其他實用的小技巧,了解這些小技巧將會為程序帶來更友好的用戶體驗。一、printf欄位寬度、精度修飾符當我們要輸出類似表格形式的樣式時,我們會用到欄位寬度修飾符。它能夠讓printf函數的輸出更加規整。
  • MSP430G2553單片機使用printf函數進行串口列印輸出
    以前在使用keil編寫51單片機程序的時候,經常使用printf函數列印輸出一些關鍵的過程數據到電腦,方便監控程序的運行狀況。最近使用IAR for MSP430 調試MSP430G2553程序的時候,發現了一些小問題,MSP430G2553單片機並沒有按照我的預期輸出數據到電腦。
  • C語言中的scanf函數
    1.空白符問題#include<stdio.h>main(){    int a; printf("input the data\n"); scanf("%d\n",&a);//這裡多了一個回車符\n   printf("%d",a);
  • scanf函數使用思路
    俺清晰的記得俺高中那會學編程的時候,很輕鬆就學到了scanf函數了,但是因為在學校是使用手機編寫程序,沒有電腦。用起來也比較糊塗。卡了好長一段時間。當時問了好多大佬,大佬就是這樣給我說,這個就是一個輸入。接著:怎麼輸入。大佬:就是這樣輸入啊!我直接懵了,一直想不通。
  • 關於scanf()函數的返回值
  • scanf()函數的一些困惑及解答
    在學生上機出現了這樣一個現象,如下面的代碼:        printf("輸入三個數:\n");    scanf("%d%d%d\n", &a, &b, &c);    ...
  • 51單片機基礎剖析(基於C語言)
    2.函數的參數和局部變量的存儲模式 C51 編譯器允許採用三種存儲器模式:SMALL,COMPACT 和LARGE。一個函數的存儲器模式確定了函數的參數的局部變量在內存中的地址空間。處於SMALL模式下的函數參數和局部變量位於8051單片機內部RAM中,處於COMPACT和LARGE模式下的函數參數和局部變量則使用單片機外部RAM。
  • 如何在單片機上使用printf函數
    當我們在調試代碼時,通常需要將程序中的某個變量列印至PC機上,來判斷我們的程序是否按預期的運行,printf函數很好的做到了這一點,它能直接以字符的方式輸出變量名和變量的值,這樣使輸出的信息很直觀;但printf函數在使用時,不僅僅要初始化串口
  • C語言中scanf函數的3種常見問題與應對技巧
    #include<stdio.h>main(){ int a; printf("input the data "); scanf("%d ",&a);//這裡多了一個回車符 printf("%d",a); return 0;}結果要輸入兩個數程序才結束,而不是預期的一個。why?
  • 關於C語言中printf與scanf的具體詳解
    結果圖 c語言中,浮點數的輸入輸出:scanf是float(REAL4),printf是double(REAL8)。
  • 數據類型題目練習6【scanf函數的用法】
    題目:scanf函數的用法。scanf函數是我們經常會用到的函數,所以大家一定要認真學習和掌握! // 使用scanf的時候,儘量避免空白符和非空白符。 // scanf("%d%d%d", &a, &b,&c); // 空白符可以是空格(space,用空格鍵輸入)、制表符(tab,用Tab鍵輸入)和新行符(newline,用回車鍵輸入),或者它們的組合.
  • C語言入門教程-Scanf
    scanf的最簡單用法是像這樣: scanf("%d", &b); 該程序將讀取用戶從鍵盤輸入的一個整數(和在printf中一樣,%d代表整型,因此b必須聲明為int),並將其存入b。 scanf函數使用的佔位符和printf的相同: int用%d float用%f char用%c 字符串(後面會討論)用%s 在使用scanf時,您必須在其變量前加上&。為什麼要這麼做的原因,在您學習指針後會很清楚。