1. 程式人生 > >51微控制器實現scanf和printf函式

51微控制器實現scanf和printf函式

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

學習微控制器有很長時間了,之前要再螢幕上顯示一個變數或者通過串列埠傳出一些變數值觀測的話,需要進行一系列的取餘取整運算,很是麻煩。

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

1.printf函式在格式化輸出時,向下呼叫了char putchar(char c);這個函式,在“stdio.h”裡可以發現有這個函式,所以我們需要自己構造一個這樣的函式,即通過串列埠putchar(),程式碼如下:

[cpp] view plaincopy
print?在CODE上檢視程式碼片派生到我的程式碼片
  1. char putchar(char c)  
  2. {  
  3.     hal_uart_putchar(c);  
  4.     return c;  
  5. }  

其中hal_uart_putchar(c);函式是我們比較熟悉的了,是51微控制器通過串列埠傳送一個位元組的函式,具體程式碼如下:

[cpp] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. void hal_uart_putchar(char i)  
  2. {  
  3.     ES = 0;  
  4.     TI = 0; //清空傳送完中斷請求標誌位
  5.     SBUF = i;  //將資料放入暫存器傳送
  6.     while(TI == 0);
    //等待發送完畢,傳送完畢 TI == 1
  7.     TI = 0; //清空傳送完中斷請求標誌位
  8.     ES = 1;  
  9. }  

有了這兩個函式,在微控制器啟動後,首先進行串列埠初始化,接著就可以使用printf了……是不是很簡單……

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

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

scanf函式在格式化輸入時,向下掉用了char getkey(void);

這個函式,在“stdio.h”裡可以發現有這個函式,所以我們需要自己構造一個這樣的函式,即通過串列埠getkey(),程式碼如下:

[cpp] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. char _getkey (void)    
  2. {  
  3.     return hal_uart_getchar();  
  4. }  

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

[cpp] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. char hal_uart_getchar(void)  
  2. {  
  3.     uchar ch;  
  4.     //Wait until a character is available:
  5.     while(uart_rx_cnt == 0);  
  6.     ES = 0;  
  7.     ch = uart_rx[uart_rx_rp];  
  8.     uart_rx_rp = (uart_rx_rp + 1) % UART_BUF_SIZE;  
  9.     uart_rx_cnt--;  
  10.     ES = 1;  
  11.     return ch;  
  12. }  

這個函式是從串列埠接收佇列中取出隊尾的一個位元組。uart_rx_cnt 表示現在串列埠佇列中的已有位元組數,uart_rx_rp指向隊尾。

最後要介紹的一個函式是串列埠接收中斷函式,程式碼如下:

[cpp] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. void UART1InterruptReceive(void) interrupt 4  
  2. {  
  3.     ES=0;//關序列口中斷
  4.     if(RI)  
  5.     {  
  6.         RI=0;//接收中斷訊號清零,表示將繼續接收
  7.         if(uart_rx_cnt < UART_BUF_SIZE)  
  8.         {  
  9.             uart_rx[uart_rx_wp] = SBUF;  
  10.             uart_rx_wp = (uart_rx_wp + 1) % UART_BUF_SIZE;  
  11.             uart_rx_cnt++;  
  12.         }  
  13.     }   
  14.     ES=1;//開序列口中斷 
  15. }  

該函式實現了串列埠的中斷接收,收到的新的位元組存放在隊首,即uart_rx_wp指向佇列的首地址,每次收到一個新的位元組,uart_rx_cnt增1。

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

測試截圖:


注:串列埠接收的佇列沒有溢位檢測……

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

有不合理的地方,請大家批評指正。