第5章 嵌入式系统软件开发与调试 由51单片机组成的微型计算机系统常被嵌入到其他设备中辅助其应用,该系统被称为嵌入式系统。当51单片机电子线路设计无误后,其后续工作将是为嵌入式系统编写控制软件。本章将介绍嵌入式系统软件开发与调试的集成环境Keil工具,Keil具备了汇编语言、C51、ARM C语言源程序的编辑、编译、连接、调试、模拟执行等功能。 5.1Keil开发环境简介 Keil是Keil Software公司出品的针对使用汇编、C51、ARM C等语言控制、管理Intel 51、ARM等系列单片机的集成编辑、编译、连接、调试、模拟运行的软件开发平台。 5.1.1Keil开发环境主要功能 Keil是应用于Windows的窗口交互式的集成开发环境(IDE),其主要功能如下。 (1) 编辑——通过编辑窗口实现汇编(*.asm)或C51语言(*.c)代码的输入和修改。 (2) 编译——C51或A51编译器对源文件代码编译生成目标文件*.obj。 (3) 连接——BL51定位连接器将目标文件生成绝对目标文件*.abs。 (4) 转换——OH51转换器将绝对目标文件转换标准的机器代码格式文件*.hex。 (5) 模拟——dScope51调试器和模拟器可针对源级或机器代码动态调试、模拟运行。 (6) 管理——Keil以工程(project)项目的形式管理所开发的应用程序。 5.1.2Keil开发应用程序流程 使用Keil集成开发环境开发51单片机应用程序流程如下。 (1) 创建一个工程项目文件,有关应用程序的所有文档都包含在该工程中。 (2) 选择51单片机芯片型号,应用程序是针对该型号的单片机开发的。 (3) 设置工程选项,使其符合应用程序开发要求。 (4) 根据应用程序需求,选择添加单片机启动代码、管理系统等到工程项目中。 (5) 创建源程序文件,输入编辑源程序文件,并添加到当前工程项目组中。 (6) 编译源程序文件,修改编译错误。 (7) 单步或连续模拟运行调试应用程序,通过调试窗口观察应用程序运行结果。 (8) 应用程序运行结果正确,Keil生成的*.hex即是写入单片机程序存储区的文档。 5.1.3Keil开发环境界面 Keil应用于Windows 操作系统的软件Keil μVision启动后其窗口界面如图51所示,Keil集成环境主菜单项有File(文件)、View(视图)、Project(项目)、Flash(下载)、Debug(调试)、Peripherals(外围设备)、Tools(工具)、SVCS(版本控制)、Window(窗口管理)、Help(帮助)等,Keil的主要功能都可以从主菜单中引用,但为更加方便、快捷,主菜单下设有快捷操作按钮工具栏,工程项目中有右键菜单。 图51Keil集成环境窗口界面图 视频讲解 5.2在Keil环境中开发应用程序 在Keil中开发应用程序是以工程项目为单元的,首先需要创建一个针对某款单片机型号的工程项目,其次在工程项目中添加应用程序代码,最后编译输出可执行代码。 5.2.1在Keil环境中创建工程项目 在Keil环境中可以创建多个工程项目(Target),每个项目可以创建(包含)多个源文件组(Source Group),每个源文件组中可以添加多个应用程序源代码文件,创建一个工程项目(包含一个源文件组)并在一个源文件组中添加应用程序源代码的操作步骤如下。 (1) 选择Keil主菜单Project中的New μVision Project菜单项。 (2) 在弹出的如图52所示的Create New Project对话框中为工程项目命名,并保存为工程项目文件。 图52创建新的工程项目界面图 (3) 在后续弹出的“Select Device for Target…”对话框中选择一款单片机型号(或兼容型号),如图53所示,对所选单片机的描述见右边窗口(Description)。 图53选择单片机型号对话框 (4) 单击“Select Device for Target…”对话框中的OK按钮,Keil μVision将会自动为所选择单片机添加合适的、标准的启动代码,弹出如图54所示的对话框——提示是否将该机型的启动代码添加到工程项目中。 图54选择添加单片机启动代码 (5) 在工程项目中需要使用单片机的启动代码时,则单击Yes按钮,但要对该启动代码的初始化工作有所了解,通常该段代码以汇编语言形式(例如,针对51单片机文件名为STARTUP.A51)被添加到工程项目中。 (6) 将应用程序源代码文件添加到工程项目源程序组(Source Group)中,在Project中Source Group 1的右键快捷菜单中选择“Add Files to Group…”菜单项,如图55所示。 图55添加应用程序源代码文件 (7) 在如图56所示的“Add Files to Group…”对话框中,选择汇编语言(*.s*、*.a*)或C51语言(*.c)的应用程序源代码文件添加到工程项目中。 图56选择汇编或C51源文件 (8) 如果C51语言程序中有自定义(非Keil集成环境提供)的头文件(*.h),则需要将之添加到工程项目中,当应用程序所需所有文件都添加到工程项目后,针对某一款单片机的工程项目创建完毕。 5.2.2在Keil环境中编译工程项目 Keil环境集成了多款编译器,面向、支持Intel 51、ARM系列单片机的汇编语言和C51、ARM C语言程序源代码实施编译操作,将程序源代码转换为单片机的可执行代码(BIN二进制代码)。Keil集成环境的编译操作分为两步: 一是将程序源代码编译为目标代码(OBJ); 二是由连接器将目标代码连接为可执行代码,一般情况输出要求为HEX格式文件(*.hex),该格式文件是Intel公司制定的,它是由十六进制数组成的机器码或数据常量文件,多数单片机系统仿真器使用、支持HEX文件格式实施仿真操作,HEX格式文件可经由转换器(HEX→BIN)转换为BIN二进制格式文件(可执行代码)后写入单片机程序存储区。 Keil环境的编译操作通常是针对工程项目而言的,在实施编译操作之前,应根据单片机型号等参数对工程项目做必要的设置,其设置与编译操作步骤如下。 (1) 选择Keil主菜单Project中Options for Target菜单项,弹出“Options for Target…”对话框,如图57所示。 图57Target设置对话框 (2) 在“Options for Target…”对话框中选择Target选项卡,根据实际开发的单片机系统设置Target选项卡中的各项内容,例如,“Memory Model”存储器模式设置中有3个选择: Small模式——变量存放单片机内部RAM区(128B)、Compact模式——变量存放单片机外部RAM区(256B)、large模式——变量存放单片机外部RAM区(64KB),依据硬件情况选择一个存储器模式。 (3) 在“Options for Target…”对话框中选择Output选项卡,如图58所示,设置编译连接后输出HEX格式文件,选中“Create HEX File”复选框,另外,在该选项卡中通过单击Select Folder for Objects按钮可以设置输出文档的存放目录。 图58Output选项卡 (4) 如果在编译和连接时有特殊要求,或使用其他编译器和连接器,可通过“Options for Target…”对话框中的C51、A51、BL51等选项卡完成设置。 (5) 编译连接设置符合单片机系统要求后,选择Keil主菜单的Project→Build target菜单项(工具栏中有编译快捷按钮或F7键),也可以选择Rebuild all target files菜单项完成对整个工程项目的编译和连接。当编译连接出现错误时,错误信息输出到信息框中,提示错误类型和行号,常见错误信息如表51所示; 当编译连接无误时,在信息框中输出的信息如图59所示,完成对工程项目的编译和连接。 表51Keil编译器常见编译错误列表 错 误 信 息 错 误 说 明 Argument list syntax error 参数表语法错误 Bad character in paramenters 参数中有不适当的字符 Bit field too large 位区域太长 Call of nonfunction 调用未定义的函数 Code has no effect 代码不可能被执行 Compound statement missing“{” 分程序漏掉“{” Declaration syntax error 声明语法错误 Division by zero 除数为零 Expression syntax error 表达式语法错误 Function definition out of place 函数定义位置错误 Function should return a value 函数需要有返回值 Hexadecimal or octal constant too large 十六进制或八进制常数太大 Illegal initialization 非法的初始化 Illegal use of floating point 非法的浮点运算 Improper use of a typedef symbol 类型定义符号使用不恰当 Inline assembly not allowed 不允许使用行汇编 Incompatible storage class 存储类别不相容 Incompatible type conversion 不相容的类型转换 Incorrect number format 错误的数据格式 Invalid indirection 无效的间接操作 No declaration for function “xxx” 没有函数xxx声明 No stack 缺少堆栈 Not a valid expression format type 不合法的表达式格式 Not an allowed type 不允许使用的类型 Out of memory 内存不够用 Possibly incorrect assignment 赋值可能不正确 续表 错 误 信 息 错 误 说 明 Redeclaration of “xxx” 重复定义xxx Register allocation failure 寄存器寻址失败 Statement missing “;” 语句后缺少“;” Too few parameters in call 函数调用时实参数少于形参数 Too many error or warning messages 错误或警告信息太多 Type mismatch in parameter “xxx” 参数xxx 类型不匹配 Undefined symbol “xxx” 没有定义的符号xxx Void functions may not return a value Void类型的函数没有返回值 图59编译链接成功后的输出信息 5.3在Keil环境中调试运行 一个工程项目在Keil环境中编译连接通过后,说明工程项目中源代码程序没有语句或语法等错误,但程序是否可实现预期结果则需要被执行后才能判断。Keil环境提供了模拟连续或单步运行程序的功能,Keil环境的各种调试窗口可观察到程序执行的结果,通过模拟运行程序可查找出程序运行时出现的错误,同时可返回程序源代码中加以修正。 5.3.1Keil环境调试前的设置 在Keil环境中模拟运行程序前需要完成必要的设置,首先根据单片机系统的实际工作频率设置模拟运行时使用的主频,单击Keil主菜单Project→Options for Target菜单项,在弹出的“Options for Target…”对话框中选择Target选项卡,在Xtal(MHz)输入框中输入模拟运行时使用的主频,如图57所示; 其次在“Options for Target…”对话框中选择Debug选项卡,如图510所示,依据实际单片机系统以及源程序情况(是否添加启动代码等)设置各个选项。 图510Debug选项卡 5.3.2Keil环境调试主界面 在Keil主菜单中选择Debug→Start/Stop Debug Session菜单项(快捷键Ctrl+F5)进入程序模拟运行调试主界面,如图511所示。 图511Keil环境调试主界面 在调试主界面中有调试操作按钮工具栏,方便调试操作; 有源程序和反汇编程序代码窗口,方便观察程序将要执行的语句; 有CPU寄存器窗口,方便查看寄存器内容; 有源程序符号窗口,方便定位查找; 有程序调用窗口,方便观察调用情况等。 5.3.3Keil环境调试操作 在Keil环境的模拟运行调试主界面中,其调试操作命令在Keil的主菜单Debug中,也可通过工具栏按钮或快捷键控制程序的运行以及在程序的运行途中设置断点等操作,Debug菜单、工具栏主要按钮、快捷键的操作功能如表52所示。 表52Keil模拟运行调试环境主要操作键表 Debug菜单项 快捷键 按 钮 图 标 功 能 说 明 Reset CPU CPU执行程序复位 Run F5 连续运行程序 Stop 停止运行程序 Step F11 单步(每条指令)跟踪执行程序 Step Over F10 单步(函数或子程序为1步)执行程序 Step Out Ctrl+F11 退出单步跟踪执行程序 Run to Cursor Line Ctrl+F10 程序执行到光标处 Show Next Statement 显示将要执行的下一条语句 Breakpoints… Ctrl+B 显示设置断点对话框 Insert/Remove Breakpoint F9 插入/消除断点 Enable/Disable Breakpoint Ctrl+F9 断点有效/失效 Disable All Breakpoints 所有断点失效 Kill All Breakpoints Ctrl+Shift+F9 解除所有断点 5.3.4Keil环境调试窗口 在Keil环境的调试界面中已经默认安排显示了一些调试窗口,通过在Keil主菜单中选择Window→Reset View to Defaults菜单项,可设置为默认显示位置,如图511所示,但这些调试窗口支持各种显示方式,任意安排窗口所显示的位置,方便观察。Keil调试环境的所有调试窗口都可以通过选择Keil主菜单View中的菜单项打开,也可以通过工具栏按钮快速打开常用的、重要的调试窗口,调试窗口工具栏如图512所示。 图512Keil环境打开调试窗口工具栏 1. 符号浏览窗口Symbol 在Keil调试环境主菜单中选择View→Symbol Window菜单项,可打开符号浏览窗口。该窗口显示工程项目中的各种符号名称,包括专有符号,用户自定义符号(函数名、变量名、标号)等,在Name显示的符号名处右击则弹出右键快捷菜单,通过相应命令可将该符号导出到其他需要观察的窗口中,如图513所示。 图513符号浏览显示窗口 2. CPU寄存器窗口Registers 在Keil调试环境主菜单中选择View→Registers Window菜单项,可打开CPU寄存器窗口,该窗口将动态显示程序运行时CPU寄存器某个时刻的内容,如图514所示。 图514CPU寄存器显示窗口 3. 观察窗口Watch 在Keil调试环境中选择View→Watch Windows→Watch1菜单项,可打开观察窗口,在观察窗口中双击Name选项或按F2键可添加需要查看的变量等,在Value显示栏中动态显示程序运行时该变量某个时刻的内容,如图515所示。另外,右击Name栏中的内容弹出右键快捷菜单,通过Number Base项可设置数据显示格式,通过“Add…to…”项可将Name栏中的符号转送到其他显示窗口。 图515观察显示窗口 4. 存储器窗口Memory 在Keil调试环境中选择,View→Memory Windows→Memory1菜单项,可打开存储器窗口。Keil调试环境提供4个存储器窗口,在存储器窗口的“Address: ”输入框中输入“存储区代码: 首地址”,则存储器窗口将从“首地址”开始逐一显示存储器中的内容,“存储区代码”有D(单片机片内RAM直接寻址区data)、I(单片机片内RAM间接寻址区idata)、X(单片机片外RAM数据区xdata)、C(单片机程序存储区ROM code)等,右击存储器窗口区数据则可以选择显示的数据格式,如图516所示。如果修改存储器内容,则双击数据区的数据(或选择右键菜单中的Modify项)实现数据修改。 图516存储器显示窗口 5. 串口模拟终端窗口Serial 在Keil调试环境中选择View→Serial Windows菜单项,可打开串口模拟终端窗口,显示通过串口传输的数据。另外,多数单片机的数据传输是通过串口实现的,C51语言函数printf()的输出内容则显示到该窗口中,通过其右键菜单可选择数据传输格式等,如图517所示。 图517串口输出显示窗口 6. 逻辑分析仪显示窗口Analysis 在Keil调试环境中选择View→Analysis Windows→Logic Analyzer菜单项,可打开逻辑分析仪窗口,在该窗口中通过单击Setup按钮输入需要分析和观察的量(符号名称),或从其他窗口导入各种量,逻辑分析仪将记录程序运行期间所有时刻各个量的状态以及时序。在程序停止运行时,可以通过逻辑分析仪窗口查看各个量在运行期间的情况,如图518所示。 图518逻辑分析仪显示窗口 5.3.5Keil调试环境中设置断点 在应用程序调试过程中,有时候不需要单步运行,观察每一条指令的运行结果,而是希望程序运行到某条指令后停止运行,观察程序运行到该指令处的运行结果,因此,需要在停止运行指令处设置断点,将光标移动到设置断点处,在Keil调试环境中选择Debug→Insert/Remove Breakpoint菜单项(或快捷键F9),实现插入断点,如图519所示。 图519在源程序中设置断点 在Keil调试环境中选择Debug→Breakpoints菜单项(或快捷键Ctrl+B),在弹出的断点(Breakpoints)对话框中可实现对断点的设置、删除等管理操作,如图520所示。 图520断点管理对话框 5.3.6Keil调试环境中可编程接口设备 在单片机系统中CPU外围一般配有多种可编程接口设备(外围设备),使用汇编语言或C51语言编写的应用程序除指挥、控制CPU工作外,还可以通过CPU对外围设备实施控制或操作,标准的外围设备有输入/输出(I/O)、中断管理、定时器/计数器、串口等接口,在Keil环境处于调试状态时,这些外围设备都可以以独立窗口的形式打开。在Keil调试环境中选择Peripherals菜单中的I/OPorts、Interrupt、Timer、Serial等菜单项打开对应的窗口,在应用程序调试运行过程中,通过窗口操作实现对可编程接口设备的控制。 1. 输入/输出并口控制窗口Parallel Port 单片机系统一般有多个输入/输出并口,对于普通51单片机系统有4个并口(P0~P3),在Keil调试环境中选择Peripherals→I/OPorts菜单项,选择打开某个并口,如图521所示(打开P0并口),通过该窗口可以控制某位为1(√)或0。 2. 中断控制窗口Interrupt System 在Keil调试环境中选择Peripherals→Interrupt菜单项,打开中断管理、控制接口,如图522所示。当选择Int0中断源操作EX0(√)项时,可实现该中断源的开中断操作。 图521输入/输出并口控制窗口 图522中断控制窗口 3. 定时器/计数器控制窗口Timer/Counter 单片机系统一般有多个定时器/计数器,对于普通51单片机系统有2个定时器/计数器(T0、T1),在Keil调试环境中选择Peripherals→Timer菜单项,选择打开某个定时器/计数器接口设备,如图523所示(打开T0),在该窗口中可以选择定时器/计数器的工作模式、设置定时器/计数器的初始值以及启动TR0(√)或停止定时器/计数器等操作。 4. 串口控制窗口Serial Channel 在Keil调试环境中选择Peripherals→Serial菜单项则打开串口管理、控制接口,如图524所示。在该窗口中可以选择串口工作模式、设置串口发送TI(√)或接收RI(√)中断等操作,以及观察串口传输的数据(SBUF内容)等。 图523定时器/计数器控制窗口 图524串口控制窗口