当前位置: 智能网 > 人工智能 > 技术文章:基于Linux的tty架构及UART驱动详解

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

放大字体 缩小字体 发布日期:2021-02-05 18:02:57   浏览次数:198


三.模块详细设计

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;


<上一页  3  4  
 
关键词: 波特

[ 智能网搜索 ]  [ 打印本文 ]  [ 违规举报

猜你喜欢

 
推荐图文
ITECH直流电源在人工智能领域的应用 基于朴素贝叶斯自动过滤垃圾广告
2020年是人工智能相关业务发展的重要一年 我国人工智能市场规模、行业短板、发展前景一览
推荐智能网
点击排行

 
 
新能源网 | 锂电网 | 智能网 | 环保设备网 | 联系方式