1、松翰C语言编程指导C+Program+Guide讲解学习松翰C语言编程指导C+Program+Guide如何用C来完成SN8系列芯片的程序设计松翰 易爱华松翰科技(深圳)有限公司SONIX TECHNOLOGY CO.,LTD.内容概览一、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函数参数与全
2、局变量六、结构体、联合在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构建具有实用性的程序一、C 与Assembly简述Assembly(汇编)的历史已经有半个多世纪了,从计算机的发明那天开始,汇编就注定要与其结缘,它作为第一种真正意义上的编程语言,在计算机的发展过程中具有无可替代的地位。汇编具有与机器语言一一对应的高效率,就是由于汇编的高
3、效率,和其紧贴硬件的特性,使其在半个世纪之后的今天依然是目前开发单片机程序的主流工具之一。但是由于编写汇编代码的工作量和难度都比较高,并且要求程序员对硬件必须有较深刻的了解,其入门就相对较难。而汇编的写法各异,不同的程序员编写的代码有着巨大的差异,这就带来了学习的难度,可读性差也成为了其推广的瓶颈,程序的维护更加艰难。随着程序复杂性的增加,开发团队的形成,应用而生的高级语言就逐渐取代了其位置。C就是高级语言中针对硬件操作最优秀的一种,C也是基于汇编的,其相互关系如图所示。随着人们不断的对C进行改善,使C的效率得到了很大的提升,其编译效率逐渐的逼近汇编。而C以其模块化的编程模式,简洁的代码,良好
4、的可读性和可维护性,成为了另一种单片机开发的主流开发工具,相比汇编而言,其具有无可比拟的优异性。图1、C与汇编的关系SN8 C 是基于标准C而又加入SONIX SN8 系列芯片特征的专用C,它面对的是SONIX SN8 系列芯片程序开发,它能产生非常简洁的能直接运行于SN8 系列芯片的优化代码。具有良好的兼容性,易学易用,既方便客户开发,又继承了原有汇编的卓越性能。在本文当中,我们将结合汇编来讲述C开发的各方面知识,以期通过对比来加深对芯片的编程应用的了解,同时,对熟悉C的程序员来说,可以更加深入了解芯片;而对于熟悉汇编的程序员来说,我们可以从对比中找到从汇编到C的转换方法。二、SN8 C s
5、tudio 的安装与使用SONIX SN8 系列的芯片是RISC内核的高性能芯片。目前,由SONIX提供的SN8 Assembly仅有59条指令,是一种高效的汇编语言,有S8ASM和M2ASM编译器分别支持其1系和2系芯片。在此基础上的SN8 C studio整合了汇编和C的编译器,11、SN8 C studio 的安装在得到SN8 C studio的安装包后,按照标准的Windows程序安装方法安装就可以将软件安装到机器上。12、SN8 C studio应用实例一、创建一个工作区与VC类似,我们的工程管理模式是以工作区方式来管理,在你准备一个项目的时候,你首先创建一个属于这个项目的工作区:1
6、、打开IDS-文件-新建,单击出现如下界面:图2-1 新建对话框2、单击workSpace 图标,进入workspace创建窗口,单击Location 编辑框后的按钮,选择你需要的工作目录,然后输入新建Workspace的name,在这里如下:图2-2 新建Workspace对话框3、单击OK,IDS 的界面生成了工作区的工作界面,出现了Workspace窗口和Output窗口。同时,打开目标文件夹,你会发现在你选定的文件夹下面,生成了一个以Workspace Name 命名的新文件夹,打开文件夹你可以看到一个新生成的.wsp文件,这就是新生成的Workspace 的配置文件:图2-3 新生成
7、的Workspace配置文件二、新建一个工程(Project)在我们成功创建一个工作区后,你会发现我们的Workspace 窗口中的Projiect数目为0,接着我们就要依据项目所用的芯片母体来创建一个工程项目了,跟创建Workspace相同,打开菜单中的 文件-新建,单击出现新建窗口,此时默认为新建Project。在右边的Project List窗口中选择你要使用的芯片母体和要创建的工程类型(一般为普通项目),此时的目标路径Location 中已经显示为你刚才建立的Workspace目录,建议将工程保存在这个目录下,不修改默认路径。给新建工程取一个有意义的Name,在框中输入。这里我们取与W
8、orkspace相同的名称,新建一个2700系列芯片的普通项目工程,设置如下图所示:1、单击文件-新建,选择合适的选项:图2-4 新建Project2、单击OK。3、新工程选项配置,在确认建立工程后,出现Project Setting 对话框,左边的Project列表中默认选中我们刚刚建立的工程,在这里我们只修改Chip 和Code Option项目下的选项,如图所示:图2-5 Project Setting 对话框4、选择正确的芯片:在Chip页中,Definition文本框中显示系统依据你选定的芯片母体系列而确定的需要调用的芯片定义文件。Chip List 表列出了当前版本的IDS所支持的
9、这一系列的各个芯片,选中其中你需要使用的芯片母体,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 管理窗口中我们可以看见当前生成的工程为Wo
10、rking project,正处被激活状态(工程名称为加粗字体):图2-8 新建Project的状态被激活打开相应的文件夹,我们会发现系统生成了很多个新的文件,其中的.prj文件即为工程文件,其他的文件为根据我们刚才的设置和不同的芯片生成的配置文件及头文件。三、新建文件完成项目的新建后,我们发现项目管理器source文件夹下是空的,没有任何文件,文件就是我们编程的主要工作了!1、打开文件-新建菜单,单击出现我们前面看过很多次的New对话框,不过比前面多了一个选项Files,选择New列表中的Files选项,单击按钮,对话框如图所示:图2-9 新建文件对话框2、在File List中选中需要创建
11、的文件类型,这里我们创建一个C Source File,给文件命名从Name 编辑框中输入,存放的地点为刚才的设定位置,默认不做修改。3、单击OK按钮,IDS打开一个编辑窗口,最大化,显示为刚刚建立的文件名的页,系统允许我们在这里进行程序的编写。四、编写程序在新建一个文件后,系统自动打开编辑器,并打开一个由用户命名的空文档,它与普通文档相比较没有什么不同的之处,只不过它可以对C的关键字进行高亮显示。在新的文档里编辑程序。C本身就是一种模块化的编程语言,SN8C的编程保持C 语言的编程风格。SN8C所具有的Non-ANSI C的特性请参看其他章节,在此不再做描述。下面是一个简单的C程序举例。例2
12、:/* * File Name : SN8C_Ex.c* Post By : Dragon.Yi* Date : 2005/09/23* Test History : V1.00.220* describe:test 2708 interrupt*/#include struct word unsigned fint:1; unsigned :7;intword;unsigned int tc0cvalue=0x64;unsigned int accbuf = 0x00;unsigned int pflagbuf = 0;_interrupt intserv(void) /The data w
13、ill 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; P0=0x00; else P0=0xff; P1=0xff; P2=0xff; P3=0xff; P4=0xff; P5=0xff; void
14、 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有全面的
15、可视化的调试工具。你可以在程序中设置断点,在程序中按自己的需求来运行。可以根据不同的需求来进行调试。1、compile 和Build完成代码的编辑后,首先要进行Compile,在菜单Build-Compile current file单击或在工具栏中单击Compile按钮和单击快捷键Ctrl+F7 均可以启动系统的Compile程序。Compile 程序会检查代码中存在的语法错误和软件设置错误,然后在Output窗口表列出来,用户可以根据表列出来的提示,对程序进行修改。若是语法错误,在列表中双击选项,系统会自动将光标移动到相对应的代码行,方便你的检查和修改。Compile 通过后,进行Buil
16、d,同样有3种方式可以启动Build程序,Build程序生成运行所需要的一些文件,同时检查硬件配置和连接错误,用户必须根据提示对程序进行修改才能顺利通过。2、选择仿真方式单击进入Project-setting,出现我们前面已经熟悉的project setting对话框,当前显示的是General 页,在primary setting组下面找到复选项use simulate。如果选中该选项,则程序就在系统提供的虚拟仿真器上仿真并显示相应结果;若不选中该选项,则程序必须在相应系列的仿真器上进行程序调试仿真。这里我们先选择它。3、进入调试模式完成compile和build之后,进入菜单Debug-b
17、egin 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用在调试工程中对定义的变量进行监视,将需要进行监视的
18、Variable 在编辑窗口中双击,然后拖放到Watch Window当中,运行程序就可以在watch window中看到Variable的存放地点和值的变化。如图:图2-12 watch window窗口系统会将产生了变化的项置成红色。为方便观察,你最多可以将Variable分别放到3个Watch window当中进行观察,他们的显示效果是一样的!5、应用Variable windowVariable window显示格式和watch window 的显示格式一样,但是variable window里面的项无法自己设定。它是以Auto的状态显示当前运行过程中被改变的Local Variabl
19、e,同样系统会将最近改变的量置成红色。6、应用Register Window:Register window里面显示的项是根据芯片的资源而定的,它显示的是当前母体芯片Ram中0x800xFF空间中专用存储器在当前运行状态下的值,单击前面的“+”号,将扩展项目展开,可以得到每一个bit的当前值。同样,在运行过程中,系统会将刚改变的项的值置为红色高亮显示,便于我们观察跟踪。图2-13 Register 窗口7、应用Call stack windowCall stack window 显示当前运行状态下,stack的使用状况和入栈的函数,用户可以根据显示来判断程序的调用状况,进而判断当前的状态是否正
20、确,有没有函数调用出错。图2-14 call stack 窗口8、应用Memory window:在程序运行当中,当你想从具体的Ram 地址而得到它的值的时候,你可以通过Memory窗口中实现,你可以直接在Go to后面的编辑框中输入地址,按Enter键确认,窗口会自动跳转到相应的位置显示该位置的值,方便我们在使用过程中的查找。9、应用Disassembly window:如果调试过程中,你需要知道程序的直接汇编码,你可以在这个窗口中观察。10、设置断点:程序调试的时候,往往需要知道程序运行过程中某个变量的运行状态,或者想知道某段程序是否执行,还有执行后的结果;或者,需要知道某段程序的运行过程
21、是否正确。这时,就必须在程序的正确位置设置断点。将光标移到正确位置,在相应的行,单击设置断点的按钮或按快捷键F9 或者从菜单项中设置都可以使该行程序被设置成为断点,被设置成断点后,运行程序,程序就会运行到断点处停下来,以便于用户控制程序的执行和观察执行的结果。如图:图2-15 断点执行状态11、跟踪程序执行:应用系统提供的debug工具,用户可以很方便地对程序的执行效果进行跟踪。你可以单步,也可越过一段程序往下执行,这要看你的需要!调试工具同样可以以3种方式打开:Debug菜单、工具栏按钮和快捷键。六、程序输出1、仿真程序结果:将仿真器与主机连接好,在project setting中清除use
22、 simulate选项的选中状态。将需要仿真的硬件系统目标板连接好。单击Debug 按钮或者按快捷键进入调试状态,就可以在实际硬件上看到程序运行的结果,对程序进行修改直到得到正确结果。我们就得到一个正确运行的可以烧录到实际芯片的程序。2、输出烧录文档在完成程序的调试仿真后,我们就需要将程序输出。系统已经在默认目录下生成程序的烧录档XXX.sn8,默认目录为当前工程文件的目录下。三、数据类型与运算SN8 C 支持标准C的所有数据类型。具体有无符号字符(unsigned char)、有符号字符(signed char)、无符号整型(unsigned int)、有符号整型(signed int)、无
23、符号长型(unsigned long)、有符号长型(signed long)、浮点(float)和指针类型。还支持所有的构造类型。图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 l
24、ong2065535float、double4Pointer2enum1表3-1、数据类型长度定义表3.2 常量与变量在程序设计的过程中,我们有些量可能是参考值,也可能是预设的值。总之,我们希望它在整个程序中保持不变,并且在程序的任何地方可以提供我们调用,用来比对某些条件是否成立等等。对于这样的值,我们可以不去定义它,而直接参考数值,这在汇编编程过程中,经常会有一些缺乏经验的程序员这样用。但这就需要程序员把程序中的这些值都牢牢记住,并且要将他们的值前后统一,这是一个非常容易出错的过程,而且也会影响了程序的可读性,这样,程序的修改和维护都非常艰难,必须处处小心翼翼,一处不慎就全盘错误!这是任何人
25、不想看到的后果。因此,建议对于程序中用到的不会改变的参考值或其他预设的值都进行一个预先的定义,给它取一个有意义的或与其相关的名字。这个过程就是常量定义,自然,这个不变的量就称为常量。在标准C中,由于面对的是功能强大的CPU系统和大内存,用户可以不去管它放置的地方。但是,面对一个单片机系统,它的Ram非常小,有时会显得很紧张。所以系统为了节省空间会将一些表格等放在系统的ROM中。而我们直接命名的常量,则由编译器自动将其替换为所需要的值,这些工作就由计算机来完成好了。我们先来看看我们用汇编编写程序时是怎么来定义常量的:如: door_service_c equ #80 ;80ms去门抖动 t0in
26、t_c equ #224 ;t0中断时间 segment_c equ #3 ;最多3段烹调注:上面数值前的#号,是SN8ASM的符号,用于提示后面的是立即数。上面定义了3个程序中会用到的参考值,顺便提一下,在定义的时候加上注释是有必要的,要不然时间久了你就又不知道你定义的到底是什么了。在上面的定义中,用的是汇编EQU关键字,在编译过程中,程序里但凡出现了EQU前面的字段都会被其后面的值直接代替,因此,很方便地减轻了程序员的工作。我们再来看看用SN8 C是如何定义这些相同的常量的:如:#define door_service_c 80 /80ms去门抖动#define t0int_c 224 /
27、t0中断时间#define segment_c 3 /;最多3段烹调上面定义的3个量是与前面汇编当中定义的3个常量是完全相同的。在进行编译预处理时,这些量就会被数值代替。还有一个特殊的地方,那就是一些数值列表,在汇编当中,查表项都是放在Code 当中的,作为Code 来处理,其实这些值也是常量,只不过他们的处理不同于一般常量而已,并且它们共用一个入口。下面是一个汇编的表:disp_automenu: ;显示菜单用第二数字表格 dw 0000h dw 0ae1fh ;A-1 dw 0ae2fh ; dw 0ae3fh ; dw 0ae4fh ; dw 0ae5fh ; dw 0ae6fh ; d
28、w 0ae7fh ;我们可以看到,汇编的表是用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 u
29、nsigned int romVeriable2;我们可以知道,当一个量放到了ROM当中就没法改变它的值了,其实就是我们说的常量。在C当中,可以通过一个头名称来访问的变量类型比较多,其中数组是比较方便的一种,我们可以通过定义一个数组来存储这些表的数值,然后通过对数组的访问来查询对应的值。如:unsigned long _ROM disp_automenu= /显示菜单用第二数字表格 0x0000,0x0ae1f,0x0ae2f,0x0ae3f,0x0ae4f, 0x0ae5f,0x0ae6f,0x0ae7f;这是一个与上面的汇编表完全相同的表,我们将它存放在_ROM中,通过调用数组来查表,这在
30、后面将详细介绍。而在程序中还有另外一类的量是会在程序中不断被改变的,比如程序中的计数器,状态寄存器等等都会随着程序的运行而改变。我们将这一类量称之为变量。我们先来看看汇编的定义变量的方法:.DATA org 0h temp1 ds 1 temp2 ds 1 temp3 ds 1 temp4 ds 1 led_dp ds 1 step ds 1 ;当前状态上面的代码定义了temp1、temp2、temp3、temp4、led_dp、step6个变量,它们分别占用一个Byte的RAM空间,那么程序当中就可以通过变量名对该变量的空间进行读写。当然在汇编中你也可以用一个变量名来访问两个或多个RAM空间,这类似于查表的操作,其定义如下:Job_mode ds 2
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1