基于ARM嵌入式系统QT软件模拟调试技术
2019-08-23吕兴朝王泽同
文/吕兴朝 王泽同
1 引言
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进行开发。
2 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应用程序不能在嵌入式系统中运行。
3 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为模拟程序界面,可以通过读写刷新按钮,根据设定值对文件进行读写,从而触发主工程调试。
4 结论
本文提供了一种通过可视化的模拟程序读写文件,方便ARM嵌入式系统QT软件在linux环境下调试。特别当系统逻辑比较复杂时,可视化的调试工具,可以大大的节省程序开发人员发现问题的时间,有非常良好的实用价值。该方法曾被笔者广泛的应用在复杂状态机的控制调试中,极大地降低了系统调试的复杂度。