第四章MCS-51汇编语言程序设计
重点及难点:
单片机汇编语言程序设计的基本概念、伪指令、单片机汇编语言程序的三种基本结构形式、常用汇编语言程序设计。
教学基本要求:
1、掌握汇编语言程序设计的基本概念;
2、掌握伪指令的格式、功能和使用方法;
3、掌握顺序结构、分支结构和循环结构程序设计的步骤和方法;
4、掌握常用汇编语言程序设计步骤和方法。
教学内容
§4.1汇编语言程序设计概述
一、汇编语言的特点
(1)助记符指令和机器指令一一对应,所以用汇编语言编写的程序效率高,占用存储空间小,运行速度快,因此汇编语言能编写出最优化的程序。
(2)使用汇编语言编程比使用高级语言困难,因为汇编语言是面向计算机的,汇编语言的程序设计人员必须对计算机硬件有相当深入的了解。
(3)汇编语言能直接访问存储器及接口电路,也能处理中断,因此汇编语言程序能够直接管理和控制硬件设备。
(4)汇编语言缺乏通用性,程序不易移植,各种计算机都有自己的汇编语言,不同计算机的汇编语言之间不能通用;但是掌握了一种计算机系统的汇编语言后,学习其他的汇编语言就不太困难了。
二、汇编语言的语句格式
[<标号>]:<操作码> [<操作数>];[<注释>]
三、汇编语言程序设计的步骤与特点
(1)建立数学模型
(2)确定算法
(3)制定程序流程图
(4)确定数据结构
(5)写出源程序
(6)上机调试程序
§4.2伪指令
伪指令是程序员发给汇编程序的命令,也称为汇编命令或汇编程序控制指令。
MCS- 51常见汇编语言程序中常用的伪指令:
第四章MCS-51汇编语言程序设计91
1.ORG (ORiGin)汇编起始地址命令
[<标号:>] ORG <地址>
2.END (END of assembly)汇编终止命令
[<标号:>] END [<表达式>]
3.EQU (EQUate)赋值命令
<字符名称> EQU <赋值项>
4.DB (Define Byte)定义字节命令
[<标号:>] DB <8位数表>
5.DW (Define Word)定义数据字命令
[<标号:>] DW <16位数表>
6.DS (Define Stonage )定义存储区命令
[<标号:>] DW <16位数表>
7.BIT位定义命令
<字符名称> BIT <位地址>
8.DA TA数据地址赋值命令
<字符名称> DATA <表达式>
§4.3单片机汇编语言程序的基本结构形式
一、顺序程序
[例4-1]三字节无符号数相加,其中被加数在内部RAM的50H、51H和52H单元中;加数在内部RAM的53H、5414和55H单元中;要求把相加之和存放在50H、51H和52H单元中,进位存放在位寻址区的00H位中。
MOV R0 ,# 52H ;被加数的低字节地址
MOV R1 ,# 55H ;加数的低字节地址
MOV A ,@ R0
ADD A ,@ R1 ;低字节相加
MOV @ R0 , A ;存低字节相加结果
DEC R0
DEC R1
MOV A ,@ R0
ADDC A ,@ R1 ;中间字节带进位相加
MOV @ R0 , A ;存中间字节相加结果
DEC R0
DEC R1
MOV A ,@ R0
ADDC A ,@ R1 ;高字节带进位相加
MOV @ R0 , A ;存高字节相加结果
CLR A
ADDC
A , # 00H ;存放进位的单元地址 MOV
@ R0 , A ;进位送00H 位保存
二、分支程序 1.单分支程序
[例4-2] 变量X 存放在V AR 单元内,函数值Y 存放在FUNC 单元中,试按下式的要求给Y 赋值。
?????<-=>=0
1000
1
X X X Y
本题的程序流程见图4-1(a )。
参考程序:
ORG 1000H
V AR DA TA 30H
FUNC DA TA 31H
MOV A , V AR
;A ← X JZ DONE
;若X=0,则转DONE JNB ACC.7 , POSI
;若X>0,则转POSI MOV A , # 0FFH
;若X<0,则Y=-1 SJMP DONE
POSI : MOV A , # 01H
;若X>0,则Y = 1 DONE : MOVE FUNC , A
;存函数值 SJMP $
END
图4-1 例4-2的分支流程图
第四章MCS-51汇编语言程序设计93
这个程序的特征是先比较判断,然后按比较结果赋值,这实际是三分支而归一的流程图,因此,至少要用两个转移指令。初学者很容易犯的一个错误是:漏掉了其中的SJMP DONE 语句,因为流程图中没有明显的转移痕迹。
这个程序也可以按图4-1(b)的流程图来编写,其特征是先赋值,后比较判断,然后修改赋值并结束。
参考程序:
ORG 1000H
V AR DA TA 30H
FUNC DA TA 31H
MOV A ,V AR ;A ←X
JZ DONE ;若X=0,则转DONE
MOV R0 ,# 0FFH ;先设X<0,R0 = FFH
JNB ACC.7 ,NEG ;若X<0,则转NEG
MOV R0 ,# 01H ;若X>0,R0 = 1 NEG:MOV A ,# 01H ;若X>0,则Y = 1
DONE:MOV FUNC , A ;存函数值
SJMP $
END
2.多分支程序
图4-2 多分支程序转移
三、循环程序
循环程序一般由4部分组成:
(1)置循环初值,即确立循环开始时的状态。
(2)循环体(工作部分),要求重复执行的部分。
(3)循环修改,循环程序必须在一定条件下结束,否则就要变成死循环。
(4)循环控制部分,根据循环结束条件,判断是否结束循环。
以上4个部分可以有两种组织方式。
[例4-3]从BLOCK单元开始存放一组无符号数,一般称为一个数据块。数据块长度放在LEN单元,编写一个求和程序,将和存入SUM单元,假设和不超过8位二进制数。
在置初值时,将数据块长度置入一个工作寄存器,将数据块首地址送入另一个工作寄存器,一般称它为数据块地址指针。每做一次加法之后,修改地址指针,以便取出下一个数来
相加,并且使计数器减1。到计数器减到0时,求和结束,把和存入SUM即可。
参考程序:各单元的地址是任意的。
LEN DA TA 20H
SUM DA TA 21H
BLOCK DA TA 22H
CLR A ;清累加器
MOV R2 ,LEN ;数据块长度送R2
MOV R1 ,# BLOCK ;数据块首址送Rl LOOP:ADD A ,@R1 ;循环做加法
INC R1 ;修改地址指针
DJNZ R2 ,LOOP ;修改计数器并判断
MOV SUM , A ;存和
以上程序在计数器初值不为零时是没有问题的,但若是数据块的长度有可能为零,则将出现问题。当R2初值为零,减1之后将为FFH,故要做256次加法之后才会停止,显然和题意不符。若考虑到这种情况,则可按图4-3(b)的方式来编写程序。在做加法之前,先判断一次R2的初值是否为零。整个程序仍基本套用原来的形式:
CLR A ;清累加器
MOV R2 ,LEN ;数据块长度送R2
MOV R1 ,# BLOCK ;数据块首址送Rl
INC R2
SJMP CHECK
LOOP:ADD A ,@R1 ;循环做加法
INC R1 ;修改地址指针CHECK:DJNZ R2 ,LOOP
MOV SUM , A ;存和
§4.4MCS-51单片机汇编语言程序设计举例
一、算术运算程序
[例4-4]假定R2、R3和R4、R5分别存放两个16位的带符号二进制数,其中R2和R4的最高位为两数的符号位。请编写带符号双字节二进制数的加减法运算程序,以BSUB为减法程序入口,以BADD为加法程序入口,以R6、R7保存运算结果。
参考程序:
BSUB:MOV A ,R4 ;取减数高字节
CPL ACC.7 ;减数符号取反以进行加法
MOV R4 , A
BADD:MOV A ,R ;取被加数
MOV C ,ACC.7
MOV F0 , C ;被加数符号保存在F0中
XRL A ,R4 ;两数高字节异或
第四章MCS-51汇编语言程序设计95
MOV C ,ACC.7 ;两数同号CY=0,两数异号CY=1
MOV A ,R2
CLR ACC.7 ;高字节符号位清“0”
MOV R2 , A ;取其数值部分
MOV A ,R4
CLR ACC.7 ;低字节符号位清“0”
MO V R4 , A ;取其数值部分
JC JIAN ;两数异号转JIAN
JIA:MOV A ,R3 ;两数同号进行加法
ADD A ,R5 ;低字节相加
MOV R7 , A ;保存和
MOV A ,R2
ADDC A ,R4 ;高字节相加
MOV R6 , A ;保存和
JB ACC.7 ,QAZ ;符号位为“1”转溢出处理QWE:MOV C ,F0 ;结果符号处理
MOV ACC.7, C
MOV R6 , A
RET
JIAN:MOV A ,R3 ;两数异号进行减法
CLR C
SUBB A ,R5 ;低字节相减
MOV R7 , A ;保存差
MOV A ,R2
SUBB A ,R4 ;高字节相减
MOV R6 , A ;保存差
JNB ACC.7 ,QWE ;判断差的符号,为“0”转QWE BMP:MOV A ,R7 ;为“1”进行低字节取补
CPL A
ADD A ,#1
MOV R7 , A
MOV A ,R6 ;高字节取补
CPL A
ADDC A ,# 0
MOV R6 , A
CPL F0 ;保存在F0中的符号取反
SJMP QWE ;转结果符号处理
QAZ: ;溢出处理
二、数制转换程序
[例4-5]在内部RAM的hex单元中存有2位十六进制数,试将其转换为ASCII码,并存放于asc和asc+1两个单元中。
主程序(MAIN):
MOV SP ,# 3FH
MAIN:PUSH hex ;十六进制数进栈
ACALL HASC ;调用转换子程序
POP asc ;第一位转换结果送asc单元
MOV A ,hex ;再取原十六进制数
SW AP A ;高低半字节交换
PUSH ACC ;交换后的十六进制数进栈
ACALL HASC
POP asc+l ;第二位转换结果送asc+l单元子程序(HASC):
HASC:DEC SP ;跨过断点保护内容
DEC SP
POP ACC ;弹出转换数据
ANL A ,# 0FH ;屏蔽高位
ADD A ,# 7 ;修改变址寄存器内容
MOVC A ,@A+PC ;查表
PUSH ACC ;查表结果进栈
INC SP ;修改堆栈指针回到断点保护内
容
INC SP
RET SP
ASCTAB:DB “0,1,2,3,4,5,6,7”;ASCII码表
DB “8,9,A,B,C,D,E,F”
三、定时程序
有多个定时需要,我们可以先设计一个基本的延时程序,使其延迟时间为各定时时间的最大公约数,然后就以此基本程序作为子程序,通过调用的方法实现所需要的不同定时。例如要求的定时时间分别为5μs 、l0μs和20μs并设计一个1s延时子程序DELAY,则不同定时的调用情况表示如下:
MOV R0 ,# 05H ;5s延时
LOOP1:LCALL DELAY
DJNZ R0 ,LOOP1
MOV R0 ,# 0AH ;10s延时
LOOP2:LCALL DELAY
第四章MCS-51汇编语言程序设计97
DJNZ R0 ,LOOP2
MOV R0 ,# 14H ;20s延时
LOOP3:LCALL DELAY
DJNZ R0 ,LOOP3
四、查表程序
一个查表程序的例子。假定有4 4键盘,键扫描后把被按键的键码放在累加器A中,键码与处理子程序入口地址的对应关系为:
并假定处理子程序在ROM64KB的范围内分布。要求以查表方法,按键码转向对应的处理子程序。参考程序如下:
MOV DPTR ,# BS ;子程序入口地址表首址
RL A ;键码值乘以2
MOV R2 , A ;暂存A
MOVC A ,@A+DPTR ;取得入口地址低位
PUSH A ;进栈暂存
INC A
MOVC A ,@A+DPTR ;取得入口地址高位
MOV DPH , A
POP DPL
CLR A
JMP @A+DPTR ;转向键处理子程序BS:DB RK0L ;处理子程序入口地址表
DB RK0H
DB RK1L
DB RK1H
DB RK2L
DB RK2H
五、数据极值查找程序
[例4-6] 内部RAM20H单元开
始存放8个无符号8位二进制数,找
出其中的最大数。极值查找操作的主
要内容是进行数值大小的比较。假定
在比较过程中,以A存放大数,与之
逐个比较的另一个数放在2AH单元中。
比较结束后,把查找到的最大数送2BH
单元中。程序流程如图所示。
参考程序如下:
MOV R0 ,# 20H ;数据区首地址
MOV R7 ,# 08H ;数据区长度
MOV A ,@R0 ;读第一个数
DEC R7
LOOP:INC R0
MOV 2AH ,@R0 ;读下一个数
CJNE A ,2AH ,CHK ;数值比较CHK:JNC LOOP1 ;A值大转移
MOV A ,@R0 ;大数送A LOOP1:DJNZ R7 ,LOOP ;继续
MOV
;极值送2BH 单元
HERE:AJMP ;停止
六、数据排序程序
[例4-7] 假定8个数连续存放在20H为首地址的内部RAM单元中,使用冒泡法进行升序排序编程。设R7为比较次数计数器,初始值为07H。TR0为冒泡过程中是否有数据互换的状态标志,TR0 = 0表明无互换发生,TR0 = 1表明有互换发生。
图4-8 极值查找程序流程
第四章 MCS-51汇编语言程序设计 99
参考程序:
SORT :
MOV R0 , # 20H ;数据存储区首单元地址
MOV R7 , # 07H ;各次冒泡比较次数
CLR TR0 ;互换标志清“0” LOOP :
MOV A , @R0 ;取前数
MOV 2BH , A ;存前数
INC R0
MOV 2AH , @R0 ;取后数
CLR C
SUBB A , @R0 ;前数减后数
JC NEXT ;前数小于后数,不互换
MOV @R0 , 2BH
DEC R0
MOV @R0 , 2AH ;两个数交换位置 INC. R0 ;准备下一次比较
SETB TR0 ;置互换标志
NEXT:DJNZ R7 ,LOOP ;返回,进行下一次比较
JB TR0 ,SORT ;返回,进行下一轮冒泡HERE:SJMP $ ;排序结束
本章小结:
本章首先介绍了单片机汇编语言程序设计的基本概念,单片机汇编语言伪指令;详细的讲述了三种汇编语言程序设计的基本结构,即:顺序结构、分支结构和循环结构程序设计的步骤和方法;然后介绍了几种汇编语言程序设计实例。
1号机程序 #in clude
51单片机汇编指令速查表 指令格式功能简述字节数周期 一、数据传送类指令 MOV A, Rn 寄存器送累加器 1 1 MOV Rn,A 累加器送寄存器 1 1 MOV A ,@Ri 内部RAM单元送累加器 1 1 MOV @Ri ,A 累加器送内部RAM单元 1 1 MOV A ,#data 立即数送累加器 2 1 MOV A ,direct 直接寻址单元送累加器 2 1 MOV direct ,A 累加器送直接寻址单元 2 1 MOV Rn,#data 立即数送寄存器 2 1 MOV direct ,#data 立即数送直接寻址单元 3 2 MOV @Ri ,#data 立即数送内部RAM单元 2 1 MOV direct ,Rn 寄存器送直接寻址单元 2 2 MOV Rn ,direct 直接寻址单元送寄存器 2 2 MOV direct ,@Ri 内部RAM单元送直接寻址单元 2 2 MOV @Ri ,direct 直接寻址单元送内部RAM单元 2 2 MOV direct2,direct1 直接寻址单元送直接寻址单元 3 2 MOV DPTR ,#data16 16位立即数送数据指针 3 2 MOVX A ,@Ri 外部RAM单元送累加器(8位地址) 1 2 MOVX @Ri ,A 累加器送外部RAM单元(8位地址) 1 2 MOVX A ,@DPTR 外部RAM单元送累加器(16位地址) 1 2 MOVX @DPTR ,A 累加器送外部RAM单元(16位地址) 1 2 MOVC A ,@A+DPTR 查表数据送累加器(DPTR为基址) 1 2 MOVC A ,@A+PC 查表数据送累加器(PC为基址) 1 2 XCH A ,Rn 累加器与寄存器交换 1 1 XCH A ,@Ri 累加器与内部RAM单元交换 1 1 XCHD A ,direct 累加器与直接寻址单元交换 2 1 XCHD A ,@Ri 累加器与内部RAM单元低4位交换 1 1 SWAP A 累加器高4位与低4位交换 1 1 POP direct 栈顶弹出指令直接寻址单元 2 2 PUSH direct 直接寻址单元压入栈顶 2 2 二、算术运算类指令 ADD A, Rn 累加器加寄存器 1 1
左边1号机,右边2号机,,功能实现 1号机程序 #include
— TMOD=0x20; //定时器1工作方式2 PCON=0x00; //波特率不倍增 TH1=0xf4; TL1=0xf4; //波特率2400 TR1=1; //定时器1开始计时 P2=0xc0; while(1) { if(p10==0&&j==0) { delay_ms(15); while(p10==0); kk=1; P2=0xf9; j=1; } if(p10==0&&j==1) { delay_ms(15); while(p10==0); kk=2; P2=0xa4; j=2; } if(p10==0&&j==2) { delay_ms(15); while(p10==0); kk=3; P2=0xb0; j=0; } if(kk==1) put('A'); if(kk==2) put('B'); if(kk==3) put('C'); delay_ms(10); } }
51串口通信程序(带详细注释) #include#include //后面有一个比较函数#define uchar unsigned char#define uint unsigned intbit UART_Flag=0; //定义串口接收标志位 uchar str[50]; //定义一数组uchar length=0; //数组长度从0 开始void init() //初 始化uart{ TMOD=0X20; //定时器1 定时器方式工作模式2,可自动重载的8 位计数器常把定时/计数器1 以模式2 作为串行口波特率发生器 SCON=0X50; //选择工作模式1 使能接收,允许发送,允许接收 EA=1; //开总中断 ES=1; //打开串口中断ET1=0; //打开定时器中断 PCON=0X80; //8 位自动重载,波特率加倍 TH1=0XFF; //用22.1184 mhz 波特率 TL1=0XFF;TR1=1; //打开中时器 }void UART_Putch(uchar dat) //输出一个字符{SBUF=dat; //把数据送给sbuf 缓 存器中 while(TI!=1);//发送标志位TI 如果发送了为1,没发送为0,没发送等待,到 了退出循环 TI=0; //到了,TI 清为0 }void init1() interrupt 4 //uart 中断,4 为串口中断{ if(RI==1) //收到数据{ uchar m=SBUF; //m 为计算机发送给串口的数据,例,open //总体思想是,计算 机通知串口,我要发数据了RI=0; //收到清0 if(m==) //判断m 这位数据有无{ UART_Putch(); //回车UART_Putch(); // 换行str[length]=; //数据最后位加0 标 志位表示发完了数据UART_Flag=1; // 传完标志位} else if(m==) { } else if(m==)//b表退格//下面几句表删锄{ UART_Putch();
51单片机汇编指令集 一、数据传送类指令(7种助记符) MOV(英文为Move):对内部数据寄存器RAM和特殊功能寄存器SFR的数据进行传送; MOVC(Move Code)读取程序存储器数据表格的数据传送; MOVX (Move External RAM) 对外部RAM的数据传送; XCH (Exchange) 字节交换; XCHD (Exchange low-order Digit) 低半字节交换; PUSH (Push onto Stack) 入栈; POP (Pop from Stack) 出栈; 二、算术运算类指令(8种助记符) ADD(Addition) 加法; ADDC(Add with Carry) 带进位加法; SUBB(Subtract with Borrow) 带借位减法; DA(Decimal Adjust) 十进制调整; INC(Increment) 加1; DEC(Decrement) 减1; MUL(Multiplication、Multiply) 乘法; DIV(Division、Divide) 除法; 三、逻辑运算类指令(10种助记符) ANL(AND Logic) 逻辑与; ORL(OR Logic) 逻辑或; XRL(Exclusive-OR Logic) 逻辑异或; CLR(Clear) 清零; CPL(Complement) 取反; RL(Rotate left) 循环左移; RLC(Rotate Left throught the Carry flag) 带进位循环左移; RR(Rotate Right) 循环右移; RRC (Rotate Right throught the Carry flag) 带进位循环右移; SWAP (Swap) 低4位与高4位交换; 四、控制转移类指令(17种助记符) ACALL(Absolute subroutine Call)子程序绝对调用; LCALL(Long subroutine Call)子程序长调用; RET(Return from subroutine)子程序返回; RETI(Return from Interruption)中断返回; SJMP(Short Jump)短转移; AJMP(Absolute Jump)绝对转移; LJMP(Long Jump)长转移; CJNE (Compare Jump if Not Equal)比较不相等则转移;
状态机思路在单片机程序设计中的应用 状态机的概念 状态机是软件编程中的一个重要概念。比这个概念更重要的是对它的灵活应用。在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。 比如说一个按键命令解析程序,就可以被看做状态机:本来在A状态下,触发一个按键后切换到了B状态;再触发另一个键后切换到C状态,或者返回到A状态。这就是最简单的按键状态机例子。实际的按键解析程序会比这更复杂些,但这不影响我们对状态机的认识。 进一步看,击键动作本身也可以看做一个状态机。一个细小的击键动作包含了:释放、抖动、闭合、抖动和重新释放等状态。 同样,一个串行通信的时序(不管它是遵循何种协议,标准串口也好、I2C也好;也不管它是有线的、还是红外的、无线的)也都可以看做由一系列有限的状态构成。 显示扫描程序也是状态机;通信命令解析程序也是状态机;甚至连继电器的吸合/释放控制、发光管(LED)的亮/灭控制又何尝不是个状态机。 当我们打开思路,把状态机作为一种思想导入到程序中去时,就会找到解决问题的一条有效的捷径。有时候用状态机的思维去思考程序该干什么,比用控制流程的思维去思考,可能会更有效。这样一来状态机便有了更实际的功用。 程序其实就是状态机。 也许你还不理解上面这句话。请想想看,计算机的大厦不就是建立在“0”和“1”两个基本状态的地基之上么? 状态机的要素 状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下: ①现态:是指当前所处的状态。 ②条件:又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。 ③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。 ④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
51单片机串口通信,232通信,485通信,程序代码1:232通信 #include
while(1) { if(flag==1) { ES=0; for(i=0;i<6;i++) { SBUF=table[i]; while(!TI); TI=0; } SBUF=a; while(!TI); TI=0; ES=1; flag=0; } } } void ser() interrupt 4 {
RI=0; a=SBUF; flag=1; } 代码2:485通信 #include
} void main() { init_1602(); init(); while(1) { if(flag==1) { display(0,a); } } } void ser() interrupt 4 { RI=0; a=SBUF; flag=1; } Love is not a maybe thing. You know when you love someone.
一、程序代码 #include
TI = 0; } T_counter = 0; } uart_receive(void) interrupt 4 { if(RI) { RI = 0; indata[R_counter] = SBUF; R_counter++; if(R_counter>=4) { R_counter = 0; flag = 1; } } } void system_initial(void) { P1M1 = 0x00; P1M0 = 0xff; P1 = 0xff; //初始化为全部关闭 temp3 = 0x3f;//初始化temp3的值与六路输出的初始值保持一致 temp = 0xf0; R_counter = 0; T_counter = 0; } void initial_comm(void) { SCON = 0x50; //设定串行口工作方式:mode 1 ; 8-bit UART,enable ucvr TMOD = 0x21; //TIMER 1;mode 2 ;8-Bit Reload PCON = 0x80; //波特率不加倍SMOD = 1 TH1 = 0xfa; //baud: 9600;fosc = 11.0596 IE = 0x90; // enable serial interrupt TR1 = 1; // timer 1 RI = 0; TI = 0; ES = 1; EA = 1; }
51串口通信协议(新型篇) C51编程:这是网友牛毅编的一个C51串口通讯程序! //PC读MCU指令结构:(中断方式,ASCII码表示) //帧:帧头标志|帧类型|器件地址|启始地址|长度n|效验和|帧尾标志 //值: 'n' 'y'| 'r' | 0x01 | x | x | x |0x13 0x10 //字节数: 2 | 1 | 1 | 1 | 1 | 1 | 2 //求和: ///////////////////////////////////////////////////////////////////// //公司名称:*** //模块名:protocol.c //创建者:牛毅 //修改者: //功能描述:中断方式:本程序为mcu的串口通讯提供(贞结构)函数接口,包括具体协议部分 //其他说明:只提供对A T89c51具体硬件的可靠访问接口 //版本:1.0 //信息:QQ 75011221 ///////////////////////////////////////////////////////////////////// #include
51 单片机汇编指令集 一、数据传送类指令( 7 种助记符) MOV(英文为Move :对内部数据寄存器RAM 和特殊功能寄存器SFR 的数据进行 传送; MOV Q Move Code )读取程序存储器数据表格的数据传送; MOVX (Move External RAM) 对外部 RAM 勺数据传送; XCH (Exchange) 字节交换; XCHD (Exchange low-order Digit) 低半字节交换; PUSH (Push onto Stack) 入栈; POP (Pop from Stack) 出栈; 二、算术运算类指令( 8 种助记符) ADD(Addition) 加法; ADDC(Add with Carry) 带进位加法; SUBB(Subtract with Borrow) 带借位减法; DA(Decimal Adjust) 十进制调整; INC(Increment) 加 1; DEC(Decrement) 减 1; MUL(Multiplication 、Multiply) 乘法; DIV(Division 、Divide) 除法; 三、逻辑运算类指令( 10 种助记符) ANL(AND Logic) 逻辑与; ORL(OR Logic) 逻辑或; XRL(Exclusive-OR Logic) 逻辑异或; CLR(Clear) 清零; CPL(Complement) 取反; RL(Rotate left) 循环左移; RLC(Rotate Left throught the Carry flag) RR(Rotate Right) 循环右移; RRC (Rotate Right throught the Carry flag) SWAP (Swap) 低 4 位与高 4 位交换; 四、控制转移类指令( 17 种助记符) ACALL ( Absolute subroutine Call )子程序绝对调用; LCALL ( Long subroutine Call )子程序长调用; RET ( Return from subroutine )子程序返回; RETI ( Return from Interruption )中断返回; SJMP ( Short Jump )短转移; AJMP ( Absolute Jump )绝对转移; LJMP( Long Jump )长转移; CJNE (Compare Jump if Not Equal) 比较不相等则转移; DJNZ (Decreme nt Jump if Not Zero) 减1后不为0则转移; JZ (Jump if Zero) 结果为0则转移; JNZ (Jump if Not Zero) 结果不为0则转移; JC (Jump if the Carry flag is set) 有进位则转移; JNC (Jump if Not Carry) 无进位则转移; JB (Jump if the Bit is set) 位为1则转移; JNB (Jump if the Bit is Not set) 位为0则转移; 带进位循环左移; 带进位循环右移;
2013-2014学年上期51单片机C语言程序设计重修复习提纲考试方式:闭卷考试。 考试题型: 填空题(每空1分,共18分);单项选择题(每空2分,共18分);问答及计算题(每题4分,共16分);编程及程序阅读题(5小题,共48分)。 考试分数: 卷面成绩70%+平时成绩15%+实验成绩15%,未缺席、无课堂违纪、作业全交且认真完成的同学平时成绩可获得满分,缺席一次平时成绩扣30分,实验好评次数3次以上且实验报告全优的同学实验成绩可得满分,实验缺席一次扣30分。缺席实验和旷课共3次以上者,无考试资格。 考试时间: 18周周一(12月30日)下午14:00:16:00,考试地点:具体考室另行通知希望大家认真复习,认真听讲,不懂就问,考试成绩不及格允许查卷,如查卷卷面批阅无误成绩不做更改。 编程题为实验或实验类似的题目有3题,其余2题也取自课堂讲授例题,请务必认真复习。第一章单片机概述及单片机知识回顾 掌握什么是单片机、单片机的应用、常见单片机类型、十进制、十六进制、二进制数制转换知识。掌握单片机的硬件组成、CPU的结构、程序计数器PC的功能、存储器结构、机器周期的计算、会画出单片机的最小系统电路图及回答单片机最小系统的组成。 第二章C51语言程序设计基础(本章填空题和选择题比重较大请务必认真复习)掌握C51语言进行软件开发与汇编语言相比的优点、掌握C51的数据类型、特殊功能位的定义、C51的基本运算(位运算重点复习)、数组的定义、C51的结构及函数。 第三章AT89S51片内并行端口及编程(本章有编程题) 掌握P0-P3并行端口的特点,会开关量检测及流水灯程序的编程。 第四章AT89S51单片机的中断系统(本章有编程题) 掌握中断系统的结构、中断请求响应被满足的条件、外部中断的触发选择方式、外部中断的使用与编程。 第五章AT89S51单片机的定时器/计数器(本章有编程器) 掌握定时器的结构,TOMD及TCON的使用,定时器方式0和方式1的特点、会计算定时器初值,会用定时器中断产生PWM波形,会用定时器对外部事件进行计数。 第六章AT89S51单片机的串行口(本章有计算题) 掌握串行通信的基础知识(课本没有的内容请参照课堂讲授笔记或PPT)、串行口的四种工作方式的特点、会计算奇偶校验码、会根据波特率计算T1的初值。 第七章AT89S51单片机与输入/输出外设接口(本章有编程题) 掌握数码管动态显示的原理、掌握矩阵式键盘的原理与编程(矩阵键盘编程必考,但不会考4X4键盘)。 第八章AT89S51单片机与D/A与A/D转换器的接口(本章有编程题) 掌握AD与DA转换的接口、ADC和DAC的技术指标、常用AD和DA转换器。掌握ADC0809和TLC2543的使用与编程(2器件其中之一有编程题)。 第九章AT89S51单片机应用系统与调试(本章有编程题) 掌握单片机应用系统的软件抗干扰方法。
51单片机多任务操作系统的原理与实现 51单片机多任务操作系统的原理与实现 -- 一个超轻量级的操作系统 前言 想了很久,要不要写这篇文章?最后觉得对操作系统感兴趣的人还是很多,写吧. 我不一定能造出玉,但我可以抛出砖. 包括我在内的很多人都对51使用操作系统呈悲观态度,因为51的片上资源太少.但对于很多要求不高的系统来说,使用操作系统可以使代码变得更直观,易于维护,所以在51上仍有操作系统的生存机会. 流行的uCos,Tiny51等,其实都不适合在2051这样的片子上用,占资源较多,唯有自已动手,以不变应万变,才能让51也有操作系统可用.这篇贴子的目的,是教会大家如何现场写一个OS,而不是给大家提供一个OS版本.提供的所有代码,也都 是示例代码,所以不要因为它没什么功能就说LAJI之类的话.如果把功能写全了,一来估计你也不想看了,二来也失去灵活性没有价值了. 下面的贴一个示例出来,可以清楚的看到,OS本身只有不到10行源代码,编译后 的目标代码60字节,任务切换消耗为20个机器周期.相比之下,KEIL内嵌的 TINY51目标代码为800字节,切换消耗100~700周期.唯一不足之处是,每个任务要占用掉十几字节的堆栈,所以任务数不能太多,用在128B内存的51里有点难度,但对于52来说问题不大.这套代码在36M主频的STC12C4052上实测,切换任务仅需2uS. #include
串口通信测试方法 1 关于串口通信的一些知识: RS-232C是目前最常用的串行接口标准,用来实现计算机和计算机之间、计算机和外设之间的数据通信。 在PC机系统中都装有异步通信适配器,利用它可以实现异步串行通信。而且MCS-51单片机本身具有一个全双工的串行接口,因此只要配以电平转换的驱动电路、隔离电路就可以组成一个简单可行的通信接口。 由于MCS-51单片机的输入和输出电平为TTL电平,而PC机配置的是RS-232C 标准串行接口,二者电气规范不一致,因此要完成PC机与单片机的数据通信,必须进行电平转换。 注明:3)RS-232C上传送的数字量采用负逻辑,且与地对称 逻辑1:-3 ~-15V 逻辑0:+3~+15V 所以与单片机连接时常常需要加入电平转换芯片: 2 实现串口通信的三个步骤: (1)硬件连接 51单片机有一个全双工的串行通讯口,所以单片机和计算机之间可以方便地进行串口通讯。进行串行通讯时要满足一定的条件,比如计算机的串口是RS232电平的,而单片机的串口是TTL电平的,两者之间必须有一个电平转换电路,我们采用了专用芯片MAX232进行转换。我们采用了三线制连接串口,也就是说和计算机的9针串口只连接其中的3根线:第5脚的GND、第2脚的RXD、第3脚的TXD。电路如下图所示,MAX232的第10脚和单片机的11脚连接,第9脚和单片机的10脚连接,第15脚和单片机的20脚连接。 使用MAX232串口通信电路图(9孔串口接头) (2)串行通信程序设计 ①通信协议的使用 通信协议是通信设备在通信前的约定。单片机、计算机有了协议这种
约定,通信双方才能明白对方的意图,以进行下一步动作。假定我们需要在PC 机与单片机之间进行通信,在设计过程中,有如下约定:
按功能分为五大类: (1)数据传送类指令(7种助记符) MOV(Move)对内部数据寄存器RAM和特殊功能寄存器SFR的数据进行传送;MOVC(Move Code)读取程序存储器数据表格的数据传送; MOVX (Move External RAM) 对外部RAM的数据传送; XCH (Exchange) 字节交换; XCHD (Exchange low-order Digit) 低半字节交换; PUSH (Push onto Stack) 入栈; POP (Pop from Stack) 出栈; (2)算术运算类指令(8种助记符) ADD(Addition) 加法; ADDC(Add with Carry) 带进位加法; SUBB(Subtract with Borrow) 带借位减法; DA(Decimal Adjust) 十进制调整; INC(Increment) 加1; DEC(Decrement) 减1; MUL(Multiplication、Multiply) 乘法; DIV(Division、Divide) 除法; (3)逻辑运算类指令(10种助记符) ANL(AND Logic) 逻辑与; ORL(OR Logic) 逻辑或; XRL(Exclusive-OR Logic) 逻辑异或; CLR(Clear) 清零; CPL(Complement) 取反; RL(Rotate left) 循环左移; RLC(Rotate Left throught the Carry flag) 带进位循环左移; RR(Rotate Right) 循环右移; RRC (Rotate Right throught the Carry flag) 带进位循环右移; SWAP (Swap) 低4位与高4位交换; (4)控制转移类指令(17种助记符) ACALL(Absolute subroutine Call)子程序绝对调用; LCALL(Long subroutine Call)子程序长调用; RET(Return from subroutine)子程序返回; RETI(Return from Interruption)中断返回; SJMP(Short Jump)短转移; AJMP(Absolute Jump)绝对转移; LJMP(Long Jump)长转移; CJNE (Compare Jump if Not Equal)比较不相等则转移; DJNZ (Decrement Jump if Not Zero)减1后不为0则转移; JZ (Jump if Zero)结果为0则转移; JNZ (Jump if Not Zero) 结果不为0则转移;
单片机c语言入门 相信很多爱好电子的朋友,对单片机这个词应该都不会陌生了吧。不过有些朋友可能只听说他叫单片机,他的全称是什么也许并不太清楚, 更不用说他的英文全称和简称了。单片机是一块在集成电路芯片上集成了一台有一定规模的微型计算机。简称为:单片微型计算机或单片机 (Single Chip Computer)。单片机的应用到处可见,应用领域广泛,主要应用在智能仪表、实时控制、通信、家电等方面。不过这一切都没 什么关系,因为我(当然也包括任何人)都是从不知道转变成知道的,再转变成精通的。现在我只想把我学习单片机的经历,详细地讲叙给大 家听听,可能有些大虾会笑话我,想:那么简单的东西还在这里卖弄。但是你错了,我只是把我个人学习的经历讲述一遍而已,仅仅对那些想 学习单片机,但又找不到好方法或者途径的朋友,提供一个帮助,使他们在学习过程中,尽量少走些弯路而已! 首先,你必须有学习单片机的热情,不是说今天去图书馆看了一个下午关于单片机的书,而明天玩上半天,后天就不知道那个本书在讲什 么东西了。还是先说说我吧,我从大二的第一个学期期末的时候才开始接触单片机,但在这之前,正如上面所说的:我知道有种芯片叫单片机, 但是具体长成什么样子,却一点也不知道!看到这里很多朋友一定会忍不住发笑。嘿嘿,你可千万别笑,有些大四毕业的人也同样不知道单片 机长成什么样子呢!而我对单片机的痴迷更是常人所不能想象的地步,大二的期末考试,我全放弃了复习,每当室友拿着书在埋头复习的时候, 我却捧着自己从图书馆借的单片机书在那看,虽然有很多不懂,但是我还是坚持了下来,当时我就想过,为了单片机值不值得我这样去付出, 或许这也是在一些三流学校的好处吧,考试挂科后,明年开学交上几十元一门的补考费,应该大部分都能过了。于是,我横下一条心,坚持看 我的单片机书和资料。 当你明白了单片机是这么一回事的时候,显而易见的问题出来了:我要选择那种语言为单片机编写程序呢?这个问题,困扰了我好久。具 体选择C51还是A51呢?汇编在我们大二之前并没有开过课,虽然看着人家的讲解,很容易明白单片机的每一时刻的具体工作情况,但是一合上 书或者资料,自己却什么也不知道了,根本不用说自己写程序了。于是,我最终还是决定学C51,毕竟C51和我们课上讲的C语言,有些类似, 编程的思想可以说是相通的。而且C51还有更大的优点就是编写大程序时的优越性更不言而喻,当然在那时,我并没有想的那么深远,C51的特 点,还是在后来的实践过程中,渐渐体会到的!朋友如果你选择了C51,那么请继续往下看,如果你选择了A51,那么你可以不要看了!因为下面讲 的全是C方面的,完全在浪费你的时间! 呵呵^_^ 第二,既然你想学好单片机,你必须得舍得花钱,如果不买些芯片回来自己动手焊焊拆拆的(但是在后期会介绍给大家一个很好用的硬件 仿真软件,并不需要你用实验板和仿真器了,直接在你的PC上完成,但是软件毕竟是软件,从某个特定的意义上来说是并不能代替硬件的),即使
51单片机声控智能小车C语言程序设计代码 #include TR0=1;//启动T0定时器 TR1=0;//关闭T1定时器 m1a=1; m2a=1; } void timer2(void) interrupt 5 { TF2=0;//软件对T2标志位清零 n++; if(n==250)//n控制查询周期时间 { n=0; switch(m) { case 1://低速挡,占空比77.8% { P2=LEDShowData[0];//七段数码管显示1 TH0=210; TL0=210;//对T0定时器赋初值 TH1=240; TL1=240;//对T1定时器赋初值 x=m; m=0; z=0; ET0=1; ET1=1; TR0=1;//启动T0定时器 break;//跳出switch } case 2://高速挡,占空比99.6% { P2=LEDShowData[1];//七段数码管显示2 TH0=1; TL0=1; //对T0定时器赋初值 TH1=255; TL1=255; //对T1定时器赋初值 x=m+1; m=0; z=0; ET0=1; ET1=1; TR0=1; //启动T0定时器 break;//跳出switch } 51单片机常见的五种流水灯编写方式通过改变赋值实现流水灯 void main() { while(1) { P2=0xfe; delay1ms(500); P2=0xfd; delay1ms(500); P2=0xfb; delay1ms(500); P2=0xf7; delay1ms(500); P2=0xef; delay1ms(500); P2=0xdf; delay1ms(500); P2=0xbf; delay1ms(500); P2=0x7f; delay1ms(500); } } 通过公式运算实现流水灯 void main() { while(1) { uint a,b=1; P2=0xfe; delayms(500); for(a=0;a<7;a++) { P2-=b; // P2=P2-b delayms(500); b=b*2; //都化为同一类型进制运算 } } } 通过操作符<<与“|”实现流水灯 (通过移位实现流水灯) void main() { uchar a,i; while(1) { a=0xfe; //点亮第一位LED灯 for(i=0;i<8;i++) { P2=a; a=a<<1; //左移一位 a=a|0x01; //左移一位后与0x01相或,保证左移后最低位为1 delay_ms(500); } } } 通过库函数_crol_(字符左移)实现流水灯 void main() { uint a; a=0xfe; while(1) { P2=a;a=_crol_(a,1); delay_ms(500); } } 采用数组实现流水灯 #include 51单片机常见的五种流水灯编写方式
51单片机与蓝牙串口通信程序