訂閱
糾錯(cuò)
加入自媒體

技術(shù)文章:基于Linux的tty架構(gòu)及UART驅(qū)動(dòng)詳解

三. 模塊詳細(xì)設(shè)計(jì)

3.1. 關(guān)鍵函數(shù)接口3.1.1. uart_register_driver功能:  uart_register_driver用于串口驅(qū)動(dòng)uart_driver注冊(cè)到內(nèi)核(串口核心層)中,通常在模塊初始化函數(shù)調(diào)用該函數(shù)。
*參數(shù):drv:要注冊(cè)的uart_driver
*返回值:成功,返回0;否則返回錯(cuò)誤碼

int uart_register_driver(struct uart_driver *drv)
3.1.2. uart_unregister_driver功能:uart_unregister 用于注銷(xiāo)我們已注冊(cè)的uart_driver,通常在模塊卸載函數(shù)調(diào)用該函數(shù),
*參數(shù) : drv:要注銷(xiāo)的uart_driver
*返回值:成功返回0,否則返回錯(cuò)誤碼

void uart_unregister_driver(struct uart_driver *drv)
3.1.3. uart_add_one_port功能:uart_add_one_port用于為串口驅(qū)動(dòng)添加一個(gè)串口端口,通常在探測(cè)到設(shè)備后(驅(qū)動(dòng)的設(shè)備probe方法)調(diào)用該函數(shù)
*參數(shù):
*     drv:串口驅(qū)動(dòng)
*     port:要添加的串口端口
*返回值:成功,返回0;否則返回錯(cuò)誤碼

int uart_add_one_port(struct uart_driver *drv,struct uart_port *port)
3.1.4. uart_remove_one_port功能:uart_remove_one_port用于刪除一個(gè)已經(jīng)添加到串口驅(qū)動(dòng)中的串口端口,通常在驅(qū)動(dòng)卸載時(shí)調(diào)用該函數(shù)
*參數(shù):
*     drv:串口驅(qū)動(dòng)
*     port:要?jiǎng)h除的串口端口
*返回值:成功,返回0;否則返回錯(cuò)誤碼

int uart_remove_one_port(struct uart_driver *drv,struct uart_port *port)
3.1.5. uart_write_wakeup功能:uart_write_wakeup喚醒上層因串口端口寫(xiě)數(shù)據(jù)而堵塞的進(jìn)程,通常在串口發(fā)送中斷處理函數(shù)中調(diào)用該函數(shù)
*參數(shù):
*     port: 需要喚醒寫(xiě)堵塞進(jìn)程的串口端口

void uart_write_wakeup(struct uart_port *port)
3.1.6. uart_suspend_port功能:uart_suspend_port用于掛起特定的串口端口
*參數(shù):
*     drv:要掛起的串口端口鎖所屬的串口驅(qū)動(dòng)
*     port:要掛起的串口端口
*返回值:成功返回0;否則返回錯(cuò)誤碼

int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
3.1.7. uart_resume_port功能:uart_resume_port用于恢復(fù)某一已掛起的串口
*參數(shù):
*     drv:要恢復(fù)的串口端口所屬的串口驅(qū)動(dòng)
*     port:要恢復(fù)的串口端口
*返回值:成功返回0;否則返回錯(cuò)誤碼

int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
3.1.8. uart_get_baud_rate功能:uart_get_baud_rate通過(guò)解碼termios結(jié)構(gòu)體來(lái)獲取指定串口的波特率
*參數(shù):
*     port:要獲取波特率的串口端口
*     termios:當(dāng)前期望的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 用于計(jì)算某一波特率的串口時(shí)鐘分頻數(shù)(串口波特率除數(shù))
*參數(shù):
*     port:要計(jì)算分頻數(shù)的串口端口
*     baud:期望的波特率
*返回值:串口時(shí)鐘分頻數(shù)

unsigned int uart_get_divisor(struct uart_port *port, unsigned int baund)
3.1.10. uart_update_timeout功能:uart_update_timeout用于更新(設(shè)置)串口FIFO超出時(shí)間
*參數(shù):
*     port:要更新超時(shí)間的串口端口
*     cfalg:termios結(jié)構(gòu)體的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層插入一個(gè)字符
*參數(shù):
*     port:要寫(xiě)信息的串口端口
*     status:RX buffer狀態(tài)
*     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用于向串口端口寫(xiě)一控制臺(tái)信息
*參數(shù):
*     port:要寫(xiě)信息的串口端口
*     s:要寫(xiě)的信息
*     count:信息的大小
*     putchar:用于向串口端口寫(xiě)字符的函數(shù),該函數(shù)有兩個(gè)參數(shù):串口端口和要寫(xiě)的字符

Void uart_console_write(struct uart_port *port,const char *s, unsigned int count,viod(*putchar)(struct uart_port*, int))
4. 模塊使用說(shuō)明4.1. 串口編程4.1.1. 串口控制函數(shù)屬性說(shuō)明tcgetatrr取屬性(termios結(jié)構(gòu))tcsetarr設(shè)置屬性(termios結(jié)構(gòu))cfgetispeed得到輸入速度cfsetispeed得到輸出速度cfstospeed設(shè)置輸出速度tcdrain等待所有輸出都被傳輸tcflow掛起傳輸或接收tcflush刷請(qǐng)未決輸出和/或輸入tcsendbreak送BREAK字符tcgetpgrp得到前臺(tái)進(jìn)程組IDTcsetpgrp設(shè)置前臺(tái)進(jìn)程組ID4.1.2. 串口配置流程(1) 保持原先串口配置,使用tegetatrr(fd, &oldtio);struct termious newtio, oldtio;
tegetattr(fd, &oldtio);
(2) 激活選項(xiàng)有CLOCAL和CREAD,用于本地連接和接收使用newtio.cflag |= CLOCAL|CREAD;
(3) 設(shè)置波特率newtio.c_cflag = B115200;
(4) 設(shè)置數(shù)據(jù)位,需使用掩碼設(shè)置newtio.c_cflag &= ~CSIZE;
Newtio.c_cflag |= CS8;
(5) 設(shè)置停止位,通過(guò)激活c_cflag中的CSTOP實(shí)現(xiàn)。若停止位為1,則清除CSTOPB,若停止位為2,則激活CSTOPnewtio.c_cflag &= ~CSTOPB; 停止位設(shè)置為1
Newtio.c_cflag |= CSTOPB; 停止位設(shè)置為2
(6) 設(shè)置流控newtio.c_cfag |= CRTSCTS 開(kāi)啟硬件流控
newtio.c_cfag |= (IXON | IXOFF | IXANY); 開(kāi)啟軟件流控
(7) 奇偶檢驗(yàn)位設(shè)置,使用c_cflag和c_ifag.設(shè)置奇校驗(yàn)newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);

設(shè)置偶校驗(yàn)

newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag |= ~PARODD;
(8) 設(shè)置最少字符和等待時(shí)間,對(duì)于接收字符和等待時(shí)間沒(méi)有什么特別的要求,可設(shè)置為0:newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN]  = 0;
(9) 處理要寫(xiě)入的引用對(duì)象tcflush函數(shù)刷清(拋棄)輸入緩沖(終端程序已經(jīng)接收到,但用戶程序尚未讀)或輸出緩沖(用戶程序已經(jīng)寫(xiě),但未發(fā)送)。int tcflash(int filedes, int quene)
quene數(shù)應(yīng)當(dāng)是下列三個(gè)常數(shù)之一:
 *TCIFLUSH 刷清輸入隊(duì)列
 *TCOFLUSH 刷清輸出隊(duì)列
 *TCIOFLUSH 刷清輸入、輸出隊(duì)列
例如:
tcflush(fd, TCIFLUSH);
(10) 激活配置,在完成配置后,需要激活配置使其生效。使用tcsetattr()函數(shù):int tcsetarr(int filedes, const struct termios *termptr);
opt 指定在什么時(shí)候新的終端屬性才起作用,
  *TCSANOW:更改立即發(fā)生
  *TCSADRAIN:發(fā)送了所有輸出后更改才發(fā)生。若更改輸出參數(shù)則應(yīng)使用此選項(xiàng)
  *TCSAFLUSH:發(fā)送了所有輸出后更改才發(fā)生。更進(jìn)一步,在更改發(fā)生時(shí)未讀的
                所有輸入數(shù)據(jù)都被刪除(刷清)
例如:tcsetatrr(fd, TCSANOW, &newtio);
4.1.3. 使用流程(1)打開(kāi)串口,例如"/dev/ttySLB0"fd = open("/dev/ttySLB0",O_RDWR | O_NOCTTY | O_NDELAY);
O_NOCTTY:是為了告訴Linux這個(gè)程序不會(huì)成為這個(gè)端口上的“控制終端”。如果不這樣做的話,所有的輸入,比如鍵盤(pán)上過(guò)來(lái)的Ctrl+C中止信號(hào)等等,會(huì)影響到你的進(jìn)程。
O_NDELAY:這個(gè)標(biāo)志則是告訴Linux這個(gè)程序并不關(guān)心DCD信號(hào)線的狀態(tài),也就是不管串口是否有數(shù)據(jù)到來(lái),都是非阻塞的,程序繼續(xù)執(zhí)行。
(2)恢復(fù)串口狀態(tài)為阻塞狀態(tài),用于等待串口數(shù)據(jù)的讀入,用fcntl函數(shù):fcntl(fd,F(xiàn)_SETFL,0);  //F_SETFL:設(shè)置文件flag為0,即默認(rèn),即阻塞狀態(tài)
(3)接著測(cè)試打開(kāi)的文件描述符是否應(yīng)用一個(gè)終端設(shè)備,以進(jìn)一步確認(rèn)串口是否正確打開(kāi)。isatty(STDIN_FILENO);
(4)讀寫(xiě)串口串口的讀寫(xiě)與普通文件一樣,使用read,write函數(shù)
read(fd, buf ,8);
write(fd,buff,8);
4.1.4. Demo

以下給出一個(gè)測(cè)溫模塊收取數(shù)據(jù)的例子

#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];
//-----------打開(kāi)uart設(shè)備文件------------------
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);

//-----------設(shè)置操作參數(shù)-----------------------
tcgetattr(fd, &oldtio);//獲取當(dāng)前操作模式參數(shù)
memset(&newtio, 0, sizeof(newtio));
//波特率=230400 數(shù)據(jù)位=8 使能數(shù)據(jù)接收
newtio.c_cflag = B230400 | CS8 | CLOCAL | CREAD | CSTOPB;
newtio.c_iflag = IGNPAR;
tcflush(fd, TCIFLUSH);//清空輸入緩沖區(qū)和輸出緩沖區(qū)
tcsetattr(fd, TCSANOW, &newtio);//設(shè)置新的操作參數(shù)
//printf("input: %s, len = %d", cmd_buf, strlen(cmd_buf));
//------------向urat發(fā)送數(shù)據(jù)-------------------
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 (。╥%10))
   printf("");
  printf("%#X ", temp->temp_col[i]);
 }
} else {
 printf("read temp colour failed");
 return -1;

free(temp);
close(fd);
tcsetattr(fd, TCSANOW, &oldtio); //恢復(fù)原先的設(shè)置
return 0;


<上一頁(yè)  1  2  3  4  
聲明: 本文由入駐維科號(hào)的作者撰寫(xiě),觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號(hào)
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯(cuò)
x
*文字標(biāo)題:
*糾錯(cuò)內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號(hào)