8051单片机原理
简答
1、MCS-51单片机有哪些功能部件组成?并说明它们各自的功能。
1.cpu:控制单片机的操作,执行指令,进行数据处理等。
2.存储器单元:提供程序存储和数据存储的空间。
ROM:存储固定的程序代码
RAM:存储运行时数据和变量。
3.I/O端口
用于连接外部设备,例如传感器、执行器和其他外围设备。
4.定时器/计数器:
用于生成精确的时间延迟、计时和产生脉冲等,可以用于控制系统的定时操作。
5.串行通信控制器(UART)
提供串行通信的能力,可用于与其他设备进行数据传输。
7.中断系统:
允许外部设备通过中断请求中断处理器的正常执行,以执行特殊的任务。
2、简述MCS-51单片机内部RAM功能分区,说明各部分的使用特点。
51单片机RAM分为四个区域
1.工作寄存器区(00H~1FH)
里面就是通用寄存器组R0-R7,每八个分一组。这个区域是最常用的数据区,数据的操作大部分在这里进行。
2.位寻址区(20H~2FH)
这里和通用寄存器组一样可以进行位寻址,也就是说可以比较方便的进行位操作,个人认为它和通用寄存器组的区别是,没有逐个的命名和分组。使用频率较高的数据,或需要位操作的数据会放在这里。
3.用户RAM区(30H~7FH)
很普通的数据缓存区,用来建立堆栈,还有放一些不太常用的数据。
4.特殊功能寄存器(80H~FFH)
特殊功能寄存器组区,支持直接寻址,各种各样的特殊功能寄存器都在这里。
3、什么叫寻址方式?请给出89C51单片机中所有的寻址方式,并为每种寻址方式提供相应的汇编指令例子。
寻址方式(Addressing Mode)是指用于确定操作数或指令地址的方法。
1,立即寻址
MOV A, #5 ; 将立即数5移动到累加器A
2.寄存器寻址
MOV A, R0 ; 将R0寄存器的内容移动到累加器A
3.直接寻址
MOV A, 30H ; 将RAM地址30H处的数据移动到累加器A
4.寄存器间接寻址
MOV A, @R0 ; 将R0寄存器中存储的地址处的数据移动到累加器A
5.变址寻址
MOV R0, #30 ; 将立即数30赋值给R0寄存器
MOV A, @R0 ; 将R0寄存器中的地址加上A寄存器中的值作为地址,将该地址处的数据移动到A寄存器
4.举出几个串口通信应用的实例,讨论使用串口的基本流程
1,从8051单片机发送温度传感器数据到PC端,实时监控温度。
2.两个8051单片机之间进行数据传输,例如通过串口实现简单的通信协议。
3,使用串口连接8051单片机和GPS模块,获取位置信息并进行处理。
流程
1.串口初始化
在8051中,使用相关寄存器(如SCON
和TMOD
)进行配置
2.发送数据
将要发送的数据加载到发送缓冲区,启动串口发送操作等待发送完成标志,确保数据已经发送完毕。
3.接收数据
收端等待串口接收寄存器中的数据。
4.处理数据:
接收端从接收缓冲区读取数据,并进行相应的处理。
实例:两个单片机相互通信
5.简述你对单片机系统中断的理解,以及中断编程时应该注意的问题。
8051单片机中断,其实就是一种“插队”机制。可以把这个想象成,你正在写代码、做事情,突然有个紧急的事情发生,像是一个按钮按下、定时器到时了,单片机就会暂时搁下手头的事情,跳去处理这个“插队”的事件,等处理完再回来接着做原来的事情。
当然,有几个要点需要记住:
-
中断服务程序要快速:中断服务程序得迅速搞定手头的事情,因为主程序也在等着。长时间的中断响应会耽误主程序的执行。
-
小心资源冲突:如果中断服务程序和主程序都要使用一些共享的资源,比如全局变量,得小心操作,不然容易出问题。得确保在中断服务程序和主程序之间的交互是安全的。
-
中断的优先级:中断有优先级,得了解清楚各个中断的重要性,按照实际需求设置优先级。
计算
1.计算延迟时间
8051机器周期 T = 12 X T A L T={\frac{12}{XTAL}} T=XTAL12
如果 XTAL=11.0592MHz \text{XTAL=11.0592MHz} XTAL=11.0592MHz,8051的机器周期 12 11.0592 M H z = 1.085 u s \frac{12}{11.0592MHz}=1.085us 11.0592MHz12=1.085us
指令 | 所用机器周期 |
---|---|
MOV | 1 |
DEC | 1 |
DJNZ | 2 |
LJMP | 2 |
SJMP | 2 |
NOP | 1 |
MUL | 4 |
MOV R2,#200 ;1
AGAIN: MOV R3,#250 ;1
HRER: NOP ;1
NOP ;1
DJNZ R3,HERE ;2
DJNZ R2,AGAIN ;2
内循环(HERE DELAY): ( 1 + 1 + 2 ) ∗ 250 ∗ 1.085 u s = 1085 u s (1+1+2)*250*1.085us=1085us (1+1+2)∗250∗1.085us=1085us
外循环(AGAIN DELAY): 1085*200=217000us=217ms \text{1085*200=217000us=217ms} 1085*200=217000us=217ms
指令延时Y: ( 2 + 1 ) ∗ 200 ∗ 1.085 = 651 u s (2+1)*200*1.085=651us (2+1)∗200∗1.085=651us
MOV R3,#250
DJNZ R2,AGAIN
子程序的第一条和最后一条指令被忽略
总共延时: 217000 + 651 = 217651 u s = 217.651 m s 217000+651=217651us=217.651ms 217000+651=217651us=217.651ms
2.在定时器中设置延时和频率
8051的机器周期 T = 12 X T A L T={\frac{12}{XTAL}} T=XTAL12
TMOD | mode(模式) | timer(所用定时器) |
---|---|---|
01H | 1 | 0 |
02H | 2 | 0 |
10H | 1 | 1 |
20H | 2 | 1 |
延迟时间
初值:TH0|TL0 or TH1|TL0
mode1: ( 65536 − i n i t i a l v a l u e (初值) ) × 1.085 u s = d e l a y t i m e (65536-initial \ value(初值))×1.085us=delay \ time (65536−initial value(初值))×1.085us=delay time
初值:TH0=TL0 or TH1 = TL0
mode2: ( 256 − i n i t i a l v a l u e (初值) ) × 1.085 u s = d e l a y t i m e (256-initial \ value(初值))×1.085us=delay \ time (256−initial value(初值))×1.085us=delay time
频率: f = 1 T f=\frac{1}{T} f=T1
3.计算波特率
8051机器周期 T = 12 X T A L T={\frac{12}{XTAL}} T=XTAL12
SMOD=0
mode 2:
baud rate | TH1(D:10进制) | TH1(H:16进制) |
---|---|---|
9600 | -3(making (256-TH1 = 3)) | FD |
4800 | -6 | FA |
2400 | -12 | F4 |
1200 | -24 | E8 |
如果SMOD = 1,baud rate×2(for rate in SMOD = 0)
X
T
A
L
12
×
2
1
−
S
M
O
D
×
16
×
(
256
−
T
H
1
)
=
b
a
u
d
r
a
t
e
\frac{XTAL}{12\times2^{1-SMOD}\times16\times(256-TH1)}=baud \ rate
12×21−SMOD×16×(256−TH1)XTAL=baud rate
编程
汇编编程
片上片内数据转换
片外RAM2000h单元开始存有1个8字节数。编写汇编程序将这个数转移到片内RAM的30h开始的单元中。
MOV DPTR, #2000h ; 设置DPTR到片外RAM的起始地址
MOV R0, #30h ; 设置片内RAM的起始地址
; 循环8次来复制8个字节
MOV R7, #08 ; 设置计数器为8
CO_LOOP:
MOVX A, @DPTR ; 从片外RAM读取数据到累加器A
MOV @R0, A ; 将累加器A的数据存储到片内RAM
INC DPTR ; 增加片外RAM地址
INC R0 ; 增加片内RAM地址
DJNZ R7, CO_LOOP ; 减少计数器并检查是否完成8次循环
ps:汇编延时创建等同样重要,需要对汇编语言的基础语法熟练记忆和运用
c语言编程
定时器相关编程
配置工作模式2,timer0,对一个端口500ms后取反
晶振每次产生十二个周期,会给TH以及TL中进位,当TH,TL为FFFF时,TF溢出由0变1.
通过此过程不断进行反转,即可获得一个占空比为50%的脉冲。
#include <REGX52.H>
void Timer0Init(void);
sbit mybit = P1^5;
void main(void)
{
while(1)
{
mybit = ~mybit;
Timer0Init();
}
}
void Timer0Init(void) // 500毫秒@12.000MHz
{
TMOD = 0x02; // 设置定时器模式为工作模式2(8位自动重载定时器)
TL0 = 0x83; // 设置定时初始值(低字节),使得定时器每溢出一次大约500毫秒(在12.000MHz的频率下)
TH0 = 0xFD; // 设置定时初始值(高字节)
TR0 = 1; // 启动定时器0
while (TF0 == 0); // 当溢出时将其加入TF可以使TF=1时跳出死循环
TF0 = 0; // 清除TF0标志
TR0 = 0; // 停止定时器0计时
}
中断相关编程
每秒点亮P1.0口的发光二极管一次,然后熄灭,使发光二极管形成闪烁效果
#include <reg52.h>
#include <intrins.h>
typedef unsigned char uchar;
sbit LED = P1 ^ 0;
uchar count = 0;
void Interrupt() interrupt 1
{
TH0 = (65536 - 46080) / 256; //触发中断时重新装填计时
TL0 = (65536 - 46080) % 256;
if (count == 20)
{
LED = ~LED;
count = 0;
}
else ++count;
}
void main(void)
{
LED = 0xff; //初始化LED
TMOD = 0x01; //初始化TMOD,定时器0,方式1
TH0 = (65536 - 46080) / 256; //装填计数
TL0 = (65536 - 46080) % 256;
EA = 1; //开放所有中断
ET0 = 1; //开放定时器0中断控制位
TR0 = 1; //定时器0开始计时
while(1)
{
_nop_();
}
}
ps:上面只是简单举例两个8051中应用定时器和中断的例子,在这门课程中,例如:矩阵键盘的扫描,数码管显示,AB的串口通信,按键中断等等同样重要