51单片机-串口通信
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)初始化
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)发送函数
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)串口中断服务函数
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)检验大小端存储函数
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单片机中数据类型所占用的字节
int n;
n = sizeof(int);
sprintf(buffer, "int size = %d", n);
send_buffer(buffer, strlen(buffer));
(6)通信协议解析函数
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);}
}