首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

51单片机总结更新

51单片机总结更新

本帖最后由 look_w 于 2017-9-23 15:47 编辑

指令理解
计算机系统中可以有多种编程语言,但硬件能够直接识别和执行的只有机器语言。只有采用翻译或解释方法把复杂的高级语言程序转换成机器语言,才能在机器硬件上直接执行来实现相应的功能。由于机器中的所有信息都是通过编码表示的,因此,指令的操作及操作的数据也必须按照一定的格式编码(约定),以便于硬件正确识别。
指令是用来指示处理器进行操作的命令,不同类型的处理器具有不同的指令系统。因为汇编是用这些指令进行编程,所以不便于移植。单片机的能力是通过指令体现的,包括了硬件能够直接实现的所有的运算或操作功能。
一款处理器都有其自己的编译器,我们写的高级程序,会由编译器生成对应的机器语言。
中断






中断寄存器,用于对中断进行控制的,例如开关总中断,必须设置相应位为1才能使用中断。
中断寄存器中也有相应的标志位,当发生中断的时候有的会置位相应的位,(所以不会自动清零的要执行中断的时候清零此标志位)单片机就会转去执行相应的中断程序。(至于如何找找中断程序,如上所示,每个中断都有一个中断入口地址,发生中断的时候,就会跳到此处执行,因为区域有限,一般此位置放的都是跳转指令,找到该位置后再跳到其他处执行程序)
矢量入口单元在编写中断程序时写入对应的“跳板指令”



中断响应
    1.响应条件
    CPU响应中断的条件有:
    ①有中断源发出中断请求;
    ②中断总允许位EA=1,即CPU开中断;
    ③申请中断的中断源的中断允许位为1;
    满足以上条件,CPU响应中断;如果中断受阻,CPU不会响应中断。
   2.响应过程
    一旦响应中断,首先置位响应的优先级触发器,然后执行一个硬件子程序调用,把断点地址压入堆栈保护,然后将对应的中断入口地址装入程序计数器PC,使程序转向该中断入口地址,以执行中断服务程序。
    :CPU响应中断结束后即转至中断服务程序的入口。从中断服务程序的第一条指令开始到返回指令为止,这个过程称为中断处理或称中断服务。中断处理包括两部分内容:一是保护现场,二是为中断源服务。
    中断返回:中断处理程序的最后一条指令是中断返回指令RETI。它的功能是将断点弹出送回PC中,使程序能返回到原来被中断的程序继续执行。



89C51中断响应过程
CPU在每个机器周期S5P2期间顺序采样每个中断源,CPU在下一个机器周期S6期间按优先级顺序查询中断标志,如查询到某个中断标志为1,将在接下来的机器周期S1期间按优先级进行中断处理,中断系统通过硬件自动将相应的中断矢量地址装入PC,以便进入相应的中断服务程序。一旦响应中断,89C51首先置位相应的中断“优先级生效”触发器,然后由硬件执行一条长调用指令,把当前的PC值压入堆栈,以保护断点,再将相应的中断服务的入口地址送入PC,于是CPU接着从中断服务程序的入口处开始执行。对于有些中断源,CPU在响应中断后会自动清除中断标志。

定时器/计数器

1.计数的定义:


计数是指对外部事件进行计数,外部事件的发生以输入脉冲的形式表示,因此计数功能的实质就是对外来的脉冲进行计数,在单片机中对应引脚T0和T1,两个脉冲输入端。


外部输入的脉冲在负跳变时有效(即外部脉冲由1变化到0),计数器加1.

  2.定时器:

定时器是通过计数器的计数来实现的,不过此时的计数脉冲来自单片机的内部,因此定时器的实质是对内部脉冲的计数,在单片机中,每个机器周期产生一次计数脉冲,计数器加1.

启动代码

51单片机复位后马上执行STARTUP.A51文件中的启动代码,根据启动代码中的设置依次执行以下操作:

  • 内部RAM清零
  • 外部RAM清零
  • 清零分页的外部RAM
  • 初始化SMALL内存模型的可重入模拟堆栈及其堆栈指针
  • 初始化LARGE内存模型的可重入模拟堆栈及其堆栈指针
  • 初始化COMPACT内存模型的可重入模拟堆栈及其堆栈指针
  • 初始化8051单片机的硬件堆栈指针
  • 将系统控制权转交给初始化全局变量的代码,如果没有被初始化的全局变量则转交给C程序文件中的main函数。

关于启动代码的一个例子
该例子是在网上找的,写的很不错,感谢。放在此处加深理解。
汇编是从0000h开始启动,那么keil c51是如何启动main()函数的?keil c51有一个启动程序startup.a51,它总是和c程序一起编译和链接。下面看看它和main()函数是如何编译的。
//
主函数如下:
void main(void)
{
    while (1)   
这是个无条件空循环。   
    {
    }
}
把上面的main()函数编译后的汇编程序和反汇编代码整理后对照如下;


[cpp] view plain copy


  • C_C51STARTUP       SEGMENT   CODE
  • PR?main?TESTMAIN       SEGMENT CODE
  • STACK          SEGMENT   IDATA
  •                 RSEG    ?STACK
  •                 DS      1
  •                 CSEG    AT      0
  • C_STARTUP:     LJMP    STARTUP1
  • C:0x0000    020003   LJMP     STARTUP1(C:0003)
  •           RSEG    ?C_C51STARTUP
  • STARTUP1:                         ;该段程序把内存清零
  • ;          MOV     R0,#IDATALEN- 1
  • C:0x0003    787F     MOV      R0,#0x7F
  • ;          CLR     A
  • C:0x0005    E4       CLR      A
  • ;          MOV     @R0,A
  • IDATALOOP:
  • C:0x0006    F6       MOV      @R0,A
  • ;          DJNZ    R0,IDATALOOP
  • C:0x0007    D8FD     DJNZ     R0,IDATALOOP(C:0006)
  • ;          MOV     SP,#?STACK-1             ;设制CPU的堆栈起始地址
  • C:0x0009    758107   MOV      SP(0x81),#0x07
  • ;          LJMP    ?C_START
  • C:0x000C    02000F   LJMP     main(C:000F)
  •     RSEG  ?PR?main?TESTMAIN
  • main:
  • ;      void main(void)
  • C:0x000F    80FE     SJMP     main(C:000F)        ;main()函数



现在分析上面的汇编程序就会明白c51程序是如何启动的。
该程序有三个代码段;
第一个代码段C_STARTUP0x0000地址,是CPU第一条指令的入口,它只有一条长跳转指令,直接跳到第二个代码段.
第二个代码段C_C51STARTUP是可重定位的段,该程序把内存清零,然后再设置CPU的堆栈,最后跳转到main()函数.
第三个代码段就是main()函数,keil c51编译器里main()的段地址名就是C_START
返回列表