技術(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;
}
發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
10月31日立即下載>> 【限時(shí)免費(fèi)下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報(bào)名>>> 【在線會(huì)議】多物理場(chǎng)仿真助跑新能源汽車(chē)
-
11月28日立即報(bào)名>>> 2024工程師系列—工業(yè)電子技術(shù)在線會(huì)議
-
12月19日立即報(bào)名>> 【線下會(huì)議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
-
即日-12.26火熱報(bào)名中>> OFweek2024中國(guó)智造CIO在線峰會(huì)
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書(shū)》
推薦專(zhuān)題
- 1 【一周車(chē)話】沒(méi)有方向盤(pán)和踏板的車(chē),你敢坐嗎?
- 2 特斯拉發(fā)布無(wú)人駕駛車(chē),還未迎來(lái)“Chatgpt時(shí)刻”
- 3 特斯拉股價(jià)大跌15%:Robotaxi離落地還差一個(gè)蘿卜快跑
- 4 馬斯克給的“驚喜”夠嗎?
- 5 大模型“新星”開(kāi)啟變現(xiàn)競(jìng)速
- 6 海信給AI電視打樣,12大AI智能體全面升級(jí)大屏體驗(yàn)
- 7 打完“價(jià)格戰(zhàn)”,大模型還要比什么?
- 8 馬斯克致敬“國(guó)產(chǎn)蘿卜”?
- 9 神經(jīng)網(wǎng)絡(luò),誰(shuí)是盈利最強(qiáng)企業(yè)?
- 10 比蘋(píng)果偉大100倍!真正改寫(xiě)人類(lèi)歷史的智能產(chǎn)品降臨
- 高級(jí)軟件工程師 廣東省/深圳市
- 自動(dòng)化高級(jí)工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷(xiāo)售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級(jí)銷(xiāo)售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專(zhuān)家 廣東省/江門(mén)市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市