第4章 汇编语言程序设计基础 §4-1 汇编语言程序设计基本概念 §4-2 汇编语言程序设计 §4-3 C语言程序设计.

Slides:



Advertisements
Similar presentations
现代电子技术实验 ——综合实验之单片机部分
Advertisements

第四章 汇编语言程序设计 程序设计概述 一、程序设计步骤 二、程序设计方法 三、汇编语言源程序的格式
第7章 AT89S51单片机的 串行口 1.
本章内容: 中断的概念 MCS-51单片机中断系统 外部事件中断及应用
第四章 指令系统及汇编语言程序设计.
8051 指令.
第4章 MCS-51程序设计 4.1 汇编语言的格式与伪指令 4.2 汇编语言程序设计步骤 4.3 查表程序设计 4.4 循环程序设计
第四章 指令系统及汇编语言程序设计.
本章分为四节,主要介绍: 4.1 程序编制的方法和技巧 4.2 源程序的编辑和汇编 4.3 基本程序结构 4.4 常用程序举例.
项目2 2个LED发光二极管控制 知识与能力目标 熟悉单片机的I/O口功能与特性。
得技通电子 问题 1 右何者非為假指令 (1) XRL (2) EQU (3) MACRO (4) ORG.
本章小结 C51单片机指令系统概述 C51单片机寻址方式 C51单片机指令系统
单片机原理与应用.
第2章 MCS-51单片机指令系统与汇编语言程序设计
報告者:朱耿育 紀翔舜 組員:詹以群 張永傑 指導老師:梁新潁
复 习 一. 计算机中的数和编码 1. 2,10,16进制数及其之间的转换(整数) 按权展开,除x取余 2
第二部分 微机原理 第4章 汇编语言 程序设计 主讲教师:喻红.
单片机应用技术 项目一 循环彩灯装置 第6讲 指令功能及汇编语言程序设计(一) 《单片机应用技术》精品课程组 湖北职业技术学院机电工程系.
本章内容: 中断的概念 MCS-51单片机中断系统 外部事件中断及应用
第二部分 微机原理 第3章 MCS-51的 指令系统 主讲教师:喻红.
一、任务描述 二、任务分析 三、任务演示 四、相关知识 五、任务布置. 一、任务描述 二、任务分析 三、任务演示 四、相关知识 五、任务布置.
单片机应用技术 项目二 电子打铃装置 第1讲 指令功能及汇编语言 程序设计(二) 《单片机应用技术》精品课程组 湖北职业技术学院机电工程系.
第3章 AT89C51指令系统 3.1基本概念内部结构和引脚功能 指令、指令系统、机器代码
单片机原理及应用 MCS-51系列单片机的基本硬件结构 MCS-51指令系统 MCS-51单片机的系统扩展与应用.
4.A/D与D/A转换器 1).DAC0832与MCS-51接口
第2章 单片机的结构原理与 简单应用 (课时:10学时).
第八章 MCS-51与数码显示器和键盘的接口 一、MCS-51与数码显示器接口 数码显示器是单片机应用产品中最常用的廉价的输 出设备,它由8个发光二极管按一定规律排列而成, 当某一发光二极管导通时,则会被点亮,控制不同 组合的二极管导通,就能显示出各种字符。 1.显示器的结构.
本 章 重 点 单片机的简单I/O扩展 8255A可编程并口芯片 8279可编程键盘/显示器接口芯片 单片机键盘接口技术
单片机原理 单 片 机 单片机接口技术 单片机应用技术.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第三章 指令系统.
第3章 指令系统及程序设计举例 3.1 指令格式与寻址方式 一、指令格式 1. 指令 操作码 目标操作数,源操作数
第四章 汇编语言程序设计.
周国运 Keil C51应用 主 页:
第二章 Java语言基础.
逆向工程-汇编语言
CPU结构和功能.
第10章 综合实训 课题一 水温控制系统设计 一、实训目的 二、课题要求 熟悉常用温度传感器AD590的特性及接口电路的设计方法;
6.1 输入/输出 6.2 CPU与外设数据传送方式 6. 3 MCS-51中断系统 6. 4 中断应用举例
本 章 重 点 单片机的结构特点 单片机的存储器特点 I/O端口的特点 CPU时序 课时安排:3个课时.
第四章 指令系统及汇编语言程序设计.
数码管数字时钟电路的设计 1. 系统硬件电路的设计
C语言程序设计 主讲教师:陆幼利.
第3章 MCS-51指令系统 介绍MCS—51系列单片机的寻址方式 介绍MCS—51系列单片机的指令系统
第4章 80C51系列指令系统 教学目的:熟悉80C51系列单片机的寻址方式及 每一种寻址方式对应的寻址空间;掌 握每一条指令功能。
4.4 实用程序举例 延时 在程序设计过程中,有时需要程序“等待”一会儿再去处理某些事情,称之为延时。计算机延时实际就是让计算机反复执行一些空操作,这样就能起到拖延时间的作用。需要执行空操作次数的多少,取决于延时时间的长短。
教学难点: 分支程序、散转程序与子程序的设计
本章内容 MCS-51单片机指令系统的格式 MCS-51单片机寻址方式 指令系统的分析
KEIL C51的应用 C语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并具备汇编语言的功能。目前,使用C语言进行程序设计已经成为软件开发的一个主流。用C语言开发系统可以大大缩短开发周期,明显增强程序的可读性,便于改进和扩充。而针对8051的C语言日趋成熟,成为了专业化的实用高级语言。
微机原理与接口技术 微机原理与接口技术 朱华贵 2015年11月13日.
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
汽车单片机应用技术 学习情景1: 汽车空调系统的单片机控制 主讲:向楠.
单片机原理及应用 实践部分 主讲人:刘 强 四川工商学院单片机教学团队 单片机原理及应用 实践部分 主讲人:刘 强
College of Computer Science & Technology
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
四、手工汇编 完成汇编的方法有两种:手工汇编和汇编程序汇编 1.手工汇编步骤 A
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
单片机原理与应用.
3. 逻辑运算指令 A、简单逻辑操作指令 CLR A. (不影响CY、AC、 OV标志) CPL A
单片机应用技术 (C语言版) 第4章 C51程序设计入门
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
循环程序设计 在程序中包含重复执行的程序段称为循环程序设计。循环程序可以使程序结构性强、可读性好,从而大大提高了程序质量。
4.3 汇编语言程序设计 顺序程序设计 顺序程序设计是最基本的程序设计。它是按照指令排列的先后顺序依次执行,每条指令都必须执行,且只执行一遍。顺序程序设计一般比较单一、简单,常常作为复杂程序的一部分。
单片机应用技术 (C语言版) 第3章 MCS-51指令系统及 汇编程序设计
第二章 MCS-51单片机程序设计 第一章 8086程序设计 第三章 微机基本系统的设计 第四章 存贮器与接口 第五章 并行接口
上节复习(11.7) 1、定时/计数器的基本原理? 2、定时/计数器的结构组成? 3、定时/计数器的控制关系?
第4章 MCS-51汇编语言程序设计 教学基本要求: (1)、了解MCS-51汇编语言程序设计的特点;
第1章 微型计算机基础.
主讲教师:廉哲 QQ: 电话: 办公室:综合楼C318
Presentation transcript:

第4章 汇编语言程序设计基础 §4-1 汇编语言程序设计基本概念 §4-2 汇编语言程序设计 §4-3 C语言程序设计

§4-1汇编语言程序设计基本概念 一、编程步骤 1)分析问题 2)数学建模 3)确定算法 4)画程序流程图 5)确定数据结构 6)编写源程序 7)调试与修改 程序设计的原则:正确性,可靠性,易读性,易移植

二、汇编语言的格式 [ 标号段:] 操作码段 操作数段 ;注释段 标号段:可有可无 操作码段:必须有,对应51指令或伪指令 [ 标号段:] 操作码段 操作数段 ;注释段 标号段:可有可无 1.由英文字母开始的字母和数字组成(<=8个字符) 2.不能使用汇编语言定义的符号 3.只能定义一次 操作码段:必须有,对应51指令或伪指令 操作数段:寄存器,特殊功能寄存器,标号,常数,$,表达式,位地址 注释段:没有要求,用于解释

三、 伪指令(8条) 伪指令:提供给汇编用的控制指令,例如要指定程序或数 据存放的起始地址;要给一些连续存放的数据确定单元等等。 这些指令在汇编时并不产生目标代码,不影响程序的执行。 1)ORG定位伪指令 ORG nn(绝对地址(16bit)或标号) 功能:指明此语句后面的程序或数据块的起始地址。 ORG伪指令总是出现在每段源程序或数据块的开始。

功能:把字节常数或字节串存入内存ROM连续单元中。 标号区段可有可无 2)DB定义字节伪指令 [标号:] DB 字节常数或字符或表达式 功能:把字节常数或字节串存入内存ROM连续单元中。 标号区段可有可无 字节常数或字符是指一个字节数据,或用逗号分开 的字节串,或用引号括起来的ASCII码字符串。 2000H A3H ORG 2000H DB 0A3H LIST: DB 26H,03H STR: DB ‘ABC' 26H 03H 41H 42H 43H

功能:把字常数或字串存入内存ROM连续单元 中。 注意:先存放高8位(低地址),再存放低8 位。 3)DW定义字伪指令 [标号:] DW 字或字串 功能:把字常数或字串存入内存ROM连续单元 中。 注意:先存放高8位(低地址),再存放低8 位。 ORG 1500H TABLE:DW 7234H,8AH,10H (1500H)=72H (1501H)=34H (1502H)=00H (1503H)=8AH (1504H)=00H (1505H)=10H

4)BIT定义位地址符号伪指令 字符名称 BIT 位地址 功能:将BIT之后的位地址赋值给字符名称。 注意:字符名称与标号不同(其后没有“:”), 但是必须的。 5)END汇编结束伪指令 [标号:] END [地址或标号] 功能:通知汇编程序结束汇编,放在程序末尾,只 有一个。 其中标号以及操作数字段的地址或标号不是必要的。

6)EQU赋值伪指令 字符名称 EQU 操作数(数或汇编符号) 功能:将数或汇编符号赋给用户定义的字符。 EQU赋过值的标号名可以用作数据地址、代码地址、 位地址或立即数(8bit/16bit)。 EQU应放在程序开头,先赋值再使用。 如: AA EQU R1 BB EQU ADD

7)DATA数据地址赋值命令 格式:字符名称 DATA 表达式 功能:将数据地址或代码地址赋值给用户定义的字符 可以先使用,后赋值 DATA只能将数据赋给字符名,EQU可以把符号赋给 字符名 可把可求值的表达式赋给字符名

8)DS定义存储空间伪指令 DS 表达式 功能:在汇编时,从指定地址开始保留DS之后“表 达式”的值所规定的存储单元。一般与ORG连用。 注意:只对程序存储器(ROM)起作用。

例:写出下列程序段中的数据在内存中的存放形式: ORG 0100H DS 02H DB 0A3H,78H,‘ABC’ DW 8EH,17H,5632H ROM:0100H ?? 0107H 00H 0101H ?? 0108H 8EH 0102H A3H 0109H 00H 0103H 78H 010AH 17H 0104H 41H ‘A’ 010BH 56H 0105H 42H ‘B’ 010CH 32H 0106H 43H ‘C’

四、 汇编语言程序的基本结构 1)顺序结构 顺序程序是最简单的程序结构,也称为直线程 序。这种程序中既无分支、循环,也不调用子程序, 程序按顺序逐一执行指令。 2)分支结构 分支程序是通过条件转移指令实现的,即根据条 件对程序的执行进行判断,若满足条件,则进行程 序转移;若不满足条件,就顺序执行程序。

3)循环结构 循环程序是最常见的程序组织方式,在程序运行时, 有时需要连续重复执行某段程序,这时可以使用循环程 序。这种设计方法可大大简化程序。 循环程序的结构一般包括如下几个部分: (1)置循环初值 (2)循环体 (3)修改控制变量 (4)循环控制部分 4)子程序结构

编程技巧: 采用循环结构和子程序 少用无条件转移指令 保护现场(通用子程序) 处理好中断(断点保护) 累加器是信息传递的枢纽,用A传递入口及返回参数

§4-2 汇编语言程序设计 例1)初始化,要求R0~R1清0,P1口清0,R4~R5置全1,片内RAM30H单元清0 §4-2 汇编语言程序设计 一、 顺序结构程序设计 无分支、无循环、不调用子程序,指令逐条顺序执行 例1)初始化,要求R0~R1清0,P1口清0,R4~R5置全1,片内RAM30H单元清0 ORG 0000H AJMP START ORG 0030H START: MOV R0,#00H MOV R1,#00H MOV P1,#00H MOV R4,#0FFH MOV R5,#0FFH MOV 30H,#00H SJMP $ END

例2)双字节加法程序,设被加数存放于片内RAM的addr1(低位)和addr2(高位),加数存放于addr3(低位)和addr4(高位),结果存放于addr1和addr2中。 START: PUSH ACC;如果原R0、R1有用,也要保护 MOV R0,#addr1;将addr1地址值送R0 MOV R1,#addr3;将addr3地址值送R1 MOV A,@R0 ;被加数低字节内容送A ADD A,@R1 ;低字节数相加 MOV @R0,A ;低字节数和存addr1 INC R0 INC R1 ;指向高位字节 MOV A,@R0 ADDC A,@R1 ;高字节数相加 MOV @R0,A ;高字节数和存addr2 POP ACC

例3)拆字。将片内RAM20H单元内容拆成两段,每段4位,并将它们分别存入21H与22H单元中。即把压缩的BCD码变成非压缩的BCD码存储。 ORG 0100H START:MOV R0,#21H ;21H→(R0) MOV A,20H ;(20H)→A ANL A,#0FH ;A∧#0FH→A MOV @R0,A ;A→((R0)) INC R0 MOV A,20H SWAP A ;A0~3<=>A4~7 ANL A,#0FH MOV @R0,A ORG 0000H AJMP START SJMP $ END

例4)16位数求补运算。16位二进制数在R1和R0中,求补结果存放在R3和R2中。 START:MOV A,R0 ;16位数低8位送A CPL A ;求反 ADD A,#01H MOV R2,A MOV A,R1 CPL A ADDC A,#00 MOV R3,A SJMP $ END

例5)编双字节乘法(16bit×8bit)子程序,并写出主程序。 思路:被乘数放在(R4)(R3)中,乘数放(R2),结果放(R7)(R6)(R5)中 (R7)(R6)(R5)=[(R4)×28+(R3)]×(R2) =(R4)×(R2)×28+(R3)×(R2) 子程序:NFA:MOV A,R2 ;乘数→A MOV B,R3 ;被乘数低位→B MUL AB MOV R5,A MOV R6,B ;(R3)×(R2)积存于(R6)(R5) MOV A,R2 MOV B,R4 ;被乘数高位→B

ADD A,R6 ;第一次乘积的高位和第二次乘积的 低位加 MOV R6,A ;存积的次高位 MOV A,B ADDC A,#00H;积的最高位加上次高位求和的进位 MOV R7,A ;存积的最高位 RET 主程序:START: MOV R2,#0D2H MOV R3,#0D3H MOV R4,#0D4H ACALL NFA AJMP $

二进制数=百位数字×64H(100)+ 十位数字×0AH(10)+个位数字 例6)BCD码化二进制数。将片内RAM21H和20H单元中的3位压缩存放的8421BCD码,转换成二进制数,结果仍存放于21H和20H。 转换方法: 二进制数=百位数字×64H(100)+ 十位数字×0AH(10)+个位数字 ORG 0100H START: MOV SP,#60H PUSH 20H ;保护十位 PUSH 20H ;保护个位 MOV A,21H ;百位→A ANL A,#0FH MOV B,#64H MUL AB

MOV 20H,A ;低位→(20H) POP ACC ANL A,#0F0H SWAP A ;取十位数字→A的低位 MOV B,#0AH MOV 21H,B ;高位→(21H) MOV 20H,A ;低位→(20H) POP ACC ANL A,#0F0H SWAP A ;取十位数字→A的低位 MOV B,#0AH MUL AB ADD A,20H MOV 20H,A ;低位与原20H内容求和存放 MOV A,B

ADDC A,21H MOV 21H,A ;高位与原21H内容求和并+进位 POP ACC ANL A,#0FH ;取个位数字→A ADD A,20H MOV 20H,A MOV A,21H ADDC A,#00H MOV 21H,A SJMP $

二、 分支程序设计 分支结构程序是根据某种条件判断结果,决定程序 的流向。 分支程序通过条件转移指令实现,实现单分支程序 转移的指令有: JZ JNZ CJNE DJNZ JC JNC JB JNB JBC(以状态位为条件判断) 分支结构程序一般分为简单分支程序和散转程序 (并行多分支)两类。

1)简单分支程序 简单分支程序流程图 开 始 程序段 1 条件满足 ? 分支程序 2 段序程 结 束 Y N 开 始 程序段 1 条件满足 3 结 束 Y N 开 始 程序段 1 满足条件 ? 2 结 束 Y N 简单分支程序流程图

例1)比较两无符号数大小,取大数。存放于内部RAM 的addr1和addr2中的两个无符号二进制数,求其中 的大数并存放于addr3中。

START:MOV A,addr1 CJNE A,addr2,LOOP1;比较不相等则跳转 SJMP LOOP3 LOOP1:JC LOOP2 ;CY=1,(addr2)>(A) MOV addr3,A ;CY=0,(addr2)<(A) LOOP2:MOV addr3,addr2 LOOP3:SJMP $ END

例2)片内RAM ONE和TWO两个单元中存有两个无符号 数,将两者中小者存入30H单元。 ORG 0100H MOV A,ONE ;第一个数送A CJNE A,TWO,BIG SJMP STORE BIG: JC STORE MOV A,TWO STORE: MOV 30H,A SJMP $ END

例3)分段函数表达。设变量x存放在内部RAM的VAR单 元,函数值y存放在FUNC中。 1 x>0 y = 0 x=0 -1 x<0

VAR DATA 30H FUNC DATA 31H ;数据地址赋值 START:MOV A,VAR JZ COMP JNB ACC.7,POSI ;最高位为0转移 MOV A,#0FFH SJMP COMP POSI: MOV A,#01H COMP: MOV FUNC,A SJMP $ END

常使用散转指令JMP @A+DPTR实现程序的跳转操 作,其中,DPTR常存放散转地址表的首地址,累 加器A存放转移地址序号。 2)散转程序(并行多分支) ( R ) = ? 1 …… n 程序 常使用散转指令JMP @A+DPTR实现程序的跳转操 作,其中,DPTR常存放散转地址表的首地址,累 加器A存放转移地址序号。 累加器A中的内容不同,散转的入口地址也不同。

例1)散转程序。根据R3的内容转向对应处理程序,处 理程序的入口地址分别为PRG0-PRGn (n小于128) ORG 0100H PJ1: MOV A,R3 RL A MOV DPTR,#JMPTAB JMP @A+DPTR JMPTAB:AJMP PRG0 AJMP PRG1 … AJMP PRGn

循环程序:程序中含有可以重复执行的程序段,该程序段称为循环体,当满足某种条件时,可重复执行。 三、循环程序设计 循环程序:程序中含有可以重复执行的程序段,该程序段称为循环体,当满足某种条件时,可重复执行。 采用循环程序优点:可以减少指令和节省存储单元,可能使程序结构紧凑和增强可读性。 循环程序一般由五部分组成: 循环初始化 循环处理 循环修改 循环控制(DJNZ可自动修改控制循环) 循环体 循环结束

(b)先判断后处理 循环程序结构类型 (a) 先处理后判断 开 始 初始化部分 循环处理部分 循环修改部分 循环结束部分 是否继续循环 ? Y N 开 始 初始化部分 循环处理部分 循环修改部分 循环结束部分 是否继续循环 ? 结 束 Y N

例1)软件延时程序。汇编语言可根据每条指令的周期数,较准确地计算出整个程序执行所用时间。 (1)单循环 根据不同初值,实现5~513(#data=1~255)个机器周期的延时 DELAY: MOV R2,#data ;单周期指令 DELAY1: DJNZ R2,DELAY1;双周期指令 RET ;双周期

(2)双重循环 TIME: MOV R1,#0FAH;1机器周期,外循环250次 L1: MOV R0,#0FFH;1机器周期,内循环255次 W1: DJNZ R0,W1 ;2机器周期 DJNZ R1,L1 ;2机器周期 NOP ;1机器周期 RET ;2机器周期

延时时间t计算: 周期数N=1+(1+2×255+2)×250+1+1+2=128255 如果fosc=6MHz,T=2us t=N×T=128255×2=256510us=256.51ms 初值为8位二进制数,3重循环可延时1s,7重循环可延时几年。 缺点:多占CPU时间。可采用定时器延时解放CPU。

例2)单字节BCD码数乘法(累加法实现)。要求:(60H)×(61H)=(62H)(63H) ORG 0000H AJMP START ORG 0030H START: MOV 63H,#00H MOV 62H,#00H CLR A LOOP:PUSH ACC ;保护累加次数计数器 MOV A,60H ADD A,63H ;取被乘数与积的低8位加 DA A MOV 63H,A

ADDC A,62H;若低8位加产生进位,则积的高8位+1 DA A MOV 62H,A POP ACC ADD A,#01H;因为要做十进制调整,不用INC A CJNE A,61H,LOOP;与乘数比较看加够次数没有 SJMP $ END

四、 子程序设计 子程序允许嵌套。 子程序在结构上应具有通用性和独立性。 编写子程序应注意: 1)子程序第一条指令的地址(子程序的初始地址或 入口地址)前必须有标号。 2)主程序调用子程序采用调用指令,子程序返回主 程序必须执行安排在子程序末尾的RET返回指令。 3)主程序调用子程序和子程序返回主程序,计算机 能自动保护和恢复主程序的断点地址。

4)对于子程序中使用到的工作寄存器、特殊功能寄 存器、内存单元等,应在子程序的开头和末尾(RET 之前)使用相应的保护和恢复指令。 5)为使子程序能在64KBROM中任意存放并被主程序正 确调用,子程序内部必须使用相对转移指令,而不 使用其它转移指令,以便汇编时生成浮动代码。 6)子程序参数可分为入口参数和出口参数。入口参 数指子程序需要的原始参数,由调用它的主程序通 过约定的工作寄存器R0-R7、特殊功能寄存器SFR、 内存单元或堆栈等预先传送给自程序使用;出口参 数是由子程序根据入口参数执行程序后获得的结果。

(1)工作寄存器或累加器传递参数 优点:程序最简单,运算速度也最高。 缺点:工作寄存器数量有限,不能传递太多的数据; 主程序必须先把数据送到工作寄存器; 参数个数固定,不能由主程序任意改定。 例)编程实现z=x2+y2。 ;子程序名SQR,如前面查平方表的例子 ;子程序功能:求一个字节数的平方 ;子程序入口:(A)=待处理的一个字节数 ;子程序出口:(A)=该数的平方和

ORG 00H AJMP START X DATA 30H Y DATA 40H Z DATA 50H ORG 0100H START: MOV A,X ACALL SQR MOV R1,A ;X2存R1 MOV A ,Y ADD A,R1 MOV Z,A SJMP $ SQR: MOV B,A MUL AB RET END

(2)用指针寄存器来传递参数 由于数据一般存放在存贮器中,而不是工作寄存器 中,故可用指针来指示数据的位置,这样可以大大 节省传递数据的工作量,并可实现可变长度运算。 一般如参数在内部RAM中,可用R0或R1作指针。 可变长度运算时,可用一个寄存器来指出数据长度, 也可在数据中指出其长度(如使用结束标记符)。

例)将(R0)和(R1)指向的内部RAM中的两个3字节无 符号整数相加,高位字节在低地址、顺序存放,结果 送到(R0)指向的内部RAM中。 ;入口:(R0)、(R1)分别指向加数和被加数的低位字节 ;出口:(R0)指向结果的高位字节 ORG 0100H MOV R7,#3 CLR C NADD1:MOV A,@R0 ADDC A,@R1 MOV @R0,A

DEC R0 DEC R1 DJNZ R7,NADD1 INC R0 RET END

子程序按栈指针访问堆栈中的参数,同时可把结果参 数送回堆栈中。 返回主程序后,用POP指令得到这些结果参数。 优点: 简单,能传递大量参数 (3)用堆栈来传递参数 主程序用PUSH指令把参数压入堆栈中。 子程序按栈指针访问堆栈中的参数,同时可把结果参 数送回堆栈中。 返回主程序后,用POP指令得到这些结果参数。 优点: 简单,能传递大量参数 不必为特定的参数分配存贮单元。 由于参数在堆栈中,简化了中断响应时的现场保护。

§4-3 C语言程序设计 一. C语言的特点 1.语言简洁、紧凑,使用方便、灵活。 2.运算符丰富。 3.数据结构丰富。具有现代化语言的各种数据结构。 4.可进行结构化程序设计。 5.可以直接对计算机硬件进行操作。 6.生成的目标代码质量高,程序执行效率高。 7.可移植性好。 C语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并具备汇编语言的功能。目前,使用C语言进行程序设计已经成为软件开发的一个主流。用C语言开发系统可以大大缩短开发周期,明显增强程序的可读性,便于改进和扩充。而针对8051的C语言日趋成熟,成为了专业化的实用高级语言。

C语言与ASM-51汇编语言 对单片机的指令系统不要求了解,仅要求对8051 的存贮器结构有初步了解; 寄存器分配、不同存贮器的寻址及数据类型等细节可由编译器管理; 程序有规范的结构,可分成不同的函数,这种方式可使程序结构化; 提供的库包含许多标准子程序,具有较强的数据处理能力; 由于具有方便的模块化编程技术,使已编好程序可容易地移植 C语言作为一种非常方便的语言而得到广泛的支持,国内最通用的是Keil C51.

用C语言编写单片机应用程序与标准的C语言程序也有相应的区别: C51包含的数据类型、变量存储模式、输入输出处理、函数等方面与标准的C语言有一定的区别。其它的语法规则、程序结构及程序设计方法等与标准的C语言程序设计相同。

二. C51程序结构 C51的语法规定、程序结构及程序设计方法都与标准的C语言程序设计相同,但C51程序与标准的C程序在以下几个方面不一样: 1. C51中定义的库函数和标准C语言定义的库函数不同。标准的C语言定义的库函数是按通用微型计算机来定义的,而C51中的库函数是按MCS-51单片机相应情况来定义的; 2.C51中的数据类型与标准C的数据类型也有一定的区别,在C51中还增加了几种针对MCS-51单片机特有的数据类型;

3. C51变量的存储模式与标准C中变量的存储模式不一样,C51中变量的存储模式是与MCS-51单片机的存储器紧密相关;

与一般C语言的结构相同,以main()函数为程序人口,程序体中包含若干语句还可以包含若干函数。 类型 函数名(参数表) { 数据说明部分 语句执行部分 }

三. 变量 变量是在程序运行过程中其值可以改变的量。一个变量由两部分组成:变量名和变量值。 在C51中,变量在使用前必须对变量进行定义,指出变量的数据类型和存储模式。以便编译系统为它分配相应的存储单元。定义的格式如下: [存储种类] 数据类型说明符 [存储器类型] 变量名1[=初值],变量名2[初值]…; C51的运算量可以是常量也可以是变量,变量的定义的标准C的差别较大,主要涉及到存储空间

1.存储种类 存储种类是指变量在程序执行过程中的作用范围。C51变量的存储种类有四种,分别是自动(auto)、外部(extern)、静态(static)和寄存器(register)。 1).auto: 使用auto定义的变量称为自动变量,其作用范围在定义它的函数体或复合语句内部,当定义它的函数体或复合语句执行时,C51才为该变量分配内存空间,结束时占用的内存空间释放。自动变量一般分配在内存的堆栈空间中。定义变量时,如果省略存储种类,则该变量默认为自动(auto)变量。

2).extern: 使用extern定义的变量称为外部变量。在一个函数体内,要使用一个已在该函数体外或别的程序中定义过的外部变量时,该变量在该函数体内要用extern说明。外部变量被定义后分配固定的内存空间,在程序整个执行时间内都有效,直到程序结束才释放。 3).static: 使用static定义的变量称为静态变量。它又分为内部静态变量和外部静态变量。在函数体内部定义的静态变量为内部静态变量,它在对应的函数体内有效,一直存在,但在函数体外不可见,这样不仅使变量在定义它的函数体外被保护,还可以实现当离开函数时值不被改变。外部静态变量上在函数外部定义的静态变量。它在程序中一直存在,但在定义的范围之外是不可见的。如在多文件或多模块处理中,外部静态变量只在文件内部或模块内部有效。

4).register: 使用register定义的变量称为寄存器变量。它定义的变量存放在CPU内部的寄存器中,处理速度快,但数目少。C51编译器编译时能自动识别程序中使用频率最高的变量,并自动将其作为寄存器变量,用户可以无需专门声明。

2.KEIL C51编译器能够识别的基本数据类型 基本数据类型 长度 取值范围 unsigned char 1字节 0~255 -128~+127 unsigned int 2字节 0~65535 signed int -32768~+32767 unsigned long 4字节 0~4294967295 signed long -2147483648~+2147483647 float 1.175494E-38~3.402823E+38 bit 1位 0或1 sbit sfr sfr16

在C51语言程序中,有可能会出现在运算中数据类型不一致的情况。C51允许任何标准数据类型的隐式转换,隐式转换的优先级顺序如下: bitcharintlongfloat signedunsigned 也就是说,当char型与int型进行运算时,先自动对char型扩展为int型,然后与int型进行运算,运算结果为int型。C51除了支持隐式类型转换外,还可以通过强制类型转换符“()”对数据类型进行人为的强制转换。

存储器类型是用于指明变量所处的单片机的存储器区域情况。存储器类型与存储种类完全不同。C51编译器能识别的存储器类型有以下几种,见表所示。 3.存储器类型 存储器类型是用于指明变量所处的单片机的存储器区域情况。存储器类型与存储种类完全不同。C51编译器能识别的存储器类型有以下几种,见表所示。 定义变量时也可以省“存储器类型”,省时C51编译器将按编译模式默认存储器类型 存储器类型 描 述 data 直接寻址的片内RAM低128B,访问速度快 bdata 片内RAM的可位寻址区(20H~2FH),允许字节和位混合访问 idata 间接寻址访问的片内RAM,允许访问全部片内RAM pdata 用Ri间接访问的片外RAM的低256B xdata 用DPTR间接访问的片外RAM,允许访问全部64k片外RAM code 程序存储器ROM 64k空间

【例】变量定义存储种类和存储器类型相关情况。 char data varl; /*在片内RAM低128B定义用直接寻址方式访问的字符型变量var1*/ int idata var2; /*在片内RAM256B定义用间接寻址方式访问的整型变量var2*/ auto unsigned long data var3; /*在片内RAM128B定义用直接寻址方式访问的自动无符号长整型变量var3*/ extern float xdata var4; /*在片外RAM64KB空间定义用间接寻址方式访问的外部实型变量var4*/ int code var5; /*在ROM空间定义整型变量var5*/ unsign char bdata var6; /*在片内RAM位寻址区20H~2FH单元定义可字节处理和位处理的无符号字符型变量var6*/

特殊功能寄存器变量 MCS-51系列单片机片内有许多特殊功能寄存器,通过这些特殊功能寄存器可以控制MCS-51系列单片机的定时器、计数器、串口、I/O及其它功能部件,每一个特殊功能寄存器在片内RAM中都对应于一个字节单元或两个字节单元。 在C51中,允许用户对这些特殊功能寄存器进行访问,访问时须通过sfr或sfr16类型说明符进行定义,定义时须指明它们所对应的片内RAM单元的地址。格式如下: sfr或sfr16 特殊功能寄存器名=地址; 【例】特殊功能寄存器的定义。 sfr PSW=0xd0; sfr SCON=0x98; sfr P1=0x90; sfr16 DPTR=0x82; sfr16 T1=0X8A; sfr用于对MCS-51单片机中单字节的特殊功能寄存器进行定义,sfr16用于对双字节特殊功能寄存器进行定义。特殊功能寄存器名一般用大写字母表示。地址一般用直接地址形式,具体特殊功能寄存器地址见前面内容。

位变量的定义 在C51中,允许用户通过位类型符定义位变量。位类型符有两个:bit和sbit。可以定义两种位变量。 bit位类型符用于定义一般的可位处理位变量。它的格式如下:bit 位变量名; 在格式中可以加上各种修饰,但注意存储器类型只能是bdata、data、idata。只能是片内RAM的可位寻址区,严格来说只能是bdata。 【例】 bit型变量的定义。 bit data a1; /*正确*/ bit bdata a2; /*正确*/ bit pdata a3; /*错误*/ bit xdata a4; /*错误*/

【例】sbit型变量的定义: sbit OV=0xd2; sbit CY=oxd7; unsigned char bdata flag; sbit flag0=flag^0; sfr P1=0x90; sbit P1_0=P1^0; sbit P1_1=P1^1; sbit P1_2=P1^2; sbit P1_3=P1^3; sbit P1_4=P1^4; sbit P1_5=P1^5; sbit P1_6=P1^6; sbit P1_7=P1^7; sbit位类型符用于定义在可位寻址字节或特殊功能寄存器中的位,定义时须指明其位地址,可以是位直接地址,可以是可位寻址变量带位号,也可以是特殊功能寄存器名带位号。格式如下: sbit 位变量名=位地址; 如位地址为位直接地址,其取值范围为0x00~0xff;如位地址是可位寻址变量带位号或特殊功能寄存器名带位号,则在它前面须对可位寻址变量或特殊功能寄存器进行定义。字节地址与位号之间、特殊功能寄存器与位号之间一般用“^”作间隔。

在C51中,为了用户处理方便,C51编译器把MCS-51单片机的常用的特殊功能寄存器和特殊位进行了定义,放在一个“reg51 在C51中,为了用户处理方便,C51编译器把MCS-51单片机的常用的特殊功能寄存器和特殊位进行了定义,放在一个“reg51.h”或“reg52.h”的头文件中,当用户要使用时,只须要在使用之前用一条预处理命令#include <reg52.h>把这个头文件包含到程序中,然后就可使用殊功能寄存器名和特殊位名称。

四. 存储模式 C51编译器支持三种存储模式:SMALL模式、COMPACT模式和LARGE模式。不同的存储模式对变量默认的存储器类型不一样。 (1)SMALL模式。SMALL模式称为小编译模式,在SMALL模式下,编译时,函数参数和变量被默认在片内RAM中,存储器类型为data。 (2)COMPACT模式。COMPACT模式称为紧凑编译模式,在COMPACT模式下,编译时,函数参数和变量被默认在片外RAM的低256字节空间,存储器类型为pdata。 (3)LARGE模式。LARGE模式称为大编译模式,在LARGE模式下,编译时函数参数和变量被默认在片外RAM的64K字节空间,存储器类型为xdata。

程序编译时,k1变量存储器类型为data,k2变量存储器类型为pdata,而m1和m2由于定义时带了存储器类型xdata,因而它们为xdata型;函数func1的形参x1和y1的存储器类型为xdata型,而函数func2由于没有指明存储模式,隐含为SMALL模式,形参x2和y2的存储器类型为data。 在程序中变量的存储模式的指定通过#pragma预处理命令来实现。函数的存储模式可通过在函数定义时后面带存储模式说明。如果没有指定,则系统都隐含为SMALL模式。 【例】变量的存储模式。 #pragma small /*变量的存储模式为SMALL*/ char k1; int xdata m1; #pragma compact /*变量的存储模式为PDATA*/ char k2; int xdata m2; int func1(int x1,int y1) large /*函数的存储模式为LARGE*/ {return(x1+y1);} int func2(int x2,int y2) /*函数的存储模式隐含为SMALL*/ { return(x2-y2);}

五.绝对地址的访问 如何对8051片内RAM、片外RAM及I/O空间进行访问,C51提供两种常用的访问绝对地址的方法。 1.绝对宏 编译器提供了一组宏定义对code、data、pdata和xdata空间进行绝对寻址。 程序中用“#include<absacc.h>”来对absacc.h中声明的宏来访问绝对地址,包括CBYTE、CWORD、DBYTE、DWORD、XBYTE、XWORD、PBYTE、PWORD,具体使用参见absacc.h头文件。其中:

CBYTE以字节形式对code区寻址; CWORD以字形式对code区寻址; DBYTE以字节形式对data区寻址; DWORD以字形式对data区寻址; XBYTE以字节形式对xdata区寻址; XWORD以字形式对xdata区寻址; PBYTE以字节形式对pdata区寻址; PWORD以字形式对pdata区寻址。

【例】片内RAM、片外RAM及I/O定义的程序如下: #include<absacc.h> #define PORTA XBYTE[0xffc0] //将PORTA定义为外部I/O口,地址为0xffc0 #define NRAM DBYTE[0x40] //将NRAM定义为片内RAM,地址为0x40 main( ) { PORTA=0x3d; //将数据3DH写入地址为0xffc0的外部I/O端口PORTA NRAM=0x01; //将数据01H写入片内RAM的0x40单元 }

关键字 _at_ 可对指定的存储器空间的绝对地址访问, 格式如下: data unsigned char y1 _at_ 0x50; //在data区定义字节变量y1, //它的地址为50H xdata unsigned int y2 _at_ 0x4000; //在xdata区定义字变量y2,地 //址为4000H   y1=0xff;   y2=0x1234;

六.C-51的包含的头文件 通常有:reg51.h math.h ctype.h stdio.h stdlib.h absacc.h

七.C-51的运算符 与C语言基本相同: + - * / %(加 减 乘 除,求余) > >= < <= (大于 大于等于 小于 小于等于) == != (测试等于 测试不等于) && || ! (逻辑与 逻辑或 逻辑非 ) >> << (位右移 位左移) & | (按位与 按位或) ^ ~ (按位异或 按位取反)

八.C-51的基本语句 与标准C语言基本相同: if 选择语言 switch/case 多分支选择语言 while 循环语言 do-while 循环语言 for 循环语言

九.中断服务程序 函数定义的一般格式如下: 函数类型 函数名(形式参数表) [interrupt m][using n] 形式参数说明 { 局部变量定义 函数体 }

interrupt m修饰符 Interrupt是中断修饰符,其中m为中断号,取值范围为 0~31 0——外部中断0 1——定时/计数器T0 2——外部中断1 3——定时/计数器T1 4——串行口中断 5——定时/计数器T2 其它值预留。

using n修饰符 修饰符using n用于指定本函数内部使用的工作寄存器组,其中n的取 值为0~3,表示寄存器组号。 (1)加入using n后,C51在编译时自动的在函数的开始处和结束处加 入以下指令。 { PUSH PSW ;标志寄存器入栈 MOV PSW,#与寄存器组号相关的常量 …… POP PSW ;标志寄存器出栈 } (2)using n修饰符不能用于有返回值的函数,因为C51函数的返回值 是放在寄存器中的。如寄存器组改变了,返回值就会出错。

编写MCS-51中断函数注意如下: (1)中断函数不能进行参数传递,如果中断函数中包含任何参数声明都将导致编译出错。 (2)中断函数没有返回值,如果企图定义一个返回值将得不到正确的结果,建议在定义中断函数时将其定义为void类型,以明确说明没有返回值。 (3)在任何情况下都不能直接调用中断函数,否则会产生编译错误。因为中断函数的返回是由8051单片机的RETI指令完成的,RETI指令影响8051单片机的硬件中断系统。如果在没有实际中断情况下直接调用中断函数,RETI指令的操作结果会产生一个致命的错误。 (4)如果在中断函数中调用了其它函数,则被调用函数所使用的寄存器必须与中断函数相同。否则会产生不正确的结果。

(5)C51编译器对中断函数编译时会自动在程序开始和结束处加上相应的内容,具体如下:在程序开始处对ACC、B、DPH、DPL和PSW入栈,结束时出栈。中断函数未加using n修饰符的,开始时还要将R0~R1入栈,结束时出栈。如中断函数加using n修饰符,则在开始将PSW入栈后还要修改PSW中的工作寄存器组选择位。 (6)C51编译器从绝对地址8m+3处产生一个中断向量,其中m为中断号,也即interrupt后面的数字。该向量包含一个到中断函数入口地址的绝对跳转。

LOO1: MOVX @DPTR,A ;0送(DPTR) INC DPTR ;DPTR+1 DJNZ R0,LOO1 例:清零程序 (将2000H—20FFH的内容清零) ★ 汇编语言程序 ORG 0000H SE01: MOV R0,#00H MOV DPTR,#2000H ;(0000H)送DPTR CLR A LOO1: MOVX @DPTR,A ;0送(DPTR) INC DPTR ;DPTR+1 DJNZ R0,LOO1 LOOP: SJMP LOOP

清零程序 (将2000H—20FFH的内容清零) xdata unsigned char buffer[256] _at_ 0x2000; void main(void) { unsigned char i;   for(i=0; i<256; i++)   { buffer[i]=0 } }

例:查找零的个数(在2000H--200FH中查出有几个字节是零,把个数放在2100H单元中) ★ 汇编语言程序 ORG 0000H L00: MOV R0,#10H ;查找16个字节 MOV R1,#00H MOV DPTR,#2000H L11: MOVX A,@DPTR CJNE A,#00H,L16 ;取出内容与00H相等吗? INC R1 ;取出个数加1 L16: INC DPTR DJNZ R0,L11 ;未完继续 MOV DPTR,#2100H MOV A,R1 MOVX @DPTR,A ;相同数个数送2100H L1E: SJMP L1E

★查找零的个数C-51程序 #include <reg51.h> main ( ) { unsigned char xdata *p=0x2000;/*指针p指向2000H单元*/ int n=0,i; for(i=0;i<16;i++) { if(*p==0) n++; /* 若该单元内容为零,则n+1 */ p++; /* 指针指向下一单元 */ } p=0x2100; /* 指针p指向2100H单元 */ *p=n; /* 把个数放在2100H单元中 */

作业1:编程在51系列单片机内部RAM的30H~50H单元中寻找是否有0AAH数值。若有,将51H单元置为FFH;若无,将51H单元置为00H。 作业2:将R1中的2个十六进制数转换为ASCII码后存放在R3和R4中。 作业3:将单片机内部RAM地址为30H~50H单元中存放的数据传输到片外RAM的3000H开始的存储单元中。 作业4:将内部RAM从40H开始16个无符号数求和,并把求和的结果存入50H(低位),51H(高位)