89C51单片机相关知识
MCU-89C51资源简析
1.中断资源
中断名称 | 中断入口地址 |
---|---|
外部中断0(INT0*) | 0003H |
定时器中断0(T0) | 000Bh |
外部中断1(INT1*) | 0013H |
定时器中断1(T1) | 001BH |
串行口中断() | 0023H |
引脚说明
引脚 | 第二功能 | 说明 |
---|---|---|
P3.0 | RXD | 串行口数据输入口 |
P3.1 | TXD | 串行口数据输出口 |
P3.2 | INT0(低电平有效) | 外部中断EXT0输入 |
P3.3 | INT1(低电平有效) | 外部中断EXT1输入 |
P3.4 | T0 | 定时器T0外部计数输入 |
P3.5 | T1 | 定时器T1外部中断输入 |
P3.6 | WR(低电平有效) | 外部数据存储器写选通输出 |
P3.7 | RD(低电平有效) | 外部数据存储器读选通输出 |
工作寄存器相关
RS1 | RS0 | 所选的寄存器区间 |
---|---|---|
0 | 0 | 0区(内部RAM地址00H~07H) |
0 | 1 | 1区(内部RAM地址08H~0FH) |
1 | 0 | 2区(内部RAM地址10H~07H) |
1 | 1 | 3区(内部RAM地址18H~1FH) |
当前寄存器区间的内布寄存器
每个寄存器区间有8个寄存器,分别提供给用户使用。
R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 |
---|---|---|---|---|---|---|---|
可间接寻址 | 可间接寻址 | 不可间接寻址 | 不可间接寻址 | 不可间接寻址 | 不可间接寻址 | 不可间接寻址 | 不可间接寻址 |
I/O引脚说明
P0口:漏极开路的双向I/O口
P1口:准双向I/O口
P2口:准双向I/O口
P3口:准双向I/O口;提供第二功能!
2.相关特殊功能寄存器介绍
a.中断允许寄存器(IE)
EA | – | – | ES | ET1 | EX1 | ET0 | Ex0 |
---|---|---|---|---|---|---|---|
AFH | – | – | ACH | ABH | AAH | A9H | A8H |
b.中断请求标志寄存器(TCON)
TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
---|---|---|---|---|---|---|---|
T1溢出中断 | T0溢出中断 | 外部中断1 | 定时器1中断 | 外部中断0 | 定时器中断0 |
c.串行口中断标志寄存器(SCON)
SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
---|---|---|---|---|---|---|---|
控制模式 | 控制模式 | 控制多机通讯 | 使能接收 | 发送的第8位数据 | j接收的第8位数据 | 发送中断标志位 | 接收中断标志位 |
d.定时器/计数器控制寄存器(TMOD)
GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
---|---|---|---|---|---|---|---|
T1 控制段 | 1:计数/0:计时 | 模式控制(H) | 模式控制(L) | T0控制段 | 1:计数/0:计时 | 模式控制(H) | 模式控制(L) |
d.优先级控制(IP)
PS | PT1 | PX1 | PT0 | PX0 | |||
---|---|---|---|---|---|---|---|
串口优先级 | T1优先级 | 外部中断1优先级 | T0优先级 | 外部中断0优先级 |
e. 串口波特率控制寄存器(PCON)
SMOD | |||||||
---|---|---|---|---|---|---|---|
波特率控制 |
d. 标志寄存器(PSW)
Cy | Ac | F0 | RS1 | RS0 | OV | — | P |
---|---|---|---|---|---|---|---|
进位标志位 | 辅助进位 | 用户使用状态标志位 | 工作寄存器区选择 | 工作寄存器区选择 | 溢出标志位 | 奇偶校验位 |
e.
3.定时器相关
在C51中我们可以利用的定时器/计数器只有两个:T0、T1
存在四种工作方式(12MHz):
方式0:计数器/定时器 为13位的1
方式1:计数器/定时器 为16位的 2
方式2:计数器/定时器为8位的【由硬件自动装载】3
方式3:计数器/定时器为两个8位的(只有T0能够工作在方式3,且此时T1停止计数)[^方式3]
装载值的计算:对于12MHz的晶振
例如:我们要计时100us,采用T0\T1的方式0、1、2都可以
方式0: (213 - X)*1us =100us; 可得:X = 8091 = 1F9B
方式1: (216 - X)*1us = 100us 可得:X = 65435 = FF9B
方式2: (28 - X)*1us = 100us; 可得:X = 155 = 9B
代码控制实现:
汇编实现:
ORG 0000H
LJMP AMIN
ORG 001BH
CPL P1.0
RETI
ORG 0100H
MAIN: MOV TMOD,#60H
MOV TL0,#9CH
MOV TH0,#9CH
SETB TR1
HERE: AJMP HERE
END
中断流水灯(T0方式1)
ORG 0000H
AJMP START ;进入主函数
ORG 000BH ;定时器T0的中断入口地址
LJMP TIMER0 ;中断处理函数
ORG 0100H
START:
MOV TMOD,#01H ;控制为T0定义为方式1
MOV TH0,#3CH ;
MOV TL0,#B0H ;
MOV A,#FEH
MOV R0,#20H
MOV IE,#10000010B ;总中断,定时器0中断
MOV IP,#10B ;中断优先级
SETB TR0 ;开启定时器
MOV P1,A
SJMP $ ;原地跳转
TIMER0:
DJNZ R0,LOOP ;延时:20H*50000 = 1.6s
MOV R0,#20;
MOV P1,A;
RL A; ;循环左移
LOOP: ;用于延时
MOV TH0,#3CH
MOV TL0,#BOH
RETI ;中断返回
END
利用GATE位来测量脉冲宽度
ORG 0000H
RESET:
AJMP MAIN;
ORG 0100H;
MAIN:
MOV SP,#60H;
MOV TMOD,#90H ;10010000
MOV TL1,#00H
MOV TH1,#00H
LOOP0: JB P3.3,LOOP1;
SETB TR1;
LOOP1:
JNB P3.3,LOOP1
LOOP2:
JB P3.3,LOOP2;
CLR TR1;
MOV A,TL1;
MOV A,TH1;
END
外部中断系统
ORG 0000H
LJMP MAIN
ORG 000BH;
LJMP INT
MAIN:
SETB EA
SETB EX0
SETB PX0
SETB IT0
INT:
CLR EA
PUSH PSW
PUSH ACC
SETB EA
CLR EA
POP ACC
POP PSW
SETB EA
RETI
INT1:
PUSH PSW
PUSH ACC
JB P1.0,IR1;
JB P1.1,IR2;
JB P1.2,IR3;
JB P1.3,IR4;
INTIR:
POP ACC;
POP PSW
RETI
IR1:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AJMP INITIR
IR2:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IR3:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IR4:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
END
4.串口中断/串口传输
四种工作方式(方式1、3的波特率与T1计数器有关)
方式0:波特率固定 fosc/124
方式1:波特率 = 2SMOD/32*定时器T1溢出率5
方式2:波特率 = 2SMOD/64*fosc 6
方式3:波特率 = 2SMOD/32*定时器T1的溢出率 7
例子:若采用串口通信方式3进行发送和接收,晶振为6Mhz,波特率设置为4800bps
(1)甲机发送程序 ORG 0000H LJMP MAIN ORG 0023H LJMP COM_INT ;中断处理函数 ORG 1000H MAIN: MOV SP,#53H ;设置堆栈指针SP MOV 78H,#20H ;将立即数20H存放到78H寄存器中 MOV 77H,#00H ;将立即数00H存放到77H寄存器中 ACALL TRAN ;调用子函数(ACALL) HERE: SJMP HERE ;原地跳转 TRAN: MOV TMOD,#20H ;设置定时器方式为方式2(8位自动装载) MOV TH1,#0FDH ;存放计数初值到TH1 MOV TL1,#0FDH ; SETB TR1 ;开启计数器 MOV SCON,#E0H ;设置串口工作方式11110000【方式3、多机通讯、允许接收、0、0】 SETB TB8 ;设置发送的第九位数据位TB8=1 MOV IE,#00H ;关闭中断 MOV SBUF,78H ;将78H寄存器上的值送入SBUF中【即20H】//数据放置到SBUF就开始发送 WAIT: JNB TI,WAIT ;当TI=0时,跳转//等待发送完成 CLR TI ;清空TI,即TI=0 MOV SBUF,77H ;将77H寄存器上的内容送入SBUF WAIT2: JNB TI,WAIT2 ; CLR TI ; MOV IE,#90H ;开启中段 CLR TB8 ;TB8=0 MOV A,#00H ; MOV SBUF,A ; WAIT1: CJNE A,#FFH,WAIT1; CLR ES ;清除串口中断标志 RET ; COM_INT: CLR TI ;清除发送完成标志位 INC A ;自增加A的值 MOV SBUF,A ;将A的值送到串口进行发送 RETI ;中断返回 END
串口应用实例:驱动AD获取到数据,并通过串口发送到PC端串口助手上
#include <reg51.h> #define uchar unsigned char #define uint unsigned int #define sel P1 #define seg P0 uchar i; uchar code smgduan[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//段选 sbit cs = P2^4; sbit dclk = P2^7; sbit din = P2^6; sbit dout = P2^5; void delay(uint i){ while(i--); } void XPT2046_writebyte(uchar wx) //串行输入1个字节的控制字 { uchar i; dclk = 0; for(i=0;i<8;i++) { din=wx>>7; wx<<=1; dclk=0; dclk=1; //上跳沿输入 } } uint XPT2046_read() //读出12位的转换数据 { uint rx=0; uchar i; for(i=0;i<12;i++) { rx<<=1; dclk=1; dclk=0; rx|=dout; //下跳沿输出 } return(rx); } uint getdata(uchar cmd) { uchar i; uint value; dclk = 0; cs = 0; XPT2046_writebyte(cmd); for(i=6; i>0; i--); //延时等待转换结果 dclk = 1; dclk = 0; value=XPT2046_read(); cs = 1; return value; } void initcomm(void) { SCON=0x50; //设置为工作方式1 0101 0000 TMOD=0x20; //设置计数器工作方式2 PCON=0x80; //波特率加倍 TH1=0xF3; //计数器初始值,波特率为4800 TL1=0xF3; EA=1; //打开总中断 ES=1; //打开串口中断 TR1=1; //打开计数器 } void uart_rx(uchar ch) { SBUF=ch; while(TI==0); TI=0; } void main(){ uint send_data = 0; uchar d1,d2,d3,d4; uchar i,j; initcomm(); while(1){ send_data=getdata(0xa4); d4=send_data/1000; send_data = send_data%1000; d3=send_data/100; send_data = send_data%100; d2=send_data/10; send_data = send_data%10; d1=send_data/1; for(j=0;j<10;j++){ for(i=0;i<4;i++){ delay(300); sel =i; switch(i){ case 0: seg = smgduan[d4];break; case 1: seg = smgduan[d3];break; case 2: seg = smgduan[d2];break; case 3: seg = smgduan[d1];break; default: seg = 0; } } } uart_rx(d4+48); uart_rx(d3+48); uart_rx(d2+48); uart_rx(d1+48); uart_rx(0x0A); } }