天天看點

淺談MDK環境下使用#include <stdio.h>的問題

在使用MDK進行嵌入式開發,特别是調試序列槽的時候經常要用到C語言的标準輸入輸出庫函數,如printf();。這樣寫出來的程式,通常編譯和連結過程都不會報錯,但是程式卻無法正常運作,檢視反彙編可以發現程式停在了BKPT 0xAB一行。

淺談MDK環境下使用#include <stdio.h>的問題

原因分析如下:

标準庫函數的預設輸出裝置是顯示器,要實作在序列槽或LCD輸出,必須重定義标準庫函數裡調用的與輸出裝置相關的函數.  例如:printf輸出到序列槽,需要将fputc裡面的輸出指向序列槽(重定向),方法如下: 隻要自己添加一個int fputc(int ch, FILE *f)函數,能夠輸出字元就可以了 #ifdef __GNUC__    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)  #else  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)  #endif   PUTCHAR_PROTOTYPE {  USART_SendData(USART1, (uint8_t) ch);   while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);  return ch;  }  因為printf()之類的函數,使用了半主機模式。使用标準庫會導緻程式無法運作,以下是解決方法: 方法1.使用微庫,因為使用微庫的話,不會使用半主機模式。 如果使用的是MDK,請在工程屬性的“Target“-》”Code Generation“中勾選”Use MicroLIB“這樣以後就可以使用printf,sprintf函數了 

淺談MDK環境下使用#include <stdio.h>的問題

方法2.仍然使用标準庫,但在主程式中需要添加以下代碼:     #pragma import(__use_no_semihosting)  // 確定沒有從  C  庫連結使用半主機的函數  _sys_exit(int x)      // 定義 _sys_exit() 以避免使用半主機模式  { x = x; }    struct __FILE  // 标準庫需要的支援函數  {  int handle;  };    FILE __stdout;   

在獨立應用程式中,不太可能支援半主機操作。 是以,必須確定您的應用程式中沒有連結 C 庫半主機函數。 

為確定沒有從 C 庫連結使用半主機的函數,必須導入符号 __use_no_semihosting。可在工程的任何 C 或彙編語言源檔案中執行此操作,如下所示: 

在 C 子產品中,使用 #pragma 指令: 

#pragma import(__use_no_semihosting)  

在彙編語言子產品中,使用 IMPORT 指令: 

IMPORT __use_no_semihosting 

如果仍然連結了使用半主機的函數,則連結器就會報告錯誤。  

下面是網上關于半主機模式的解釋: 【半主機是用于 ARM 目标的一種機制,可将來自應用程式代碼的輸入/輸出請求傳送至運作調試器的主機。 例如,使用此機制可以啟用 C 庫中的函數,如 printf() 和 scanf(),來使用主機的螢幕和鍵盤,而不是在目标系統上配備螢幕和鍵盤。 這種機制很有用,因為開發時使用的硬體通常沒有最終系統的所有輸入和輸出裝置。 半主機可讓主機來提供這些裝置。 半主機是通過一組定義好的軟體指令(如 SVC)來實作的,這些指令通過程式控制生成異常。 應用程式調用相應的半主機調用,然後調試代理處理該異常。 調試代理提供與主機之間的必需通信。 半主機接口對 ARM 公司提供的所有調試代理都是通用的。 在無需移植的情況下使用 RealView ARMulator ISS、指令集系統模型 (ISSM)、實時系統模型 (RTSM)、RealView ICE 或 RealMonitor 時,會執行半主機操作,請參閱Figure 8.1。 在很多情況下,半主機由庫函數内的代碼調用。 應用程式還可以直接調用半主機操作。 有關 ARM C 庫中的半主機支援的詳細資訊,請參閱《庫和浮點支援指南》中的第 2 章 C 和 C++ 庫。】  

繼續閱讀