# 使用虚拟终端模拟串口控制LED灯
## 项目简述
### 题目选择
个人选择的题目的是第五题,即
要求:利用现有电路,使用串口模拟终端,向单片机发送命令,用于控制LED灯。不同命令控制不同的显示效果可自行设计。
选择第五题的理由是题目包含的信息量看起来更多,也看起来更加有趣一点(笑
### 项目整体结构
1. 电路部分
电路部分的设计并未有变化,即还是使用原先的8052.dsn。
<img src="./8052.PNG">
2. C语言代码部分
代码部分分为主要分为两个部分,负责主体逻辑的test.c文件(包含main函数)和负责配置串口,发送数据的UART.c 和UART.h文件。
<img src="./代码部分.PNG">
在UART.h 中,定义了uart_init,uart_sendByte,UART_Routine这几个函数,uart_init函数负责在最开始时配置串口相关的寄存器参数,uart_sendByte函数负责通过发送单个字符至终端,UART_Routine为中断函数,负责接受终端输入并控制LED的亮灭,而这几个函数的具体实现则在UART.c中。
在test.c中,首先引用reg52.h和UART.h这两个头文件,之后在main函数中调用uart_init进行初始化,并调用uart_sendByte函数发送0x4F,0x4B(即OK)。
## 细节分析
### 串口
UART(Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和其他设备之间进行通信。其相关寄存器如图所示:
<img src="寄存器.PNG">
即我们在使用串口进行通讯之前,首先要配置相关的寄存器,本程序的配置在uart_init函数中实现
```c
void uart_init()//9600bps@11.0592MHz
{
SCON = 0x50;
TMOD = 0x20;
TH1 = 0xfd;
TL1 = TH1;
PCON = 0x00;
EA = 1;
ES = 1;
TR1 = 1;
}
```
这里可以简单讲一下赋值的依据,首先可以看见我们将SCON寄存器赋为0x50,即(01010000),依据如下:
<img src="SCON.PNG">
图中可以看见SM0、SM1的值对应四种工作方式,我们选择的工作方式是方式1,故SM0=0,SM1=1。即最开头的01,之后可以看见我们又将REN的值也调为1,其作用如下图所示:
<img src="REN.PNG">
在SCON其余的值对本程序不影响,故设置为0。
PCON寄存器主要负责电源控制,作用如图:
<img src="PCON.PNG">
图中有点错误在于SMOD=0是各工作方式波特率正常,故赋位0,其余各位也暂无影响,故也赋值为0,即PCON=0x00。
### 定时器
说完了SCON和PCON,可以发现还有几个寄存器没有提到,即TMOD,TH1,TL1,TR1(负责时钟配置),和EA,ES(负责中断配置)。
在串口通讯的过程中,定时器被用作通信的时钟源。因为在全双工的uart串口通讯过程中必定存在与外界设备沟通的时序问题,所以也应当会存在一个时钟源(个人猜测)。相关寄存器如图所示:
<img src="定时器.PNG">
其中,TMOD寄存器的作用如下图所示,
<img src="TMOD.PNG">
我们需要修改的部分只有定时器1的控制模式
<img src="TMOD45.PNG">
选择8位自动重装定时器模式,则TMOD=0x20(00100000)。
在设置完定时器1的模式后,我们需要规定串口的波特率。在使用串口做通讯时,一个很重要的参数就是波特率,只有上下位机的波特率一样时才可以进行正常通讯。而波特率是指串行端口每秒内可以传输的波特位数,具体类似于串口的传输速率。
波特率的计算公式如图:
<img src="波特率.PNG">
<img src="溢出速率.PNG">
而T1即定时器1在模式2下的溢出率由TL1值决定,TH1与TL1相同,负责设定定时器1的重装值。这里我们采用的参数是较为经典的9600波特率,晶振11.0592M。整体的计算过程较为复杂,有个偷懒的办法,交给软件去算,以下截图为stc-isp软件自动生成的结果。
<img src="stc.PNG">
多了一些其他参数,但无伤大雅(*^_^*)。
### 中断
在前面提到过配置部分除了定时器的配置外,还配置了相关的中断设置,那么中断的具体定义如图:
<img src="中断.PNG">
那么本次使用的中断请求为串口(uart)中断,可以理解为当串口收到数据时,cpu会暂停当前的工作(main函数),进而去处理中断函数所规定的内容。(虽然个人有点不太明白为什么不能写成在main函数中轮询SBUF寄存器,可能是模块化?),那么首先应当允许使用该中断,即:
<img src="EA.PNG">
```c
EA = 1;
ES = 1;
```
接下来需要编写对应的中断函数,因为中断函数不在main函数中调用,所以需要知道其中断号以标识其为中断函数。而串口中断号在下图中显示
<img src ="中断号.PNG">
那么以此编写中断函数代码
```c
void UART_Routine() interrupt 4
{
if(RI==1) //如果接收标志位为1,接收到了数据
{
if(SBUF>0x2f&&SBUF<0x3a)
{
int k=SBUF-0x30;
P0 = ~(1<<k);//点亮对应LED灯
};
uart_sendByte(0x0D); //换行符
uart_sendByte(SBUF); //将受到的数据发回串口
uart_sendByte(0x0D);
RI=0; //接收标志位清0
}
}
```
在该函数中,我们首先检验是否收到了数据,接下来从SBUF寄存器中读出该数据,如果该数据在0~7范围内(对应acsii码为0x30-0x37),则点亮该对应的led灯,最后将收到的数据再返回串口,接受标志位置0。
同时将数据发回串口的功能由uart_sendByte函数实现,代码如下
```c
void uart_sendByte(unsigned char byte)
{
SBUF=byte;//赋值缓冲区寄存器
while(TI==0);//判断发送中断请求后标志位是否归位
TI=0;//若未归位则置标志位为0
}
```
依据如图:
<img src="TI.PNG">
## 运行结果
按下运行键后可得如图所示,首先先向终端发送“OK”字符。
<img src="运行结果1.PNG">
接着向终端输入1,可以看见第二个LED亮起
<img src="输入1.PNG">
再输入6,可以看见第七个LED亮起
<img src="输入6.PNG">
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
第一次尝试51单片机.zip (48个子文件)
code_resource_010
test.c 401B
期中作业
stc.PNG 15KB
TI.PNG 48KB
TMOD45.PNG 47KB
模式2.PNG 80KB
中断.PNG 189KB
输入1.PNG 104KB
SCON.PNG 172KB
输入6.PNG 99KB
8052.PNG 101KB
溢出速率.PNG 14KB
波特率.PNG 58KB
EA.PNG 82KB
演示.pptx 1.29MB
代码部分.PNG 5KB
PCON.PNG 88KB
TMOD.PNG 79KB
~$演示.pptx 165B
定时器.PNG 61KB
README.md 6KB
运行结果1.PNG 55KB
REN.PNG 24KB
寄存器.PNG 81KB
中断号.PNG 45KB
8052.DSN 117KB
Objects
test.hex 478B
test.obj 1KB
Delay.obj 901B
test.build_log.htm 1012B
STARTUP.obj 828B
UART.obj 3KB
test 5KB
test.lnp 133B
STARTUP.A51 6KB
test.c.bak 3KB
Listings
UART.lst 3KB
test.lst 2KB
main.lst 528B
test.m51 7KB
STARTUP.lst 14KB
Delay.lst 1KB
Delay.h 79B
UART.h 125B
Delay.c 138B
UART.c 1KB
.gitignore 8B
test.uvproj 14KB
README.md 59B
共 48 条
- 1
资源评论
LeapMay
- 粉丝: 2w+
- 资源: 2305
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功