串口: 每次传输是按位为单位进行传输的接口. 如uart, usb, 网络, sata. 一般就是只用一根数据线来接收或发送数据。
并口: 每次传输是两位或以上为单位进行传输的接口. 一般会用多根数据线来接收或发送数据.
单工: 只能单向传输的导线
半双工: 可以双向传输的导线,但某一时刻只能一个方向传输
全双工: 可以同时双向传输, 一般用两根单向导线实现
uart: 通用异步接收传送器(串口, COM口)
uart: Universal Asynchronous Receiver and Transmitter
uart图示:
计算机里根据到底就是使用二进制, 0和1, 物理上用高低电平表示.
011010可以使用低电平, 高电平, 高电平, 低电平, ……
把数据110010发给另一计算机, 可导线把相应的电平转给对方.对方可通过判断导线的电平从而知道发过来的是数据0还是数据1
设备A发(改变导线电平): 设备B接收(判断导线电平)
发送端设备与接收端设备的收发间隔时间必须保持一致
波特率(baud rate): 一秒钟内收发多少位数据, 也可算出一位数据在导线上需保持电平状态的时间
常用的波特率: 4800, 9600, 115200
Bps(byte 字节每秒钟), bps(bit, 位每秒钟)
一般情况下, 设备都是用电源负极作地线使用, 不同的设备的电源负极对真正的地线来说压降有可能不一样,
所以, 互相通信的设备都会共用地线, 保证基准电平一致.
按帧来收发数据:
一帧的组成 : 始启位(1位), 5/6/7/8位数据, 1位奇偶校验/或者不用, 1/2位停止位
数据线空闲时是高电平, 起始位是一个持续一位时间的低电平信号, 停止位是高电平
8N1: 表示使用8位数据位, 不用校验, 1位停止位来表示数据帧.
注意:起始位没有选择, 只有一位.
//
一个最基本的串口由三根线组成:
设备A: 设备B
TXD –>— RXD
RXD —<– TXD
GND —— GND
完善点的串口多引入CTS, RTS两根线(用于硬件流控). 发送端发数据前通过RTS发出请求信号, 如果接收端可以接收数据则会回一个信号确认, 发送端再接着发出数据.
CTS –<– RTS
RTS –>– CTS
注意:硬件流控一般情况下是不用的, 除非对方在使用,否则要关闭
/
TTL电平:
二进制1: 1.8v, 3.3v, 5v
0: 0v
串口直接从cpu里引出时,是使用TTL电平的
导线越长,内阻越大. 内阻会分部分压降, 接收会有可以接收到电平时, 电压值已经下降很多.
解决这个问题: 引入RS232接口标准, 是uart的接口标准之一.
RS232的电平:
二进制1: -3 ~ -25v
0: 3 ~ 25v
ttl电平与rs232电平, 可由芯片互转換. 如MAX232, SP3232
注意: rs232只是改变uart引脚的电平,uart的线原有多少根还是多少根的
uart的接口标准还有 RS485, RS422
RS232早期是25个针脚, 可接modem, 56kb/s
后面精简为9个针脚,除了上面5个针脚外,还有4针脚可用于接modem.
RS232共有9个针脚: tx, rx, gnd, cts, rts
还有4个用于接modem(非常老的产物)
///
串口硬件需通过相应的驱动代码来配置, 而驱动是由应用程序来调用的
///
在Linux系统里,串口的设备文件是: ttyS0—ttyS3
usb转uart的设备文件: ttyUSB0 — ttyUSB1
//
1. open(“/dev/ttyS0”, O_RDWR|O_NOCTTY|O_NONBLOCK);
O_NOCTTY指定打开的串口设备文件不会成为本进程的控制终端. 在终端上执行程序后,可按”ctrl+c”键终止程序运行. 如果打开的串口设备文件成为本进程的控制终端时, 发过来数据刚好与”ctrl+c”的键码一致时,就会终止程序的运行
O_NONBLOCK指定打开串口设备文件时,不管串口的工作状态. 不加上此标志, 会一直等串口的状态恢复为空闲时再会成功打开, 有可能会死堵塞.
//恢复为堵塞工作模式
fcntl(fd, F_SETFL, 0);///
//配置波特率, 数据位, 校验位, 停止位
struct termios opts;tcgetattr(fd, &opts); //先把原来的属性获取保存到opts结构体变量里
//ioctl(fd, TCGETS, &opts);//在opts结构体变量修改波特率的配置
cfsetispeed(&opts, B9600);
cfsetospeed(&opts, B9600);opts.c_cflag |= CREAD|CLOCAL; //启动接收器, 不管modem的控制线状态
/// 8N1
opts.c_cflag &= ~CSIZE; //在c_cflag里把表示数据位的位域清零
opts.c_cflag |= CS8;
opts.c_cflag &= ~PARENB; //不用校验
opts.c_cflag &= ~CSTOPB; //使用一位停止位
opts.c_cflag &= ~CRTSCTS; //关闭硬件流件//如PC对PC通信,需要设raw input, raw output
opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
opts.c_oflag &= ~OPOST;///把opts变量里的属性传给串口驱动,让配置生效
tcsetattr(fd, TCSANOW, &opts);
//ioctl(fd, TCSETS, &opts);
//配置好后,就可以通过read/write函数收发数据了
RS232是uart接口标准之一.
RS485也是uart的接口标准之一. 使用差分传输, 远距离传输, 抗干扰能力强
云台, 舞台灯光控制, 小型飞机的控制总线
差分传输是通过两根数据线的电压差来表示0/1. 发送的数据线需两根.
例: 相差10V表示1, 相差0V表示0
tx+(5) ————–[3V]————- 2V
tx-(-5v) ---------------[3V]------------ -8V
//
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main(void)
{
int fd, ret;
fd = open("/dev/ttyS0", O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd < 0)
{
perror("open ttyS0");
return 1;
}
fcntl(fd, F_SETFL, 0); //重设为堵塞状态, 去掉O_NONBLOCK
//////////////////
struct termios opts;
tcgetattr(fd, &opts); //把原设置获取出来,存放在opts
//设置波特率
cfsetispeed(&opts, B19200);
cfsetospeed(&opts, B19200);
opts.c_cflag |= CLOCAL|CREAD; //忽略modem控制线, 启动接收器
// 8N1
opts.c_cflag &= ~PARENB;
opts.c_cflag &= ~CSTOPB;
opts.c_cflag |= CS8;
opts.c_cflag &= ~CRTSCTS; //关闭硬件流控
opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //raw input
opts.c_oflag &= ~OPOST; // raw output
tcsetattr(fd, TCSANOW, &opts);
//////////////////
char data[1024];
while (1)
{
ret = read(fd, data, sizeof(data));
data[ret] = 0;
printf("got : %s\n", data);
}
close(fd);
return 0;
}