松翰C语言编程指导C+Program+Guide讲解学习Word下载.docx
- 文档编号:18573534
- 上传时间:2022-12-28
- 格式:DOCX
- 页数:63
- 大小:346.99KB
松翰C语言编程指导C+Program+Guide讲解学习Word下载.docx
《松翰C语言编程指导C+Program+Guide讲解学习Word下载.docx》由会员分享,可在线阅读,更多相关《松翰C语言编程指导C+Program+Guide讲解学习Word下载.docx(63页珍藏版)》请在冰豆网上搜索。
九、内嵌汇编
9.1如何内嵌汇编
9.2内嵌汇编时变量的传递
十、程序结构
10.1主函数与子函数
10.2构建可复用文件
10.3构建具有实用性的程序
Assembly(汇编)的历史已经有半个多世纪了,从计算机的发明那天开始,汇编就注定要与其结缘,它作为第一种真正意义上的编程语言,在计算机的发展过程中具有无可替代的地位。
汇编具有与机器语言一一对应的高效率,就是由于汇编的高效率,和其紧贴硬件的特性,使其在半个世纪之后的今天依然是目前开发单片机程序的主流工具之一。
但是由于编写汇编代码的工作量和难度都比较高,并且要求程序员对硬件必须有较深刻的了解,其入门就相对较难。
而汇编的写法各异,不同的程序员编写的代码有着巨大的差异,这就带来了学习的难度,可读性差也成为了其推广的瓶颈,程序的维护更加艰难。
随着程序复杂性的增加,开发团队的形成,应用而生的高级语言就逐渐取代了其位置。
C就是高级语言中针对硬件操作最优秀的一种,C也是基于汇编的,其相互关系如图所示。
随着人们不断的对C进行改善,使C的效率得到了很大的提升,其编译效率逐渐的逼近汇编。
而C以其模块化的编程模式,简洁的代码,良好的可读性和可维护性,成为了另一种单片机开发的主流开发工具,相比汇编而言,其具有无可比拟的优异性。
图1、C与汇编的关系
SN8C是基于标准C而又加入SONIXSN8系列芯片特征的专用C,它面对的是SONIXSN8系列芯片程序开发,它能产生非常简洁的能直接运行于SN8系列芯片的优化代码。
具有良好的兼容性,易学易用,既方便客户开发,又继承了原有汇编的卓越性能。
在本文当中,我们将结合汇编来讲述C开发的各方面知识,以期通过对比来加深对芯片的编程应用的了解,同时,对熟悉C的程序员来说,可以更加深入了解芯片;
而对于熟悉汇编的程序员来说,我们可以从对比中找到从汇编到C的转换方法。
SONIXSN8系列的芯片是RISC内核的高性能芯片。
目前,由SONIX提供的SN8Assembly仅有59条指令,是一种高效的汇编语言,有S8ASM和M2ASM编译器分别支持其1系和2系芯片。
在此基础上的SN8Cstudio整合了汇编和C的编译器,
1.1、SN8Cstudio的安装
在得到SN8Cstudio的安装包后,按照标准的Windows程序安装方法安装就可以将软件安装到机器上。
1.2、SN8Cstudio应用实例
一、创建一个工作区
与VC类似,我们的工程管理模式是以工作区方式来管理,在你准备一个项目的时候,
你首先创建一个属于这个项目的工作区:
1、打开IDS->
文件->
新建,单击出现如下界面:
图2-1新建对话框
2、单击workSpace图标,进入workspace创建窗口,单击Location编辑框后的按钮,选择你需要的工作目录,然后输入新建Workspace的name,在这里如下:
图2-2新建Workspace对话框
3、单击OK,IDS的界面生成了工作区的工作界面,出现了Workspace窗口和Output窗口。
同时,打开目标文件夹,你会发现在你选定的文件夹下面,生成了一个以WorkspaceName命名的新文件夹,打开文件夹你可以看到一个新生成的.wsp文件,这就是新生成的Workspace的配置文件:
图2-3新生成的Workspace配置文件
二、新建一个工程(Project)
在我们成功创建一个工作区后,你会发现我们的Workspace窗口中的Projiect数目为0,接着我们就要依据项目所用的芯片母体来创建一个工程项目了,跟创建Workspace相同,打开菜单中的文件->
新建,单击出现新建窗口,此时默认为新建Project。
在右边的ProjectList窗口中选择你要使用的芯片母体和要创建的工程类型(一般为普通项目),此时的目标路径Location中已经显示为你刚才建立的Workspace目录,建议将工程保存在这个目录下,不修改默认路径。
给新建工程取一个有意义的Name,在框中输入。
这里我们取与Workspace相同的名称,新建一个2700系列芯片的普通项目工程,设置如下图所示:
1、单击文件->
新建,选择合适的选项:
图2-4新建Project
2、单击OK。
3、新工程选项配置,在确认建立工程后,出现ProjectSetting对话框,左边的Project列表中默认选中我们刚刚建立的工程,在这里我们只修改Chip和CodeOption项目下的选项,如图所示:
图2-5ProjectSetting对话框
4、选择正确的芯片:
在Chip页中,Definition文本框中显示系统依据你选定的芯片母体系列而确定的需要调用的芯片定义文件。
ChipList表列出了当前版本的IDS所支持的这一系列的各个芯片,选中其中你需要使用的芯片母体,Selected文本框和Description文本框相应会自动改变。
如图:
图2-6选择芯片
5、设置正确的CodeOption选项和ICEMODE:
ICEMODE的设置在SN8P1xxx芯片中是用于选择是否是ICE仿真模式,在CodeOption列表中自动显示选定芯片母体的CodeOption选项,在OptionValue项的默认值上单击,出现一个下拉列表,单击选择合适的选项。
图2-7设置正确的CodeOption
6、单击OK,系统生成一个没有文件的工程,在Workspace管理窗口中我们可以看见当前生成的工程为Workingproject,正处被激活状态(工程名称为加粗字体):
图2-8新建Project的状态被激活
打开相应的文件夹,我们会发现系统生成了很多个新的文件,其中的.prj文件即为工程文件,其他的文件为根据我们刚才的设置和不同的芯片生成的配置文件及头文件。
三、新建文件
完成项目的新建后,我们发现项目管理器source文件夹下是空的,没有任何文件,文件就是我们编程的主要工作了!
1、打开文件->
新建菜单,单击出现我们前面看过很多次的New对话框,不过比前面多了一个选项——Files,选择New列表中的Files选项,单击按钮,对话框如图所示:
图2-9新建文件对话框
2、在FileList中选中需要创建的文件类型,这里我们创建一个CSourceFile,给文件命名从Name编辑框中输入,存放的地点为刚才的设定位置,默认不做修改。
3、单击OK按钮,IDS打开一个编辑窗口,最大化,显示为刚刚建立的文件名的页,系统允许我们在这里进行程序的编写。
四、编写程序
在新建一个文件后,系统自动打开编辑器,并打开一个由用户命名的空文档,它与普通文档相比较没有什么不同的之处,只不过它可以对C的关键字进行高亮显示。
在新的文档里编辑程序。
C本身就是一种模块化的编程语言,SN8C的编程保持C语言的编程风格。
SN8C所具有的Non-ANSIC的特性请参看其他章节,在此不再做描述。
下面是一个简单的C程序举例。
例2:
/******************************************************************
*
*FileName:
SN8C_Ex.c
*PostBy:
Dragon.Yi
*Date:
2005/09/23
*TestHistory:
V1.00.220
*describe:
test2708interrupt
*
*******************************************************************/
#include<
sn8p2708a.h>
structword{
unsignedfint:
1;
unsigned:
7;
}intword;
unsignedinttc0cvalue=0x64;
unsignedintaccbuf=0x00;
unsignedintpflagbuf=0;
__interruptintserv(void)
{//Thedatawillautostore!
_bCLR(&
INTRQ,5);
TC0C=tc0cvalue;
intword.fint=1;
}
voidinitIO(void);
voidinitINT(void);
voidmain(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;
}
}
voidinitIO(void)
{
P0M=0xFF;
P1M=0xFF;
P2M=0xFF;
P3M=0xFF;
P4M=0xFF;
P5M=0xFF;
voidinitINT(void)
INTRQ=0x00;
INTEN=0x00;
TC0M=0x00;
TC0M=0x20;
TC0C=0x64;
_bSET(&
INTEN,5);
TC0M,7);
STKP,7);
注:
程序只作为程序架构提供参考!
五、调试程序
在完成代码编辑后,想要马上顺利运行基本上是不可能的,每一个程序都有经过调试的过程,程序的调试在IDS中非常方便,IDS有全面的可视化的调试工具。
你可以在程序中设置断点,在程序中按自己的需求来运行。
可以根据不同的需求来进行调试。
1、compile和Build
完成代码的编辑后,首先要进行Compile,在菜单Build->
Compilecurrentfile单击或在工具栏中单击Compile按钮和单击快捷键Ctrl+F7均可以启动系统的Compile程序。
Compile程序会检查代码中存在的语法错误和软件设置错误,然后在Output窗口表列出来,用户可以根据表列出来的提示,对程序进行修改。
若是语法错误,在列表中双击选项,系统会自动将光标移动到相对应的代码行,方便你的检查和修改。
Compile通过后,进行Build,同样有3种方式可以启动Build程序,Build程序生成运行所需要的一些文件,同时检查硬件配置和连接错误,用户必须根据提示对程序进行修改才能顺利通过。
2、选择仿真方式
单击进入Project->
setting,出现我们前面已经熟悉的projectsetting对话框,当前显示的是General页,在primarysetting组下面找到复选项usesimulate。
如果选中该选项,则程序就在系统提供的虚拟仿真器上仿真并显示相应结果;
若不选中该选项,则程序必须在相应系列的仿真器上进行程序调试仿真。
这里我们先选择它。
3、进入调试模式
完成compile和build之后,进入菜单Debug->
beginDebug,单击菜单项或直接按快捷键F5或在图标选项中选择按钮单击都可进入调试模式,进入调试模式后,系统界面变成如下图:
图2-11调试程序界面
系统界面出现Ramwindow、Watchwindow、variablewindow、Registerwindow、callstackwindow和Disassemblywindow,这些窗口都是调试程序要用到的。
程序的指针指向程序的入口处,即Main()函数的第一条语句。
4、应用Watchwindow:
在调试过程中如何应用watchwindow?
Watchwindow用在调试工程中对定义的变量进行监视,将需要进行监视的Variable在编辑窗口中双击,然后拖放到WatchWindow当中,运行程序就可以在watchwindow中看到Variable的存放地点和值的变化。
图2-12watchwindow窗口
系统会将产生了变化的项置成红色。
为方便观察,你最多可以将Variable分别放到3个Watchwindow当中进行观察,他们的显示效果是一样的!
5、应用Variablewindow
Variablewindow显示格式和watchwindow的显示格式一样,但是variablewindow里面的项无法自己设定。
它是以Auto的状态显示当前运行过程中被改变的LocalVariable,同样系统会将最近改变的量置成红色。
6、应用RegisterWindow:
Registerwindow里面显示的项是根据芯片的资源而定的,它显示的是当前母体芯片Ram中0x80~0xFF空间中专用存储器在当前运行状态下的值,单击前面的“+”号,将扩展项目展开,可以得到每一个bit的当前值。
同样,在运行过程中,系统会将刚改变的项的值置为红色高亮显示,便于我们观察跟踪。
图2-13Register窗口
7、应用Callstackwindow
Callstackwindow显示当前运行状态下,stack的使用状况和入栈的函数,用户可以根据显示来判断程序的调用状况,进而判断当前的状态是否正确,有没有函数调用出错。
图2-14callstack窗口
8、应用Memorywindow:
在程序运行当中,当你想从具体的Ram地址而得到它的值的时候,你可以通过Memory窗口中实现,你可以直接在Goto后面的编辑框中输入地址,按Enter键确认,窗口会自动跳转到相应的位置显示该位置的值,方便我们在使用过程中的查找。
9、应用Disassemblywindow:
如果调试过程中,你需要知道程序的直接汇编码,你可以在这个窗口中观察。
10、设置断点:
程序调试的时候,往往需要知道程序运行过程中某个变量的运行状态,或者想知道某段程序是否执行,还有执行后的结果;
或者,需要知道某段程序的运行过程是否正确。
这时,就必须在程序的正确位置设置断点。
将光标移到正确位置,在相应的行,单击设置断点的按钮或按快捷键F9或者从菜单项中设置都可以使该行程序被设置成为断点,被设置成断点后,运行程序,程序就会运行到断点处停下来,以便于用户控制程序的执行和观察执行的结果。
图2-15断点执行状态
11、跟踪程序执行:
应用系统提供的debug工具,用户可以很方便地对程序的执行效果进行跟踪。
你可以单步,也可越过一段程序往下执行,这要看你的需要!
调试工具同样可以以3种方式打开:
Debug菜单、工具栏按钮和快捷键。
六、程序输出
1、仿真程序结果:
将仿真器与主机连接好,在projectsetting中清除usesimulate选项的选中状态。
将需要仿真的硬件系统目标板连接好。
单击Debug按钮或者按快捷键进入调试状态,就可以在实际硬件上看到程序运行的结果,对程序进行修改直到得到正确结果。
我们就得到一个正确运行的可以烧录到实际芯片的程序。
2、输出烧录文档
在完成程序的调试仿真后,我们就需要将程序输出。
系统已经在默认目录下生成程序的烧录档XXX.sn8,默认目录为当前工程文件的目录下。
SN8C支持标准C的所有数据类型。
具体有无符号字符(unsignedchar)、有符号字符(signedchar)、无符号整型(unsignedint)、有符号整型(signedint)、无符号长型(unsignedlong)、有符号长型(signedlong)、浮点(float)和指针类型。
还支持所有的构造类型。
图3-1数据类型
3.1专有数据类型
虽然SN8C支持C的所有数据类型,但是由于它面对的是8-bit单片机,所以必然会考虑数据类型的定义方法和长度。
在这些方面,SN8C有它自己的专有的定义特征和数据长度,在使用时一定要加于区分。
请看下表:
数据类型
Size(Byte)
数据取值范围
Signedchar(short、int)
1
-128~+127
Unsignedchar(short、int)
0~255
Signedlong
2
-32768~+32767
Unsignedlong
0~65535
float、double
4
Pointer
enum
表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前面的字段都会被其后面的值直接代替,因此,很方便地减轻了程序员的工作。
我们再来看看用SN8C是如何定义这些相同的常量的:
#definedoor_service_c80//80ms去门抖动
#definet0int_c224//t0中断时间
#definesegment_c3//;
上面定义的3个量是与前面汇编当中定义的3个常量是完全相同的。
在进行编译预处理时,这些量就会被数值代替。
还有一个特殊的地方,那就是一些数值列表,在汇编当中,查表项都是放在Code当中的,作为Code来处理,其实这些值也是常量,只不过他们的处理不同于一般常量而已,并且它们共用一个入口。
下面是一个汇编的表:
disp_automenu:
;
显示菜单用第二数字表格
dw0000h
dw0ae1fh;
A-1
dw0ae2fh;
dw0ae3fh;
dw0ae4fh;
dw0ae5fh;
dw0ae6fh;
dw0ae7fh;
我们可以看到,汇编的表是用DW关键字定义一个word,它是存放在.code段里面的,通过表头地址来得到每一个相对应的值。
那么在SN8C里面又如何来处理这些表呢?
在讲到表的处理之前,必须先提一提变量定义关键字的问题。
SN8C定义一个变量时,可以指明它所放置的地方(RAM或ROM),分别用关键字__RAM和__ROM来指定存放的地点,如:
Unsignedint__RAMramVeriable;
//将变量存放在RAM中
__RAMunsignedintramVeriable2;
Unsignedint__ROMromVeriable;
//将变量存放在ROM中
__ROMunsignedintromVeriable2;
我们可以知道,当一个量放到了ROM当中就没法改变它的值了,其实就是我们说的常量。
在C当中,可以通过一个头名称来访问的变量类型比较多,其中数组是比较方便的一种,我们可以通过定义一个数组来存储这些表的数值,然后通过对数组的访问来查询对应的值。
unsignedlong__ROMdisp_automenu[]=//显示菜单用第二数字表格
0x0000,0x0ae1f,0x0ae2f,0x0ae3f,0x0ae4f,
0x0ae5f,0x0ae6f,0x0ae7f
};
这是一个与上面的汇编表完全相同的表,我们将它存放在__ROM中,通过调用数组来查表,这在后面将详细介绍。
而在程序中还有另外一类的量是会在程序中不断被改变的,比如程序中的计数器,状态寄存器等等都会随着程序的运行而改变。
我们将这一类量称之为变量。
我们先来看看汇编的定义变量的方法:
.DATA
org0h
temp1ds1
temp2ds1
temp3ds1
temp4ds1
led_dpds1
stepds1;
当前状态
上面的代码定义了temp1、temp2、temp3、temp4、led_dp、step6个变量,它们分别占用一个Byte的RAM空间,那么程序当中就可以通过变量名对该变量的空间进行读写。
当然在汇编中你也可以用一个变量名来访问两个或多个RAM空间,这类似于查表的操作,其定义如下:
Job_modeds2
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 松翰 语言 编程 指导 Program Guide 讲解 学习