嵌入式开发<单片机软件调试>
前言
本人从事单片机软件设计工作多年,既从事过裸机系统的设计,也在小型嵌入式实时操作系统下进行过设计。在这些年的开发工作中,对产品设计逐步形成了一定的认识,并进行了较多的总结。因此,一直以来,都想整理这些东西,希望对有需要的人能提供一些帮助或参考。
在诸多的想法中进行系统的整理其实还是有一定的工作量。目前来说,也只能一点一点的完成。之前本人已经对一些较普通的驱动进行了整理,并进行了优化,感兴趣的朋友可以前去看看(其中包含完整代码并已经调试通过)。
其实,在产品设计中涉及到诸多方面,比如产品的信息与参数,产品的调试信息与运行状态数据(甚至形成关键日志),产品的软件升级方法等等。这些东西应该形成一个统一的约定,便于公司及开发同事形成共同的方法,对于设计与维护都会有益。关于产品的信息与参数这方面的内容,我在之前的嵌入式调试工具(串口调试工具与网络调试工具中有详细说明)。
当然,这些东西太多,肯定不会一股脑的写出来。这次的主题是软件调试,而在这里主要讲的是交互式调试,其可用于修改产品信息与参数,查看运行状态数据等等。可使得产品在无任何输入输出接口时,仍然可以进行交互操作。并且,其使用接口可以是普通的串口(RS232),也可以是RS485,以太网,无线网络,只要能与电脑通信方便,对使用的接口原则上没有限制。
另外,还有一点。我们设计的以单片机为主控的产品,其实有很多是没有输入输出接口的,其调试与测试都是很困难的,甚至让人感觉无从下手。因此,设计交互式调试方法,就使得这方面的工作变得非常容易,所以,这也是这个工作有必要和有意义的体现。
一、交互式调试设计依赖工具
原则上来讲,所依赖的工具没有特别要求,只要能找一个相应接口的调试工具即可。比如RS232与RS485接口就可以使用普通的串口调试助手;使用网络接口,则可以使用网络调试助手。当然,有条件的情况下,你或者你的公司可以开发一款适用于自己的调试工具,它可以是专用的,也可以是通用的。
本人就根据自己及公司产品特点以及软件开发的习惯,自行开发了两款通用调试工具,即串口调试工具与网络调试工具,二者除网络通信方式相关内容不同外,其余几乎一致,也很容易使用。并且目前已经形成公司产品开发调试及生产和维护不可缺少的工具。
二、交互式调试设计的使用方法
以下均以串口调试工具(或串口助手)为例
1.普通方法
在串口工具中,一般有发送区和接收区。交互调试,首先得通过串口给设备发送命令字符串。因此,其交互过程为:
1) 在发送区,输入自定义的命令字符串(或带参数);
2) 设备接收后进行命令比较,如未能查找到此命令,则不响应或提示错误;
3) 如能查找到命令,则执行其要求的操作;
4) 适当的在接收区输出操作结果;
5) 如当前命令仅仅启动一个操作,并且后续仍然有交互操作,则需要按照上面的类似步骤继续执行,直至整个功能执行完毕;
以上方法,存在诸多问题,使得实际使用时并不方便。其缺点体现在以下几个方面:
A, 不容易记住:
如果公司没有进行统一规定,则每一个开发工程师可能对同一个功能会使用不同的方式,甚至有些人会使用中文字符串。如时间久了,可能开发的工程师都不记得了。
即便公司进行了统一规定,记住这些命令也是不容易的,因此会制作一个命令表格,在使用时需要调出此表格,并进行复制与粘贴操作。
无论如何,这种输入字符串的方式是非常不方便的,也制约了这种交互式操作的便利性。
B, 不容易使用:
这里的不容易使用,已经不特指是否能记住的问题。而是指此命令可能不知道应该如何使用。比如,是否需要参数数据,甚至参数数据的格式如何等等,也就是使用方法的问题。
当然,公司也可以在指定命令表时,将使用方法即参数定义等等写在一起。但与上一个缺点有一个共性的地方就是,当用户在使用时,它并没有这个命令表,可能因为某种原因会导致他需要暂停维护工作。
C, 存在使用风险:
在设计的众多操作命令中,可能会存在一些风险性较高的操作。比如恢复出厂设置、删除数据、格式化磁盘等等。有时候可能你确实需要执行这个操作,但有时候又难免你是误操作。
如果没有进行有效拦截,并进行确认,这可能会造成灾难性的后果。当然,你可以在应用程序中对操作的用户进行提示,但万一某一个工程师忘记这样做了呢,所以这并不是一个好的方法。
D, 其它问题:
其它的问题虽然不是致命的,或严重的,但也可能存在不方便的地方。比如,设计的命令当中肯定有些是不希望生产、测试、客户使用的。可能仅仅是我们开发人员自己的一个测试命令。而且,即便是生产、测试、维护他们能使用的命令也不一定相同,可能有些命令就是不给维护使用,有些命令也不给生产使用。其实,对于上面提到的问题,也就是命令分类的问题。当然,我们也可以在命令表里面进行分类,然后给到客户,但这也是一件很麻烦的事情。
还有,比如测试人员,在测试的过程中发现了一个BUG,但可能他根本记不住之前进行过什么操作。如果能完整的记录其操作过程,对于解决BUG是有很大帮助的。
当然还有一些其它的问题,这里不再一一列出。
2.定制方法
这里提到的定制方法,即本人使用的方法。首先,本人开发了两款相似的调试工具(上面已经提到),其主要核心是解决了操作命令的相关问题。针对以上问题而设计的主要功能为功能按钮,其具有的特点如下:
1) 提供功能按钮页面
在功能按钮页面中,可执行功能按钮导入、导出、删除。
2) 保存功能按钮与选择
另外,可在接收区执行功能按钮的保存。这需要接收区的文本信息满足一定的格式,这样工具软件可以进行识别。
同时,因为这个保存功能,可以在用户产品中设计输出满足格式的功能按钮文本,这样用户在任何地点使用均可以调出按钮文本并进行保存。
保存的功能按钮被保留在本地硬盘上,通过一个下拉菜单,用户可以选择已经保存的按钮功能文件,并调出其功能按钮执行相应的操作。
3) 功能按钮的核心内容
功能按钮包含诸多元素,使其执行测试操作非常方便,其主要内容如下:
A, 按钮名称:
这个以顾名思义的方式由设计者进行命名,可以中午也可以英文,只要能表达其执行的功能即可。只是其名称被限定在8个中文字符(16个英文字符)内;
B, 按钮功能:
实际上就是操作命令,即用户点击此按钮后,通过发送区发送到产品的命令字符串,当然这个也是由设计者进行自定义的,并且其定义的字符串完全可以不需要公司进行约定。因为这个命令与操作的用户无关,用户不再需要记住此命令;
C, 按钮确认:
指示用户点击此按钮时,是否弹出确认操作的提示框,此设置可避免用户误操作。
D, 按钮参数:
指示在执行此命令时,是否必须在发送区输入命令参数。如果设置为Y,则工具软件在执行此按钮时将检查发送区是否有参数数据,并在没有参数数据时拒绝执行此命令,并弹出提示窗口(如果有按钮参数说明提示性内容,则一并输出);
另外,此项还兼具另一个功能,当其被设置为H时,则指示按钮功能内容为HEX数据,而非ASCII字符。
E, 提示信息:
这是一个可选项,当这个按钮必须输入参数数据时,应该设置此项。主要以字符串方式填写此功能按钮的说明以及参数数据的使用说明等等。
这里首先列出功能按钮文本格式
按钮文件:ZGLJ-C2-new调试按钮
=============================================
按钮名称 按钮命令 确认 参数 提示信息
------------------------------------------------------------
{
重启设备} {
C-RESTARTS} {
N} {
N} {
}
{
恢复出厂设置} {
C-SETFACTORY} {
Y} {
N} {
将设备基本信息、工作参数及通信参数恢复到默认值}
=============================================
以上主要介绍的是交互调试的使用方法,并重点介绍了本人开发与之配合使用的工具。如果你感兴趣,可以在最后的链接中去下载并使用。当然,你也可以自行开发或者使用普通工具软件。不过,如果你使用的是普通串口助手或网络助手,可能达不到此文所讲的目的。
下面将重点介绍产品设备中如何进行相应的设计。
三、交互式调试产品设计
上文提到,我设计的工具软件具备一个重要功能,即可以通过接收区的文本信息进行按钮文本保存。这是一个非常重要的功能(当然,你为了不设计这个功能,可以按照前面介绍的按钮文本格式自行编辑)。不过,我仍然建议在你的产品中具备这个功能,因为它确实是非常的方便。
1, 全局需要使用的宏定义
#define getStrAddr(str) (char*)(&str)
#define GetDebugCmd(BuffStr,CmdStr) (strncmp(BuffStr, CmdStr, strlen(CmdStr))==0)
#define UNUSED(x) x=x
#define buttonMax 18
#define buttonFiles 3
以下分别说明其作用:
1)getStrAddr获取FLASH中存储的字符串地址;
2)GetDebugCmd比较输入字符串与命令字符串;
3)UNUSED参数未使用(避免警告信息);
4)buttonMax设计的功能按钮总数;
5)buttonFiles输出的功能按钮文本总数;
2,设计一个功能按钮表格
说明:设计的这个表格,可以放在芯片的FLASH中,不必存储在RAM中。
1) 功能按钮数据结构
typedef void (*pButtonFunc)(tSerialBuff *);
这是功能按钮对应函数原型,其中tSerialBuff结构为本人设计的串口驱动缓存,在此不必关心。