继电器数据回环
052.6.8 继电器数据回环
#include "reg52.h"
#include <intrins.h>
typedef unsigned char uchar;
typedef unsigned int uint;
uint count = 0;
uchar recv;
sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit BEEP = P1^6;
sbit JDQ1 = P2^0;
void Delay_xms(uint xms) //@11.0592MHz
{
uchar data i, j;
while (xms)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
xms--;
}
}
void UART_Send_Byte(uchar send_byte)
{
SBUF = send_byte;
while (TI == 0);
TI = 0;
}
void UART_Send_Str(uchar *send_str)
{
while (*send_str != '\0')
{
UART_Send_Byte(*send_str++);
}
}
void main()
{
SCON = 0x50;
PCON &= 0x7F;
TMOD &= 0x0F;
TMOD |= 0x20;
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
ES = 1;
EA = 1; // 打开总中断
while (1)
{
Delay_xms(1000);
}
}
/*****************
串口的中断处理函数
*****************/
void UART_Routine(void) interrupt 4
{
if (RI == 1)
{
RI = 0;
recv = SBUF;
SBUF = recv;
while (TI == 0);
TI = 0;
}
}
一、继电器
1.1 继电器的原理
继电器本质上是一个由电信号控制的机械开关。单片机输出的是低压、小电流控制信号,继电器触点负责接通或切断另一条负载回路,因此可用小信号控制单片机引脚不能直接驱动的负载。
继电器模块应分成三个层次理解:
- 控制信号层:单片机的
P2.0接模块的IN,决定模块是否触发。 - 驱动与线圈层:模块上的限流、反相或放大电路驱动继电器线圈;单片机引脚不直接承担线圈电流。
- 触点与负载层:
COM、NO、NC是一组机械触点,它们接在独立的负载回路中。
视频中的单路模块采用低电平触发,功能链路如下。模块的具体晶体管接法可能随型号变化,但作用关系相同:
控制侧(低压)
单片机 P2.0
│
└── IN ──> 输入限流/反相电路 ──> 线圈驱动管 ──> 继电器线圈
│ │
├─ 触发指示灯 │
└────续流保护─┘
模块 VCC ──> 线圈和驱动电路供电
模块 GND ──> 与单片机 GND 相连,作为控制信号的共同参考点
- 输入电阻限制
IN端电流,保护单片机和驱动器件。 - 驱动管完成电流放大或电平反相。继电器线圈通常需要的电流高于GPIO适合直接提供的电流,所以不能把裸继电器线圈直接接到
P2.0。 - 续流二极管通常反向并在线圈两端。线圈断电时会产生反向感应电压,二极管为线圈电流提供衰减通路,避免高压尖峰损坏驱动管。
- 电源指示灯只说明模块已经得到工作电源;触发指示灯说明驱动端进入触发状态。指示灯亮或听到吸合声,并不能完全证明外部负载回路接线正确、触点也一定完好。
视频所用模块的触发关系为:
P2.0/IN状态 | 模块状态 | 线圈状态 | 导通触点 |
|---|---|---|---|
低电平,约 0~1.2 V | 触发 | 得电吸合 | COM—NO |
| 高电平 | 未触发 | 失电释放 | COM—NC |
这里的 0~1.2 V 是视频中这块模块标示的低电平范围,不是所有继电器的统一参数。有些模块是高电平触发,有些带光耦或 JD-VCC 独立线圈电源,接线前应以模块丝印和说明书为准。
代码中的 sbit JDQ1 = P2^0; 只是给 P2.0 起了一个便于理解的名字。本讲的数据回环程序没有再给 JDQ1 赋值,因此这段程序本身不执行继电器开关动作。
1.1.1 电磁继电器百度百科
电磁继电器的核心部件包括线圈、铁芯、衔铁、复位弹簧和触点:
线圈失电(释放) 线圈得电(吸合)
复位弹簧 电磁吸力
↓ ↓
NC ●──────● COM NO ● NC ● ●──────● NO
动触点 动触点
COM
结果:COM 与 NC 导通 结果:COM 与 NO 导通
工作过程可以分为四步:
- 线圈通电后产生磁场,铁芯成为电磁铁。
- 电磁力吸引衔铁,使与衔铁相连的动触点发生位移。
- 动触点离开
NC,转而接触NO,负载回路随之切换。 - 线圈断电后磁力消失,复位弹簧使衔铁回到静止位置,
COM再次接回NC。
“常开”和“常闭”中的“常”,是指线圈未通电、继电器未吸合的常态,不是指单片机输出高电平或低电平:
| 触点名称 | 线圈未得电 | 线圈得电 |
|---|---|---|
NO(Normally Open,常开) | 与 COM 断开 | 与 COM 导通 |
NC(Normally Closed,常闭) | 与 COM 导通 | 与 COM 断开 |
COM(Common,公共端) | 接向 NC | 切换到 NO |
电磁继电器的线圈侧和机械触点侧在器件内部没有直接导线连接,因而能够实现控制回路与负载回路之间的电气隔离。不过,“继电器有隔离”不等于整块模块在任何条件下都绝对安全:模块是否带光耦、控制电源是否真正分开、PCB爬电距离和外壳防护是否合格,都要单独判断。
1.1.2 继电器插图
视频中的蓝色接线端子标有 NO、COM 和 NC。辨认端子时必须看模块丝印,不能只凭“中间一定是COM”来判断,因为不同模块的端子排列可能不同。
用低压灯理解负载侧接法
对初学者可先用安全的直流低压灯或LED灯模块验证,不要直接进行220V市电实验。例如希望继电器吸合后灯才亮,可使用 NO:
12 V 电源正极 ── 保险丝 ── COM
\
\ 线圈吸合后,COM 与 NO 接通
NO ── 12 V 灯 ── 12 V 电源负极
单片机侧:P2.0 ── IN 继电器模块:VCC、GND
负载侧: 12 V电源与灯 只经过COM、NO触点
此时的电流通路为:
线圈未吸合:COM 与 NO 断开 → 负载回路无电流 → 灯灭
线圈已吸合:12V+ → 保险丝 → COM → NO → 灯 → 12V- → 灯亮
如果希望设备在继电器未触发时默认工作,触发后停止,则把负载回路改用 COM 和 NC。COM 只是机械开关的公共触点,并不天然等于电源正极、负极或地;它接什么电位由负载回路的设计决定。
控制侧与负载侧的边界
flowchart LR
A[51单片机 P2.0] -->|低电平触发| B[模块输入与驱动电路]
B --> C[继电器线圈]
C -.磁力推动.-> D[机械触点 COM/NO/NC]
E[独立的负载电源] --> D
D --> F[灯或其他负载]
F --> E
虚线表示磁力造成的机械动作,不是控制侧和负载侧之间的导线。继电器适合控制灯、风扇、电磁阀等负载,但选择时必须同时检查:
- 线圈额定电压是否与模块供电匹配;
- 触点的交流/直流电压、电流和负载类型是否在额定范围内;
- 电机、灯丝等负载的启动电流可能远高于稳定工作电流;
- 继电器有机械寿命和电气寿命,不适合无节制地高速开关。
安全提示: 220V市电可能造成致命触电和火灾。初学阶段只做隔离的低压直流实验。市电控制还涉及保险、接地、阻燃外壳、线径、爬电距离和接线端防触碰等要求,不应仅凭一块裸露继电器模块搭接。
二、数据回环
2.1 继续上节代码
数据回环是指:单片机从串口收到一个字节后,不改变其数值,立即把同一个字节从串口发回。完整路径是:
电脑串口助手
│ 发送
▼
USB转TTL的 TXD ──> 单片机 RXD(P3.0)
│
▼
接收移位寄存器
│ 收满1帧,RI=1
▼
SBUF
│ 串口中断读取
▼
recv
│ 再写入SBUF
▼
发送移位寄存器
│ 发送完成,TI=1
▼
USB转TTL的 RXD <── 单片机 TXD(P3.1)
│ 接收
▼
电脑串口助手显示回传数据
初始化寄存器的作用如下:
| 语句 | 关键位 | 作用 |
|---|---|---|
SCON = 0x50 | SM0=0, SM1=1 | 串口方式1,8位UART,可变波特率 |
SCON = 0x50 | REN=1 | 允许串口接收 |
PCON &= 0x7F | SMOD=0 | 波特率不加倍 |
TMOD &= 0x0F | 清除高4位 | 清除定时器1原来的模式设置,不影响定时器0 |
| `TMOD | = 0x20` | M1=1, M0=0 |
TH1 = TL1 = 0xFD | 重装值为253 | 配合11.0592 MHz晶振产生9600 bit/s |
TR1 = 1 | TCON.TR1=1 | 启动定时器1 |
ES = 1 | IE.ES=1 | 允许串口中断 |
EA = 1 | IE.EA=1 | 打开总中断开关 |
在串口方式1、SMOD=0、定时器1方式2时:
$ \text{Baud}=\frac{2^{SMOD}}{32}\times\frac{f_{osc}}{12\times(256-TH1)} $
代入 fosc = 11.0592 MHz、TH1 = 0xFD = 253:
$ \text{Baud}=\frac{1}{32}\times\frac{11059200}{12\times(256-253)}=9600\ \text{bit/s} $
串口中断入口 interrupt 4 由接收标志 RI 和发送标志 TI 共用。本程序的回环过程为:
if (RI == 1)
{
RI = 0; // 软件清除接收完成标志
recv = SBUF; // 读出刚收到的1字节
SBUF = recv; // 把同一字节交给发送硬件
while (TI == 0); // 等待发送完成
TI = 0; // 软件清除发送完成标志
}
SBUF在程序中只有一个名字,但硬件内部的接收缓冲器和发送缓冲器是分开的:读 SBUF 取得接收数据,写 SBUF 启动发送。RI、TI 都必须由软件清零。
按照常见的 8N1 格式,一个字节在线路上包含1个起始位、8个数据位和1个停止位,共10位。9600 bit/s时传完一帧约需:
$ t_{byte}=\frac{10}{9600}\approx1.04\ \text{ms} $
先接收一帧、再回发一帧,纯线路往返时间至少约为 2.08 ms,还要叠加中断响应、USB转换和串口助手显示延迟。
本例为了直观看到回环,在串口中断里一直等待 TI=1,约占用1 ms。低速、少量数据时可以工作,但工程中通常要求中断服务尽快结束;连续高速接收时,长时间停留在中断中可能造成后续字节来不及处理。更稳妥的方式是中断中只读取 SBUF 并放入缓冲区,再由主循环或发送中断逐字节发送。
还要注意,当前的 UART_Send_Byte()、UART_Send_Str() 没有被调用。如果以后在 ES=1 时从主程序使用轮询发送,发送完成也会触发串口中断;届时中断函数必须同时判断并处理 TI,否则可能反复进入串口中断。应统一采用“轮询发送”或“发送中断”中的一种完整策略。
2.2 程序文件打开
下载程序前要先关闭串口助手占用的COM口。一个串口通常不能同时被下载工具和串口助手独占打开;若提示端口打开失败或下载无响应,应先检查串口助手是否仍处于“打开”状态。
经过单片机的数据回环测试
- 下载程序后,打开对应COM口,设置为
9600、8位数据位、无校验、1位停止位。 - 串口助手的发送区和接收区都选择
ASCII,发送字符a,接收区也应显示a。 - 两边都选择
HEX,发送61,接收区也应显示61。因为ASCII字符a的字节值就是十六进制0x61。 - 如果一边选ASCII、另一边选HEX,同一个字节会显示成不同外观;数据并没有因此改变。
视频所用软件以蓝色显示发送、绿色显示接收,这是该串口助手的界面规则,不是串口协议规定的颜色。
USB转TTL自身的硬件回环测试
把USB转TTL模块的 TXD 与 RXD 短接,不连接单片机,即可检查转换模块的基本收发通路:
电脑应用 ──USB──> USB转TTL发送器 ── TXD
│
└──短接线──> RXD
│
电脑应用 <─USB──── USB转TTL接收器 <────────────────┘
操作时应先确认引脚丝印,只短接 TXD 和 RXD,不要把电源脚与地脚短接。选择正确COM口并打开后,发送任意数据,若接收区出现完全相同的字节,说明USB枚举与驱动、串口助手、转换芯片的基本发送端和接收端大体正常。
在这种自身回环中,没有第二个独立设备使用另一套时钟来解释数据;同一个USB转TTL转换器按照当前配置发送,又按照同一配置接收,所以可在芯片支持范围内换用多种波特率进行测试。波特率仍然参与UART收发,并不是“回环时不需要波特率”。一旦连接单片机或其他串口设备,双方的波特率、数据位、校验位和停止位必须一致。
自身回环成功只能说明转换模块和电脑侧链路基本正常,不能证明以下部分没有问题:
- 单片机程序与晶振频率;
- 单片机
TXD/RXD的交叉接线和共地; - 3.3 V、5 V等逻辑电平是否兼容;
- 外部设备的波特率和帧格式;
- 继电器模块及其负载回路。
因此排查串口故障时,可先做USB转TTL自身回环,再接入单片机测试。这样能把问题逐步缩小到电脑侧、转换模块、接线或单片机程序中的某一部分。