目录
2.1串口连接
2.2工作原理||数据通讯格式
2.2.1起始位
2.2.2数据位
2.2.3奇偶校验位
2.2.4停止位
2.2.5协议层
2.2.6波特率
2.2.7数据校验
2.3传输步骤
2.4IMX6ULL驱动开发-基于UART框架发送/接收串口数据
2.4.1在设备树中添加uart3子节点
2.4.2编写串口测试程序
2.5优缺点
UART(Universal Asynchronous Receiver/Transmitter)通用异步接收器/发送器,通常称为UART,是一种广泛应用于嵌入式领域的串行、异步、全双工通信协议。
2.1串口连接
UART 通道有两条数据线。每个设备上都有一个 RX 引脚和一个 TX 引脚(RX 用于接收,TX 用于发送)。每个设备的 RX 引脚都连接到另一个设备的 TX 引脚。
UART属于异步通信,没有时钟信号。它会在数据包中增加开始和停止位。这些位定义了数据包的开始和结束,因此接收UART知道何时读取这些数据。 当接收UART检测到起始位时,它将以特定的波特率的频率读取(数据传输速度的度量),以每秒比特数(bps)表示。两个UART必须以大约相同的波特率工作,发送的接收UART之间的波特率只能相差约10%。
2.2工作原理||数据通讯格式
2.2.1起始位
每次通信开始时,发送方发送一个逻辑“0”信号(VOL),表示传输字符的开始。由于总线空闲时为高电平,因此在开始通信时先发送一个与空闲状态明显不同的信号,即(低位 0)。
2.2.2数据位
起始位之后是我们要传输的数据。数据位可以是5、6、7、8、9位等组成一个字符(通常是8位)。如ASCII码(7位)、扩展BCD码(8位)。首先发送最低位(个位),最后发送最高位。用低电平 表示“0”,高电平表示“1”,完成数据位的传输。
2.2.3奇偶校验位
将该位添加到数据位后,“1”位的个数应为偶数(偶校验)或奇数(奇校验),以验证数据传输的正确性。校验位实际上就是调整数,串口校验分为几种方式:
无奇偶校验
奇校验:如果数据位中“1”的个数为偶数,则奇偶校验位为“1”,如果“1”的个数为奇数,则奇偶校验位为“0”。
偶校验:如果数据中“1”的个数为偶数,则奇偶校验位为“0”,如果数据中“1”的个数为奇数,则奇偶校验位为“1”。
标记奇偶校验:校验位始终为1(不常用)。
奇偶校验:奇偶校验位始终为0(不常用)
2.2.4停止位
它是字符数据的结束标记。它可以是 1 位、1.5 位或 2 位 VOH。由于数据在传输线上是定时的,并且每个设备都有自己的时钟,所以在通信时两个设备之间很可能会出现小的不同步。因此停止位不仅表示传输的结束,而且还为计算机提供了纠正时钟的机会。停止位越多,数据传输越稳定,但数据传输速度越慢。
2.2.5协议层
在协议层中,规定了数据包的内容,由起始位、主要数据、校验位和停止位组成。双方的数据包格式必须约定一致,才能正常发送和接收数据。
2.2.6波特率
由于异步通信中没有时钟信号,因此两个通信设备需要就波特率达成一致。常见的有4800、9600、115200等。
通讯起始和停止信号:串行通讯的数据包从起始信号开始,以停止信号结束。数据包的起始信号用逻辑0的数据位表示,数据包的停止信号可以用0.5、1、1.5或2个逻辑1的数据位表示,只要双方同意即可。
2.2.7数据校验
有效数据后有一个可选的数据校验位。由于数据通信比较容易受到外界干扰,导致传输数据出现倾斜,可以在传输过程中添加校验位来解决这个问题。校验方式有奇校验、偶校验、0校验(空格)、1校验(标记)、无奇偶校验。
奇校验要求有效数据和奇偶校验位中“1”的数量为奇数。
例如,8位有效数据为01101001,共有4个“1”。如果校验位为“1”,则最后发送的数据为8位有效数据加1位校验位,共9位。偶校验和奇校验的要求正好相反。要求帧数据中“1”的个数和奇偶校验位均为偶数,如数据帧:11001010,此时数据帧中“1”的个数为4个,因此偶校验位为“0”(偶数)。0校验表示无论有效数据的内容是什么,校验位始终为“0”,1校验表示校验位始终为“1”。
2.3传输步骤
1.发送UART从数据总线并行接收数据
2.发送UART将起始位、奇偶校验位和停止位添加到数据帧。
3.整个数据包从发送UART串行发送到接收UART。接收UART以预先配置的波特率对数据线进行采样。
4.接收UART丢弃数据帧中的起始位、奇偶校验位和停止位:
5.接收UART将串行数据转换回并行数据,并将其传输到接收端的数据总线:
2.4IMX6ULL驱动开发-基于UART框架发送/接收串口数据
2.4.1在设备树中添加uart3子节点
1)设置UART3引脚
在iomucx节点中添加uart3子节点:
pinctrl_uart3: uart3grp {fsl,pins = <MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0x1b0b1MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0x1b0b1>; };
检查一下这两个引脚是否被使用
已经被uart2用作rts和cts引脚,直接注释掉:
2)添加uart3节点
&uart3 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart3>;status = "okay";
};
3)测试是否生成设备文件
重新编译设备树
make dtbs
使用新的设备树启动,查看是否生成对应的串口设备文件:
可以看到,系统已经有ttymxc2这个串口设备口,对应UART3,应用程序可以通过访问此设备实现对UART3的操作。
2.4.2编写串口测试程序
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <termios.h>
#include <string.h>int uart_setup(int fd)
{struct termios newtio;// 获取原有串口配置if (tcgetattr(fd, &newtio) < 0) {return -1;}// 修改控制模式,保证程序不会占用串口newtio.c_cflag |= CLOCAL;// 修改控制模式,能够从串口读取数据newtio.c_cflag |= CREAD;// 不使用流控制newtio.c_cflag &= ~CRTSCTS;// 设置数据位newtio.c_cflag &= ~CSIZE;newtio.c_cflag |= CS8;// 设置奇偶校验位newtio.c_cflag &= ~PARENB;newtio.c_iflag &= ~INPCK; // 设置停止位newtio.c_cflag &= ~CSTOPB;// 设置最少字符和等待时间newtio.c_cc[VTIME] = 1;newtio.c_cc[VMIN] = 1;// 修改输出模式,原始数据输出newtio.c_oflag &= ~OPOST;newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);// 设置波特率cfsetispeed(&newtio, B115200); cfsetospeed(&newtio, B115200);// 清空终端未完成的数据tcflush(fd,TCIFLUSH);// 设置新属性if(tcsetattr(fd, TCSANOW, &newtio) < 0) {return -1;}return 0;
}int uart_send(int fd, char *buf, int len)
{int count;count = write(fd, buf, len);return count == len ? len : -1;
}int main(int argc, char *argv[])
{int fd;int ret;int count = 100;char send_buf[] = "Hello World!\r\n";if (argc != 2) {printf("usage: ./test_uart [device]\n");return -1;}/* 打开串口 */fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);if (fd < 0) {printf("open dev fail!\n");return -1;}/* 设置串口 */ret = uart_setup(fd);if (ret < 0) {printf("uart setup fail!\n");close(fd);return -1;}while (count--) {ret = uart_send(fd, send_buf, strlen(send_buf));if (ret < 0) {printf("send fail!\n");} else {printf("send ok!\n");}sleep(2);}close(fd);
}
编译:
arm-linux-gnueabihf-gcc test_uart.c -o test_uart
运行:
./test_uart /dev/ttymxc2
再看看另一侧的串口终端是否收到数据:
2.5优缺点
优点: 1.仅使用两根线 2.异步通信,无需时钟信号 3.具有奇偶校验位以允许进行错误检查、 4.只要双方都设置好数据包的结构 缺点: 1.数据帧的大小最大为9位 2.不支持多个从属系统或多个系统 3.每个UART的波特率必须在彼此的10%之内