订阅
纠错
加入自媒体

技术文章:基于Linux的tty架构及UART驱动详解

2021-02-05 17:06
一口Linux
关注

三. 模块详细设计

3.1. 关键函数接口3.1.1. uart_register_driver功能:  uart_register_driver用于串口驱动uart_driver注册到内核(串口核心层)中,通常在模块初始化函数调用该函数。
*参数:drv:要注册的uart_driver
*返回值:成功,返回0;否则返回错误码

int uart_register_driver(struct uart_driver *drv)
3.1.2. uart_unregister_driver功能:uart_unregister 用于注销我们已注册的uart_driver,通常在模块卸载函数调用该函数,
*参数 : drv:要注销的uart_driver
*返回值:成功返回0,否则返回错误码

void uart_unregister_driver(struct uart_driver *drv)
3.1.3. uart_add_one_port功能:uart_add_one_port用于为串口驱动添加一个串口端口,通常在探测到设备后(驱动的设备probe方法)调用该函数
*参数:
*     drv:串口驱动
*     port:要添加的串口端口
*返回值:成功,返回0;否则返回错误码

int uart_add_one_port(struct uart_driver *drv,struct uart_port *port)
3.1.4. uart_remove_one_port功能:uart_remove_one_port用于删除一个已经添加到串口驱动中的串口端口,通常在驱动卸载时调用该函数
*参数:
*     drv:串口驱动
*     port:要删除的串口端口
*返回值:成功,返回0;否则返回错误码

int uart_remove_one_port(struct uart_driver *drv,struct uart_port *port)
3.1.5. uart_write_wakeup功能:uart_write_wakeup唤醒上层因串口端口写数据而堵塞的进程,通常在串口发送中断处理函数中调用该函数
*参数:
*     port: 需要唤醒写堵塞进程的串口端口

void uart_write_wakeup(struct uart_port *port)
3.1.6. uart_suspend_port功能:uart_suspend_port用于挂起特定的串口端口
*参数:
*     drv:要挂起的串口端口锁所属的串口驱动
*     port:要挂起的串口端口
*返回值:成功返回0;否则返回错误码

int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
3.1.7. uart_resume_port功能:uart_resume_port用于恢复某一已挂起的串口
*参数:
*     drv:要恢复的串口端口所属的串口驱动
*     port:要恢复的串口端口
*返回值:成功返回0;否则返回错误码

int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
3.1.8. uart_get_baud_rate功能:uart_get_baud_rate通过解码termios结构体来获取指定串口的波特率
*参数:
*     port:要获取波特率的串口端口
*     termios:当前期望的termios配置(包括串口波特率)
*     old:以前的termios配置,可以为NULL
*     min:可以接受的最小波特率
*     max:可以接受的最大波特率
*     返回值:串口波特率

unsigned int uart_get_baund_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old,unsigned int min, unsigned int max)
3.1.9. uart_get_divisor功能:uart_get_divisor 用于计算某一波特率的串口时钟分频数(串口波特率除数)
*参数:
*     port:要计算分频数的串口端口
*     baud:期望的波特率
*返回值:串口时钟分频数

unsigned int uart_get_divisor(struct uart_port *port, unsigned int baund)
3.1.10. uart_update_timeout功能:uart_update_timeout用于更新(设置)串口FIFO超出时间
*参数:
*     port:要更新超时间的串口端口
*     cfalg:termios结构体的cflag值
*     baud:串口的波特率

void uart_update_timeout(struct uart_port *port,unsigned int cflag, unsigned int baud)
3.1.11. uart_insert_char功能:uart_insert_char用于向uart层插入一个字符
*参数:
*     port:要写信息的串口端口
*     status:RX buffer状态
*     overrun:在status中的overrun bit掩码
*     ch:需要插入的字符
*     flag:插入字符的flag:TTY_BREAK,TTY_PSRIYY, TTY_FRAME

void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun,unsigned int ch, unsigned int flag)
3.1.12. uart_console_write功能:uart_console_write用于向串口端口写一控制台信息
*参数:
*     port:要写信息的串口端口
*     s:要写的信息
*     count:信息的大小
*     putchar:用于向串口端口写字符的函数,该函数有两个参数:串口端口和要写的字符

Void uart_console_write(struct uart_port *port,const char *s, unsigned int count,viod(*putchar)(struct uart_port*, int))
4. 模块使用说明4.1. 串口编程4.1.1. 串口控制函数属性说明tcgetatrr取属性(termios结构)tcsetarr设置属性(termios结构)cfgetispeed得到输入速度cfsetispeed得到输出速度cfstospeed设置输出速度tcdrain等待所有输出都被传输tcflow挂起传输或接收tcflush刷请未决输出和/或输入tcsendbreak送BREAK字符tcgetpgrp得到前台进程组IDTcsetpgrp设置前台进程组ID4.1.2. 串口配置流程(1) 保持原先串口配置,使用tegetatrr(fd, &oldtio);struct termious newtio, oldtio;
tegetattr(fd, &oldtio);
(2) 激活选项有CLOCAL和CREAD,用于本地连接和接收使用newtio.cflag |= CLOCAL|CREAD;
(3) 设置波特率newtio.c_cflag = B115200;
(4) 设置数据位,需使用掩码设置newtio.c_cflag &= ~CSIZE;
Newtio.c_cflag |= CS8;
(5) 设置停止位,通过激活c_cflag中的CSTOP实现。若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPnewtio.c_cflag &= ~CSTOPB; 停止位设置为1
Newtio.c_cflag |= CSTOPB; 停止位设置为2
(6) 设置流控newtio.c_cfag |= CRTSCTS 开启硬件流控
newtio.c_cfag |= (IXON | IXOFF | IXANY); 开启软件流控
(7) 奇偶检验位设置,使用c_cflag和c_ifag.设置奇校验newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);

设置偶校验

newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag |= ~PARODD;
(8) 设置最少字符和等待时间,对于接收字符和等待时间没有什么特别的要求,可设置为0:newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN]  = 0;
(9) 处理要写入的引用对象tcflush函数刷清(抛弃)输入缓冲(终端程序已经接收到,但用户程序尚未读)或输出缓冲(用户程序已经写,但未发送)。int tcflash(int filedes, int quene)
quene数应当是下列三个常数之一:
 *TCIFLUSH 刷清输入队列
 *TCOFLUSH 刷清输出队列
 *TCIOFLUSH 刷清输入、输出队列
例如:
tcflush(fd, TCIFLUSH);
(10) 激活配置,在完成配置后,需要激活配置使其生效。使用tcsetattr()函数:int tcsetarr(int filedes, const struct termios *termptr);
opt 指定在什么时候新的终端属性才起作用,
  *TCSANOW:更改立即发生
  *TCSADRAIN:发送了所有输出后更改才发生。若更改输出参数则应使用此选项
  *TCSAFLUSH:发送了所有输出后更改才发生。更进一步,在更改发生时未读的
                所有输入数据都被删除(刷清)
例如:tcsetatrr(fd, TCSANOW, &newtio);
4.1.3. 使用流程(1)打开串口,例如"/dev/ttySLB0"fd = open("/dev/ttySLB0",O_RDWR | O_NOCTTY | O_NDELAY);
O_NOCTTY:是为了告诉Linux这个程序不会成为这个端口上的“控制终端”。如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程。
O_NDELAY:这个标志则是告诉Linux这个程序并不关心DCD信号线的状态,也就是不管串口是否有数据到来,都是非阻塞的,程序继续执行。
(2)恢复串口状态为阻塞状态,用于等待串口数据的读入,用fcntl函数:fcntl(fd,F_SETFL,0);  //F_SETFL:设置文件flag为0,即默认,即阻塞状态
(3)接着测试打开的文件描述符是否应用一个终端设备,以进一步确认串口是否正确打开。isatty(STDIN_FILENO);
(4)读写串口串口的读写与普通文件一样,使用read,write函数
read(fd, buf ,8);
write(fd,buff,8);
4.1.4. Demo

以下给出一个测温模块收取数据的例子

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <log/log.h>
#include <stdlib.h>
#define UART_DEVICE     "/dev/ttySLB1"
struct temp {
float temp_max1;
float temp_max2;
float temp_max3;
float temp_min;
float temp_mean;
float temp_enviromem;
char temp_col[1536];
};
int main(void)

int count, i, fd;
struct termios oldtio, newtio;
struct temp *temp;
temp = (struct temp *)malloc(sizeof(struct temp));
if (!temp) {
 printf("malloc failed");
 return -1;

char cmd_buf1[] = { 0xAA, 0x01, 0x04, 0x00, 0x06, 0x10, 0x05, 0x00, 0xBB};
char cmd_buf2[] = { 0xAA, 0x01, 0x04, 0x00, 0x00, 0xA0, 0x00, 0x03, 0xBB};
char cmd_buf3[] = { 0xAA, 0x01, 0x04, 0x00, 0x03, 0x10, 0x01, 0x00, 0xBB};
char read_buf[2000];
//-----------打开uart设备文件------------------
fd = open(UART_DEVICE, O_RDWR | O_NOCTTY);
if (fd < 0) {
 printf("Open %s failed", UART_DEVICE);
 return -1;
} else {
 printf("Open %s successfully", UART_DEVICE);

//-----------设置操作参数-----------------------
tcgetattr(fd, &oldtio);//获取当前操作模式参数
memset(&newtio, 0, sizeof(newtio));
//波特率=230400 数据位=8 使能数据接收
newtio.c_cflag = B230400 | CS8 | CLOCAL | CREAD | CSTOPB;
newtio.c_iflag = IGNPAR;
tcflush(fd, TCIFLUSH);//清空输入缓冲区和输出缓冲区
tcsetattr(fd, TCSANOW, &newtio);//设置新的操作参数
//printf("input: %s, len = %d", cmd_buf, strlen(cmd_buf));
//------------向urat发送数据-------------------
for (i = 0; i < 9; i++)
 printf("%#X ", cmd_buf1[i]);
count = write(fd, cmd_buf1, 9);
if (count != 9) {
 printf("send failed");
 return -1;

usleep(500000);
memset(read_buf, 0, sizeof(read_buf));
count = read(fd, read_buf, sizeof(read_buf));
if (count > 0) {
 for (i = 0; i < count; i++);
 temp->temp_max1 = read_buf[7] << 8 | read_buf[6];
 temp->temp_max2 = read_buf[9] << 8 | read_buf[8];
 temp->temp_max3 = read_buf[11] << 8 | read_buf[10];
 temp->temp_min  = read_buf[13] << 8 | read_buf[12];
 temp->temp_mean = read_buf[15] << 8 | read_buf[14];
 printf("temp->temp_max1 = %f", temp->temp_max1 * 0.01);
 printf("temp->temp_max2 = %f", temp->temp_max2 * 0.01);
 printf("temp->temp_max3 = %f", temp->temp_max3 * 0.01);
 printf("temp->temp_min  = %f", temp->temp_min  * 0.01);
 printf("temp->temp_mean = %f", temp->temp_mean * 0.01);
 
} else {
 printf("read temp failed");
 return -1;

count = write(fd, cmd_buf3, 9);
if (count != 9) {
 printf("send failed");
 return -1;

usleep(365);
memset(read_buf, 0, sizeof(read_buf));
count = read(fd, read_buf, sizeof(read_buf));
if (count > 0) {
 for (i = 0; i < count; i++);
 temp->temp_enviromem = read_buf[7] << 8 | read_buf[6];
 printf("temp->temp_enviromem = %f", temp->temp_enviromem * 0.01);
} else {
 printf("read enviromem failed");
 return -1;

 
count = write(fd, cmd_buf2, 9);
if (count != 9) {
 printf("send failed");
 return -1;

usleep(70000);
memset(read_buf, 0, sizeof(read_buf));
memset(temp->temp_col, 0, sizeof(temp->temp_col));
count = read(fd, read_buf, sizeof(read_buf));
printf("count = %d", count);
if (count > 0) {
 for (i = 0; i < count - 7; i++)
 temp->temp_col[i] = read_buf[i+6];
 for (i = 0; i < 1536; i++)
 {
  if (!(i%10))
   printf("");
  printf("%#X ", temp->temp_col[i]);
 }
} else {
 printf("read temp colour failed");
 return -1;

free(temp);
close(fd);
tcsetattr(fd, TCSANOW, &oldtio); //恢复原先的设置
return 0;


<上一页  1  2  3  4  
声明: 本文由入驻维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。

发表评论

0条评论,0人参与

请输入评论内容...

请输入评论/评论长度6~500个字

您提交的评论过于频繁,请输入验证码继续

暂无评论

暂无评论

    人工智能 猎头职位 更多
    扫码关注公众号
    OFweek人工智能网
    获取更多精彩内容
    文章纠错
    x
    *文字标题:
    *纠错内容:
    联系邮箱:
    *验 证 码:

    粤公网安备 44030502002758号