实验三、基于串行口的数据传输实验(4学时)
实验内容:基于单片机的数据传输系统中,有甲、乙两个单片机,利用串口进行数据传输。
甲机:根据需要随时检测系统中3个开关的状态并进行显示,开关闭合,对应的指示灯LED点亮;开关断开,对应的指示灯LED灭。利用外中断0实现随时检测开关状态。将开关状态传送至乙机。
(1)利用外中断1启动/停止发送数据。
(2)定时1s发送一次数据。
乙机:收到甲机传送过来的开关状态,利用3位发光二极管进行显示,开关闭合,
对应的指示灯LED点亮;开关断开,对应的指示灯LED灭。
当3个开关都闭合时,数码管显示On;
其他情况时,显示OF。(提示:PROTEUS仿真时数码管位选线采用P1口的引脚)
要求:
1、波特率自定、晶振11.0592Mhz
2、绘制硬件电路图
3、编写甲机、乙机程序
注意:甲机程序两个,分别为利用外中断1启动/停止发送数据和利用定时器
定时1s发送一次数据
乙机接收程序分别采用查询和中断两种方式编写
4、调试
这个怎么做,51单片机串口通信实验
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
3条回答 默认 最新
檀越@新空间 2026-04-27 21:05关注晚上好🌙🌙🌙
本答案参考通义千问根据你的实验要求,这是一个典型的51单片机串口通信实验,涉及甲机与乙机之间的数据传输。下面我将为你详细解答如何完成这个实验,并提供完整的代码和实现步骤。
一、实验目标
-
甲机功能:
- 检测3个开关状态(通过外部中断0触发)。
- 利用外中断1启动/停止发送数据。
- 定时器1每1秒发送一次数据。
- 将开关状态通过串口发送给乙机。
-
乙机功能:
- 接收甲机发送的开关状态。
- 用3个LED显示对应状态。
- 当三个开关都闭合时,数码管显示“On”;否则显示“Off”。
二、硬件电路设计(简要说明)
1. 甲机硬件电路
- P1口:连接3个开关(低电平有效),用于检测状态。
- P2口:连接3个LED(高电平点亮)。
- P3.2:外中断0(INT0)输入,检测开关变化。
- P3.3:外中断1(INT1)输入,控制发送数据的启停。
- P3.0:串口发送端(TXD)。
- P3.1:串口接收端(RXD)。
- 定时器1:用于定时1秒发送数据。
2. 乙机硬件电路
- P1口:连接3个LED,显示开关状态。
- P1.0-P1.2:数码管位选线(注意:在PROTEUS中使用P1口引脚作为位选)。
- P3.0:串口接收端(RXD)。
- P3.1:串口发送端(TXD)。
- 数码管:共阴极,显示“On”或“Off”。
提示:在PROTEUS仿真中,确保数码管的位选线正确接在P1口上。
三、软件设计思路
甲机程序(分两种):
1. 外中断1控制发送(启动/停止)
- 设置
EA=1,开启全局中断。 - 设置
EX1=1,允许外中断1。 - 设置
IT1=1,外中断1为下降沿触发。 - 在中断服务函数中切换发送标志位(如
send_flag)。
2. 定时器1定时发送(1秒一次)
- 初始化定时器1为模式1(16位)。
- 计算定时时间(1秒)对应的初值。
- 启动定时器1。
- 每次定时溢出后发送数据。
乙机程序(分两种):
1. 查询方式接收数据
- 不使用中断,通过不断读取
RI标志判断是否有数据到达。 - 收到数据后,更新LED显示。
2. 中断方式接收数据
- 设置
EA=1,开启全局中断。 - 设置
ES=1,允许串口中断。 - 在中断服务函数中读取数据并更新LED显示。
四、波特率设置(11.0592MHz晶振)
-
波特率选择为9600 bps。
-
使用定时器1工作于模式2(8位自动重装),计算初值:
$$ \text{TH1} = \text{TL1} = 256 - \frac{11059200}{12 \times 9600} = 256 - 96 = 160 = 0xA0 $$
五、关键代码实现
1. 甲机程序(外中断1控制发送)
#include <reg51.h> #define LED P2 // 3个LED连接到P2口 sbit INT1 = P3^3; // 外中断1 unsigned char send_flag = 0; // 发送标志 unsigned char switch_state = 0; // 开关状态 void UART_Init() { SCON = 0x50; // 8位异步串行,允许接收 TMOD |= 0x20; // 定时器1模式2 TH1 = 0xA0; TL1 = 0xA0; TR1 = 1; // 启动定时器1 } void External_Interrupt1() interrupt 3 { send_flag = !send_flag; // 切换发送状态 } void main() { UART_Init(); IT1 = 1; // 外中断1为下降沿触发 EX1 = 1; // 允许外中断1 EA = 1; // 全局中断开启 while (1) { if (send_flag) { SBUF = switch_state; // 发送当前开关状态 while (!TI); // 等待发送完成 TI = 0; // 清除发送标志 } } }2. 甲机程序(定时器1定时发送)
#include <reg51.h> #define LED P2 unsigned char switch_state = 0; void UART_Init() { SCON = 0x50; TMOD |= 0x20; TH1 = 0xA0; TL1 = 0xA0; TR1 = 1; } void Timer1_ISR() interrupt 3 { static unsigned int count = 0; count++; if (count == 1000) { // 假设1秒 = 1000次定时 SBUF = switch_state; while (!TI); TI = 0; count = 0; } } void main() { UART_Init(); ET1 = 1; // 允许定时器1中断 EA = 1; while (1) { // 主循环可以处理其他逻辑 } }3. 乙机程序(查询方式接收)
#include <reg51.h> #define LED P1 // 3个LED连接到P1口 void UART_Init() { SCON = 0x50; TMOD |= 0x20; TH1 = 0xA0; TL1 = 0xA0; TR1 = 1; } void main() { UART_Init(); while (1) { if (RI) { // 接收完成 LED = SBUF; // 显示开关状态 RI = 0; // 清除接收标志 } // 检查是否全开 if (LED == 0x07) { // 0b00000111 // 显示 "ON" } else { // 显示 "OFF" } } }4. 乙机程序(中断方式接收)
#include <reg51.h> #define LED P1 void UART_Init() { SCON = 0x50; TMOD |= 0x20; TH1 = 0xA0; TL1 = 0xA0; TR1 = 1; } void UART_ISR() interrupt 4 { LED = SBUF; // 显示开关状态 RI = 0; // 清除接收标志 } void main() { UART_Init(); ES = 1; // 允许串口中断 EA = 1; while (1) { // 主循环可以处理其他逻辑 } }
六、调试步骤
-
硬件连接检查:
- 确保所有引脚连接正确,尤其是串口(P3.0和P3.1)。
- 检查数码管的位选线是否连接到P1口。
-
仿真环境配置:
- 使用PROTEUS搭建电路图。
- 添加虚拟串口工具(如VirtualSerialPort)进行通信测试。
-
程序烧录:
- 使用STC-ISP或KEIL烧录程序到单片机。
-
功能测试:
- 测试甲机能否检测开关状态。
- 测试乙机能否正确显示LED和数码管。
- 测试外中断1是否能控制发送。
七、总结
| 功能点 | 实现方式 | |--------|----------| | 开关状态检测 | 外部中断0 | | 数据发送控制 | 外部中断1 或 定时器1 | | 数据接收方式 | 查询或中断 | | 显示方式 | LED + 数码管 |
八、注意事项
- 波特率必须一致,否则无法通信。
- 串口初始化必须正确,包括SCON、TMOD、TH1、TL1等寄存器。
- 中断优先级需要合理设置,避免冲突。
- 数码管显示逻辑需根据实际硬件调整。
如果你需要我帮你绘制PROTEUS电路图,或者进一步优化代码,请告诉我!
解决 无用评论 打赏 举报-