松翰C语言编程指导C+Program+Guide

上传人:彩*** 文档编号:66912491 上传时间:2022-03-29 格式:DOC 页数:55 大小:1.57MB
返回 下载 相关 举报
松翰C语言编程指导C+Program+Guide_第1页
第1页 / 共55页
松翰C语言编程指导C+Program+Guide_第2页
第2页 / 共55页
松翰C语言编程指导C+Program+Guide_第3页
第3页 / 共55页
点击查看更多>>
资源描述
.如何用 C来完成 SN8系列芯片的程序设计松翰易爱华松翰科技(深圳)有限公司SONIX TECHNOLOGY CO.,LTD.1/53.内容概览一、 C 与 Assembly 简述二、 SN8 C studio 的安装与使用2.1SN8 C studio 的安装2.2SN8 C studio 应用实例三、数据类型与运算3.1专有数据类型3.2常量与变量3.3数据的存储类型与存储结构四、程序流程控制4.1顺序结构4.2分支判断结构4.3循环控制结构五、函数5.1函数的定义5.2函数参数传递与返回值5.3函数参数与全局变量六、结构体、联合在 SN8 C 程序中的应用6.1结构体6.2联合七、中断7.1中断函数的定义7.2中断过程的分析7.3中断函数的结构八、位操作8.1位的定义8.2位的运算8.3位比较在程序流程控制中的应用九、内嵌汇编9.1如何内嵌汇编9.2内嵌汇编时变量的传递十、程序结构10.1主函数与子函数10.2构建可复用文件10.3构建具有实用性的程序2/53.一、 C 与 Assembly 简述Assembly(汇编)的历史已经有半个多世纪了,从计算机的发明那天开始,汇编就注定要与其结缘, 它作为第一种真正意义上的编程语言,在计算机的发展过程中具有无可替代的地位。汇编具有与机器语言一一对应的高效率,就是由于汇编的高效率,和其紧贴硬件的特性,使其在半个世纪之后的今天依然是目前开发单片机程序的主流工具之一。但是由于编写汇编代码的工作量和难度都比较高,并且要求程序员对硬件必须有较深刻的了解,其入门就相对较难。而汇编的写法各异,不同的程序员编写的代码有着巨大的差异,这就带来了学习的难度,可读性差也成为了其推广的瓶颈,程序的维护更加艰难。随着程序复杂性的增加,开发团队的形成,应用而生的高级语言就逐渐取代了其位置。C 就是高级语言中针对硬件操作最优秀的一种,C 也是基于汇编的, 其相互关系如图所示。随着人们不断的对C 进行改善,使C 的效率得到了很大的提升,其编译效率逐渐的逼近汇编。而 C 以其模块化的编程模式,简洁的代码,良好的可读性和可维护性,成为了另一种单片机开发的主流开发工具,相比汇编而言,其具有无可比拟的优异性。C 代码汇编代码机器语言图 1、C 与汇编的关系SN8 C 是基于标准C 而又加入SONIX SN8系列芯片特征的专用C,它面对的是SONIXSN8 系列芯片程序开发,它能产生非常简洁的能直接运行于SN8 系列芯片的优化代码。具有良好的兼容性,易学易用,既方便客户开发,又继承了原有汇编的卓越性能。在本文当中,我们将结合汇编来讲述C 开发的各方面知识,以期通过对比来加深对芯片的编程应用的了解,同时,对熟悉C 的程序员来说,可以更加深入了解芯片;而对于熟悉汇编的程序员来说,我们可以从对比中找到从汇编到C 的转换方法。3/53.二、 SN8 C studio的安装与使用SONIX SN8系列的芯片是RISC 内核的高性能芯片。 目前,由 SONIX 提供的 SN8 Assembly仅有 59 条指令,是一种高效的汇编语言,有S8ASM 和 M2ASM 编译器分别支持其1 系和 2 系芯片。在此基础上的SN8 C studio 整合了汇编和C 的编译器,1 1、SN8 C studio 的安装在得到 SN8 C studio 的安装包后,按照标准的 Windows 程序安装方法安装就可以将软件安装到机器上。12、SN8 C studio 应用实例一、创建一个工作区与 VC 类似,我们的工程管理模式是以工作区方式来管理,在你准备一个项目的时候,你首先创建一个属于这个项目的工作区:1、打开 IDS- 文件 -新建,单击出现如下界面:图 2-1 新建对话框4/53.2、单击workSpace 图标,进入workspace 创建窗口,单击Location编辑框后的按钮,选择你需要的工作目录,然后输入新建Workspace 的 name,在这里如下:图 2-2 新建 Workspace 对话框3、单击 OK,IDS 的界面生成了工作区的工作界面,出现了Workspace 窗口和 Output 窗口。同时,打开目标文件夹,你会发现在你选定的文件夹下面,生成了一个以Workspace Name 命名的新文件夹,打开文件夹你可以看到一个新生成的.wsp 文件,这就是新生成的Workspace 的配置文件:图 2-3 新生成的 Workspace 配置文件二、新建一个工程( Project )在我们成功创建一个工作区后,你会发现我们的Workspace 窗口中的Projiect 数目为 0,接着我们就要依据项目所用的芯片母体来创建一个工程项目了,跟创建Workspace 相同,打开菜单中的文件 -新建,单击出现新建窗口,此时默认为新建Project。在右边的Project List 窗口中选择你要使用的芯片母体和要创建的工程类型(一般为普通项目) ,此时的目标路径Location中已经显示为你刚才建立的Workspace 目录,建议将工程保存在这个目录下,不修改默认路径。给新建工程取一个有意义的Name,在框中输入。这里我们取与Workspace 相同的名称,新建一个 2700 系列芯片的普通项目工程,设置如下图所示:1、单击文件 -新建,选择合适的选项:5/53.图 2-4 新建 Project2、单击 OK 。3、新工程选项配置,在确认建立工程后,出现Project Setting 对话框,左边的Project 列表中默认选中我们刚刚建立的工程, 在这里我们只修改 Chip 和 Code Option 项目下的选项, 如图所示:图 2-5 Project Setting对话框6/53.4、选择正确的芯片:在 Chip 页中,Definition文本框中显示系统依据你选定的芯片母体系列而确定的需要调用的芯片定义文件。Chip List表列出了当前版本的IDS 所支持的这一系列的各个芯片,选中其中你需要使用的芯片母体,Selected 文本框和Description 文本框相应会自动改变。如图:图 2-6 选择芯片5、设置正确的Code Option 选项和 ICE MODE :ICE MODE的设置在SN8P1xxx 芯片中是用于选择是否是ICE 仿真模式,在Code Option列表中自动显示选定芯片母体的Code Option 选项,在Option Value 项的默认值上单击,出现一个下拉列表,单击选择合适的选项。如图:图 2-7 设置正确的 Code Option6、单击 OK ,系统生成一个没有文件的工程,在Workspace 管理窗口中我们可以看见当7/53.前生成的工程为Working project ,正处被激活状态(工程名称为加粗字体):图 2-8 新建 Project 的状态被激活打开相应的文件夹,我们会发现系统生成了很多个新的文件,其中的.prj 文件即为工程文件,其他的文件为根据我们刚才的设置和不同的芯片生成的配置文件及头文件。三、新建文件完成项目的新建后,我们发现项目管理器source 文件夹下是空的,没有任何文件,文件就是我们编程的主要工作了!1、打开文件 - 新建菜单, 单击出现我们前面看过很多次的New 对话框, 不过比前面多了一个选项Files,选择 New 列表中的 Files 选项,单击按钮,对话框如图所示:图 2-9 新建文件对话框2、在 File List 中选中需要创建的文件类型,这里我们创建一个C Source File ,给文件命名从 Name 编辑框中输入,存放的地点为刚才的设定位置,默认不做修改。3、单击 OK 按钮, IDS 打开一个编辑窗口,最大化,显示为刚刚建立的文件名的页,系统允许我们在这里进行程序的编写。四、编写程序在新建一个文件后,系统自动打开编辑器,并打开一个由用户命名的空文档,它与普通文档相比较没有什么不同的之处,只不过它可以对 C 的关键字进行高亮显示。在新的文档里编辑程序。8/53.C 本身就是一种模块化的编程语言,SN8C 的编程保持C 语言的编程风格。SN8C 所具有的Non-ANSI C的特性请参看其他章节,在此不再做描述。下面是一个简单的C 程序举例。例 2:/* File Name : SN8C_Ex.c* Post By : Dragon.Yi* Date : 2005/09/23* describe:test 2708 interrupt*/#include struct wordunsigned fint:1; unsigned :7;intword;unsigned int tc0cvalue=0x64; unsigned int accbuf = 0x00; unsigned int pflagbuf = 0; _interrupt intserv(void)/The data will auto store!_bCLR(&INTRQ,5);TC0C = tc0cvalue;intword.fint = 1;void initIO(void);void initINT(void);void main(void)STKP=0x07;initIO();initINT();while(1)if(intword.fint!=0)P1=0x00;P2=0x00;P3=0x00;P4=0x00;P5=0x00;9/53.P0=0x00;elseP0=0xff;P1=0xff;P2=0xff;P3=0xff;P4=0xff;P5=0xff;void initIO(void)P0M=0xFF;P1M=0xFF;P2M=0xFF;P3M=0xFF;P4M=0xFF;P5M=0xFF;void initINT(void)INTRQ=0x00;INTEN=0x00;TC0M=0x00;TC0M=0x20;TC0C=0x64;_bCLR(&INTRQ,5);_bSET(&INTEN,5);_bSET(&TC0M,7);_bSET(&STKP,7);注:程序只作为程序架构提供参考!五、调试程序在完成代码编辑后,想要马上顺利运行基本上是不可能的,每一个程序都有经过调试的过程,程序的调试在IDS 中非常方便, IDS 有全面的可视化的调试工具。你可以在程序中设置断点,在程序中按自己的需求来运行。可以根据不同的需求来进行调试。1、 compile 和 Build完成代码的编辑后,首先要进行Compile ,在菜单 Build-Compile current file单击或在工10/53.具栏中单击Compile 按钮和单击快捷键Ctrl+F7均可以启动系统的Compile 程序。 Compile 程序会检查代码中存在的语法错误和软件设置错误,然后在 Output 窗口表列出来, 用户可以根据表列出来的提示,对程序进行修改。若是语法错误,在列表中双击选项,系统会自动将光标移动到相对应的代码行,方便你的检查和修改。Compile通过后,进行Build ,同样有 3 种方式可以启动 Build 程序, Build 程序生成运行所需要的一些文件,同时检查硬件配置和连接错误,用户必须根据提示对程序进行修改才能顺利通过。2、 选择仿真方式单击进入 Project-setting ,出现我们前面已经熟悉的project setting 对话框, 当前显示的是General 页,在 primary setting 组下面找到复选项use simulate。如果选中该选项,则程序就在系统提供的虚拟仿真器上仿真并显示相应结果;若不选中该选项,则程序必须在相应系列的仿真器上进行程序调试仿真。这里我们先选择它。3、 进入调试模式完成 compile 和 build 之后,进入菜单Debug-begin Debug ,单击菜单项或直接按快捷键F5 或在图标选项中选择按钮单击都可进入调试模式,进入调试模式后,系统界面变成如下图:图 2-11 调试程序界面系统界面出现 Ram window 、Watch window 、variable window 、Register window 、call stack window 和 Disassembly window ,这些窗口都是调试程序要用到的。程序的指针指向程序的入口处,即Main ()函数的第一条语句。4、 应用 Watch window :在调试过程中如何应用watch window ? Watch window 用在调试工程中对定义的变量进行监视,将需要进行监视的Variable 在编辑窗口中双击,然后拖放到Watch Window 当中,运行程序就可以在watch window 中看到 Variable 的存放地点和值的变化。如图:11/53.图 2-12 watch window 窗口系统会将产生了变化的项置成红色。为方便观察,你最多可以将Variable 分别放到 3 个 Watch window 当中进行观察,他们的显示效果是一样的!5、 应用 Variable windowVariable window 显示格式和watch window的显示格式一样, 但是 variable window 里面的项无法自己设定。它是以Auto 的状态显示当前运行过程中被改变的Local Variable ,同样系统会将最近改变的量置成红色。6、 应用 Register Window :Register window 里面显示的项是根据芯片的资源而定的,它显示的是当前母体芯片Ram中 0x800xFF 空间中专用存储器在当前运行状态下的值,单击前面的“+”号,将扩展项目展开,可以得到每一个 bit 的当前值。同样,在运行过程中,系统会将刚改变的项的值置为红色高亮显示,便于我们观察跟踪。图 2-13 Register 窗口7、 应用 Call stack windowCall stack window显示当前运行状态下,stack 的使用状况和入栈的函数,用户可以根据显示来判断程序的调用状况,进而判断当前的状态是否正确,有没有函数调用出错。图 2-14 call stack 窗口12/53.8、 应用 Memory window :在程序运行当中,当你想从具体的Ram 地址而得到它的值的时候,你可以通过Memory窗口中实现, 你可以直接在 Go to 后面的编辑框中输入地址, 按 Enter 键确认, 窗口会自动跳转到相应的位置显示该位置的值,方便我们在使用过程中的查找。9、 应用 Disassembly window :如果调试过程中,你需要知道程序的直接汇编码,你可以在这个窗口中观察。10、设置断点:程序调试的时候,往往需要知道程序运行过程中某个变量的运行状态,或者想知道某段程序是否执行,还有执行后的结果;或者,需要知道某段程序的运行过程是否正确。这时,就必须在程序的正确位置设置断点。将光标移到正确位置, 在相应的行, 单击设置断点的按钮或按快捷键 F9 或者从菜单项中设置都可以使该行程序被设置成为断点,被设置成断点后,运行程序,程序就会运行到断点处停下来,以便于用户控制程序的执行和观察执行的结果。如图:图 2-15 断点执行状态11、跟踪程序执行:应用系统提供的debug 工具,用户可以很方便地对程序的执行效果进行跟踪。你可以单步,也可越过一段程序往下执行,这要看你的需要!调试工具同样可以以3 种方式打开: Debug 菜单、工具栏按钮和快捷键。六、程序输出1、 仿真程序结果:将仿真器与主机连接好,在 project setting 中清除 use simulate 选项的选中状态。将需要仿真的硬件系统目标板连接好。 单击 Debug 按钮或者按快捷键进入调试状态, 就可以在实际硬件上看到程序运行的结果,对程序进行修改直到得到正确结果。我们就得到一个正确运行的可以烧录到实际芯片的程序。2、 输出烧录文档在完成程序的调试仿真后,我们就需要将程序输出。系统已经在默认目录下生成程序的烧录档 XXX.sn8 ,默认目录为当前工程文件的目录下。13/53.三、数据类型与运算SN8 C 支持标准C 的所有数据类型。具体有无符号字符(unsigned char)、有符号字符( signed char)、无符号整型( unsigned int )、有符号整型 (signed int )、无符号长型( unsigned long)、有符号长型( signed long )、浮点( float )和指针类型。还支持所有的构造类型。字符型( char)整型( int)基本类型长整型( long)浮点型( float )数组( array)数据类型构造类型结构体( struct)共用体( union)指针类型枚举( enum)空类型图 3-1 数据类型3.1 专有数据类型虽然 SN8 C 支持 C 的所有数据类型,但是由于它面对的是8-bit 单片机,所以必然会考虑数据类型的定义方法和长度。在这些方面,SN8 C 有它自己的专有的定义特征和数据长度,在使用时一定要加于区分。请看下表:数据类型Size( Byte)数据取值范围Signed char( short、 int )1-128+127Unsigned char(short 、 int)10255Signed long2-32768+32767Unsigned long2065535float 、 double414/53.Pointer2enum1表 3-1、数据类型长度定义表3.2 常量与变量在程序设计的过程中,我们有些量可能是参考值,也可能是预设的值。总之,我们希望它在整个程序中保持不变,并且在程序的任何地方可以提供我们调用,用来比对某些条件是否成立等等。对于这样的值,我们可以不去定义它,而直接参考数值,这在汇编编程过程中,经常会有一些缺乏经验的程序员这样用。但这就需要程序员把程序中的这些值都牢牢记住,并且要将他们的值前后统一,这是一个非常容易出错的过程,而且也会影响了程序的可读性,这样,程序的修改和维护都非常艰难,必须处处小心翼翼,一处不慎就全盘错误!这是任何人不想看到的后果。因此,建议对于程序中用到的不会改变的参考值或其他预设的值都进行一个预先的定义,给它取一个有意义的或与其相关的名字。这个过程就是常量定义,自然,这个不变的量就称为常量。在标准 C 中,由于面对的是功能强大的CPU 系统和大内存,用户可以不去管它放置的地方。但是,面对一个单片机系统,它的Ram 非常小,有时会显得很紧张。所以系统为了节省空间会将一些表格等放在系统的 ROM 中。而我们直接命名的常量,则由编译器自动将其替换为所需要的值,这些工作就由计算机来完成好了。我们先来看看我们用汇编编写程序时是怎么来定义常量的:如:door_service_cequ#80;80ms 去门抖动t0int_cequ#224;t0 中断时间segment_cequ#3;最多 3 段烹调注:上面数值前的#号,是 SN8ASM 的符号,用于提示后面的是立即数。上面定义了3 个程序中会用到的参考值,顺便提一下, 在定义的时候加上注释是有必要的,要不然时间久了你就又不知道你定义的到底是什么了。在上面的定义中,用的是汇编EQU 关键字,在编译过程中,程序里但凡出现了EQU 前面的字段都会被其后面的值直接代替,因此,很方便地减轻了程序员的工作。我们再来看看用SN8 C 是如何定义这些相同的常量的:如:#define door_service_c80 /80ms 去门抖动#definet0int_c224/t0 中断时间#definesegment_c3/;最多 3 段烹调上面定义的 3 个量是与前面汇编当中定义的 3 个常量是完全相同的。 在进行编译预处理时,这些量就会被数值代替。还有一个特殊的地方, 那就是一些数值列表, 在汇编当中, 查表项都是放在 Code 当中的,作为 Code 来处理,其实这些值也是常量,只不过他们的处理不同于一般常量而已,并且它们共用一个入口。下面是一个汇编的表:disp_automenu:;显示菜单用第二数字表格dw0000h15/53.dw0ae1fh;A-1dw0ae2fh;dw0ae3fh;dw0ae4fh;dw0ae5fh;dw0ae6fh;dw0ae7fh;我们可以看到,汇编的表是用DW 关键字定义一个word ,它是存放在 .code 段里面的,通过表头地址来得到每一个相对应的值。那么在 SN8 C 里面又如何来处理这些表呢?在讲到表的处理之前,必须先提一提变量定义关键字的问题。SN8 C 定义一个变量时,可以指明它所放置的地方( RAM 或 ROM ),分别用关键字 _RAM 和_ROM 来指定存放的地点,如:Unsigned int _RAM ramVeriable;/将变量存放在RAM 中_RAM unsigned int ramVeriable2;Unsigned int _ROM romVeriable;/将变量存放在ROM 中_ROM unsigned int romVeriable2;我们可以知道, 当一个量放到了ROM 当中就没法改变它的值了,其实就是我们说的常量。在 C 当中,可以通过一个头名称来访问的变量类型比较多,其中数组是比较方便的一种,我们可以通过定义一个数组来存储这些表的数值,然后通过对数组的访问来查询对应的值。如:unsigned long _ROM disp_automenu=/ 显示菜单用第二数字表格0x0000,0x0ae1f,0x0ae2f,0x0ae3f,0x0ae4f,0x0ae5f,0x0ae6f,0x0ae7f;这是一个与上面的汇编表完全相同的表,我们将它存放在_ROM 中,通过调用数组来查表,这在后面将详细介绍。而在程序中还有另外一类的量是会在程序中不断被改变的,比如程序中的计数器,状态寄存器等等都会随着程序的运行而改变。我们将这一类量称之为变量。我们先来看看汇编的定义变量的方法:.DATAorg0htemp1ds1temp2ds1temp3ds1temp4ds1led_dpds1stepds1;当前状态上面的代码定义了temp1、 temp2、 temp3、 temp4、 led_dp、 step6 个变量,它们分别占用16/53.一个 Byte 的 RAM 空间,那么程序当中就可以通过变量名对该变量的空间进行读写。当然在汇编中你也可以用一个变量名来访问两个或多个RAM 空间,这类似于查表的操作,其定义如下:Job_modeds2Power_modeds4对上面的 job_mode 变量可以通过 job_mode 和 job_mode+1 来读写定义的两个存储单元,以此类推 power_mode 或其他多个 RAM 空间定义的变量可以通过相同的方法来定义。可见,SN8ASM 定义变量的方法主要是通过DS 关键字来申请需要的变量空间,空间一旦被申请,就在整个程序流程里面被占用,也就是说定义一个变量就少一个空间,这对于RAM本身就很少的单片机而言,不能不说是一种浪费。那么 SN8C 又是如何来定义变量的呢?要说到 C 的变量,就不能不提一提变量的有效作用域。我们知道, 汇编当中定义的变量都是在整个程序中有效的,在程序中任何地方都可以改变变量的值,这样程序员就会经常遇到这样的情况:在调试程序时发现变量的值有误,却无法判断变量到底在什么地方被错误赋值或被赋予了错误的值,从而不得不在整个程序中到处设置断点,运行多次才找出问题的所在。这就是汇编当中变量定义造成不方便的地方!而 C 的变量的定义区分了作用域,分为全局变量和局部变量,而区分定义这两种变量的方法很简单,只是在不同的位置定义就行了,这与标准C 所规定的方法是一样的,后面再详细讨论。下面是 SN8 C 定义的几个变量:unsigned int temp1;unsigned int temp2;unsigned int temp3;unsigned int temp4;unsigned int led_dp;unsigned int step;/ 当前状态unsigned long job_mode;unsigned long power_mode1;float powerValue;int temp1_1;/ 有符号的long temp2_2;从上面的定义可以看到C 的变量不仅区分了作用域,还有不同长度的变量类型,这样就方便了程序员的使用。与面向数学运算的计算机相比,单片机的编程对变量类型或数据类型的选择更具有关键性意义。 SN8 系列单片机是8-bit 处理器的单片机,只有Byte 型的数据是处理器直接支持的。对于 C 这样的高级语言,不管使用何种数据类型,虽然某一行程序从字面上看,其操作十分简单,然而,实际上系统的 C 编译器需要用一系列机器指令对其复杂的变量类型、数据类型的进行处理。相同的一行语句,变量选择的类型不同,处理时就会产生很大的差别,产生的代码更是差别很多。特别是当使用浮点变量时,将明显地赠加运算时间和程序的长度。当程序必须保证运算精度时, C 编译器将调用相应的子程序库,把它们加到程序中。然而许多不熟练的程序员,在编写 C 程序时往往会使用大量的、不必要的变量类型。这就导致C 编译器相应地增加所调用的库函数以处理大量增加的变量类型,并最终导致程序变得过于庞大,运行速度减慢,甚至因此会在 Link 时,出现因程序过大而装不进ROM 的情况。所以必须特别慎重的选择变量和数据17/53unsigned)格式。.类型。而对于有符号与无符号的变量类型。在编写程序时,如果使用 signed 和 unsigned 两种数据类型,那么就得使用两种格式类型的库函数。这将使得占用的存储空间成倍增长。因此在编程时,如果只强调程序的运算速度而又不进行负数运算时,最好采用无符号(Note :1、选择数据类型的时候,在能够顺利完成功能的情况下,请尽量选择占空间少的数据类型,这样不管是在RAM空间使用上还是在产生代码效率上都是有益的!2、能使用无符号数的都使用无符号数,以免处理出错,因为芯片内部是以无符号数处理的。3、 切记! C 语言对大小写敏感,在开始定义变量的时候就要注意要有相应的规范可循,用驼峰式是一个好的选择,这对于习惯于汇编的程序员来说,可能不大习惯!当然, 在标准 C 编程当中, 经常会有为书写方便, 对数据类型进行缩写定义, 这在 SN8 C 也是允许的。如:#define uchar unsigned char#define uint unsigned int这样,在以后的编程中,就可以用 uchar 代替 unsigned char,用 uint 代替 unsigned int 来定义变量。3.3 数据的存储类型与存储结构在前面分析查表类型数据定义的时候已经提到了数据在单片机里的存储,会分为 ROM 和RAM 两部分,我们分别称之为程序存储器(ROM )和数据存储器(RAM )。它们在我们编写汇编的时候,会分别用关键字.code 和 .data 来预先声明。通常 SN8 系列单片机不用扩展存储器,它提供种类丰富的机型,你完全可以根据你的需求来选择合适的机型。因此,数据只存储在片内,寻址也不存在片内片外的区分。SN8P 单片机的数据存储器(RAM )的结构如下:18/53.Bank00000H128Byte 用户存储区通用存储区007FH0080H80HFFH 为系统寄存系统寄存器区器区域00FFHBank100100更多的用户存储区通用存储区01FFh图 3-2、 RAM区结构SN8P 系列单片机的通用RAM 区的大小依不同的芯片而不同,但都是按BANK来划分,每一个 BANK 内的地址为 00HFFH 。而所有芯片的 Bank0 的 80H FFH 的空间都是留给系统专用的系统寄存器区。其实我们上面定义的变量都是放在RAM 区的数据结构,在定义一个变量时,我们前面已经提到可以用 _RAM 和 _ROM 关键字来指定存储的地方, 而变量定义一般都放在 RAM 当中,因而 _RAM 关键字是缺省项。看下面的例子:unsigned int temp1;unsigned int _RAM temp2;_RAM unsigned int temp3;unsigned long job_mode;unsigned long _RAM job_mode2;_RAM unsigned long job_mode3;float powerValue;float _RAM powerValue;_RAM float powerValue;int temp1_1;/ 有符号的int _RAM temp1-2;_RAM temp1-3;long temp2_2;其实上面的定义都是相同的效果,就是定义变量,并将其放置在数据存储区(RAM )内。也就是说,我们在定义一个变量,按我们C 常用的方法定义就自动地放到RAM 里了,缺省项给我们带来了很大的方便。上面已经说明了,在RAM 存储区内, 80HFFH 是系统寄存器区。那么我们又是如何来定义系统寄存器区呢?我们先来看看系统寄存器都有哪些内容:0123456789ABCDEF19/53.8LHRZYXPFLAG RBANK -9AMPM-A -P4CON -B DAMADMADBADR-PEDGEC -P2M-P4MP5M-INTRQ INTENOSCM-WDTRTC0RPCLPCHD P0-P2-P4P5-T0M-TC0MTC0CTC1MTC1CTC1RSTKPE P0UR-P2UR-P4URP5UR-YZ-F STK7L STK7H STK6L STK6H STK5L STK5H STK4LSTK4HSTK3LSTK3H STK2L STK2H STK1L STK1H STK0LSTK0H表 3-2、 SN8P 系列单片机系统寄存器列表根据不同的芯片的资源, 寄存器的内容会随之改变, 但是他们定义的区域都不变。 这些寄存器都分别对应了芯片内部的资源, SN8 C 针对这部分的系统资源, 对这些寄存器进行了定义,其定义的形式如下:#defineL(*(_RAM unsigned int*)0x80)#defineH(*(_RAM unsigned int*)0x81)#defineR(*(_RAM unsigned int*)0x82)#defineZ(*(_RAM unsigned int*)0x83)#defineY(*(_RAM unsigned int*)0x84)#defineX(*(_RAM unsigned int*)0x85)#definePFLAG (*(_RAM unsigned int*)0x86)这些定义都被包含在相应芯片的头文档里( .h),因此并不需要用户自己去定义寄存器的相应名称,只需要在程序的开头包含相应的头文档就行了。如下所示:#include Note :这些系统寄存器都是以大写字母进行定义的, 在编写程序时要注意这一点。20/53disp5 = 0xffU;上述简短的几条语句分别完成一定目的的初始化,虽然在这里没有强制要求什么样的顺序,但是执行过程中是严格按语句的先后来开关目标的。.四、程序流程控制程序流程控制是程序的精华所在,正确的程序流程才能实现正确的程序功能。安排精巧的程序流程控制才可能使程序具有高效率。程序流程控制不管是在 C 还是在汇编中都是程序设计者最值得思考的地方。4.1顺序结构顺序结构是程序最基本的流程,其语句顺序执行,PC 指针依次下移, 是 CPU 内部处理指令的初始方法。这也是编程思维的最初级方式,也是程序的最基本方式和流程。顺序结构流程:A 操作B 操作图 4-1 顺序结构流程其实, 其描述的是一个向量方式发展的问题,是所有问题发展和描述的基本方法,具有明确的方向性和时间性,如图中的A 操作的发展方向只有一个,即接下来就是B 操作,中间既没有反复也没有曲折变化,B 一定发生在A 的后面。我们平时可以看到的C 语言的实现:(微波炉开机初始化)key_bibi_f = 1;/上电响一声menu_disp_h = 0xf0U;/上电显示 0:00menu_disp_l = 0;SN8ASM 的实现:b0bsetkey_bibi_f;上电响一声21/53.mova,#0f0hmovmenu_disp_h,amova,#00h;上电显示0:00movmenu_disp_l,amova,#11111111bmovdisp5,a这是一段功能完全与上面这段 C 相同的汇编实现,我们可以看见在顺序结构的汇编语句当中没有任何的跳转和判断,都是按原功能的顺序来描述。从对比当中我们完全可以找到它们的逻辑上的一一对应关系。4.2 选择结构事实上,完全顺序结构的流程的程序很少,因为很多事情并不是一帆风顺,顺流而下。很多情况下,事件的发生都需要具备一定的条件,只有一定条件下才有可能实现。这就得使用选择结构来描述。选择结构流程图:P 为真?A操作B操作图 4-2 选择结构流程图简单选择结构只判断一个条件的真假来决定下面的需要执行的操作,这是一个最简单的判断。C 语言实现:( BCD 码调整)if(result_buf 0x0a)result_buf = input + 6;22/53.elseresult_buf = input;我们看见在C 语言当中,我们用判断语句来实现这样一个判断逻辑,不管是什么样的条件,我们只计算其真假,做出判断。Ifelse 是一个非常好的判断组合,很容易用它来完成下列我们用汇编来实现的功能。SN8 汇编实现:cmprsa,#0ahnopb0bts0fcjmp $+3b0mova,yretb0mova,yadd a,#6h;调整后的数放在a事实上,在汇编程序中,我们会遇到几种情况的条件选择:一是当条件是一个位变量时,我们可以直接用b0bts 指令来进行判断。一是当条件是是否满足一个预定的值,我们可以用CMPRS 指令来进行判断,当然也可以将其转化为标志位来判断。也可以用减法的方法将其转化成为标志位进行判断,就看需要来安排了更深入。A 、串行多分支结构流程:事实上大多数时候,单个的条件无法分析判断复杂的问题,有时候一个结果的出现需要很多个条件同时成立,而每一个条件成立,又都有不同的结果产生,这样就会有一系列的有层次的判断!23/53.YNP1 为真?NYP2 为真?YNPn 为真?C1C2C3C4图 4-3 串行多分支结构流程图C 用 if
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 办公文档 > 演讲稿件


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!