裸机程序(3)
一、UART
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是一种异步串行通信协议,也是嵌入式系统中最常用的通信接口之一,主要用于实现两个设备之间的短距离数据传输。
核心功能
UART 是一种硬件电路或模块(可集成在芯片中,如单片机的 UART 外设),负责将并行数据(如 CPU 内部的 8 位数据)转换为串行数据(逐位传输)发送出去,同时将接收到的串行数据转换为并行数据供设备处理。
工作原理
UART 采用异步通信方式,无需专用时钟线,收发双方通过约定波特率(传输速率)实现同步。通信时,数据以 “帧” 为单位传输,帧结构固定(可配置):
- 起始位:1 位低电平(逻辑 0),标志一帧数据开始;
- 数据位:5~9 位(最常用 8 位),传输实际数据(如 ASCII 码);
- 校验位(可选):1 位(奇校验 / 偶校验 / 无校验),用于简单错误检测;
- 停止位:1~2 位高电平(逻辑 1),标志一帧数据结束。
9600,o,8,1
表示波特率位9600,o表示奇校验,8位数据位,1位停止位;
odd:奇校验,even:偶校验,none:无校验;
同步与异步:
同步需要SCL时钟信号线,让二者按照同样同一节奏传输;
异步无需信号线,约定波特率,以起始位+停止位来传输;
奇校验是指包括检验位本身前面是否有奇数个1,偶校验同理;
波特率:
由波特率决定:单位时间内传输的比特数;
常见的波特率有:1200、2400、4800、9600、115200。
注意:
1.空闲时为高电平,有数据起始位传递低电平;
2.发送的第一个比特在最右边(高位优先)。
关键特性
- 全双工通信:通过两根独立线路(TX 发送线、RX 接收线)实现同时收发数据;
- 电平兼容性:UART 本身定义的是逻辑信号(0/1),实际传输时需配合电平标准(如 TTL、RS232),需通过转换器(如 MAX232)适配不同电平;
- 灵活性:可通过软件配置波特率、数据位、校验位、停止位等参数,适配不同设备;
- 低成本:仅需 2 根信号线(TX、RX)+ GND 共地,硬件简单。
关于通信方式:
单工:一方单方面发送,另一方单方面接收;
半双工:双方都能实现发送与接收,但一方发送时另一方只能接收不能发送;
全双工:双方都可随时发送与接收,无其他限制;
通信(并行|串行)优缺点,并行干扰;全双工通信/半双工/单工
二、串口通信
串口通信是一种特殊的串行通信:异步全双工串行通信 。
连接方式:
设备 A 的发送线(TX) 连接设备 B 的接收线(RX);
设备 A 的接收线(RX) 连接设备 B 的发送线(TX);
两者地线(GND) 相连(共地,确保电平参考一致)
传输协议:
串口通信的 “电平标准” 定义了 “逻辑 0/1” 对应的电压,影响传输距离和抗干扰能力:
- TTL 电平:0=0V,1=3.3V/5V(单片机引脚常用),传输距离短(≤10 米),适合板内或近距离设备(如单片机与传感器)。
- RS232 电平:0=+3~+15V,1=-3~-15V(电脑 DB9 串口常用),传输距离中等(≤15 米),需通过芯片(如 MAX232)与 TTL 转换。
- RS485 电平:以差分信号(A、B 线电压差)表示 0/1,抗干扰极强,传输距离长(≤1200 米),支持多设备组网(如工业传感器总线)。
主从应答机制:
是一种基于 “主设备主导、从设备响应” 的通信规则,广泛应用于嵌入式系统、工业总线、传感器网络等场景。其核心逻辑是:由唯一的 “主设备” 发起通信请求、控制通信时序,多个 “从设备” 被动接收请求、执行指定操作,并向主设备返回 “应答信息”,以此确保通信的有序性、可靠性和可追溯性。Modbus 是基于 “主从应答机制” 设计的具体工业通信协议。
下列代码基于串口通信完成了主从应答机制:
#include <reg52.h>
#include "delay.h"
#include <stdio.h>
#include <string.h>
#include "key.h"
#include "digiter.h"
#include "led.h"xdata char rcv_buffer[64];
int pos = 0;void init_uart(void)
{unsigned char t;t = SCON;t &= ~(3 << 6); //清0t |= (1 << 6) | (1 << 4); //方式1 0 1, 允许串行接受状态,开启RXDSCON = t;PCON |= (1 << 7); //波特率加倍IE |= (1 << 7) | (1 << 4);t = TMOD;t &= ~(3 << 4);t |= (2 << 4);t &= ~(3 << 6);TMOD = t;TH1 = 208;TL1 = 208;TCON |= (1 << 6);
}void uart_handler(void) interrupt 4
{if((SCON & (1 << 0)) != 0){rcv_buffer[pos++] = SBUF;//P2 = SBUF;SCON &= ~(1 << 0); //标志位还原}
}void send_char(char ch)
{SBUF = ch;while((SCON & (1 << 1)) == 0);SCON &= ~(1 << 1);
}void send_buffer(const char *p, int len)
{while(len -- ){send_char(*p++);}
}int digiter_num = 0;int main(void)
{init_uart(); while(1){//send_char('A');//65//send_buffer(s, strlen(s));if(pos != 0){delay(0xFFFF);if(strcmp(rcv_buffer, "Hello") == 0){send_buffer("jj", 2);}else if(strcmp(rcv_buffer, "World") == 0){send_buffer("yes", 3);}memset(rcv_buffer, 0, sizeof(rcv_buffer));}delay(0x9FFF); }return 0;
}