www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式教程
[導(dǎo)讀]串口是計(jì)算機(jī)一種常用的接口,常用的串口有RS-232-C接口。它是于1970年由美國電子工業(yè)協(xié)會(huì)(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計(jì)算機(jī)終端生產(chǎn)廠家共同制定的用于串行通信的標(biāo)準(zhǔn),它的全稱是“數(shù)據(jù)終端設(shè)備(DTE)和數(shù)據(jù)通信設(shè)備(DCE)之間串行二進(jìn)制數(shù)據(jù)交換接口技術(shù)標(biāo)準(zhǔn)”。

6.4嵌入式Linux串口應(yīng)用編程6.4.1串口概述

常見的數(shù)據(jù)通信的基本方式可分為并行通信與串行通信兩種。

n 并行通信是指利用多條數(shù)據(jù)傳輸線將一個(gè)字?jǐn)?shù)據(jù)的各比特位同時(shí)傳送。它的特點(diǎn)是傳輸速度快,適用于傳輸距離短且傳輸速度較高的通信。

n 串行通信是指利用一條傳輸線將數(shù)據(jù)以比特位為單位順序傳送。特點(diǎn)是通信線路簡單,利用簡單的線纜就可實(shí)現(xiàn)通信,降低成本,適用于傳輸距離長且傳輸速度較慢的通信。

串口是計(jì)算機(jī)一種常用的接口,常用的串口有RS-232-C接口。它是于1970年由美國電子工業(yè)協(xié)會(huì)(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計(jì)算機(jī)終端生產(chǎn)廠家共同制定的用于串行通信的標(biāo)準(zhǔn),它的全稱是“數(shù)據(jù)終端設(shè)備(DTE)和數(shù)據(jù)通信設(shè)備(DCE)之間串行二進(jìn)制數(shù)據(jù)交換接口技術(shù)標(biāo)準(zhǔn)”。該標(biāo)準(zhǔn)規(guī)定采用一個(gè)DB25芯引腳的連接器或9芯引腳的連接器,其中25芯引腳的連接器如圖6.3所示。

圖6.325引腳串行接口圖

S3C2410X內(nèi)部具有兩個(gè)獨(dú)立的UART控制器,每個(gè)控制器都可以工作在Interrupt(中斷)模式或者DMA(直接存儲(chǔ)訪問)模式。同時(shí),每個(gè)UART均具有16字節(jié)的FIFO(先入先出寄存器),支持的最高波特率可達(dá)到230.4Kbps。UART的操作主要可分為以下幾個(gè)部分:數(shù)據(jù)發(fā)送、數(shù)據(jù)接收、產(chǎn)生中斷、設(shè)置波特率、Loopback模式、紅外模式以及硬軟流控模式。

串口參數(shù)的配置讀者在配置超級(jí)終端和minicom時(shí)也已經(jīng)接觸過,一般包括波特率、起始位比特?cái)?shù)、數(shù)據(jù)位比特?cái)?shù)、停止位比特?cái)?shù)和流控模式。在此,可以將其配置為波特率115200、起始位1b、數(shù)據(jù)位8b、停止位1b和無流控模式。

在Linux中,所有的設(shè)備文件一般都位于“/dev”下,其中串口1和串口2對應(yīng)的設(shè)備名依次為“/dev/ttyS0”和“/dev/ttyS1”,而且USB轉(zhuǎn)串口的設(shè)備名通常為“/dev/ttyUSB0”和“/dev/ttyUSB1”(因版本不同該設(shè)備名會(huì)有所不同),可以查看在“/dev”下的文件以確認(rèn)。在本章中已經(jīng)提到過,在Linux下對設(shè)備的操作方法與對文件的操作方法是一樣的,因此,對串口的讀寫就可以使用簡單的read()、write()函數(shù)來完成,所不同的只是需要對串口的其他參數(shù)另做配置,下面就來詳細(xì)講解串口應(yīng)用開發(fā)的步驟。

6.4.2串口設(shè)置詳解

串口的設(shè)置主要是設(shè)置structtermios結(jié)構(gòu)體的各成員值,如下所示:

#include<termios.h>

structtermios

{

unsignedshortc_iflag;/*輸入模式標(biāo)志*/

unsignedshortc_oflag;/*輸出模式標(biāo)志*/

unsignedshortc_cflag;/*控制模式標(biāo)志*/

unsignedshortc_lflag;/*本地模式標(biāo)志*/

unsignedcharc_line;/*線路規(guī)程*/

unsignedcharc_cc[NCC];/*控制特性*/

speed_tc_ispeed;/*輸入速度*/

speed_tc_ospeed;/*輸出速度*/

};

termios是在POSIX規(guī)范中定義的標(biāo)準(zhǔn)接口,表示終端設(shè)備(包括虛擬終端、串口等)??谑且环N終端設(shè)備,一般通過終端編程接口對其進(jìn)行配置和控制。在具體講解串口相關(guān)編程之前,先了解一下終端相關(guān)知識(shí)。

終端有3種工作模式,分別為規(guī)范模式(canonicalmode)、非規(guī)范模式(non-canonicalmode)和原始模式(rawmode)。

通過在termios結(jié)構(gòu)的c_lflag中設(shè)置ICANNON標(biāo)志來定義終端是以規(guī)范模式(設(shè)置ICANNON標(biāo)志)還是以非規(guī)范模式(清除ICANNON標(biāo)志)工作,默認(rèn)情況為規(guī)范模式。

在規(guī)范模式下,所有的輸入是基于行進(jìn)行處理。在用戶輸入一個(gè)行結(jié)束符(回車符、EOF等)之前,系統(tǒng)調(diào)用read()函數(shù)讀不到用戶輸入的任何字符。除了EOF之外的行結(jié)束符(回車符等)與普通字符一樣會(huì)被read()函數(shù)讀取到緩沖區(qū)之中。在規(guī)范模式中,行編輯是可行的,而且一次調(diào)用read()函數(shù)最多只能讀取一行數(shù)據(jù)。如果在read()函數(shù)中被請求讀取的數(shù)據(jù)字節(jié)數(shù)小于當(dāng)前行可讀取的字節(jié)數(shù),則read()函數(shù)只會(huì)讀取被請求的字節(jié)數(shù),剩下的字節(jié)下次再被讀取。

在非規(guī)范模式下,所有的輸入是即時(shí)有效的,不需要用戶另外輸入行結(jié)束符,而且不可進(jìn)行行編輯。在非規(guī)范模式下,對參數(shù)MIN(c_cc[VMIN])和TIME(c_cc[VTIME])的設(shè)置決定read()函數(shù)的調(diào)用方式。設(shè)置可以有4種不同的情況。

n MIN=0和TIME=0:read()函數(shù)立即返回。若有可讀數(shù)據(jù),則讀取數(shù)據(jù)并返回被讀取的字節(jié)數(shù),否則讀取失敗并返回0。

n MIN>0和TIME=0:read()函數(shù)會(huì)被阻塞直到MIN個(gè)字節(jié)數(shù)據(jù)可被讀取。

n MIN=0和TIME>0:只要有數(shù)據(jù)可讀或者經(jīng)過TIME個(gè)十分之一秒的時(shí)間,read()函數(shù)則立即返回,返回值為被讀取的字節(jié)數(shù)。如果超時(shí)并且未讀到數(shù)據(jù),則read()函數(shù)返回0。

n MIN>0和TIME>0:當(dāng)有MIN個(gè)字節(jié)可讀或者兩個(gè)輸入字符之間的時(shí)間間隔超過TIME個(gè)十分之一秒時(shí),read()函數(shù)才返回。因?yàn)樵谳斎氲谝粋€(gè)字符之后系統(tǒng)才會(huì)啟動(dòng)定時(shí)器,所以在這種情況下,read()函數(shù)至少讀取一個(gè)字節(jié)之后才返回。

按照嚴(yán)格意義來講,原始模式是一種特殊的非規(guī)范模式。在原始模式下,所有的輸入數(shù)據(jù)以字節(jié)為單位被處理。在這個(gè)模式下,終端是不可回顯的,而且所有特定的終端輸入/輸出控制處理不可用。通過調(diào)用cfmakeraw()函數(shù)可以將終端設(shè)置為原始模式,而且該函數(shù)通過以下代碼可以得到實(shí)現(xiàn)。

termios_p->c_iflag&=~(IGNBRK|BRKINT|PARMRK|ISTRIP

|INLCR|IGNCR|ICRNL|IXON);

termios_p->c_oflag&=~OPOST;

termios_p->c_lflag&=~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);

termios_p->c_cflag&=~(CSIZE|PARENB);

termios_p->c_cflag|=CS8;

下面講解設(shè)置串口的基本方法。設(shè)置串口中最基本的包括波特率設(shè)置,校驗(yàn)位和停止位設(shè)置。在這個(gè)結(jié)構(gòu)中最為重要的是c_cflag,通過對它的賦值,用戶可以設(shè)置波特率、字符大小、數(shù)據(jù)位、停止位、奇偶校驗(yàn)位和硬軟流控等。另外c_iflag和c_cc也是比較常用的標(biāo)志。在此主要對這3個(gè)成員進(jìn)行詳細(xì)說明。c_cflag支持的常量名稱如表6.11所示。其中設(shè)置波特率宏名為相應(yīng)的波特率數(shù)值前加上‘B’,由于數(shù)值較多,本表沒有全部列出。

表6.11 c_cflag支持的常量名稱

CBAUD

波特率的位掩碼

B0

0波特率(放棄DTR)

B1800

1800波特率

B2400

2400波特率

續(xù)表

B4800

4800波特率

B9600

9600波特率

B19200

19200波特率

B38400

38400波特率

B57600

57600波特率

B115200

115200波特率

EXTA

外部時(shí)鐘率

EXTB

外部時(shí)鐘率

CSIZE

數(shù)據(jù)位的位掩碼

CS5

5個(gè)數(shù)據(jù)位

CS6

6個(gè)數(shù)據(jù)位

CS7

7個(gè)數(shù)據(jù)位

CS8

8個(gè)數(shù)據(jù)位

CSTOPB

2個(gè)停止位(不設(shè)則是1個(gè)停止位)

CREAD

接收使能

PARENB

PARODD

校驗(yàn)位使能

使用奇校驗(yàn)而不使用偶校驗(yàn)

HUPCL

最后關(guān)閉時(shí)掛線(放棄DTR)

CLOCAL

本地連接(不改變端口所有者)

CRTSCTS

硬件流控

在這里,不能直接對c_cflag成員初始化,而要將其通過“與”、“或”操作使用其中的某些選項(xiàng)。輸入模式標(biāo)志c_iflag用于控制端口接收端的字符輸入處理。c_iflag支持的常量名稱如表6.12所示。

表6.12 c_iflag支持的常量名稱

INPCK

奇偶校驗(yàn)使能

IGNPAR

忽略奇偶校驗(yàn)錯(cuò)誤

PARMRK

奇偶校驗(yàn)錯(cuò)誤掩碼

ISTRIP

裁減掉第8位比特

IXON

啟動(dòng)輸出軟件流控

IXOFF

啟動(dòng)輸入軟件流控

IXANY

輸入任意字符可以重新啟動(dòng)輸出(默認(rèn)為輸入起始字符才重啟輸出)

IGNBRK

忽略輸入終止條件

BRKINT

當(dāng)檢測到輸入終止條件時(shí)發(fā)送SIGINT信號(hào)

INLCR

將接收到的NL(換行符)轉(zhuǎn)換為CR(回車符)

IGNCR

忽略接收到的CR(回車符)

ICRNL

將接收到的CR(回車符)轉(zhuǎn)換為NL(換行符)

IUCLC

將接收到的大寫字符映射為小寫字符

IMAXBEL

當(dāng)輸入隊(duì)列滿時(shí)響鈴

c_oflag用于控制終端端口發(fā)送出去的字符處理,c_oflag支持的常量名稱如表6.12所示。因?yàn)楝F(xiàn)在終端的速度比以前快得多,所以大部分延時(shí)掩碼幾乎沒什么用途。

表6.13 c_oflag支持的常量名稱

OPOST

啟用輸出處理功能,如果不設(shè)置該標(biāo)志,則其他標(biāo)志都被忽略

OLCUC

將輸出中的大寫字符轉(zhuǎn)換成小寫字符

ONLCR

將輸出中的換行符(‘\n’)轉(zhuǎn)換成回車符(‘\r’)

ONOCR

如果當(dāng)前列號(hào)為0,則不輸出回車符

OCRNL

將輸出中的回車符(‘\r’)轉(zhuǎn)換成換行符(‘\n’)

ONLRET

不輸出回車符

OFILL

發(fā)送填充字符以提供延時(shí)

OFDEL

如果設(shè)置該標(biāo)志,則表示填充字符為DEL字符,否則為NUL字符

NLDLY

換行延時(shí)掩碼

CRDLY

回車延時(shí)掩碼

TABDLY

制表符延時(shí)掩碼

BSDLY

水平退格符延時(shí)掩碼

VTDLY

垂直退格符延時(shí)掩碼

FFLDY

換頁符延時(shí)掩碼

c_lflag用于控制控制終端的本地?cái)?shù)據(jù)處理和工作模式,c_lflag所支持的常量名稱如表6.14所示。

表6.14 c_lflag支持的常量名稱

ISIG

若收到信號(hào)字符(INTR、QUIT等),則會(huì)產(chǎn)生相應(yīng)的信號(hào)

ICANON

啟用規(guī)范模式

ECHO

啟用本地回顯功能

ECHOE

若設(shè)置ICANON,則允許退格操作

ECHOK

若設(shè)置ICANON,則KILL字符會(huì)刪除當(dāng)前行

ECHONL

若設(shè)置ICANON,則允許回顯換行符

ECHOCTL

若設(shè)置ECHO,則控制字符(制表符、換行符等)會(huì)顯示成“^X”,其中X的ASCII碼等于給相應(yīng)控制字符的ASCII碼加上0x40。例如:退格字符(0x08)會(huì)顯示為“^H”(’H’的ASCII碼為0x48)

ECHOPRT

若設(shè)置ICANON和IECHO,則刪除字符(退格符等)和被刪除的字符都會(huì)被顯示

ECHOKE

若設(shè)置ICANON,則允許回顯在ECHOE和ECHOPRT中設(shè)定的KILL字符

NOFLSH

在通常情況下,當(dāng)接收到INTR、QUIT和SUSP控制字符時(shí),會(huì)清空輸入和輸出隊(duì)列。如果設(shè)置該標(biāo)志,則所有的隊(duì)列不會(huì)被清空

TOSTOP

若一個(gè)后臺(tái)進(jìn)程試圖向它的控制終端進(jìn)行寫操作,則系統(tǒng)向該后臺(tái)進(jìn)程的進(jìn)程組發(fā)送SIGTTOU信號(hào)。該信號(hào)通常終止進(jìn)程的執(zhí)行

IEXTEN

啟用輸入處理功能

c_cc定義特殊控制特性。c_cc所支持的常量名稱如表6.13所示。

表6.13 c_cc支持的常量名稱

VINTR

中斷控制字符,對應(yīng)鍵為CTRL+C

VQUIT

退出操作符,對應(yīng)鍵為CRTL+Z

VERASE

刪除操作符,對應(yīng)鍵為Backspace(BS)

VKILL

刪除行符,對應(yīng)鍵為CTRL+U

VEOF

文件結(jié)尾符,對應(yīng)鍵為CTRL+D

VEOL

附加行結(jié)尾符,對應(yīng)鍵為Carriagereturn(CR)

VEOL2

第二行結(jié)尾符,對應(yīng)鍵為Linefeed(LF)

VMIN

指定最少讀取的字符數(shù)

VTIME

指定讀取的每個(gè)字符之間的超時(shí)時(shí)間

下面就詳細(xì)講解設(shè)置串口屬性的基本流程。

1.保存原先串口配置

首先,為了安全起見和以后調(diào)試程序方便,可以先保存原先串口的配置,在這里可以使用函數(shù)tcgetattr(fd,&old_cfg)。該函數(shù)得到fd指向的終端的配置參數(shù),并將它們保存于termios結(jié)構(gòu)變量old_cfg中。該函數(shù)還可以測試配置是否正確、該串口是否可用等。若調(diào)用成功,函數(shù)返回值為0,若調(diào)用失敗,函數(shù)返回值為-1,其使用如下所示:

if(tcgetattr(fd,&old_cfg)!=0)

{

perror("tcgetattr");

return-1;

}

2.激活選項(xiàng)

CLOCAL和CREAD分別用于本地連接和接受使能,因此,首先要通過位掩碼的方式激活這兩個(gè)選項(xiàng)。

newtio.c_cflag|=CLOCAL|CREAD;

調(diào)用cfmakeraw()函數(shù)可以將終端設(shè)置為原始模式,在后面的實(shí)例中,采用原始模式進(jìn)行串口數(shù)據(jù)通信。

cfmakeraw(&new_cfg);

3.設(shè)置波特率

設(shè)置波特率有專門的函數(shù),用戶不能直接通過位掩碼來操作。設(shè)置波特率的主要函數(shù)有:cfsetispeed()和cfsetospeed()。這兩個(gè)函數(shù)的使用很簡單,如下所示:

cfsetispeed(&new_cfg,B115200);

cfsetospeed(&new_cfg,B115200);

一般地,用戶需將終端的輸入和輸出波特率設(shè)置成一樣的。這幾個(gè)函數(shù)在成功時(shí)返回0,失敗時(shí)返回-1。

4.設(shè)置字符大小

與設(shè)置波特率不同,設(shè)置字符大小并沒有現(xiàn)成可用的函數(shù),需要用位掩碼。一般首先去除數(shù)據(jù)位中的位掩碼,再重新按要求設(shè)置。如下所示:

new_cfg.c_cflag&=~CSIZE;/*用數(shù)據(jù)位掩碼清空數(shù)據(jù)位設(shè)置*/

new_cfg.c_cflag|=CS8;

5.設(shè)置奇偶校驗(yàn)位

設(shè)置奇偶校驗(yàn)位需要用到termios中的兩個(gè)成員:c_cflag和c_iflag。首先要激活c_cflag中的校驗(yàn)位使能標(biāo)志PARENB和是否要進(jìn)行偶校驗(yàn),同時(shí)還要激活c_iflag中的對于輸入數(shù)據(jù)的奇偶校驗(yàn)使能(INPCK)。如使能奇校驗(yàn)時(shí),代碼如下所示:

new_cfg.c_cflag|=(PARODD|PARENB);

new_cfg.c_iflag|=INPCK;

而使能偶校驗(yàn)時(shí),代碼如下所示:

new_cfg.c_cflag|=PARENB;

new_cfg.c_cflag&=~PARODD;/*清除偶校驗(yàn)標(biāo)志,則配置為奇校驗(yàn)*/

new_cfg.c_iflag|=INPCK;

6.設(shè)置停止位

設(shè)置停止位是通過激活c_cflag中的CSTOPB而實(shí)現(xiàn)的。若停止位為一個(gè),則清除CSTOPB,若停止位為兩個(gè),則激活CSTOPB。以下分別是停止位為一個(gè)和兩個(gè)比特時(shí)的代碼:

new_cfg.c_cflag&=~CSTOPB;/*將停止位設(shè)置為一個(gè)比特*/

new_cfg.c_cflag|=CSTOPB;/*將停止位設(shè)置為兩個(gè)比特*/

7.設(shè)置最少字符和等待時(shí)間

在對接收字符和等待時(shí)間沒有特別要求的情況下,可以將其設(shè)置為0,則在任何情況下read()函數(shù)立即返回,如下所示:

new_cfg.c_cc[VTIME]=0;

new_cfg.c_cc[VMIN]=0;

8.清除串口緩沖

由于串口在重新設(shè)置之后,需要對當(dāng)前的串口設(shè)備進(jìn)行適當(dāng)?shù)奶幚恚@時(shí)就可調(diào)用在<termios.h>中聲明的tcdrain()、tcflow()、tcflush()等函數(shù)來處理目前串口緩沖中的數(shù)據(jù),它們的格式如下所示。

inttcdrain(intfd);/*使程序阻塞,直到輸出緩沖區(qū)的數(shù)據(jù)全部發(fā)送完畢*/

inttcflow(intfd,intaction);/*用于暫停或重新開始輸出*/

inttcflush(intfd,intqueue_selector);/*用于清空輸入/輸出緩沖區(qū)*/

在本實(shí)例中使用tcflush()函數(shù),對于在緩沖區(qū)中的尚未傳輸?shù)臄?shù)據(jù),或者收到的但是尚未讀取的數(shù)據(jù),其處理方法取決于queue_selector的值,它可能的取值有以下幾種。

n TCIFLUSH:對接收到而未被讀取的數(shù)據(jù)進(jìn)行清空處理。

n TCOFLUSH:對尚未傳送成功的輸出數(shù)據(jù)進(jìn)行清空處理。

n TCIOFLUSH:包括前兩種功能,即對尚未處理的輸入輸出數(shù)據(jù)進(jìn)行清空處理。

如在本例中所采用的是第一種方法:

tcflush(fd,TCIFLUSH);

9.激活配置

在完成全部串口配置之后,要激活剛才的配置并使配置生效。這里用到的函數(shù)是tcsetattr(),它的函數(shù)原型是:

tcsetattr(intfd,intoptional_actions,conststructtermios*termios_p);

其中參數(shù)termios_p是termios類型的新配置變量。

參數(shù)optional_actions可能的取值有以下3種:

n TCSANOW:配置的修改立即生效。

n TCSADRAIN:配置的修改在所有寫入fd的輸出都傳輸完畢之后生效。

n TCSAFLUSH:所有已接受但未讀入的輸入都將在修改生效之前被丟棄。

該函數(shù)若調(diào)用成功則返回0,若失敗則返回-1,代碼如下所示:

if((tcsetattr(fd,TCSANOW,&new_cfg))!=0)

{

perror("tcsetattr");

return-1;

}

下面給出了串口配置的完整函數(shù)。通常,為了函數(shù)的通用性,通常將常用的選項(xiàng)都在函數(shù)中列出,這樣可以大大方便以后用戶的調(diào)試使用。該設(shè)置函數(shù)如下所示:

intset_com_config(intfd,intbaud_rate,

intdata_bits,charparity,intstop_bits)

{

structtermiosnew_cfg,old_cfg;

intspeed;

/*保存并測試現(xiàn)有串口參數(shù)設(shè)置,在這里如果串口號(hào)等出錯(cuò),會(huì)有相關(guān)的出錯(cuò)信息*/

if(tcgetattr(fd,&old_cfg)!=0)

{

perror("tcgetattr");

return-1;

}

/*設(shè)置字符大小*/

new_cfg=old_cfg;

cfmakeraw(&new_cfg);/*配置為原始模式*/

new_cfg.c_cflag&=~CSIZE;

/*設(shè)置波特率*/

switch(baud_rate)

{

case2400:

{

speed=B2400;

}

break;

case4800:

{

speed=B4800;

}

break;

case9600:

{

speed=B9600;

}

break;

case19200:

{

speed=B19200;

}

break;

case38400:

{

speed=B38400;

}

break;

default:

case115200:

{

speed=B115200;

}

break;

}

cfsetispeed(&new_cfg,speed);

cfsetospeed(&new_cfg,speed);

/*設(shè)置停止位*/

switch(data_bits)

{

case7:

{

new_cfg.c_cflag|=CS7;

}

break;

default:

case8:

{

new_cfg.c_cflag|=CS8;

}

break;

}

/*設(shè)置奇偶校驗(yàn)位*/

switch(parity)

{

default:

case'n':

case'N':

{

new_cfg.c_cflag&=~PARENB;

new_cfg.c_iflag&=~INPCK;

}

break;

case'o':

case'O':

{

new_cfg.c_cflag|=(PARODD|PARENB);

new_cfg.c_iflag|=INPCK;

}

break;

case'e':

case'E':

{

new_cfg.c_cflag|=PARENB;

new_cfg.c_cflag&=~PARODD;

new_cfg.c_iflag|=INPCK;

}

break;

case's':/*asnoparity*/

case'S':

{

new_cfg.c_cflag&=~PARENB;

new_cfg.c_cflag&=~CSTOPB;

}

break;

}

/*設(shè)置停止位*/

switch(stop_bits)

{

default:

case1:

{

new_cfg.c_cflag&=~CSTOPB;

}

break;

case2:

{

new_cfg.c_cflag|=CSTOPB;

}

}

/*設(shè)置等待時(shí)間和最小接收字符*/

new_cfg.c_cc[VTIME]=0;

new_cfg.c_cc[VMIN]=1;

/*處理未接收字符*/

tcflush(fd,TCIFLUSH);

/*激活新配置*/

if((tcsetattr(fd,TCSANOW,&new_cfg))!=0)

{

perror("tcsetattr");

return-1;

}

return0;

}

6.4.3串口使用詳解

在配置完串口的相關(guān)屬性后,就可以對串口進(jìn)行打開和讀寫操作了。它所使用的函數(shù)和普通文件的讀寫函數(shù)一樣,都是open()、write()和read()。它們之間的區(qū)別的只是串口是一個(gè)終端設(shè)備,因此在選擇函數(shù)的具體參數(shù)時(shí)會(huì)有一些區(qū)別。另外,這里會(huì)用到一些附加的函數(shù),用于測試終端設(shè)備的連接情況等。下面將對其進(jìn)行具體講解。

1.打開串口

打開串口和打開普通文件一樣,都是使用open()函數(shù),如下所示:

fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);

可以看到,這里除了普通的讀寫參數(shù)外,還有兩個(gè)參數(shù)O_NOCTTY和O_NDELAY。

n O_NOCTTY標(biāo)志用于通知Linux系統(tǒng),該參數(shù)不會(huì)使打開的文件成為這個(gè)進(jìn)程的控制終端。如果沒有指定這個(gè)標(biāo)志,那么任何一個(gè)輸入(諸如鍵盤中止信號(hào)等)都將會(huì)影響用戶的進(jìn)程。

n O_NDELAY標(biāo)志通知Linux系統(tǒng),這個(gè)程序不關(guān)心DCD信號(hào)線所處的狀態(tài)(端口的另一端是否激活或者停止)。如果用戶指定了這個(gè)標(biāo)志,則進(jìn)程將會(huì)一直處在睡眠狀態(tài),直到DCD信號(hào)線被激活。

接下來可恢復(fù)串口的狀態(tài)為阻塞狀態(tài),用于等待串口數(shù)據(jù)的讀入,可用fcntl()函數(shù)實(shí)現(xiàn),如下所示:

fcntl(fd,F_SETFL,0);

再接著可以測試打開文件描述符是否連接到一個(gè)終端設(shè)備,以進(jìn)一步確認(rèn)串口是否正確打開,如下所示:

isatty(STDIN_FILENO);

該函數(shù)調(diào)用成功則返回0,若失敗則返回-1。

這時(shí),一個(gè)串口就已經(jīng)成功打開了。接下來就可以對這個(gè)串口進(jìn)行讀和寫操作。下面給出了一個(gè)完整的打開串口的函數(shù),同樣考慮到了各種不同的情況。程序如下所示:

/*打開串口函數(shù)*/

intopen_port(intcom_port)

{

intfd;

#if(COM_TYPE==GNR_COM)/*使用普通串口*/

char*dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};

#else/*使用USB轉(zhuǎn)串口*/

char*dev[]={"/dev/ttyUSB0","/dev/ttyUSB1","/dev/ttyUSB2"};

#endif

if((com_port<0)||(com_port>MAX_COM_NUM))

{

return-1;

}

/*打開串口*/

fd=open(dev[com_port-1],O_RDWR|O_NOCTTY|O_NDELAY);

if(fd<0)

{

perror("openserialport");

return(-1);

}

/*恢復(fù)串口為阻塞狀態(tài)*/

if(fcntl(fd,F_SETFL,0)<0)

{

perror("fcntlF_SETFL\n");

}

/*測試是否為終端設(shè)備*/

if(isatty(STDIN_FILENO)==0)

{

perror("standardinputisnotaterminaldevice");

}

returnfd;

}

2.讀寫串口

讀寫串口操作和讀寫普通文件一樣,使用read()和write()函數(shù)即可,如下所示:

write(fd,buff,strlen(buff));

read(fd,buff,BUFFER_SIZE);

下面兩個(gè)實(shí)例給出了串口讀和寫的兩個(gè)程序,其中用到前面所講述的open_port()和set_com_config()函數(shù)。寫串口的程序?qū)⒃谒拗鳈C(jī)上運(yùn)行,讀串口的程序?qū)⒃谀繕?biāo)板上運(yùn)行。

寫串口的程序如下所示。

/*com_writer.c*/

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<errno.h>

#include"uart_api.h"

intmain(void)

{

intfd;

charbuff[BUFFER_SIZE];

if((fd=open_port(HOST_COM_PORT))<0)/*打開串口*/

{

perror("open_port");

return1;

}

if(set_com_config(fd,115200,8,'N',1)<0)/*配置串口*/

{

perror("set_com_config");

return1;

}

do

{

printf("Inputsomewords(enter'quit'toexit):");

memset(buff,0,BUFFER_SIZE);

if(fgets(buff,BUFFER_SIZE,stdin)==NULL)

{

perror("fgets");

break;

}

write(fd,buff,strlen(buff));

}while(strncmp(buff,"quit",4));

close(fd);

return0;

}

讀串口的程序如下所示:

/*com_reader.c*/

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<errno.h>

#include"uart_api.h"

intmain(void)

{

intfd;

charbuff[BUFFER_SIZE];

if((fd=open_port(TARGET_COM_PORT))<0)/*打開串口*/

{

perror("open_port");

return1;

}

if(set_com_config(fd,115200,8,'N',1)<0)/*配置串口*/

{

perror("set_com_config");

return1;

}

do

{

memset(buff,0,BUFFER_SIZE);

if(read(fd,buff,BUFFER_SIZE)>0)

{

printf("Thereceivedwordsare:%s",buff);

}

}while(strncmp(buff,"quit",4));

close(fd);

return0;

}

在宿主機(jī)上運(yùn)行寫串口的程序,而在目標(biāo)板上運(yùn)行讀串口的程序,運(yùn)行結(jié)果如下所示。

/*宿主機(jī),寫串口*/

$./com_writer

Inputsomewords(enter'quit'toexit):hello,Reader!

Inputsomewords(enter'quit'toexit):I'mWriter!

Inputsomewords(enter'quit'toexit):Thisisaserialporttestingprogram.

Inputsomewords(enter'quit'toexit):quit

/*目標(biāo)板,讀串口*/

$./com_reader

Thereceivedwordsare:hello,Reader!

Thereceivedwordsare:I'mWriter!

Thereceivedwordsare:Thisisaserialporttestingprogram.

Thereceivedwordsare:quit

另外,讀者還可以考慮一下如何使用select()函數(shù)實(shí)現(xiàn)串口的非阻塞讀寫,具體實(shí)例會(huì)在本章的后面的實(shí)驗(yàn)中給出。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢抑制與過流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉