域名查询网站wordpress高德地图插件
- 作者: 五速梦信息网
- 时间: 2026年04月20日 06:52
当前位置: 首页 > news >正文
域名查询网站,wordpress高德地图插件,谷歌网站流量统计,wordpress做商品筛选目录 前言一、tty体系二、串口硬件基础知识三、Linux下的串口编程3.1 打开串口3.2 从串口读写数据,问题1、2的诞生3.3 关闭串口3.4 串口配置3.4.1 获取/设置串口的参数3.4.2 设置波特率3.4.3 设置控制模式标志3.4.4 设置本地模式标志3.4.5 设置输入模式标志3.4.6 设置输出模式标… 目录 前言一、tty体系二、串口硬件基础知识三、Linux下的串口编程3.1 打开串口3.2 从串口读写数据,问题1、2的诞生3.3 关闭串口3.4 串口配置3.4.1 获取/设置串口的参数3.4.2 设置波特率3.4.3 设置控制模式标志3.4.4 设置本地模式标志3.4.5 设置输入模式标志3.4.6 设置输出模式标志3.4.7 设置控制字符3.4.8 清空发送/接收缓冲区 四、解决问题 1、24.1 cfmakeraw() RAW模式4.2 改进串口数据读取 五、完整的示例代码六、参考链接 前言
在嵌入式Linux中串口是一个字设备访问具体的串行端口的编程与读写文件的操作类似只需打开相应的设备文件即可操作。串口编程特殊在于串口通信时相关参数与属性的设置。嵌入式Linux的串口编程时应注意若在根文件中没有串口设备文件应使用mknod命令创建这这里假设串口设备是/dev/ttyS0介绍一下串口的编程过程。 mknod /dev/ttyS0 c 4 64
一、tty体系
tty是teletype的缩写在上世纪计算机还很昂贵的时候多人可以通过这种终端来连接并共用一台计算机发展到今日tty已经成为了字符类设备的统称这类设备包括控制台、UART等物理串行接口以及伪终端。也就是说开发板物理串口一般对应linux中/dev目录下的tty设备文件访问这些文件就访问硬件串口了。
二、串口硬件基础知识
串口是一类以串行方式传输数据的接口每次1bit这类接口常用于网络设备、键盘、鼠标、调制解调器、以及终端设备teletype上世纪电脑还是大块头时大家通过这种设备远程共用一台电脑等。
常用bps每秒传输的位数或称为波特率来表示串口的通讯速度常见的有9600bps、38400bps、115200bps等。
对于常用的RS232接口除了常见的TXD、RXD、GND这三个必须的通讯信号线外还有一些用于控制的信号线
名称方向用途DCDData Carrier Detect输入如果读到低电平逻辑1说明线缆对面的设备已经正确连接。DTRData Terminal Ready输出输出低电平逻辑1表明我方已经准备好数据传输一般软件打开串行端口时此信号会自动拉低。CTSClear To Send输入如果读到低电平逻辑1说明线缆对面的设备允许我们此时发送数据。RTSRequest To Send输出输出低电平逻辑1以请求线缆对面的设备传输数据大多数时候此信号线总是输出低电平。 一般在连接时我方的DTR连接对方的DCD我方的RTS连接对方的CTS反之亦然。**DCD和DTR信号用于设备检测CTS和RTS信号用于进行信号流控制除此之外还有一种软件信号流控制方法当然我在工作中很少用到这些。 三、Linux下的串口编程
既然Linux下串口设备是以文件的形式存在我们当然可以用通用的文件I/O函数访问它们不过访问设备文件一般需要超级管理员权限在开发板上我们一般以root身份登录系统这当然也就不存在问题。除此之外为了对串口进行设置Linux系统提供了一个名为 termios.h 的文件里面包含串口设置相关的数据结构以及函数接口这些函数接口归根结底其实也是调用了文件I/O函数中的ioctl函数。
下面的示例代码中均默认包含以下头文件
#include stdio.h
#include string.h
#include unistd.h / UNIX standard function definitions /
#include fcntl.h / File control definitions /
#include errno.h / Error number definitions /
#include termios.h / POSIX terminal control definitions /3.1 打开串口
以下代码演示如何正确打开一个串口设备文件
打开串口设备文件的操作与普通文件的操作类似都采用标准的I/O操作函数open()。 fd open(/dev/ttyS0,O_RDWR|O_NDELAY|O_NOCTTY);open()函数有两个参数第一个参数是要打开的文件名此处为串口设备文件/dev/ttyS0);第二个参数设置打开的方式O_RDWR表示打开的文件可读/写O_NDELAY表示以非阻塞方式打开ONOCTTY表示若打开的文件为终端设备则不会将终端作为进程控制终端。
3.2 从串口读写数据,问题1、2的诞生
串口的数据读/写与普通文件的读/写一样都是使用read()/write()函数实现。 n write( fd, buf, len ); //将buf中len个字节的数据从串口输出返回输出的字节数 n read( fd, buf, len ); //从串口读入len个字节的数据并放入buf, 返回读取的字节数 示例如下 写数据
/** write data to serial port return the length of bytes actually written on success, or -1 on error*/
ssize_t write_port(int fd, void buf,size_t len)
{ssize_t actual_write;actual_write write(fd, buf, len);if (actual_write -1){/ write failure /perror(write_port: Unable to write port - );}return actual_write;
}
读数据
/** read data from serial port return the length of bytes actually read on success, or -1 on error*/
ssize_t read_port(int fd, void buf, size_t len)
{ssize_t actual_read;actual_read read(fd, buf, len);if (actual_read -1){/ read failure /perror(read_port: Unable to read port - );}return actual_read;
}
函数实现了读取功能但是存在两个问题 1.只有在读完一行才会退出也就是读到’\r’或’\n’否则进程会一直堵塞到read函数上; 2.如果串口没有收到数据函数会一直堵塞直到超时或接收到数据最小接收长度以及超时时间可以通过后面提到的配置函数进行配置 问题1可以通过设置串口终端工作在RAW模式解决问题2可以通过设置串口的最小接收字节数和超时时间解决具体见 3.4 小节的串口配置内容。
3.3 关闭串口
关闭串口的操作很简单将打开的串口设备文件句柄关闭即可。
close(fd);3.4 串口配置
Linux提供了一组用于配置串口终端的数据结构以及对应的函数接口称为 “POSIX termios interface”。要使用它们只需要包含此头文件
#include termios.h / POSIX terminal control definitions */它的参数设置需要使用struct termios结构体这个结构体在termio.h文件中定义且应在程序中包含这个头文件。
typedef unsigned char cc_t ;
typedef unsigned int speed_t ;
typedef unsigned int tcflag_t ;
struct termios{tcflag_t c_iflag ; /输入模式标志/tcflag_t c_oflag ; /输出模式标志/tcflag_t c_cflag ; /控制模式标志/tcflag_t c_lflag ; /本地模式标志/tcflag_t c_line ; /行规程类型一般应用程序不使用/cc_t c_cc[NCC]; /控制字符/speed_t c_ispeed ; /输入数据波特率/speed_t c_ospeed ; /输出数据波特率/};串口的设置主要是设置这个结构体的各成员值然后利用该结构体将参数传给硬件驱动程序。在Linux中串口以串行终端的方式进行处理因而可以使用tcgetattr()/tcsetattr()函数获取/设置串口的参数。
3.4.1 获取/设置串口的参数
通过系统提供的如下两个接口我们可以获取当前串口的状态或设置新的状态
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);这两个参数都有一个批向termios结构体的指针作为参数用于返回当前终端的属性或设置该终端的属性。参数fd就是用open()函数打开的终端文件句柄而串口就是用open()打开的串口设备文件句柄。tcsetattr()函数的optional_action参数用于指定新设定的参数起作用的时间其设定值可以为
TCSANOW 改变立即生效TCSADRAIN 在所有的输出都被传输后改变生效适用于更改影响输出参数的情况。TCSAFLUSH 在所有输出都被传输后改变生效丢弃所有末读入的输入清空输入缓 存。
3.4.2 设置波特率
使用cfsetospeed()/cfsetispeed()函数设置波特率它们分别用于在termios结构体中设置输出和输入的波特率。设置波特率可以使用波特率常数其定义为字母“B速率”如B19200就是波特率为19200bpsB115200就是波特率为115200bps。
int cfsetispeed( struct termios *termios_p, speed_t speed ); //speed为波特率常数
int cfsetospeed( struct termios *termios_p, speed_t speed );例
cfsetispeed( ttys0_opt, B115200 );
cfsetospeed( ttys0_opt, B115200 );3.4.3 设置控制模式标志
控制模式标志c_cflag主要用于设置串口对DCD信号状态检测、硬件流控制、字符位宽、停止位和奇偶校验等常用标志位如下 CLOCAL 忽略DCD信号若不使用MODEM或没有串口没有CD脚就设置此标志 CREAD 启用接收装置可以接收字符 CRTSCTS 启用硬件流控制对于许多三线制的串不应使用需设置CRTCTS CSIZE 字符位数掩码常用CS8 CSTOPB 使用两个停止位若用一位应设置CSTOPB PARENB 启用奇偶校验 例如下面的代码将串口设置为忽略DCD信号启用接收装置关闭硬件流控制传输数据时使用8位数据位和一位停止位8N1不使用奇偶校验。 struct temios ttys0ttyso_opt.c_cflag | CLOCAL | CREAD ; //将CLOCAL与CREAD位设置为1ttys0_opt.c_cflag ~CRTSCTS ; //将硬件流控制位CRTSCTS清0其他位不变ttys0_opt.c_cflag CSIZE //清除数据位掩码ttys0_opt.c_cflag | CS8 ; //设置8位数据位标志CS8ttys0_opt.c_cflag ~(PARENB|CSTOPB); //使用1位停止位停用奇偶校验3.4.4 设置本地模式标志
本地模式标志c_lflag主要用于设置终端与用户的交互方式常见的设置标志位有ICANONECHO和ECHOE等。其中ICANON标志位用于实现规范输入即read()读到行结束符后返回常用于终端的处理若串口用于发送/接收数据则应清除此标志使用非规范模式(raw mode)。非规范模式中输入数据不组成行不处规范模式中的特殊字符。在规范模式中当设置ECHO标志位时用户向终端输入的字符将被回传给用户当设置ECHOE标志位时用户输入退格键时则回传“退格空格退格”序列给用户使得退格键覆盖的字符从显示中消失这样更符合用户的习惯若未设置此标志输入退格键时则光标回退一个字符但原有的字符未从显示中消失。
3.4.5 设置输入模式标志
输入模式标志c_iflag主要用于控制串口的输入特性常用的设置有IXOFF和IXON分别用于软件流控制。其中IXOFF用于防止输入缓冲区溢出IXON则是在输入数据中识别软件流控制标志。由于许多嵌入式系统无法使用硬件流控制因此只能使用软件流控制数据传输的速度但是它可能降低串口数据传输效率。启用软件流控制的代码如下 ttys0_opt.c_iflag | IXOFF|IXON ;3.4.6 设置输出模式标志
输出模式标志c_oflag主要用于对串口在规范模式时输出的特殊字符处理而对非规范模式无效。
3.4.7 设置控制字符
在非规范模式中控制字符数组c_cc[]中的变量c_cc[VMIN]和c_cc[VTIME]用于设置read()返回前读到的最少字节数和读超时时间其值分为四种情况
1.c_cc[VMIN]0c_cc[VTIME]0 读到一个字节后启动定时器其超时时间为c_cc[VTIME],read()返回的条件为至少读到c_cc[VMIN]个字符或定时器超期。2.c_cc[VMIN]0, c_cc[VTIME] 0 只要读到数据的字节数大于等于c_cc[VMIN]则read()返回否则将无限期阻塞等待。3.c_cc[VMIN] 0, c_cc[VTIME]0 只要读到数据则read()返回若定时器超期定时时间c_cc[VTIME]却未读到数据则read()返回04.c_cc[VMIN] 0, c_cc[VTIME] 0 若有数据则read()读取指定数量的数据后返回若没有数据则read()返回0
在termios结构体中填写完这些参数后接下来就可以使用tcsetattr()函数设置串口的属性。
tcsetattr( fd, old_opt ); //将原有的设置保存到old_opt以便程序结束后恢复
tcsetattr( fd, TCSANOW, ttsy0_opt );3.4.8 清空发送/接收缓冲区
为保证读/写操作不被串口缓冲区中原有的数据干拢可以在读/写数据前用tcflush()函数清空串口发送/接收缓冲区。tcflush()函数的参数可为
TCIFLUSH 清空输入队列
TCOFLUSH 清空输出队列
TCIOFLUSH 同时清空输入和输出队列四、解决问题 1、2
4.1 cfmakeraw() RAW模式
示例为一个串口配置函数其将串口配置为传入的波特率8位数据位无校验位RAW格式
/** config serial port baud * and set data format to 8N1(8bits data, no parity bit, 1 stop bit)* return 0 on success, or -1 on error/
int config_port(int fd, speed_t baud)
{struct termios term;/ read serial port configure /if (tcgetattr(fd, term) ! 0){perror(config_port: Unable to read configure - );return -1;}/ set baudrate /cfsetspeed(term, baud);/ 8N1 mode /term.c_cflag ~PARENB;term.c_cflag ~CSTOPB;term.c_cflag ~CSIZE;term.c_cflag | CS8;/ enbale raw mode /cfmakeraw(term);/ write serial port configure /if (tcsetattr(fd, TCSADRAIN, term) ! 0){perror(config_port: Unable to write configure - );return -1;}
}cfmakeraw() 函数使得串口工作于RAW模式在此模式下tty子系统会将从串口收到的所有字节数据直接递交给应用层而不进行额外处理此时read()函数会在读取完缓冲区的所有数据后立刻退出并返回实际读到的数值而不是等到\r或\n的到来这便解决了上面读取函数的问题1。
4.2 改进串口数据读取
可以在开启串口的RAW模式后通过配置termios结构体中的成员
.c_cc[VTIME]; / 指定超时时间 /
.c_cc[VMIN]; / 指定最少读取的字节 /来指定read读取时至少需要读到多少字节才返回这个需要配合串口的RAW格式也可以对接收的超时时间进行设置如果将这 两者都设为0则不管是否读到数据read函数都会立刻退出这就解决了前面提到的问题2。
五、完整的示例代码
仅供参考
#include errno.h / Error number definitions /
#include fcntl.h / File control definitions /
#include stdio.h
#include string.h
#include termios.h / POSIX terminal control definitions /
#include unistd.h / UNIX standard function definitions //** open serial port return file descriptor on success or -1 on error.*/
int open_port(char path)
{int fd;fd open(path, O_RDWR | O_NOCTTY | O_NDELAY);if (fd -1){/ open failure, print system error msg. /perror(open_port: Unable to open port - );}else{/ clear file descriptor flags /fcntl(fd, F_SETFL, 0);return fd;}
}/** write data to serial port return the length of bytes actually written on success, or -1 on error*/
ssize_t write_port(int fd, void buf, size_t len)
{ssize_t actual_write;actual_write write(fd, buf, len);if (actual_write -1){/ write failure /perror(write_port: Unable to write port - );}return actual_write;
}/ set timeout and minimum number of bytes to read /
int read_port_setup(int fd, cc_t timeout_sec, cc_t min_bytes)
{struct termios term;/ read serial port configure /if (tcgetattr(fd, term) ! 0){perror(config_port: Unable to read configure - );return -1;}/ set timeout in deciseconds for noncanonical read */term.c_cc[VTIME] timeout_sec * 10;/* set minimum number of bytes to read /term.c_cc[VMIN] min_bytes;/ write serial port configure /if (tcsetattr(fd, TCSADRAIN, term) ! 0){perror(config_port: Unable to write configure - );return -1;}
}/** read data from serial port return the length of bytes actually read on success, or -1 on error** fd - file descriptor* buf - pointer of buffer to receive bytes* len - buffer* sec - timeout second* min - minimum bytes to read*/
ssize_t read_port(int fd, void buf, size_t len, cc_t sec, cc_t min)
{ssize_t actual_read;/ setup serial port /if (read_port_setup(fd, sec, min) -1){return -1;}/ read bytes from serial port /actual_read read(fd, buf, len);if (actual_read -1){/ read failure /perror(read_port: Unable to read port - );}return actual_read;
}/** config serial port baud and set data format to 8N1 (8bits data, no parity bit, 1 stop bit)* return 0 on success, or -1 on error/
int config_port(int fd, speed_t baud)
{struct termios term;/ read serial port configure /if (tcgetattr(fd, term) ! 0){perror(config_port: Unable to read configure - );return -1;}/ set baudrate /cfsetspeed(term, baud);/ 8N1 mode /term.c_cflag ~PARENB;term.c_cflag ~CSTOPB;term.c_cflag ~CSIZE;term.c_cflag | CS8;/ enbale raw mode /cfmakeraw(term);/ write serial port configure */if (tcsetattr(fd, TCSADRAIN, term) ! 0){perror(config_port: Unable to write configure - );return -1;}
}/** close serial port */
int close_port(int fd)
{if (close(fd) -1){perror(close_port: Unable to close port - );return -1;}return 0;
}int main(int argc, char *argv[])
{char path /dev/ttyS0;int fd;char send_string[] hello world!\n;char read_string[20] ;ssize_t length;/ open port /fd open_port(path);if (fd 0){printf(open %s success, fd %d.\n, path, fd);}/ config port /config_port(fd, B9600);/ write data to port /length write_port(fd, send_string, sizeof(send_string));if (length 0){printf(%ld bytes written.\n, length);}/ read data from port /length read_port(fd, read_string, 20, 5, 5);if (length 0){printf(%ld bytes read : , length);for (ssize_t i 0; i length; i){printf(%02X , (int)(read_string[i]));}printf(\n);}/ close port */close_port(fd);return 0;
}六、参考链接
linux 串口编程 嵌入式linux入门3-2-串口
- 上一篇: 域名不变 新网站西安做网页的公司
- 下一篇: 域名的网站建设方案书怎么写深圳 公司网站设计
相关文章
-
域名不变 新网站西安做网页的公司
域名不变 新网站西安做网页的公司
- 技术栈
- 2026年04月20日
-
域名备案记录查询咸阳seo培训
域名备案记录查询咸阳seo培训
- 技术栈
- 2026年04月20日
-
域名 网站财税公司做网站
域名 网站财税公司做网站
- 技术栈
- 2026年04月20日
-
域名的网站建设方案书怎么写深圳 公司网站设计
域名的网站建设方案书怎么写深圳 公司网站设计
- 技术栈
- 2026年04月20日
-
域名等于网站网址吗微微网站建设
域名等于网站网址吗微微网站建设
- 技术栈
- 2026年04月20日
-
域名等于网站网址吗专业网页制作地址
域名等于网站网址吗专业网页制作地址
- 技术栈
- 2026年04月20日
