文/呂興朝 王澤同
ARM公司于1991年成立于英國劍橋,主要設計了基于精簡指令集的ARM核微處理器,它只參與IP核的設計,而不從事芯片的生產。世界其他半導體廠商Philips、Samsung、Atmel、 Analog Devices、Sharp、ST、TI、瑞芯微、全志等通過向ARM公司購買其設計的ARM微處理器核,加入自己的ARM外圍電路,形成了自己的ARM處理器芯片。如美國TI公司的335X系列、中國的全志A35系列、中國的瑞芯微RK3288系列等。微處理器廠商通過和授權主板廠商或公司合作,開發基于ARM處理器的開發板,用于各種工業控制、嵌入式應用等。如飛凌嵌入式FET1012A系列核心板、周立功ARM9系列開發板。ARM處理器體積小、低功耗、低成本、高性能,基于ARM的嵌入式系統被廣泛應用于醫療器械、工業控制、機械制造、機器人、人工智能、航空航天等諸多領域。基于ARM嵌入式系統通常運行的是linux系統,主流可視化的應用程序的開發一般基于QT進行開發。
QT開發需要準備的工具:
(1)ubuntu或debian系統安裝鏡像。
(2)VmwarePlayer.工具
(3)QT IDE源碼。
(4)交叉編譯工具。
如果開發PC是windows系統,則首先要在windows上安裝虛擬機軟件VmwarePlayer,用于運行linux。如果開發PC操作系統是ubuntu或者debian系統,則不需用工具1和2。在VmwarePlayer中新建虛擬機,安裝ubuntu或debian系統。
通過交叉編譯工具編譯QT IDE源碼得到可以在嵌入式系統中編譯的qmake。使用linux系統自帶的g++編譯器編譯QT IDE源碼,可以得到在linux桌面系統中編譯的qmake。需要注意的是這兩個編譯是不同的,一個是可以在ARM中編譯運行的,一個是可以在linux桌面系統中編譯運行的。兩者不可以混用,即用交叉編譯工具編譯的qmake編譯出來的QT應用程序不能在linux桌面系統中運行,用linux桌面系統編譯出來的QT應用程序不能在嵌入式系統中運行。
本文以操作ARM嵌入式系統開發板的GPIO以及RS232串口為例。
假定系統需求為:
(1)ARM嵌入式系統可以通過GPIO1控制一個電平輸出。
(2)ARM嵌入式系統可以通過GPIO2采集一個電平輸入。

圖1:主程序界面

圖2:模擬程序界面
(3)ARM嵌入式系統可以通過RS232串口讀取溫度傳感器模塊的實時溫度,溫度傳感器返回給ARM嵌入式系統ADC值,QT軟件通過溫度與ADC值的Map關系可以得知溫度。
ARM嵌入式系統開發板的GPIO口通常分為兩種:一種是輸入GPIO,一種是輸出GPIO。輸入GPIO就是采集輸入口的電平,linux系統內核通過驅動解析硬件輸入,將輸入口的電平信號轉換為1或0,上層QT系統軟件通過讀取驅動接口獲取到1或者0。輸出GPIO是上層QT系統軟件通過內核驅動將1或0輸出到硬件上,硬件接口將輸出高電平或低電平。RS232串口可以輸入或輸出串口幀數據。通過自定義數據幀格式實現ARM嵌入式系統與溫度傳感器模塊的通信。當需要讀取溫度時,ARM嵌入式系統向溫度傳感器模塊發送讀取溫度命令幀格式數據,溫度傳感器模塊收到讀取指令后返回溫度值的幀格式數據,然后QT軟件根據幀格式提取溫度值的ADC值,通過ADC值與溫度值的Map關系進行轉換。
虛擬機中并不存在gpio口或者指定串口,主工程需要驗證輸入輸出的gpio口數據或串口數據是否正確。只通過單機上打斷點查看寄存器的值的調試方法,只能查看輸出是否正確,輸入則無法驗證,并且操作可視性差,不方便查看。可以通過模擬硬件的虛擬程序輔助主工程進行調試,主工程和模擬硬件程序對指定文件進行共同讀寫,模擬程序寫入的值則可以觸發主程序通過斷點調試輸入信息,模擬程序也可以顯示主程序的輸出。
下面通過實際工程示例來說明整個操作過程。
首先新建QT主工程,通過預編譯定義來區分是在linux系統中運行還是在ARM嵌入式系統中運行。當主程序運行在linux系統模式時,可以使用gdb進行打斷點調試。當需要運行在ARM嵌入式系統時,只需要修改預編譯定義,使用交叉編譯的qmake進行編譯即可。
下面為主工程程序偽碼:
//gpio輸出操作
#ifdef arm //運行在arm系統模式
system(“echo 1 > /sys/class/gpio/gpio1/value”);//向gpio1輸出1
#else //運行在linux系統模式
FILE* fp=fopen(“/sys/class/simulation/gpio1”,”w”);
char cTemp[1]={1};
fwrite(cTemp,1,sizeof(cTemp),fp); //模擬向文件/sys/class/simulation/gpio1輸出1
fclose(fp);
#endif
//gpio輸入操作
#ifdef arm //運行在arm系統模式
system(“cat /sys/class/gpio/gpio1/value”);//讀取gpio1的值
#else //運行在linux系統模式
FILE* fp=fopen(“/sys/class/simulation/gpio2”,”r”);
char cTemp[1]={1};
fread(cTemp,1,sizeof(cTemp),fp); //讀取模擬文件/sys/class/simulation/gpio2
fclose(fp);
#endif
//串口讀取操作
#ifdef arm //運行在arm系統模式
//寫入讀取指令
//讀取溫度ADC
#else //運行在linux系統模式
FILE* fp=fopen(“/sys/class/simulation/serial”,”rb+”);
char cTemp[1]={1};
fwrite(cTemp,1,sizeof(cTemp),fp); //向模擬串口文件/sys/class/simulation/serial輸出讀指令(假定輸出1為讀指令)
fread(cTemp,1,sizeof(cTemp),fp); //讀取模擬串口文件/sys/class/simulation/serial (假定讀到的為1個byte的ADC數據)
fclose(fp);
//根據Map解析ADC溫度值
#endif
圖1為主工程界面。
新建QT模擬工程,模擬工程中可以對指定文件的進行讀寫操作,方便主工程調試。
下面為模擬工程程序偽碼:
//輸出gpio2操作
FILE* fp=fopen(“/sys/class/simulation/gpio2”,”w”);
char cTemp[1]={1};
fwrite(cTemp,1,sizeof(cTemp),fp); //向文件/sys/class/simulation/gpio2輸出1
fclose(fp);
//讀取gpio1操作
FILE* fp=fopen(“/sys/class/simulation/gpio1”,”r”);
char cTemp[1]={1};
fread(cTemp,1,sizeof(cTemp),fp); //讀取文件/sys/class/simulation/gpio1
fclose(fp);
//串口寫入操作
FILE* fp=fopen(“/sys/class/simulation/serial”,”rb+”);
char cTemp[1]={0x55};
fwrite(cTemp,1,sizeof(cTemp),fp); //寫入模擬串口ADC溫度/sys/class/simulation/serial fclose(fp);
圖2為模擬程序界面,可以通過讀寫刷新按鈕,根據設定值對文件進行讀寫,從而觸發主工程調試。
本文提供了一種通過可視化的模擬程序讀寫文件,方便ARM嵌入式系統QT軟件在linux環境下調試。特別當系統邏輯比較復雜時,可視化的調試工具,可以大大的節省程序開發人員發現問題的時間,有非常良好的實用價值。該方法曾被筆者廣泛的應用在復雜狀態機的控制調試中,極大地降低了系統調試的復雜度。