单片机 子程序中,当满足要求就转移到子程序,如果子程序没有返回指令,是不是顺序执行下一条,不管是不是子程序

单片机的指令系统
查看: 703|
摘要: 本文主要对单片机的指令系统进行想详细讲解,介绍了5种指令:数据传送指令、算术运算指令、逻辑运算指令、位操作类指令和控制转移指令的格式及功能。在学习的过程中掌握这5种指令的功能和使用方法,会使用这些指令熟 ...
一、数据传送指令
数据传送指令主要负责把数据、地址或立即数传送到寄存器或存储单元中。这类指令共有29条,可分为以下3大类:基本数据传送指令,数据交换指令,栈操作指令。
执行数据传送指令时,除以累加器A为目的操作数的指令会对奇偶标志位P有影响外,其余指令执行时均不会影响任何标志位。
1.&基本数据传送指令
根据数据取自何方和传到何方,MOV指令有着许多不同的形式。
(1)以累加器A为目的操作数类指令
这组指令的作用是把源操作数指向的内容送到累加器A。有立即数、直接、寄存器和寄存器间接寻址方式:
MOV&&A,&#data& ;&data→(A)&
MOV&&A,&direct& ;(direct)→(A)&
MOV&&A,&Ri&& ;(Ri)→(A)&
MOV&&A,&@Rj& ;((Rj))→(A)&
(2)&以寄存器Ri为目的操作数的指令
这组指令的功能是把源操作数指定的内容送到所选定的工作寄存器Ri中。有立即、直接和寄存器寻址方式:&
(3)以直接地址为目的操作数的指令
这组指令的功能是把源操作数指定的内容送到由直接地址direct所选定的片内RAM中。有立即、直接、寄存器和寄存器间接4种寻址方式:
(4)以间接地址为目的操作数的指令
这组指令的功能是把源操作数指定的内容送到以Rj中的内容为地址的片内RAM中。有立即、直接和寄存器3种寻址方式
(5)&查表指令
这组指令的功能是对存放于程序存储器中的数据表格进行查找传送,使用变址寻址方式:
MOVC&&A,&@A+DPTR &&;((A)+(DPTR))→(A)
MOVC&&A,&@A+PC& &&;((PC))+1→(PC),((A)+(PC))→(A)&
(6)&累加器A与片外数据存储器RAM传送指令
&这组指令的作用是累加器A与片外RAM间的数据传送。使用寄存器寻址方式:
&MOVX&&@DPTR,&A& &&;(A)→((DPTR))
&MOVX&&A,&&@DPTR& &&;((DPTR))→(A)
&MOVX&&A,&&@Rj& &&;((Rj))→(A)
&MOVX&&@Rj,A&& &&;(A)→((Rj))
(7)16位数据传送指令
这条指令的功能是把16位常数送入数据指针寄存器。
MOV&&DPTR,&#data16 &&;&dataH→(DPH),dataL→(DPL)
2.&交换指令
MOV指令主要完成从一处到另一处的拷贝,XCH指令则可实现数据的双向传送。所有的操作都涉及到累加器A,可以把把累加器A中的内容与源操作数所指的数据相互交换。
XCH&&A,&direct&& ;(A)←→(direct)
XCH&&A,&Ri& ;(A)←→(Ri)
XCH&&A,&@Rj&&& ;(A)←→((Rj))
XCHD&&A,&@Rj&& ;(A3-0)←→((Rj)3-0)
SWAP&&A&&&&&& ;(A3-0)←→(A7-4)
3.&入栈/出栈指令
这类指令的作用是把直接寻址单元的内容传送到堆栈指针SP所指的单元中,以及把SP所指单元的内容送到直接寻址单元中。
⑴&PUSH指令
堆栈的入栈指令,该指令可以把某片内RAM单元(低128字节)或某专用寄存器的内容入栈。
PUSH&direct&&&&& ;(SP)+1→(SP),(direct)→(SP)
⑵&POP指令
堆栈的出栈指令,该指令用于恢复某片内RAM单元(低128字节)或某专用寄存器的内容。
POP&direct&&&&& ;(SP)→(direct),(SP)-1→(SP) 二、算术运算指令
在51系列的指令系统中,提供了完备的加、减、乘、除算术运算指令及增量(加1)、减量(减1)运算,可处理不带符号或带符号的8/16二进制数。除加1和减1指令外,算术运算指令会影响进位、半进位和溢出位三个标志位。
1.&不带进位的加法指令
这组指令的作用是把立即数,直接地址、工作寄存器及间接地址内容与累加器A的内容相加,运算结果存在A中。
ADD&&A,&#data& ;(A)+&data→(A)&
ADD&&A,&(A)+(direct)→(A)
ADD&&A,&R(A)+(Ri)→(A)&
ADD&&A,&@R(A)+((Rj))→(A)
本组指令的执行将影响标志位AC、CY、OV、P。当和的第3、7位有进位时,分别将AC,CY标志位置位;否则复位。对于无符号数,进位标志位CY=1,表示溢出;CY=0表示无溢出。带符号数运算的溢出取决于第6、7位,若这2位中有一位产生进位,而另一位不产生进位,则溢出标志位OV置位,否则被复位。
2.&带进位加法指令
这组指令的作用是把立即数,直接地址、工作寄存器及间接地址内容与累加器A的内容以及进位位C相加,运算结果存在A中。
本组指令执行对标志位AC、CY、OV、P的影响与ADD指令相同。
3.&增量指令
这组指令的的功能均为原寄存器的内容加1,结果送回原寄存器。这组指令共有直接、寄存器、寄存器间接寻址等寻址方式:
INC&&A& ;(A)+1→(A)
INC&&direct& ;(direct)+1→(direct)
INC&&Ri& ;(Rn)+1→(Ri)
INC&&@Rj&& ;((Rj))+1→((Rj))&
INC&&DPTR& ;(DPTR)+1→(DPTR)
增量指令不会对任何标志有影响。
4.&带借位减法指令
这组指令包含立即数、直接地址、间接地址及工作寄存器与累加器A连同借位位C内容相减,结果送回累加器A中。
SUBB&&A,&#data&& ;(A)-&data&-(C)→(A)&
SUBB&&A,&direct&& ;(A)-(direct)&-&(C)→(A)
SUBB&&A,&Ri&&& ;(A)-(Ri)&-(C)→(A)&
SUBB&&A,&@Rj&& ;(A)-((Rj))&-(C)→(A)&
本指令执行将影响标志位AC、CY、OV、P。若第七位有借位,则将CY置位,否则CY复位。若第3位有错位,则置位辅助进位标志AC,否则&AC复位。若第7和第6位中有一位需借位,而另一位不借位,则置位溢出标志OV。
当在进行单字节或多字节减法前,不知道进位标志位CY的值,则应在减法指令前先将CY复位清“0”。
5.&减量指令
这组指令的作用是把所指的寄存器内容减1,结果送回原寄存器,这组指令共有直接、寄存器、寄存器间接寻址等寻址方式:
DEC&&A &&;(A)-1→(A)
DEC&&direct& &&;(direct)-1→(direct)
DEC&&Ri&& &;(Ri)-1→(Ri)
DEC&&@Rj& &;((Rj))-1→((Rj))
运算结果不影响任何标志位。
6.&乘法指令
这条指令的作用是把累加器A和寄存器B中的8位无符号数相乘,所得到的是16位乘积,这个结果低8位存在累加器A,而高8位存在寄存器B中。
&MUL&&AB ;(A)×(B)→(B)和(A)
乘法指令需要4个机器周期。
如果乘积大于255(0FFH),即B的内容不为0时,则置位溢出标志位OV,否则OV复位。进位标志位CY总是复位为0。
7.&除法指令
这条指令的作用是把累加器A的8位无符号整数除以寄存器B中的8位无符号整数,所得到的商存在累加器A,而余数存在寄存器B中。
DIV&&AB&&&&&&&;(A)÷(B)→(A)和(B)
除法指令需要4个机器周期。
本指令总是将CY和OV标志位复位。当除数(B中内容)为00H时,那么执行结果将为不定值,则置位溢出标志位OV。
8.&十进制调整指令
在进行BCD码运算时,这条指令总是跟在ADD或ADDC指令之后,其功能是将执行加法运算后存于累加器A中的结果进行调整和修正。
&DA&&A 三、逻辑运算指令
在51系列单片机的指令系统中提供的逻辑运算指令主要包括ANL(与),ORL(或),XRL(异或)等指令。
1.&逻辑与指令ANL
这组指令的功能是在指出的变量之间以位为基础的逻辑与操作。操作数有寄存器寻址、直接寻址、寄存器间接寻址和立即寻址等寻址方式:
ANL&&A,&#data&&&&;(A)∧&data&→(A)
ANL&&A,&direct &;(A)∧&(direct)&→(A)
ANL&&A,&Ri &;(A)∧&(Ri)→(A)
ANL&&A,&@Rj &;(A)∧&((Rj))→(A)
ANL&&direct,&#data &;(direct)∧&data&→(direct)
ANL&&direct,&A& &;(direct)∧&(A)&→(A)
2.&逻辑或指令ORL
这组指令的功能是在所指出的变量之间执行以位为基础的逻辑或操作,结果存到目的变量中去。操作数有立即寻址、直接寻址、寄存器寻址和寄存器间接寻址方式:
3.&逻辑异或指令XRL
这组指令的功能是在所指出的变量之间执行以位为基础的逻辑异或操作,结果存放到目的变量中去。操作数有立即寻址、直接寻址、寄存器寻址和寄存器间接寻址方式:
4.&循环移位指令
这4条指令的作用是将累加器中的内容循环左或右移一位,后两条指令是连同进位位CY一起移位。
RL&&A& ;&累加器A中的内容左移一位。
RR&&A&& ;&累加器A中的内容右移一位。
RLC&&A&& ;&累加器A中的内容连同进位位CY左移一位。
RRC&&A& ;&累加器A中的内容连同进位位CY右移一位。
5.&求反指令
这条指令将累加器中的内容按位取反。
CPL&&A& ;&累加器中的内容按位取反。
6.&清零指令
这条指令将累加器中的内容清0。
CLR&&A&& ;&0→(A),累加器中的内容清0。 四、位操作类指令
MCS-51单片机内部有一个布尔处理机,对位地址空间具有丰富的位操作指令。
1.&位传送指令
&这2条指令的功能是把由源操作数指出的布尔变量送到目的操作数指定的位中去。其中一个操作数必须为进位标志,另一个可以是任何直接寻址位。&
MOV&&C,&bit&&& ;&bit→CY,某位数据送CY。
MOV&&bit,&C&& ;&CY→bit,CY数据送某位。&
本组指令不影响其他寄存器和标志位。
2.&位变量修改指令
这些指令对CY及可寻址位进行置位或复位操作
CLR&&C&& ;&0→CY,复位CY。
CLR&&bit&& ;&0→bit,复位某一位。
SETB&&C&& ;&1→CY,置位CY。
SETB&&bit&&& ;&1→bit,置位某一位。&&
本组指令不影响其他标志。
3.&位变量逻辑指令
位运算都是逻辑运算,有与、或、非三种指令
ANL&&C,bit&& &;&(CY)∧(bit)→CY
ANL&&C,&/bit&&&&&;&(CY)∧()→CY
ORL&&C,bit&& &;&(CY)∨(bit)→CY
ORL&&C,/bit&&& &;&(CY)∧()→CY
CPL&&C&&&& &;&()→CY
CPL&&bit&&&&& &;&()→bit
4.&位变量条件转移指令
位变量条件转移指令是以位的状态作为实现程序转移的判断条件:
JC&&rel&& ;&(CY)=1转移,(PC)+2+rel→PC,否则程序往下执行,(PC)+2→PC。
JNC&&rel&& &;&(CY)=0转移,(PC)+2+rel→PC,否则程序往下执行,(PC)+2→PC。
JB&&bit,&rel& &;位状态为1转移。
JNB&&bit,&rel&&&;位状态为0转移。
JBC&&bit,&rel&&& &;位状态为1转移,并使该位清“0”。 五、控制转移指令
一般情况下指令是顺序执行的逐条执行的,但实际上程序不可能全部顺序执行而经常需要改变程序的执行流程,常用的控制转移指令有:
1.&无条件转移指令
这组指令执行完后,程序就会无条件转移到指令所指向的地址上去。长转移指令访问的程序存储器空间为16地址64kB,绝对转移指令访问的程序存储器空间为11位地址2kB空间。
LJMP&&addr16&& ;&addr16→(PC)
AJMP&&addr11& ;(PC)+2→(PC),addr11→(PC10-0)
SJMP&&rel&& & ;(PC)+&2&+&rel→(PC)
JMP&&@A+DPTR&&;(A)+(DPTR)→(PC)
2.&条件转移指令
条件转移指令是依某种特定条件转移的指令。条件满足时转移(相当于一条相对转移指令),条件不满足时则顺序执行下面的指令。目的地址在下一条指令的起始地址为中心的256个字节范围中(-128~+127)。当条件满足时,先把PC指向指向下一条指令的第一个字节地址,再把有符号的相对偏移量加到PC上,计算出转向地址。
JZ&&rel&&&& & ;&A=0,(PC)+&2&+&rel→(PC)
JNZ&&rel&& ;&A≠0,(PC)+&2&+&rel→(PC)
3.&比较不相等转移指令
这组指令的功能是比较前面两个操作数的大小。如果它们的值不相等则转移。在PC指向下一条指令的起始地址后,通过把指令最后一个字节的有符号的相对偏移量加到PC上,并计算出转向地址。操作数有寄存器寻址、直接寻址,寄存器间接寻址和立即寻址等方式。
CJNE&&A,&direct,&rel&& ;&A≠(direct),(PC)+&3&+&rel→(PC)
CJNE&&A,&#data,&rel& ;&A≠data,(PC)+&3&+&rel→(PC)
CJNE&&Ri,&#data,&rel&& ;&A≠data,(PC)+&3&+&rel→(PC)
CJNE&&@Rj,&#data,&rel& ;&A≠data,(PC)+&3&+&rel→(PC)
4.&减1不为0转移指令
这组指令把源操作数减1,结果回送到源操作数中去,如果结果不为0则转移,跳到标号rel处执行,等于0就执行下一条指令。源操作数有寄存器寻址和直接寻址方式。该指令通常用于实现循环计数。
&DJNZ&&Ri,&rel&&&&&&;(Ri)-1→(Ri),(Ri)≠0,(PC)+&2&+&rel→(PC)
DJNZ&direct,&rel&&&&;(direct)-1→(direct),(direct)≠0,(PC)+&2&+&rel→(PC)
5.&子程序返回指令
编程时一般都把需要反复执行的一些程序编写成子程序,当需要用它们时,就用一个调用命令使程序按调用的地址去执行,这就需要子程序的调用指令和返回指令。
LCALL&&addr16 ;长调用指令,可在64kB空间调用子程序。此时(PC)+&3→(PC),(SP)+&1→(SP),(PC7-0)→(SP),(SP)+&1→(SP),(PC15-8)→(SP),addr16→(PC),即分别从堆栈中弹出调用子程序时压入的返回地址。
ACALL&&addr11& ;绝对调用指令,可在2kB空间调用子程序,此时(PC)+&2→(PC),(SP)+&1→(SP),(PC7-0)→(SP),(SP)+&1→(SP),(PC15-8)→(SP),addr11→(PC10-0)。
RET&& &;&子程序返回指令。此时(SP)→(PC15-8),(SP)-&1→(SP),(SP)→(PC7-0),(SP)-&1→(SP)RET指令通常安排在子程序的末尾,使程序能从子程序返回到主程序。
RETI& &;&中断返回指令,除具有RET功能外,还具有恢复中断逻辑的功能,需注意的是,RETI指令不能用RET代替&。&&&
空操作也是CPU控制指令,它没有使程序转移的功能,一般用于软件延时。指令为:NOP
上一篇:下一篇:
看过《单片机的指令系统》的人还看了以下文章:
Powered by &
这里是—这里可以学习 —这里是。
栏目导航:豆丁微信公众号
君,已阅读到文档的结尾了呢~~
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
子程序的调用和返回指令
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='http://www.docin.com/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口KEIL调试运行到调用子程序的指令后,没有跳到子程序里? - 单片机/MCU论坛 -
中国电子技术论坛 -
最好最受欢迎电子论坛!
后使用快捷导航没有帐号?
KEIL调试运行到调用子程序的指令后,没有跳到子程序里?
20:40:34  
我在用KEIL调试汇编语言时遇到一个问题,在用单步调试运行到调用子程序的指令后,没有跳到子程序里,这样导致了我无法看到子程序内各条指令的执行情况。那位大侠知道怎么解决,望不吝赐教。
Keil单步调试有3种:Step(F11)、Step Over(F10)、Step Out(Ctrl+F11)。Step是真正的单步,遇到函数调用会进入函数内部执行。Step Over是执行一条语句,如果这条语句是个函数调用,则整个被调用的函数全部执行完,效果相当于在下一条语句前设置断点。StepOut是从一个函数中跳出,效果相当于全速运行,遇到“return”等函数指令后停止,如果一直没遇到就会一直运行。
如果你用Step Over,就会出现你说的情况。请使用Step单步调试。如果不是这个原因,可以把代码或者工程贴出来,看看是你软件的问题还是代码的问题
20:40:35  
Keil单步调试有3种:Step(F11)、Step Over(F10)、Step Out(Ctrl+F11)。Step是真正的单步,遇到函数调用会进入函数内部执行。Step Over是执行一条语句,如果这条语句是个函数调用,则整个被调用的函数全部执行完,效果相当于在下一条语句前设置断点。StepOut是从一个函数中跳出,效果相当于全速运行,遇到“return”等函数指令后停止,如果一直没遇到就会一直运行。
如果你用Step Over,就会出现你说的情况。请使用Step单步调试。如果不是这个原因,可以把代码或者工程贴出来,看看是你软件的问题还是代码的问题
22:31:06  
可能是子程序条件不成立,可以查看寄存器是否符合条件;也可能是单步默认调试模式直接把子程序执行完并返回原点,设置中断点可以解决,或者试下F10、F11单步总有一个行
09:19:42  
Keil单步调试有3种:Step(F11)、Step Over(F10)、Step Out(Ctrl+F11)。Step是真正的单步,遇到函数调用会进入函数内部执行。Step Over是执行一条语句,如果这条语句是个函数调用,则整个被调用的函数全部执行完,效果相当于在下一条语句前设置断点。StepOut是从一个函数中跳出,效果相当于全速运行,遇到“return”等函数指 ...
果真如此,谢谢,问题解决了。分给了你了,因为你的回答比另一个的更详细,易懂
Powered by
供应链服务
版权所有 (C) 深圳华强聚丰电子科技有限公司当没有循环指令,单片机执行到最后一条命令时,是停在此处,还是从头再来。_百度知道
当没有循环指令,单片机执行到最后一条命令时,是停在此处,还是从头再来。
书上说单片机工作时,程序计数器PC的内容自动加1指向ROM下一单元内容。只有当有跳转,或中断时改变PC的值。在STC
用编程语言编程时 ,当没有循环指令,单片机执行到最后一条命令时,是停在此处,还是从头再来。
我的 是从头再来呢
我有更好的答案
没有真正遇到过,只能分析了,我的结论是从头开始循环,分析如下:PC的工作原理是取当前指令,根据当前指令进行PC赋值,遇到跳转、子程序调用、堆栈恢复指令时,PC被这些绝对目的地址(当然也有相对指令,这里暂时忽略)进行赋值;否则依据当前指令逐字节读取指令内容。(我是这样理解的,可以看下相应片子的数据手册)另外,PC也是寄存器,也执行加法及进位操作,加法时满足寄存器加法的普遍方式:加法结果超过寄存器最大表示范围时,结果溢出,也就是进位位被忽略了。这样在您的程序执行到ROM的最后(不是程序的最后)一条指令时(虽然您可能没有有意识地在这个位置编制代码,但ROM中这个位置还是有值的,根据烧入器的设置,程序之外的ROM可以选择FF、00等,或者人为充填其他内容),芯片首先将FF、00、或其他内容作为指令进行处理,同时依照以上规则,进行PC赋值,如果内容被理解成非跳转指令,则PC的值在FFFF之后在进行累加,这样产生溢出,可能新值为0000,这样程序就从0000地址开始执行了。很长时间不摸单片机了,参考一下吧。其实自己用仿真器试试就行了。
采纳率:51%
程序跑到最后,你不控制下当然是继续向下跑了,而下边空着的程序段,一般编译器都给弄成00写片,是NOP,跑到最后,PC到FFFF再跑就又从0000开始了,跟RESET一样。
停在此处!你的会从头再来可能是你在程序中写有上电复位
为您推荐:
其他类似问题
从头再来的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。单片机调用中断服务子程序和调用子程序的区别是什么?
单片机调用中断服务子程序和调用子程序的区别是什么?
09-11-01 &
基于51单片机中断跳出指令“RETI”浅议&   最近在基于51单片机编程的过程中出现了个很奇怪的问题“程序执行中在寄存器EA=1,ET0=1,TR0=1条件下,单TF0=1时并没有执行中断”。在有过单片机中断编程经历者都知道当EA=1,ET0=1的条件下,满足TF0=1时,如果在此期间没有更高优先级的中断执行的情况下定时器中断0必定会产生中断响应。而在我所编写的程序中仅使用了定时器中断0,一个中断也就谈不上存在优先级问题。经过我对自己程序的检查并对各教材中断程序对比发现我的程序中的一个问题:由于中断的不可控性决定其跳出中断返回主程序的不确定,而由于程序需要中断跳出后能跳到指定的地址。为了解决这个问题我在中断结束的地方直接用了无条件跳转指令“LJMPADR16”其中ADR16是我想在中断结束后程序所运行的地址,而没有经过指令“RETI”。问题找到了这就意味着我的程序和其他程序不同的地方就是没有执行“RETI”而直接跳出。/p&   为了解决问题所在我查阅了很多单片机方面的资料,教材。几乎所有的教材对指令“RETI”的作用千篇一律都是:“中断程序完成后,一定要执行一条RETI指令,执行这条指令后,CPU将会把堆栈中保存着的地址取出,送回PC,那么程序就会从主程序的中断处继续往下执行了。”如果“RETI”的作用仅仅在于“把堆栈中保存着的地址取出送回PC”;那么我用指令“POPDPH”和“POPDPL”两条指令取代其做用不就可以达到同样的推出地址的效果么?这样可以解决由于只有进堆栈指令(硬件自动生成)没有出堆栈所导致的堆栈溢出错误,但是并不能解决文章开始所提到的“进不了中断”问题。这让我更加相信书上所介绍的关于指令“RETI”作用并不完全。经过查阅各种资料文献,我发现了个以往在介绍单片机硬件,以及寄存器上教材,老师,没有提及的“‘优先级生效’触发器“的概念。资料指出“根据8051的结构特点,其中断系统中含有两个不可寻址的“优先级生效”触发器。一个用于指出CPU是否正在执行高优先级的中断服务程序,这个触发器为1时,系统将屏蔽所有的中断请求;另一个则指出CPU是否正在执行低优先级中断服务程序,该触发器为1时,将阻止除高优先级以外的一切中断请求。由此可见,若要响应同级甚至是低级中断请求,必须使得该“优先级生效”触发器清零。但该触发器又是不可寻址的,所以无法用软件直接清零。”问题是不是在这里呢?而“优先级生效”触发器清零过程是怎样执行的呢?是在硬件自动执行的那么是在什么时候执行的呢?带着问题我去解决问题。假设我可以将程序满足跳出中断后跳到自己原来指定地址“ADR16”又满足执行指令“RETI”。经过反复思考我用“DEC SP”;“DEC SP”;“MOVDPTR,#ADR16”;“PUSHDPL”;“PUSHDPL”“PUSHDPH”四条指令代替,问题得到了解决。/p&   总结:中断指令“RETI”做为中断跳出指令除了将堆栈中保存着的地址取出,送回PC;使程序从主程序的中断处继续往下执行。的作用外还有将“优先级生效”触发器清零。自己做的程序也是出现了这个错误,由于对“优先级生效”触发器清零,导致第二次进不了中断(相当于同优先级申请)。/p&  后记:在解决这个问题时候我所用的知识是课本上的,而又不完全是课本上的。在这个过程中我用已学的知识解决了自己的问题,并进一步推出中断过程的一些新的知识,我认为新知识的学习有很大程度的要靠自己在已学过知识的基础上通过运用,总结,推导等过程获得新知识。着也是当代大学生运用知识,获取新知识的一种能力。/p
请登录后再发表评论!
在Linux操作系统下有3类主要的设备文件类型:块设备、字符设备和网络设备。这种分类方法可以将控制输入/输出设备的驱动程序与其他操作系统软件分离开来。 字符设备与块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般紧接着发生。块设备则不然,它利用一块系统内存作为缓冲区,若用户进程对设备的请求能满足用户的要求,就返回请求的数据;否则,就调用请求函数来进行实际的I/O操作。块设备主要是针对磁盘等慢速设备设计的,以免耗费过多的CPU时间用来等待。网络设备可以通过BSD套接口访问数据。 每个设备文件都有其文件属性(c/b),表示是字符设备还是块设备。另外每个文件都有2个设备号,第一个是主设备号,标识驱动程序;第二个是从设备号,标识使用同一个设备驱动程序的、不同的硬件设备。设备文件的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问驱动程序。 系统调用时操作系统内核与应用程序之间的接口,设备驱动程序是操作系统内核与机器硬件之间的接口。设备驱动程序是内核的一部分,它完成以下功能: *对设备初始化和释放 *把数据从内核传送到硬件和从硬件读取数据 *读取应用程序传送给设备文件的数据和回送应用程序请求的数据 *检测和处理设备出现的错误 MTD(Memory Technology Device)设备是闪存芯片、小型闪存卡、记忆棒之类的设备,它们在嵌入式设备中的使用正在不断增加。MTD驱动程序是在Linux下专门为嵌入式环境开发的新的一类驱动程序。相对于常规块设备驱动程序,使用MTD驱动程序的优点在于他们能更好的支持、管理给予闪存设备,有基于扇区的擦除和读/写操作的更好的接口。 驱动程序结构 Linux的设备驱动程序可以分为3个主要组成部分: 1. 自动配置和初始化子程序,负责监测所要驱动的硬件设备是否存在和能否正常工作。如果该设备正常,则对这个设备及其相关的设备驱动程序需要的软件状态进行初始化。这部分驱动程序仅在初始化时被调用一次。 2. 服务于I/O请求的子程序,又称为驱动程序的上半部分。调用这部分程序是由于系统调用的结果。这部分程序在执行时,系统仍认为是与进行调用的进程属于同一个进程,只是由用户态变成了核心态,具有进行此系统调用的用户程序的运行环境,因而可以在其中调用sleep()等与进行运行环境有关的函数。 3. 中断服务子程序,又称为驱动程序的下半部分。在Linux系统中,并不是直接从中断向量表中调用设备驱动程序的中断服务子程序,而是由Linux系统来接收硬件中断,再由系统调用中断服务子程序。中断可以在任何一个进程运行时产生,因而在中断服务程序被调用时,不能依赖于任何进程的状态,也就不能调用任何与进程运行环境有关的函数。因为设备驱动程序一般支持同一类型的若干设备,所以一般在系统调用中断服务子程序时,都带有一个或多个参数,以唯一标识请求服务的设备。 在系统内部,I/O设备的存/取通过一组固定的入口点来进行,这组入口点是由每个设备的驱动程序提供的。具体到Linux系统,设备驱动程序所提供的这组入口点由一个文件操作结构来向系统进行说明。file_operation结构定义于linux/fs.h文件中。 struct file_operation{int (*lseek)(struct inode *inode, struct file *filp, off_t off, int pos);int (*read)(struct inode *inode, struct file *filp, char *buf, int count);int (*write)(struct inode *inode, struct file *filp, const char *buf, int count);int (*readdir)(struct inode *inode, struct file *filp, struct dirent *dirent, int count);int (*select)(struct inode *inode, struct file *filp, int sel_type, select_table *wait);int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned int arg);int (*mmap)(void);int (*open)(struct inode *inode, struct file *filp);int (*release)(struct inode *inode, struct file *filp);int (*fasync)(struct inode *inode, struct file *filp);}; file_operation结构中的成员几乎全部是函数指针,所以实质上就是函数跳转表。每个进程对设备的操作都会根据major、minor设备号,转换成对file_operation结构的访问。 常用的操作包括以下几种: *lseek, 移动文件指针的位置,只能用于可以随机存取的设备。 *read, 进行读操作,参数buf为存放读取结果的缓冲区,count为所要读取的数据长度。返回值为负表示读取操作发生错误;否则,返回实际读取的字节数。对于字符型,要求读取的字节数和返回的实际读取字节数都必须是inode-i_blksize的倍数。 *write, 进行写操作,与read类似 *readdir, 取得下一个目录入口点,只有与文件系统相关的设备程序才使用。 *select, 进行选择操作。如果驱动程序没有提供select入口,select操作会认为设备已经准备好进行任何I/O操作。 *ioctl, 进行读、写以外的其他操作,参数cmd为自定义的命令 *mmap, 用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用 *open, 打开设备准备进行I/O操作。返回0表示打开成功,返回负数表示失败。如果驱动程序没有提供open入口,则只要/dev/driver文件存在就认为打开成功。 *release, 即close操作。 在用户自己的驱动程序中,首先要根据驱动程序的功能,完成file_operation结构中函数实现。不需要的函数接口可以直接在file_operation结构中初始化为NULL。file_operation变量会在驱动程序初始化时注册到系统内部。当操作系统对设备操作时,会调用驱动程序注册的file_operation结构中的函数指针。 Linux对中断的处理 在Linux系统里,对中断的处理是属于系统核心部分,因而如果设别与系统之间以中断方式进行数据交换,就必须把该设备的驱动程序作为系统核心的一部分。设备驱动程序通过调用request_irq函数来申请中断,通过free_irq来释放中断。它们被定义为: #include int request_irq(unsigned int irq, void (*handler)(int irq, void dev_id, struct pt_regs *regs),unsigned long flags,const char *device,void *dev_id);void free_irq(unsigned int irq, void *dev_id); 参数irq表示所要申请的硬件中断号;handler为向系统登记的中断处理子程序,中断产生时由系统来调用,调用时所带参数irq为中断号;dev_id为申请时告诉系统的设备标识;regs为中断发生时的寄存器内容;device为设备名,将会出现在/proc/interrupts文件里;flag是申请时的选项,它决定中断处理程序的一些特性,其中最重要的是中断处理程序是快速处理程序还是慢速处理程序。快速处理程序运行时,所有中断都被屏蔽,而慢速处理程序运行时,除了正在处理的中断外,其他中断都没有被屏蔽。在Linux系统中,中断可以被不同的中断处理程序共享。 作为系统核心的一部分,设备驱动程序在申请和释放内存时不是调用malloc和free,而代之以调用kmalloc和kfree,它们被定义为: #include void *kmalloc(unsigned int len, int priority);void kfree(void *obj); 参数len为希望申请的字节数;obj为要释放的内存指针;priority为分配内存操作的优先级,即在没有足够空闲内存时如何操作,一般用GFP_KERNEL。
请登录后再发表评论!
简单点讲就是子程序可以在程序中通过程序人为调用,什么时候调用都可以;而中断服务程序必须由相应的中断机构来执行,不能人为调用。
请登录后再发表评论!
中断服务子程序入口地址相对某一中断是固定的,调用子程序的偏移地址是随机的,基本过程差不多,返回时,中断服务子程序用的是RETI 调用子程序是RET调用中断服务子程序和调用子程序都会把当前偏移地址的下一地址压栈,但调用子程序的返回指令RET不影响标志位,RETI从中断程序返回,并会清除内部相应的中断状态寄存器。我说的是80C51的
请登录后再发表评论!
基于51单片机中断跳出指令“RETI”浅议&   最近在基于51单片机编程的过程中出现了个很奇怪的问题“程序执行中在寄存器EA=1,ET0=1,TR0=1条件下,单TF0=1时并没有执行中断”。在有过单片机中断编程经历者都知道当EA=1,ET0=1的条件下,满足TF0=1时,如果在此期间没有更高优先级的中断执行的情况下定时器中断0必定会产生中断响应。而在我所编写的程序中仅使用了定时器中断0,一个中断也就谈不上存在优先级问题。经过我对自己程序的检查并对各教材中断程序对比发现我的程序中的一个问题:由于中断的不可控性决定其跳出中断返回主程序的不确定,而由于程序需要中断跳出后能跳到指定的地址。为了解决这个问题我在中断结束的地方直接用了无条件跳转指令“LJMPADR16”其中ADR16是我想在中断结束后程序所运行的地址,而没有经过指令“RETI”。问题找到了这就意味着我的程序和其他程序不同的地方就是没有执行“RETI”而直接跳出。/p&   为了解决问题所在我查阅了很多单片机方面的资料,教材。几乎所有的教材对指令“RETI”的作用千篇一律都是:“中断程序完成后,一定要执行一条RETI指令,执行这条指令后,CPU将会把堆栈中保存着的地址取出,送回PC,那么程序就会从主程序的中断处继续往下执行了。”如果“RETI”的作用仅仅在于“把堆栈中保存着的地址取出送回PC”;那么我用指令“POPDPH”和“POPDPL”两条指令取代其做用不就可以达到同样的推出地址的效果么?这样可以解决由于只有进堆栈指令(硬件自动生成)没有出堆栈所导致的堆栈溢出错误,但是并不能解决文章开始所提到的“进不了中断”问题。这让我更加相信书上所介绍的关于指令“RETI”作用并不完全。经过查阅各种资料文献,我发现了个以往在介绍单片机硬件,以及寄存器上教材,老师,没有提及的“‘优先级生效’触发器“的概念。资料指出“根据8051的结构特点,其中断系统中含有两个不可寻址的“优先级生效”触发器。一个用于指出CPU是否正在执行高优先级的中断服务程序,这个触发器为1时,系统将屏蔽所有的中断请求;另一个则指出CPU是否正在执行低优先级中断服务程序,该触发器为1时,将阻止除高优先级以外的一切中断请求。由此可见,若要响应同级甚至是低级中断请求,必须使得该“优先级生效”触发器清零。但该触发器又是不可寻址的,所以无法用软件直接清零。”问题是不是在这里呢?而“优先级生效”触发器清零过程是怎样执行的呢?是在硬件自动执行的那么是在什么时候执行的呢?带着问题我去解决问题。假设我可以将程序满足跳出中断后跳到自己原来指定地址“ADR16”又满足执行指令“RETI”。经过反复思考我用“DEC SP”;“DEC SP”;“MOVDPTR,#ADR16”;“PUSHDPL”;“PUSHDPL”“PUSHDPH”四条指令代替,问题得到了解决。/p&   总结:中断指令“RETI”做为中断跳出指令除了将堆栈中保存着的地址取出,送回PC;使程序从主程序的中断处继续往下执行。的作用外还有将“优先级生效”触发器清零。自己做的程序也是出现了这个错误,由于对“优先级生效”触发器清零,导致第二次进不了中断(相当于同优先级申请)。/p&  后记:在解决这个问题时候我所用的知识是课本上的,而又不完全是课本上的。在这个过程中我用已学的知识解决了自己的问题,并进一步推出中断过程的一些新的知识,我认为新知识的学习有很大程度的要靠自己在已学过知识的基础上通过运用,总结,推导等过程获得新知识。着也是当代大学生运用知识,获取新知识的一种能力。/p
请登录后再发表评论!}

我要回帖

更多关于 单片机软件工程师要求 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信