第二讲:物理层接口与驱动开发
各位同学,今天咱们聊聊物理层。说白了,就是POS机和外界通信的那根“线”怎么干活。
我做了十几年嵌入式通信,最深的体会是:物理层搞不定,上层协议再漂亮也是白搭。你想想看,数据发不出去,或者发出去全是乱码,应用层写得再好有什么用?
2.1 串口通信:RS232 vs RS485
串口是POS机最常用的物理接口。但RS232和RS485,很多人傻傻分不清。
2.1.1 RS232:点对点的老将
RS232是单端信号,一根信号线对地。电压范围是±3V到±15V。逻辑1是负电压,逻辑0是正电压——这个和TTL电平刚好相反,要注意。
我在项目中遇到过一个问题:某款POS机接打印机,死活通信不上。查了半天,发现是电平转换芯片坏了,输出只有±2V,接收端不认。嗯,RS232的电压余量一定要留够。
| 参数 | RS232 | RS485 |
|---|---|---|
| 信号方式 | 单端 | 差分 |
| 最大距离 | 约15米 | 约1200米 |
| 节点数 | 1对1 | 最多32个节点 |
| 电压范围 | ±3V ~ ±15V | ±1.5V ~ ±6V |
2.1.2 RS485:长距离多节点
RS485用差分信号,抗干扰能力强。POS机在超市收银台,旁边就是大功率电器,这时候RS485就比RS232靠谱得多。
我建议:如果距离超过10米,或者环境有电磁干扰,果断选RS485。别为了省一个电平转换芯片的钱,后面调试到崩溃。
2.2 GPIO模拟UART:没有串口怎么办?
有些低成本MCU,硬件UART数量不够。或者你用的引脚被其他功能占用了。怎么办?用GPIO模拟。
说白了,就是用两个普通IO口,一个当TX,一个当RX,靠软件定时器来模拟波特率。
2.2.1 基本原理
UART一帧数据包括:起始位(低电平)、8个数据位(LSB first)、可选的校验位、停止位(高电平)。
模拟发送很简单:拉低TX引脚(起始位),然后按位发送数据,最后拉高(停止位)。关键是时序要准。
// GPIO模拟UART发送一个字节
void gpio_uart_send_byte(uint8_t data) {
// 起始位:拉低
GPIO_WriteLow(TX_PIN);
delay_us(BIT_TIME);
// 发送8个数据位,LSB first
for (int i = 0; i < 8; i++) {
if (data & 0x01) {
GPIO_WriteHigh(TX_PIN);
} else {
GPIO_WriteLow(TX_PIN);
}
data >>= 1;
delay_us(BIT_TIME);
}
// 停止位:拉高
GPIO_WriteHigh(TX_PIN);
delay_us(BIT_TIME);
}
2.2.2 接收的坑
接收比发送难。因为你要检测起始位的下降沿,然后精确采样每个数据位的中点。
我曾经犯过一个错误:采样点选在了数据位的边缘。结果电平刚好在跳变,读到的数据全是错的。正确做法是:在每位的中点采样,也就是延时半个位时间后再读。
2.3 SPI接口调试:高速通信的利器
SPI在POS机里常用于连接安全模块、显示屏、SD卡等。速度比UART快得多,但调试起来也麻烦一些。
2.3.1 四根线搞定
SCK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。
注意:SPI有四种模式,由时钟极性(CPOL)和时钟相位(CPHA)决定。我见过太多人栽在这个上面。
| 模式 | CPOL | CPHA | 数据采样边沿 |
|---|---|---|---|
| 模式0 | 0 | 0 | 上升沿采样 |
| 模式1 | 0 | 1 | 下降沿采样 |
| 模式2 | 1 | 0 | 下降沿采样 |
| 模式3 | 1 | 1 | 上升沿采样 |
怎么确定用哪种模式?看从设备的数据手册。如果手册说“数据在时钟上升沿锁存”,那就是模式0或模式3。具体看空闲时时钟电平。
2.4 物理层波形分析:示波器是照妖镜
做物理层开发,示波器就是你的眼睛。没有它,你就是在黑暗中摸索。
2.4.1 看什么?
- 电压幅值:信号有没有达到接收端要求的电平?RS232要±5V以上,TTL要3.3V或5V。
- 上升/下降时间:太慢会导致位宽失真,太快会产生过冲和振铃。
- 时序关系:时钟和数据之间的建立时间、保持时间够不够?
- 噪声:有没有毛刺?电源纹波会不会耦合到信号线上?
2.4.2 实战案例
有一次,POS机读卡器偶尔读不到卡。用示波器一看,SPI时钟线上有个窄毛刺,刚好在数据采样时刻出现。原因是PCB走线太长,信号反射造成的。
解决办法:在时钟线靠近源端串一个22Ω电阻,吸收反射。毛刺消失了,问题解决。
2.5 驱动开发要点总结
写物理层驱动,我总结了三条原则:
- 先看波形,再写代码。用示波器确认硬件连接没问题,再动手写驱动。否则你都不知道是硬件问题还是软件问题。
- 分层测试。先测发送,再测接收。发送用示波器看波形对不对,接收用串口助手或逻辑分析仪看数据对不对。
- 异常处理不能省。超时、帧错误、溢出错误,都要有对应的处理逻辑。我见过太多驱动,正常通信没问题,一遇到干扰就死机。
好了,物理层就讲到这里。下一讲咱们聊聊数据链路层,看看怎么把物理层传过来的比特流,组装成完整的报文帧。
公众号:蓝海资料掘金营,微信deep3321