凌阳单片机使用中的一些问题.docx
《凌阳单片机使用中的一些问题.docx》由会员分享,可在线阅读,更多相关《凌阳单片机使用中的一些问题.docx(37页珍藏版)》请在冰豆网上搜索。
凌阳单片机使用中的一些问题
凌阳单片机使用中的一些问题
1.指令长度
一个指令中包含的2进制代码的位数,称为指令长度。
指令长度=操作码的长度+操作数地址的长度X操作数地址个数
2.简述时钟周期、机器周期、指令周期的概念及三者之间的关系
时钟周期
时钟周期也称为振荡周期,定义为时钟脉冲的倒数(可以这样来理解,时钟周期就是单片机外接晶振的倒数,例如12M的晶振,它的时间周期就是1/12us),是计算机中最基本的、最小的时间单位。
在一个时钟周期内,CPU仅完成一个最基本的动作。
对于某种单片机,若采用了1MHZ的时钟频率,则时钟周期为1us;若采用4MHZ的时钟频率,则时钟周期为250us。
由于时钟脉冲是计算机的基本工作脉冲,它控制着计算机的工作节奏(使计算机的每一步都统一到它的步调上来)。
显然,对同一种机型的计算机,时钟频率越高,计算机的工作速度就越快。
但是,由于不同的计算机硬件电路和器件的不完全相同,所以其所需要的时钟周频率范围也不一定相同。
我们学习的8051单片机的时钟范围是1.2MHz-12MHz。
在8051单片机中把一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示)。
机器周期
在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作。
例如,取指令、存储器读、存储器写等,这每一项工作称为一个基本操作。
完成一个基本操作所需要的时间称为机器周期。
一般情况下,一个机器周期由若干个S周期(状态周期)组成。
8051系列单片机的一个机器周期同6个S周期(状态周期)组成。
前面已说过一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示),8051单片机的机器周期由6个状态周期组成,也就是说一个机器周期=6个状态周期=12个时钟周期。
指令周期
指令周期是执行一条指令所需要的时间,一般由若干个机器周期组成。
指令不同,所需的机器周期数也不同。
对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。
对于一些比较复杂的指令,例如转移指令、乘法指令,则需要两个或者两个以上的机器周期。
通常含一个机器周期的指令称为单周期指令,包含两个机器周期的指令称为双周期指令。
3、寻址方式
寻址方式就是寻找操作数或操作数地址的方式。
8086提供了与操作数有关和与I/O端口地址有关的两类寻址方式。
与操作数有关的寻址方式有七种,分别是立即寻址,寄存器寻址,直接寻址,寄存器间接寻址,寄存器相对寻址,基址加变址寻址,相对基址加变址寻址;与I/0端口有关的寻址方式有直接端口寻址和间接端口寻址方式。
一、与操作数有关的寻址方式
1.立即数寻址方式
操作数直接存放在指令中,紧跟在操作码之后的寻址方式就是立即数寻址方式。
例如:
MOVAX,2345H
MOVAL,0EH
2.寄存器寻址
操作数存放在CPU的内存寄存器时,可在指令中指出寄存器名,这就是寄存器寻址方式。
例如:
MOVAX,BX
ADDAX,BX
3.存储器寻址方式
8086指令系统提供了以下5种针对存储器的寻址方式。
直接寻址、寄存器间接寻址、寄存器相对寻址、基址加变址寻址和相对基址加变址寻址。
用于说明操作数所在存储单元的地址。
由于总线接口单元BIU能根据需要自动引用段寄存器得到段值,所以这五种方式也就是确定存放操作数的存储单元有效地址EA的方法。
有效地址EA是一个16位的无符号数,在利用这五种方法计算有效地址时,所得的结果认为是一个无符号数。
(1).直接寻址:
指令中给出的地址码即为操作数的有效地址,就是直接寻址方式。
例子:
MOVAX,[2000H]
MOVAX,2000H-->2000H为存放操作数单元号的符号地址
上面两者是不等效的
(2).寄存器间接寻址方式:
你就想成:
你已经站在你要找的"门户号(家)"的"单元号",你要找到它,必须知道它在当前"单元号"几楼.假如它在6楼,那你就上到6楼就OK了!
!
注意,最高只有16楼,因为什么呢?
那就用DEBUG的D命令看看呀,慢慢数哦,呵呵!
!
例子:
MOVAX,[BX]
计算公式:
物理地址=16d*(DS)+(BX)
物理地址=16d*(DS)+(SI)
物理地址=16d*(DS)+(DI)
物理地址=16d*(SS)+(BP)
(3).寄存器相对寻址方式:
你就想成:
你要找的"门户号(家)"其实就在你家的楼上或者楼下,你要找到它,就必须知道它在你楼上几楼,或者在楼下几楼!
就OK了!
例子:
MOVAX,COUNT[SI]
MOVAX,[COUNT+SI]
其中COUNT为位移量的符号地址
计算公式:
物理地址=16d*(DS)+(BX)+8位位移量
物理地址=16d*(SI)+(BX)+16位位移量
物理地址=16d*(DI)+(BX)+16位位移量
物理地址=16d*(SS)+(BP)+8位偏移量
(4).基址变址寻址方式:
你就想成:
你要找的"门户号(家)"是跟住在同一栋楼的不同"单元号",你要找到它,就必须知道它是该栋的哪个"单元号",并且住在几楼!
那样你就可以找到它了!
例子:
MOVAX,[BX][DI]
MOVAX,[BX+DI]
计算公式:
物理地址=16d*(DS)+(BX)+(SI)
物理地址=16d*(DS)+(BX)+(DI)
物理地址=16d*(SS)+(BP)+(SI)
物理地址=16d*(SS)+(BP)+(DI)
(5).相对基址变址寻址方式:
你就想成:
你要找的"门户号(家)"是跟住在同一栋楼的不同"单元号",它比你高几层楼或者低几层楼,然后用的你目前的楼数+/-就可以得出你要找的住在几楼了!
例子:
MOVAX,MASK[BX][SI]
MOVAX,MASK[BX+SI]
MOVAX,[MASK+BX+SI]
以上三个例子是等效的!
!
计算公式:
物理地址=16d*(DS)+(BX)+(SI)+8位位移量
物理地址=16d*(DS)+(BX)+(DI)+16位位移量
物理地址=16d*(SS)+(BP)+(SI)+8位位移量
物理地址=16d*(SS)+(BP)+(DI)+16位位移量
上述共计七种操作数寻址方式,与80C51单片机的完全一致。
二、与I/0端口有关的寻址方式
8086微处理器采用独立编址的I/0端口,有专门的输入指令IN和输出指令OUT,寻址方式有以下两种。
1.直接端口寻址
直接端口寻址是在指令中直接给出要访问的端口地址,一般采用2位十六进制数表示,也可以是符号,访问的端口范围0~255.
例如:
INAL,20H
表示从I/0端口地址为20H的端口中取数据送入AL寄存器中。
2.间接端口寻址
若访问的端口地址大于255时,就要用间接寻址方式。
可以访问的端口范围0~65535.
例如:
MOVDX,356H;将端口地址356H送入DX寄存器
OUTDX,AL;将AL中的内容输出到DX指定的端口
一、基础实验
1、熟悉μ’nSP™IDE环境下的汇编程序的编写
2、熟悉μ’nSP™IDE环境下的C语言的编写
1、2两个实验通过观察寄存器窗口、变量窗口和内存窗口并单步运行来了解程序的执行情况。
3、使用汇编语言实现A口的输出实验
4、使用C语言实现A口的输出实验
5、使用汇编语言实现A口为输入B口为输出实验
6、使用C语言实现A口为输入B口为输出实验
3、4、5、6四个实验
方法一:
采用软件仿真的方法,观察了解程序的执行情况,注意:
DownLoad后要按下F5键才能看到仿真的结果。
方法二:
采用硬件运行的方法来验证结果,下载到实验系统中以后就使它自动运行。
方法三:
采用软硬件调试的方法来验证结果,下载到实验系统中以后通过IDE的各种调试方法(比如:
单步运行)来运行程序。
试验:
自己新建工程和源文件,把实验4中的main.c的内容复制、粘贴到新源文件中,并且要hardware.asm文件复制到新工程文件夹中,然后将hardware.asm文件加入工程的源文件中,之后编译、下载、运行,结果正确。
注意:
实验5和6时,按键的输入必须在拨码开关S28处于上面时才可以。
5、6两个实验中的key.asm修改为:
//Progarm:
Theheadfileforkey.asminassemblyview
//Arrangedby:
AndyHsu
//Lastmodifieddate:
//Functions:
//F_Key_Scan_Initial;
//F_Key_Scan_ServiceLoop;
//F_Key_DebounceCnt_Down;
//
//callF_SP_GetCh;
.INCLUDEhardware.inc;
.PUBLICF_Key_Scan_Initial;
.PUBLICF_Key_Scan_ServiceLoop;
.PUBLICF_Key_DebounceCnt_Down;
.PUBLIC_SP_GetCh;
.PUBLICF_SP_GetCh;
.PUBLICR_KeyStrobe;
//////////////////////////////////////////////////////////////////
//RAMDefineArea
//////////////////////////////////////////////////////////////////
.RAM
.VARR_DebounceReg;//forkeyboardscan每次的即时键值
.VARR_KeyStrobe;//forkeyboardscan去抖动后的最终键值
.VARR_DebounceCnt;//forkeyboardscan
.DEFINEC_DebounceCnt0x0002;
.CODE
//////////////////////////////////////////////////////////////////
//Function:
InitializationforF_Key_Scan_ServiceLoop
//////////////////////////////////////////////////////////////////
F_Key_Scan_Initial:
r1=0x0000;//
[R_DebounceReg]=r1;//
r1=C_DebounceCnt;//
[R_DebounceCnt]=r1;//resetdebouncecounter
retf;
//////////////////////////////////////////////////////////////////
//Function:
F_Key_Scan_ServiceLoop
//////////////////////////////////////////////////////////////////
F_Key_Scan_ServiceLoop:
r1=[P_IOA_Data];//getkeydatafromIOA
r1=r1and0xff;//
r2=[R_DebounceReg];//
[R_DebounceReg]=r1;//
cmpr2,[R_DebounceReg];//
jeL_KS_StableTwoSample;//
r1=C_DebounceCnt;//debouncetimesetting
[R_DebounceCnt]=r1;//
retf;//
L_KS_StableTwoSample:
r1=[R_DebounceCnt];//
jzL_KS_StableOverDebounce;//
retf;
L_KS_StableOverDebounce:
r1=[R_DebounceReg];//
[R_KeyStrobe]=r1;//savestablekeycodetoR_KeyStrobe
retf;
//////////////////////////////////////////////////////////////////
//Function:
debouncecounterdowncount
//////////////////////////////////////////////////////////////////
F_Key_DebounceCnt_Down:
r1=[R_DebounceCnt];//DebouncesubroutineforF_IO_Key_Scan:
jzL_DebounceCntZero;//stopcountifzero
r1-=0x0001;//
[R_DebounceCnt]=r1;//
L_DebounceCntZero:
//
retf;//
//****************************************************************
//Function:
GetKeycodeforI/OPort
//Destoryregister:
r1,r2
//****************************************************************
_SP_GetCh:
F_SP_GetCh:
r1=[R_KeyStrobe];//GetKeycode
r2=0x0000;//ClearKeyStrobefornextkey
[R_KeyStrobe]=r2;//
retf;
//Endofkey.asm
7、定时器TimerA/B实验
本实验的几个关键问题:
(1)溢出频率的计算
Fosc默认为24.576MHZ
time_clk=Fosc/2=12.288MHZ
情况一:
若r1=0x0000;//设定TA_TIMEOUT/16=(time_clk/65535)/16=11.7Hz
[P_TimerA_Data]=r1;
并且占空比为50%,波形和二极管的闪烁现象比较明显。
情况二:
若r1=0xff9f;//设定TA_TIMEOUT/16=(time_clk/96)/16=8kHz
[P_TimerA_Data]=r1;
并且占空比为50%,波形很好,但二极管的闪烁现象没有。
情况三:
若r1=0xc000;//设定TA_TIMEOUT/16=(time_clk/16383)/16=46.9Hz
[P_TimerA_Data]=r1;
并且占空比为50%,波形很好,但二极管的闪烁现象也没有。
(2)改变系统频率和PWM波占空比的方法
方法一:
直接改变r1的值太麻烦,因为每次必须查找书上对应的表格
r1=time_pwm或time_clk;
[P_TimerA_Ctrl]=r1;
方法二:
//选择不同的时钟源,占空比都为8/16,观察示波器中频率的变化
.definetimefosc_20x0230;//clkA选择fosc/2Hz
.definetimefosc_2560x0231;//clkA选择fosc/256Hz
.definetimeclk_327680x0232;//clkA选择32768Hz
.definetimeclk_81920x0233;//clkA选择8192Hz
.definetimeclk_40960x0234;//clkA选择4096Hz
.definetimeclk_20480x0205;//clkB选择2048Hz
.definetimeclk_10240x020d;//clkB选择1024Hz
.definetimeclk_2560x0215;//clkB选择256Hz
.definetimeclk_40x0225;//clkB选择4Hz
.definetimeclk_20x022d;//clkB选择2Hz
//频率选择fosc/2Hz,设置不同的占空比
.definetimepwm_10x0070;//脉宽选择1/16
.definetimepwm_20x00b0;//脉宽选择2/16
.definetimepwm_30x00f0;//脉宽选择3/16
.definetimepwm_40x0130;//脉宽选择4/16
.definetimepwm_50x0170;//脉宽选择5/16
.definetimepwm_60x01b0;//脉宽选择6/16
.definetimepwm_70x01f0;//脉宽选择7/16
.definetimepwm_80x0230;//脉宽选择8/16
.definetimepwm_90x0270;//脉宽选择9/16
.definetimepwm_100x02b0;//脉宽选择10/16
.definetimepwm_110x02f0;//脉宽选择11/16
.definetimepwm_120x0330;//脉宽选择12/16
.definetimepwm_130x0370;//脉宽选择13/16
.definetimepwm_140x03b0;//脉宽选择14/16
.definetime_clktimefosc_256;//占空比为50%时频率的选择
.definetime_pwmtimepwm_8;//频率为fosc/2Hz时脉宽的选择
以上方法也不好,因为频率和脉宽要求同时改变时,就非常麻烦。
方法三:
//实现功能:
1)选择不同的时钟源,同一占空比一定,观察示波器中频率的变化
//2)选择同一时钟源,改变占空比,观察示波器,比较脉冲宽度
//3)时钟源频率和占空比同时改变
//日期:
2003/6/9
//============================================================
//频率的选择
.definetimefosc_20x0030;//clkA选择fosc/2Hz
.definetimefosc_2560x0031;//clkA选择fosc/256Hz
.definetimeclk_327680x0032;//clkA选择32768Hz
.definetimeclk_81920x0033;//clkA选择8192Hz
.definetimeclk_40960x0034;//clkA选择4096Hz
.definetimeclk_20480x0005;//clkB选择2048Hz
.definetimeclk_10240x000d;//clkB选择1024Hz
.definetimeclk_2560x0015;//clkB选择256Hz
.definetimeclk_40x0025;//clkB选择4Hz
.definetimeclk_20x002d;//clkB选择2Hz
//占空比的选择
.definetimepwm_10x0040;//脉宽选择1/16
.definetimepwm_20x0080;//脉宽选择2/16
.definetimepwm_30x00c0;//脉宽选择3/16
.definetimepwm_40x0100;//脉宽选择4/16
.definetimepwm_50x0140;//脉宽选择5/16
.definetimepwm_60x0180;//脉宽选择6/16
.definetimepwm_70x01c0;//脉宽选择7/16
.definetimepwm_80x0200;//脉宽选择8/16
.definetimepwm_90x0240;//脉宽选择9/16
.definetimepwm_100x0280;//脉宽选择10/16
.definetimepwm_110x02c0;//脉宽选择11/16
.definetimepwm_120x0300;//脉宽选择12/16
.definetimepwm_130x0340;//脉宽选择13/16
.definetimepwm_140x0380;//脉宽选择14/16
.definetime_clktimefosc_2;//频率选择
.definetime_pwmtimepwm_2;//脉宽选择
.defineP_TimerA_Data0x700A;
.defineP_TimerA_Ctrl0x700B;
.defineP_IOB_DATA0x7005;
.defineP_IOB_DIR0x7007;
.defineP_IOB_ATTRI0x7008;
.defineP_Feedback0x7009;
.definep_watchdog_clear0x7012;
r1=time_clk|time_pwm;
[P_TimerA_Ctrl]=r1;
8、系统时钟实验
没有问题,能否改成跑马灯的形式。
9、FIQ中断实验
FIQ三个中断的入口地址均为FFF6H,因此产生这种中断时必须要进行判断。
FIQ_fosc/1024和IRQ0_fosc/1024类似于时基中断,也就是给定一个系统时钟频率比如24.576MHZ,中断频率就为24.576MHZ/1024,凌阳技