基于ARM Cortex-M3的STM32系列嵌入式微控制器应用实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第3章 STM32单片机程序模块化设计与机器人运动控制

本章将介绍程序调试方法,以及如何利用模块化的程序设计思想,设计机器人的运动控制模块以实现各种巡航动作。这些编程技术在后面的章节都会用到,与后面章节唯一不同的是,本章机器人在无感觉的情况下巡航,而在后面的章节中,机器人将根据传感器检测到的信息进行智能巡航。本章所要完成的主要任务包括:STM32单片机程序调试方法,利用模块化设计方法对STM32单片机编程,实现一些基本巡航动作函数:向前、向后、左转、右转和原地旋转等。这些函数都能够被多次调用,以使机器人可以实现复杂巡航运动。

3.1 STM32单片机程序调试方法

程序运行是连续执行的,但是当程序执行遇到问题时,我们如何来判断是哪条语句出问题了呢?尤其是从本章开始,我们将要编写的程序会越来越复杂,因此我们要学会如何调试程序,以及如何将一个复杂的程序模块化,模块内的函数代码相对简单。这也是程序设计的一个原则:“松耦合,强内聚”,内聚是子程序内部的关系,耦合是不同子程序的关系。就是要求各个函数模块独立性高一些,即使修改了其中的某个函数,其他的函数也不需要做修改。比如,我们每个程序都要用到的2个函数:开发板初始化函数和串口初始化函数。

任务一 程序调试

打开发光 二极管闪 烁程序,即工程文 件Led_Blink.Uv2,将光标移动到想要程序运行时需要暂停的语句处,如延时语句处,单击图3.1所示的图标(或按F9键)。这样你就给程序加了一个断点,如图3.2所示。当你想取消断点时,可以再按一次这个图标(或按F9键)。设置断点也可以直接在你要设置的语句最前面的空白处双击一下。

图3.1 断点设置

图3.2 程序加入断点后的效果

注意:若设置成功,那里会有一个小红点的,不然你就需要重新操作

断点与调试

断点就是程序运行到断点处就暂停下来,不运行了(断点所在的语句不会执行);你可以看一下你设的变量在这个时候是什么值,从而判断程序有没有什么逻辑上的错误或其他的问题。

调试是学习语言的好方法,对于新手来说写一个完整的程序难免出现错误,如果直接运行程的话,是很难发现程序的错误。调试可以为程序的语句设置断点,开始调试之后当运行到设置了断点的语句时程序会停下来,之后你可以选择逐个语句运行,也可以逐个方法运行,可以监视每个变量的变化,直到程序结束。这样你就可以很容易发现程序的错误所在。通俗地说,调试就是人跟着程序跑一次。相当于你规划了一个路线到达某地,但你不知道该路线是否真的能到达你想去的地方,要验证该路线是否正确的最好办法就是按照路线走一遍。

单击图3.3(a)所示的图标(或按Ctrl+F5键)进入调试模式,然后再单击图3.3(b)所示的图标(或按F5键)运行程序,这时程序就会停在断点处,如图3.4和图3.5所示。这时你可以通过调试窗口检查程序的执行状态,包括寄存器窗口、存储器窗口、查看和调用栈窗口、反汇编窗口和外设窗口等,这里不再赘述。

图3.3 程序调试

图3.4 程序调试开始

图3.5 程序运行到断点处

程序调试开始时,会有一个黄颜色箭头出现在main函数入口处(图3.4),表示程序运行停在这里。单击图3.3(b)所示的图标(或按F5键),黄颜色箭头出现在第一个断点处时(图3.5),此时发光二极管亮;你可继续按F5键运行程序,黄颜色箭头会出现在第二个断点处时,此时发光二极管灭。试试看,连续按F5键,发光二极管什么现象。

单步调试

程序调试开始时,即黄颜色箭头出现在main函数入口处(图3.4),你还可以单击图3.6(a)所示的图标(或按F11键),或单击图3.6(b)所示的图标(或按F10键)单步运行程序,即一条语句一条语句地执行程序。它们的区别在于当程序运行到子函数调用时:

(1)Step into会进入到子函数体,并继续开始单步执行每条语句,直到当前子函数结束返回上层调用函数;

(2)Step over将子函数调用仅当做一条语句单步执行,不会进入到子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步单步执行。

图3.6(c)所示的图标(或按Ctrl+F11键)表示跳出当前运行的函数,即将本函数余下语句执行完返回上层调用函数。即当单步执行到子函数内时,用Step out就可以执行完子函数余下部分,并返回到上一层函数。

图3.6(d)所示的图标(或按Ctrl+F10键)表示运行到当前光标所在语句处。

图3.6 调试模式说明

此时,可以单击图3.6(e)、(f)、(g)所示图标,分别打开Stack、Memory、逻辑分析仪窗口进一步观察程序中各个变量、所用到的寄存器,以及引脚电平的变化,从而判断程序有没有逻辑上的错误或其他的问题。也可以单击图3.6(h)所示图标,查看汇编代码,并和C语言代码对比分析,加深对STM32微控制器的理解。调试模式下的工作区主要用于显示汇编代码、C语言代码的执行跟踪及调试信息,这对应用程序的开发非常重要。单击图3.6(i)所示图标时,将复位CPU,终止正在调试的程序,重新从代码起始位置开始。

注意按下“Debug”图标进入调试模式时,需复位开发板,才能开始调试。

设置断点和单步调试执行程序对于我们理解程序的运行过程和调试错误等都十分有用,所以要学会通过不断尝试来好好运用它!这里所用的方法,可以同样适用于使用Keil软件开发51单片机程序,或者使用VS.net,VC++编写PC程序,具有一定的通用性。Debug菜单下的常用命令总结如下

Start/Stop Debug Session:开始或停止调试。图3.3(a)所示。

Run:执行程序,直到遇见下一个断点。图3.3(b)所示。

Step:单步执行。图3.6(a)所示,图标上显示Step into。

Step Over:函数单步执行,即将一个子函数作为一条语句来执行。图3.6(b)所示。

Step Out of Current Function:跳出当前的函数执行。图3.6(c)所示。

Run to Cursor line:执行到光标所在行。图3.6(d)所示。

Stop Running:停止执行。

Breakpoints:打开断点对话框。

Insert/Remove Breakpoint:在当前行插入/删除一个断点。图3.1所示。

Enable/Disable Breakpoint:激活当前行的断点或使断点无效。

Disable All Breakpoints:使程序所有断点无效。

Kill All Breakpoints:删除掉程序所有断点。

该你了——一条语句一条语句地执行程序!

软件仿真

RealView MDK开发工具提供了强大的软件仿真功能,可以不需要将程序下载到开发板上进行调试,而是采用MDK的软件仿真功能进行调试,达到事半功倍的效果!

单击图标,或右键单击“Target 1”,选择“Option for target ‘Target 1’”,或单击Project菜单下的Options for Target(工程属性),或单击“Flash”菜单下的“Configure Flash Tools”,弹出“Options for Target”对话框,选择“Debug”页面,选中“Use Simulator”之后确定,如图3.7所示。注意需重新编辑,使设置成功。

图3.7 软件仿真设置

编译成功后,进入Debug模式,按照前面介绍的方法即可进入软件仿真模式。这时,可以选择外围模块进行仿真,不同型号的STM32单片机会有不同的外设仿真功能。打开“Peripheral菜单”,可以打开多个外设仿真对话框,如图3.8所示。

图3.8 外设仿真对话框

LED闪烁程序只用到了GPIOC端口,关闭其他对话框,仅保留“GPIOC”外设仿真对话框,如图3.9所示。因为这时程序还没有运行,所以GPIOC端口是初始值。

图3.9 GPIOC外设仿真对话框

单击Debug工具条的运行按钮,在仿真对话框里就可以看到程序的运行结果了。当执行完教学开发板初始化函数BSP_Init()后,GPIOC的各项参数会发生变化,如图3.10(a)所示。看看初始化函数BSP_Init()的代码是不是这样呢?通过单步执行程序,可以发现PC13引脚的参数会发生变化,如图3.10(b)和(c)所示。

图3.10 GPIOC外设参数的变化情况

如果想观察引脚的电平变化,可以单击图标,打开逻辑分析仪,如图3.11(a)所示。然后单击“Setup…”按钮,在观测引脚设置对话框中添加GPIOC_IDR,并设置相关参数,如图3.11(b)~(e)所示。

图3.11 逻辑分析仪设置

单击“Debug”菜单下的“Run”菜单项或按F5键,开始软件仿真。稍等一下之后,可以单击“Debug”菜单下的“Stop Running”菜单项,停止仿真。

单击“Zoom”的“All”按钮,可以查看整个仿真期间PC13引脚的电平变化情况。单击“In”按钮,可以将时间轴网格为变小;单击“Out”按钮,可以将时间轴网格为变大,通过这两个按钮可以将时间轴网格调整到一个合适的大小,以利于观测显示波形。如图3.12所示,PC13引脚的输出电平每隔一定的时间变化一次,对应的发光二极管交替闪烁。从图中可以看出存在一定的误差,因此,最好用示波器验证一下PC13引脚的输出波形。软件仿真存在一定的误差。

要想得到精确的延时时间,可以使用后面将要学习到的定时器,来控制发光二极管交替闪烁。

图3.12 PC13引脚的电平变化情况