1.基本概念
(1)串行通信,并行通信
通信方式 | 数据传输方式 | 所需数据线数量 | 传输速度 | 传输距离 | 抗干扰能力 | 硬件成本 | 常见接口/应用 |
---|---|---|---|---|---|---|---|
串行通信 | 数据一位一位 (bit) 依次传输 | 少(通常 1 根数据线 + 控制线) | 相对较低(单次仅 1 bit),但可通过高速协议弥补 | 长距离可靠(可达数米到数十公里) | 高(线少、同步机制强) | 成本低(布线简单) | UART、SPI、I²C、USB、CAN、RS232、RS485 |
并行通信 | 多个位(一般 8 位或 16 位)同时在多条线上并行传输 | 多(一般 8/16/32 根数据线 + 控制线) | 高(一次传多个 bit) | 短距离(通常在 PCB 内或板间连接) | 差(易受时序偏差和干扰影响) | 成本高(线多、排布复杂) | 内存总线、CPU 与外设总线、老式打印机并口 (LPT) |
(2)单工,半双工,全双工通信
通信方式 | 传输方向 | 是否可同时双向 | 带宽利用率 | 常见接口/标准 | 典型应用场景 | 举例 |
---|---|---|---|---|---|---|
单工 (Simplex) | 只能单向传输 | 否 | 低(仅一方使用通道) | 无特殊接口要求 | 信息广播、数据采集 | 收音机、电视广播、键盘输入 |
半双工 (Half Duplex) | 可双向传输,但同一时刻只能一个方向 | 否 | 中等(通道可切换方向,但有等待时间) | RS485、对讲机协议 | 节点较多但不要求实时双向通信的总线系统 | 对讲机、RS485 总线、旧式无线电台 |
全双工 (Full Duplex) | 可双向传输 | 是(同时收发) | 高(收发通道同时利用) | RS232、UART、TCP/IP、光纤通信 | 实时交互、数据吞吐要求高 | 电话、以太网、UART 串口通信 |
(3)什么是串口通信
串口通信:指通过串行接口(如 UART)逐位传输数据的通信方式。
(4)串口通信的通信时序
- 空闲时数据线为高电平;
- 发送发发送一个低电平表示起始位;
- 发送的第一个比特是最低为(最右边);
- 校验位分为奇校验,偶校验和无校验。奇校验是指确保数据位加上校验位中"1",1的总数为奇数;偶校验是指确保数据位加上校验位中"1",1的总数为偶数;
- 为保证下一个字节发送前的起始位能够表现出来,校验位之后发送一个停止位1。
(5)串口通信的速率(波特率)
决定因素:
串口的时钟频率(晶振 + 分频器)。
通信双方必须设置为相同的波特率。
常见波特率 :
9600、19200、38400、57600、115200、230400 bps 等。
(6)同步通信、异步通信
同步通信:通信双方共享同一个时钟信号,数据和时钟同步进行(如 SPI、I²C)。
异步通信:没有公共时钟,用起始位/停止位来实现同步(如 UART)。
串口通信(UART) :属于 异步通信。
(7)TTL,RS232,RS485
标准 | 电平范围 | 逻辑定义 | 通信方式 | 传输距离 | 特点/应用场景 |
---|---|---|---|---|---|
TTL | 0V(低) ~ 5V/3.3V(高) | 高电平=1,低电平=0 | 单端 | < 1m | 芯片之间短距离通信,常见于 MCU、模块接口(如 STM32、Arduino 的 UART) |
RS232 | -3V ~ -15V 表示逻辑 1;+3V ~ +15V 表示逻辑 0(与 TTL 相反) | 反逻辑 | 点对点 | ≤ 15m | 早期电脑串口、调制解调器,抗干扰比 TTL 强 |
RS485 | 差分信号:A、B 两根线电压差 | A-B > +200mV = 1;A-B < -200mV = 0 | 半双工或全双工(多点总线) | ≤ 1200m | 抗干扰强,支持多机通信,常用于工业现场总线、485 转换器 |
2.代码
(1)初始化
cs
void init_uart(void)
{
unsigned char t;
t = SCON;
t &= ~(3 << 6);
t |= (1 << 6) | (1 << 4);
SCON = t;
PCON |= (1 << 7);
TCON |= (1 << 6);
t = TMOD;
t &= ~(0xFFFF);
t |= (1 << 5);
t |= (1 << 0);
TMOD = t;
TH1 = 204;
TL1 = 204;
TH0 = a >> 8;
TL0 = a;
IE |= (1 << 4) | (1 << 7) | (1 << 1);
}
(2)发送函数
cs
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++);
}
}
(3)串口中断服务函数
cs
xdata char rcv_buffer[64] = {0};
int pos = 0;
void uart_handler(void) interrupt 4
{
if((SCON & (1 << 0)) != 0)
{
rcv_buffer[pos++] = SBUF;
SCON &= ~(1 << 0);
}
}
8051 的存储空间分为几类:
DATA:内部 RAM 的低 128 字节(0x00 ~ 0x7F),可直接寻址。
IDATA:内部 RAM 的全部 256 字节(0x00 ~ 0xFF),间接寻址。
XDATA :外部 RAM(0x0000 ~ 0xFFFF,最大 64KB),通过
MOVX
指令访问。CODE:程序存储器(ROM/Flash),存放程序和常量。
(4)检验大小端存储函数
cs
void check_mcu_endianness(void)
{
int n = 0x1234;
unsigned char *s = (unsigned char *)&n;
int i;
for (i = 0; i < sizeof(n); ++i)
{
sprintf(buffer, "%X", s[i]);
send_buffer(buffer, strlen(buffer));
send_char(' ');
}
send_char('\n');
}
(5)检测51单片机中数据类型所占用的字节
cs
int n;
n = sizeof(int);
sprintf(buffer, "int size = %d", n);
send_buffer(buffer, strlen(buffer));
(6)通信协议解析函数
cs
unsigned char sumOfTheArray(unsigned char *p, int len)
{
unsigned char sum = 0;
int i;
for(i = 0;i < len; ++i)
{
sum += p[i];
}
return sum;
}
void timer0_handler(void) interrupt 1
{
P2 ^= (1 << 1);
TH0 = a >> 8;
TL0 = a;
}
int *p;
int n = 0;
void parse(void)
{
if((unsigned char)rcv_buffer[0] == 0xAA && (unsigned char)rcv_buffer[pos - 1] == 0x0D)
{
if((unsigned char)rcv_buffer[1] == 0x01)
{
if(sumOfTheArray(rcv_buffer, 5) == (unsigned char)rcv_buffer[5])
{
if((unsigned char)rcv_buffer[2] == 0x01)
{
p = (int *)&rcv_buffer[3];
n = *p;
TCON &= ~(1 << 4);
}
else if((unsigned char)rcv_buffer[2] == 0x02)
{
p = (int *)&rcv_buffer[3];
n = *p;
if(200 == n)
{
a = HZ200;
TCON |= (1 << 4);
}
else if(400 == n)
{
a = HZ400;
TCON |= (1 << 4);
}
}
}
}
}
}
int main(void)
{
init_uart();
while(1)
{
if(pos != 0)
{
delay(0xFFFF);
parse();
pos = 0;
memset(rcv_buffer, 0, sizeof(rcv_buffer));
}
show_number(n);
}
}