收藏 分享(赏)

第五章 单片机的C语言程序设计 及仿真调试本章学习目标掌.ppt

上传人:杨桃文库 文档编号:12119763 上传时间:2021-09-19 格式:PPT 页数:88 大小:930KB
下载 相关 举报
第五章 单片机的C语言程序设计 及仿真调试本章学习目标掌.ppt_第1页
第1页 / 共88页
第五章 单片机的C语言程序设计 及仿真调试本章学习目标掌.ppt_第2页
第2页 / 共88页
第五章 单片机的C语言程序设计 及仿真调试本章学习目标掌.ppt_第3页
第3页 / 共88页
第五章 单片机的C语言程序设计 及仿真调试本章学习目标掌.ppt_第4页
第4页 / 共88页
第五章 单片机的C语言程序设计 及仿真调试本章学习目标掌.ppt_第5页
第5页 / 共88页
点击查看更多>>
资源描述

1、1/88,第五章 单片机的C语言程序设计 及仿真调试 本章学习目标 掌握单片机C语言程序中的常用功能 掌握Keil C的程序设计 掌握STC15F2K60S2单片机C语言程序调试过程,2/88,汇编语言和C语言的选择问题 设计规模较小的嵌入式应用系统时,可以使用汇编语言。因为代码一般不长,且较简单。当程序比较复杂,且没有很好的注释时,使用汇编编程的可读性和可维护性会很差,代码的可重性也比较低。 使用C语言编程,编写简单、直观易读、便于维护、通用性好。在控制任务比较复杂或者具有大量运算的系统中,C语言优势明显。由于模块化,用C语言编写的程序具有很好的可移植性。,3/88,5.1 单片机C语言程序

2、中的常用功能,一、逻辑运算和位运算 1、逻辑运算符 按逻辑运算符用于逻辑运算,包括与(,6/88,逻辑非运算符(!) 功能:表示对表达式的真值取反。 例如,如果变量s小于10,程序需执行某些操作,则条件代码如下: (s=10) /s不大于等于10,7/88,2、位运算符 很多系统程序常要求进行位(bit)运算或处理。语言提供了六种位运算符: 按位与( char code array =“hello!”; unsigned char xdata arr1044;,29/88,(4)特殊功能寄存器(SFR) STC15F2K60S2单片机的特殊功能寄存器(SFR)寻址区,用来控制定时器、计数器、串

3、口、I/O及其他部件。 为了支持SFR及其可寻址位的声明,引入了sfr、sbit等关键词。,30/88,sfr:字节寻址。语法如下: sfr sfr_name=int_constant; 如 sfr P0=0 x80; 0 x80为P0口的地址,“=”后为常数,并且这个 常数必须在特殊功能寄存器的地址范围内,位于 0 x80到0 xFF之间。,31/88,sfr16:字寻址 如sfr16 DPTR=0 x82; 指定DPTR的地址DPL=0 x82,DPH=0 x83。 sbit:位寻址 用于声明可位寻址的特殊功能寄存器的位变量。,32/88,sbit可以有下面声明方法: 方法1:sbit b

4、itname=sfr_namebit_number; 其中,sfr_name必须是已定义的SFR的名字, bit_number是位号(07)。 如:sbit CY=PSW7;/定义CY为PSW的第7位。 方法2:sbit bitname=sfr_addressbit_number; 其中,sfr_address是SFR所在的地址(0 x800 xff), bit_number是位号(07)。 如:sbit OV=0 xD02;/定义PSW中的OV位 方法3:sbit bitname=bit_address; 其中,bit_address是位地址。 如:sbit EA=0 xAF;/第0 xAF

5、位为EA,33/88,对于大多数8051内核单片机,Keil提供了一个包含所有特殊功能寄存器和它们的位的定义的头文件reg51.h。通过包含头文件可以很容易的进行新的扩展。 附录C提供了STC15F2K60S2单片机的头文件stc15.h的内容,其中包含了标准8051单片机寄存器的定义,编程时只需包含这一个文件即可。该文件可以从中下载。,34/88,2、_at_关键字 若要实现变量的绝对定位(称为绝对变量), 可以直接在数据定义后加上“_at_ 常数地址”即 可。 注意: (1)绝对变量不能被初始化; (2)bit型函数及变量不能用_at_指定。,35/88,例如: unsigned char

6、 idata ADCdata _at_ 0 x40; /指定ADCdata变量在40H处 unsigned char xdata buffer20 _at_ 0 x0010; /指定buffer数组从XRAM的0010H单元开始,36/88,3、存储模式 存储模式决定了没有明确指定存储类型的变量时,函数参数等的缺省存储区域,有Small、Compact和Large三种模式。,指定存储模式,图5-1 指定存储模式,37/88,(1)Small模式 在该模式中所有变量都默认位于单片机内部数据存储器,这和使用data指定存储器类型的方式一样。此模式访问变量的效率很高,但所有的数据对象和堆栈必须适合内

7、部RAM堆栈的大小。如果将变量都配置在内部数据存储器内,Small模式是最佳选择。 该模式的优点是访问速度快,缺点是空间有限,只适用于小程序。,38/88,(2)Compact模式 所有缺省变量均位于外部RAM区的一页内(256字节),这和使用pdata指定存储器类型一样,在STARTUP.A51文件中说明,也可用pdata指定。 该模式空间比Small宽裕,速度比Small慢,比Large快,是一种中间状态。,39/88,(3)Large模式 所有缺省变量可放在多达64KB的外部RAM区,这和使用xdata指定存储器类型一样,使用数据指针DPTR进行寻址。通过数据指针访问外部数据存储器的效率

8、较低,特别是当变量为2个字节或更多字节时。该模式的数据访问比Small和Compact产生更多的代码。 优点是空间大,可存变量多,缺点是速度较慢。,40/88,4、变量或数据类型,表5-1 C51数据类型,41/88,C51提供以下几种扩展数据类型: bit:位变量值为0或1。 sbit:从字节中定义的位变量(0或1)。 sfr:sfr字节地址(0 x800 xff)。 sfr16:sfr字地址(0 x800 xff,其实是占用 两个连续的地址)。 其余数据类型如:char、enum、short、 int、long、float等与ANSI C相同。下面着 重介绍位变量及其声明。,42/88,(

9、1)bit型变量 bit型变量可用于变量类型和函数声明、函数返回值等,存储于内部RAM的20H2FH单元中。 注意: 1)使用禁止中断(#pragma disable)或包含明确的寄存器组切换(using n)的函数不能返回位值,否则,编译器会识别出来并产生一个错误信息。 2)位不能声明为一个指针。如bit *bit_poiter;是错误的。 3)不能有bit数组如:bit arr5;是错误的。,43/88,(2)可位寻址区说明 使用sbit声明可独立访问可位寻址对象的位。sbit声明要求基址对象的存贮器类型为“bdata”,否则只有绝对的位声明方法是合法的。 位的位置(操作符号后的数字)的最

10、大值依赖于指定的基类型 对于char/uchar而言是07, 对于int/uint/short/ushort而言是015, 对于long/ulong而言是031。,44/88,下面举例说明位寻址的声明方法。 例如, int bdata bittest _at_ 0 x20; /也可以省略“_at_ 0 x20” sbit bit0bittest 0; /0 x20单元的第0位 sbit bit15= bittest 15; /0 x21单元的第7位 注意:可位寻址对象的位的声明只能放到main函数的外部,作为全局变量使用,否则,编译会出错。,45/88,二、扩展I/O口的使用 STC15F2K

11、60S2单片机除了芯片上的I/O口 外,还可在片外扩展I/O端口。 由于使用C语言访问外部I/O时用到指针的功 能,因此,首先介绍Keil C51的指针。,46/88,1、Keil C51指针 Keil C51支持一般指针(Generic Pointer)和存储器指针(Memory Specific Pointer)。 一般指针的声明和使用均与标准C相同,同时还可以说明指针的存储类型。,47/88,例如,下面的语句都声明pt为指向保存在外部RAM中unsigned char数据的指针,但pt本身的保存位置却不同: unsigned char xdata *pt; /pt本身依存储模式存放 un

12、signed char xdata * data pt; /pt被保存在内部RAM中 unsigned char xdata * xdata pt; /pt被保存在外部RAM中,48/88,一般指针本身用3个字节存放,分别为存储器类型,高位偏移量和低位偏移量。基于存储器的指针,说明时即指定了存储类型,例如: char data * str; /str指向data区中char型数据 int xdata * pow; /pow指向外部RAM的int型整数 这种指针存放时,只需一个字节或2个字节就够了,因为只需存放偏移量。,49/88,关于堆栈指针SP 的设定 一般情况下,用户不需要在C语言程序中修

13、改堆栈指针SP,但要关心一下SP的位置。C51为变量分配好内部RAM后,将SP放在第一个空闲的内部RAM处,可以在编译后生成的.m51文件中观察到栈顶的位置,一般程序编译连接成功后要习惯性地看一下.m51文件,看一下是不是有足够的栈空间可用。 另外,C51是在startup.A51中设置SP指针的,用CODE选项生成的汇编代码中是找不到这段代码的。startup.A51是C51的初始化代码,单片机复位后先执行这段代码,完成初始化后由它调用main( )函数。特殊需要时,可以修改这段代码,然后连接到用户的程序中去。,50/88,2、外部扩展I/O口的访问 在C51中有两种方法访问外部I/O端口。

14、 方法1:使用自定义指针。 由于片外I/O端口与片外存储器统一编址,所 以可以定义xdata类型的指针访问外部I/O端口。,51/88,例如,某单片机应用系统中,使用8255扩展I/O端口,采用线选法对8255进行地址译码,单片机的P 2.7(A15)接8255的片选引脚, 8255的命令字地址为7FF3H, PA口地址为7FF0H, PB口地址为7FF1H, PC口地址为7FF2H, 访问8255的C程序如下:,52/88,写端口程序: char xdata *com8255; /定义指向外部存储区的指针 com8255=0 x7ff3; /使指针指向8255的控制口地址7FF3H *com

15、8255=0 x81; /输出81H到端口 以上C程序相当于下面的汇编语言程序: MOV DPTR,#7FF3H MOV A,#81H MOVX DPTR,A,53/88,读端口程序: char xdata *com8255; /定义指针 com8255=0 x7ff0; /使指针指向8255的PA口地址7FF0H char i; i=*com8255; /读PA端口到变量i,54/88,方法2:使用C51预定义指针。 为了方便地访问外部存储器及I/O端口,在 C51中的absacc.h头文件做了如下定义,利用这 些定义可以方便地访问外部I/O端口。 #define CBYTE (unsign

16、ed char volatile code *) 0) #define DBYTE (unsigned char volatile data *) 0) #define PBYTE (unsigned char volatile pdata *) 0) #define XBYTE (unsigned char volatile xdata *) 0),55/88,例如: #include #define PORTA XBYTE 0 x7ff0 /其中,PORTA为程序定义的I/O端口名称, 内的内容 /7ff0H为PORTA的地址 void main(void) char a; PORTA=0

17、 x81; /*输出81H到端口7ff0H a=PORTA; /读端口7ff0H到变量a ,56/88,三、Keil C51函数 C51的函数声明对ANSI C作了扩展,具体包 括: 1、中断函数声明 中断函数通过使用interrupt关键字和中断号(031)来声明。中断号告诉编译器中断服务程序的入口地址。,57/88,STC15F2K60S2单片机的中断号及中断服务程序入口地址如表所示。,表5-2中断号及中断服务程序入口地址,58/88,例如,串行口1的中断函数可以声明如下: void UART1_ISR (void) interrupt 4 using 1 /* 中断服务程序的代码 */

18、上述代码声明了串行口1中断服务函数。其中,interrupt 4说明是串行口1的中断,using 1指明采用工作寄存器区1区,using 1在中括号中,说明该段可以省略。其他中断函数的定义与此类似。中断函数具体是哪个中断的函数,与中断号有关,而与函数名无关 。,59/88,2、指定工作寄存器区 当需要指定函数中使用的工作寄存器区时,使用关键字using后跟一个0到3的数,对应着工作寄存器0到3区。 例如,在下面的函数中使用了工作寄存器1区(相当于PSW.4=0,PSW.3=1): unsigned char GetKey(void) using 1 /*用户程序代码*/ ,60/88,3、指定

19、存储模式 用户可以使用small,compact 及large说明存储模式。 例如: void fun1(void) small 提示:small说明的函数内部变量全部使用内部RAM。关键的、经常性的、耗时的地方可以这样声明,以提高运行速度。,61/88,4、函数的参数传递规则 最多只能有3个参数通过寄存器传递,规律如表5-3所示。,表5-3 函数的参数传递规则,62/88,5、函数返回值的规定 函数返回值一律放于寄存器中,规则如表5-4所示。,表5-4 函数返回值的规定,63/88,6、函数的重入 可以在函数前声明函数的可重入性,只对一个函数有效。 如果声明为不可重入的,说明该函数调用过程中

20、将不可被中断。 递归或可重入函数指定在主程序和中断中都可调用的函数,容易产生问题。因为单片机和PC不同,PC使用堆栈传递参数,且静态变量以外的内部变量都在堆栈中;而单片机一般使用寄存器传递参数,内部变量一般在RAM中,函数重入时会破坏上次调用的数据。,64/88,可以用以下两种方法解决函数的重入问题: 第一种方法: 在相应的函数前使用“#pragma disable”声 明,即只允许主程序或中断之一调用该函数。 第二种方法: 将该函数说明为可重入的。如下: void func(param.) reentrant;,65/88,Keil C51编译后将生成一个可重入变量堆栈,然后就可以模拟通过堆

21、栈传递变量的方法。 因为单片机内部堆栈空间的限制,C51没有像大系统那样使用调用堆栈。一般在C语言中调用过程时,会把过程的参数和过程中使用的局部变量入栈。,66/88,为了提高效率,C51没有提供这种堆栈,而是提供一种压缩栈。每个过程被给定一个空间,用于存放局部变量。过程中的每个变量都存放在这个空间的固定位置。当递归调用这个过程时,会导致变量被覆盖。 在某些实时应用中,非重入函数是不可取的。因为,函数调用时可能会被中断程序中断,而在中断程序中可能再次调用这个函数,所以C51允许将函数定义成重入函数。重入函数可被递归调用和多重调用,而不用担心变量被覆盖,因为每次函数调用时的局部变量都会被单独保存

22、。因为这些堆栈是模拟的,重入函数一般都比较大,运行起来也比较慢。,67/88,由于一般可重入函数由主程序和中断调用,所以通常中断程序使用与主程序不同的工作寄存器组。 另外,对可重入函数,在相应的函数前面加上开关#pragma noaregs,以禁止编译器使用绝对寄存器寻址,可生成不依赖于寄存器组的代码。,68/88,四、 STC15F2K60S2单片机C51程序框架 #include “stc15.h” /* stc15.h为单片机寄存器定义头文件,具体内容参见附录C */ void delay(long delaytime); /声明子函数,子函数可以有返回值 void main(void)

23、 /此处可存放应用系统的初始化代码 while(1) /主程序循环 /根据需要填入适当的内容 delay(100); /可以调用用户自定义的子函数 ,69/88,/-各个子函数的声明- void delay(long delaytime) while(delaytime0) delaytime-; /子函数的实现代码 /-各个中断函数的实现- void INT0_ISR(void) interrupt 0 /外部中断0服务子函数 /根据需要填入程序代码 void T0_ISR(void) interrupt 1 /定时器0中断服务子函数 /根据需要填入程序代码 void INT1_ISR(vo

24、id) interrupt 2 /外部中断1服务子函数 /根据需要填入程序代码 void T1_ISR(void) interrupt 3 /定时器1中断服务子函数 /根据需要填入程序代码 ,70/88,void UART1_ISR(void) interrupt 4 /串口1中断服务子函数 /根据需要填入程序代码,注意中断请求标志的清零 void ADC_ISR (void) interrupt 5 /ADC中断服务子函数 /根据需要填入程序代码,注意中断请求标志的清零 void LVD_ISR (void) interrupt 6 /低电压检测中断子函数 /根据需要填入程序代码,注意中断请

25、求标志的清零 void PCA_ISR (void) interrupt 7 /PCA中断子函数 /根据需要填入程序代码,注意中断请求标志的清零 void UART2_ISR (void) interrupt 8 /串口2中断子函数 /根据需要填入程序代码,注意中断请求标志的清零 void SPI_ISR (void) interrupt 9 /SPI中断子函数 /根据需要填入程序代码,注意中断请求标志的清零 ,71/88,void INT2_ISR(void) interrupt 10 /外部中断2服务子函数 /根据需要填入程序代码 void INT3_ISR(void) interrupt

26、 11 /外部中断3服务子函数 /根据需要填入程序代码 void T2_ISR(void) interrupt 12 /定时器2中断服务子函数 /根据需要填入程序代码 void INT4_ISR(void) interrupt 16 /外部中断4服务子函数 /根据需要填入程序代码 ,72/88,【例5-1】编程实现通过延时函数,P1.0输出方波信号,并通过示波器观察程序输出波形的周期。 #include “stc15.h” /STC15F2K60S2单片机寄存器定义头文件 sbit P10=P10;/定义P1.0引脚 void delay(unsigned long cnt); /延时函数声明

27、 void main(void) P10=1; while(1) /主程序循环 delay(60000); P10=P10; void delay(unsigned long cnt) /延时函数 while(cnt0) cnt-; ,73/88,可以使用集成开发环境(IDE)对单片机程序 进行软件模拟调试。由于此时无需任何硬件与开 发,可以降低程序开发的成本,并且程序开发可 以在系统硬件完成之前开始。,5.3 单片机C语言程序调试,74/88,模拟仿真调试的方法和过程与汇编语言模拟仿 真调试的过程相同。但是,软件模拟调试无法仿 真精确的硬件信号,难以仿真过程控制中的通信 网络时序及实时转换,

28、因此当软件开发过程进入 必须有最终硬件参与共同完成的阶段时,就需要 进行在系统调试。传统的仿真方法是使用仿真器 进行仿真和调试。下面介绍如何使用仿真器进行 程序的仿真和调试。,75/88,一、使用仿真器进行程序的仿真调试 使用宏晶单片机仿真器适用于STC单片机应用 技术的学习和实验程序的调试,使用过程如下: 1、硬件设置 目前的仿真方式为双CPU仿真:监控CPU和 仿真CPU。仿真CPU目标芯片必须是宏晶的 IAP系列(目前只支持IAP15F2K60S2,仿真 完成后,可以直接将程序下载STC15F2K60S2 单片机中)。,76/88,计算机、仿真器和学习板连接示意图如图所示:,图5-2 计

29、算机、仿真器和学习板连接示意图,77/88,2、软件设置 用户程序中需要在0 x73的地址处保留6个字节。 C语言程序,需在代码中添加如下语句: char code reserved6 _at_ 0 x73; /在程序中进行声明 汇编语言程序,需在代码中添加如下语句: CSEG AT 73H ;在代码段33H定址 RESERVED: DS 6 ;保留6字节 或者 ORG 73H ;在代码段33H定址 RESERVED: DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH ;保留6字节,78/88,对于汇编语言程序,复位入口的程序必须为跳转指令(建议使用长跳转),如: ORG 0

30、;复位入口地址 LJMP RESET ;使用LJMP指令 ;其它中断向量 ORG 73H ;保留字节地址 RESERVED: DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH ;保留6字节 ORG 0100H ;用户代码地址 RESET: ;复位入口 ;用户代码,79/88,按照上述要求,将例5-1中的程序进行改写,改写后的程序如下: #include “stc15.h” /STC15F2K60S2单片机寄存器定义头文件 char code reserved6 _at_ 0 x73; /在程序中进行声明 sbit P10=P10;/定义P1.0引脚 void delay(uns

31、igned long cnt); /延时函数声明 void main(void) P10=1; while(1) /主程序循环 delay(60000); P10=P10; void delay(unsigned long cnt) /延时函数 while(cnt0) cnt-; ,80/88,3、仿真代码占用的资源 程序空间 : 5K字节(0 xDC000 xF3FF) RAM : 0字节 XRAM : 0字节 I/O : P3.0/P3.1,81/88,4、Keil环境中的设置 设置晶振频率 使用ProjectOptions for Target Target命令打 开选项设置窗口,如图所

32、示。,在此编辑框中输入晶振频率,图5-3 设置晶振频率,82/88,设置Output选项 在“Output”选项中作如图所示的设置。选中“Create HEX File”复选框,Keil每进行一次Build,都生成可以 下载到单片机的HEX文件。,选中“Create HEX File”复选框,图5-4 设置“Output”属性,83/88,选择硬件仿真 在“Debug”选项卡中,选中右半部分中的“Use”, 从下拉列表框中选择“Keil Monitor-51 Driver”,并 选中“Run to main”选项。如图所示。,选择Keil Monitor-51 Driver,选中“Run to

33、 main”,图5-5 选择硬件仿真,84/88,设置串口 在图5-5中,单击“Settings”按钮,弹出串口设置对话框,如图所示。,Setting,选择串口号,图5-6 设置串口对话框,图5-5 选择硬件仿真,85/88,其中,RTS和DTR是PC机在和单片机通信时给单片机的握手信号主要的任务是设置串口号,其他可以不改变。 串口号是仿真时,仿真器所使用的串口号。 如果采用了USB转RS232芯片,需要特别注意串口号的选择。 选中“Serial Interrupt”选项可以在全速运行程序时暂停用户程序的执行。 设置完成后,就可以进行程序的调试了。,86/88,使用仿真器进行程序的仿真时,需要

34、注意如下问题: 仿真器与计算机USB连接须等待10秒以上,等仿真器上电稳定后再进行程序的调试。 每次调试程序之前,需要重新上电。 对IAP_TRIG寄存器写0 x5A和0 xA5的语句不可单步调试 即不要仿真EEPROM功能。 不能写PCON寄存器的第5位。 程序中不能对P3.0和P3.1进行写操作。 不要关中断。 目前的版本不能全速运行程序。一旦全速运行,只能通过复位单片机来停止调试过程。 EEPROM第一个扇区不能用。,87/88,图5-7无法调试时的弹出窗口,调试时,有时可能出现如图5-7所示的情形。,88/88,调试时若出现前图所示情况,可能的原因有以下几点 keil的选项设置不正确,按照步骤4)重新设置。 串口设置不正确,重新设置串口。 程序正在全速运行或调试前单片机未复位,给学习板重新上电复位后再进行程序调试。 把仿真器与电脑重新连接,等待10秒以上稳定后再调试程序。 设置完成后,就可以采用与第四章中介绍的类似的方法进行程序的调试了。,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 大学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报