1. 程式人生 > >linux串列埠應用程式設計入門,文件勝於一切教程

linux串列埠應用程式設計入門,文件勝於一切教程

接觸過linux程式設計的應該都知道,學習linux應用最好的參考資料就是系統自帶的手冊——通過man命令查詢程式設計手冊。

通過搜尋引擎搜尋與linux串列埠程式設計相關的關鍵字,找到與串列埠程式設計相關的結構體或者函式就可以開始自學串列埠應用程式設計了。

學習環境:deepin 15.3 64位系統,開發板:nanopc-t1,執行ubuntu 14.04LTS,核心版本:3.8.13.16,交叉編譯鏈:arm-linux-gnueabihf-gcc,版本4.7.3

我是從串列埠相關的termios結構體開始入手的,終端中輸入man 3 termios

[email protected]
:~$ man 3 termios
就能開啟串列埠程式設計手冊了,學習過程中遇到的串列埠相關的問題都可以在這裡找到答案。

開啟手冊,可以看到串列埠相關的許多函式,而且很多函式都含有struct termios這個結構體,所以這個結構體一定是重點,繼續往下翻手冊可以看到這個結構體的介紹

DESCRIPTION
       The termios functions describe a general terminal interface that is provided to control asynchronous  communi‐
       cations ports.
   The termios structure
       Many of the functions described here have a termios_p argument that is a pointer to a termios structure.  This
       structure contains at least the following members:

           tcflag_t c_iflag;      /* input modes */
           tcflag_t c_oflag;      /* output modes */
           tcflag_t c_cflag;      /* control modes */
           tcflag_t c_lflag;      /* local modes */
           cc_t     c_cc[NCCS];   /* special characters */

描述中說到,termios這個結構體是用於描述一個串列埠的各個引數的,結構體包含輸入,輸出模式等引數。不過,這些引數跟學微控制器時配置的引數完全不一樣,而且最重要的一點貌似沒有——這個結構體描述的是哪個串列埠。繼續翻手冊,又發現了一個讀取設定和生效配置的說明

Retrieving and changing terminal settings
       tcgetattr() gets the parameters associated with the object referred by fd  and  stores  them  in  the  termios
       structure  referenced by termios_p.  This function may be invoked from a background process; however, the ter‐
       minal attributes may be subsequently changed by a foreground process.

       tcsetattr() sets the parameters associated with the terminal (unless support is required from  the  underlying
       hardware  that is not available) from the termios structure referred to by termios_p.  optional_actions speci‐
       fies when the changes take effect:
這樣的話我們只需要修改跟我們預期的配置不一樣的地方然後再生效配置就好了。那首先我們就要開始使用這個函式看看串列埠原本的引數了。

回到手冊的頭部

SYNOPSIS
       #include <termios.h>
       #include <unistd.h>

       int tcgetattr(int fd, struct termios *termios_p);

可以看到所有的函式生明和需要的標頭檔案,首先把手冊列出來的標頭檔案新增到我們的程式碼中

#include <termios.h>
#include <unistd.h>

int main(void)
{
    return 0;
}

再看tcgetattr函式的第一個入口引數為fd,很明顯這個為檔案描述符,不難想到我們要控制的是哪個串列埠就是由這個引數來決定的。檔案描述符在開啟檔案的時候生成,所以我們需要開啟串列埠裝置,同樣利用man 命令查詢open函式的使用方法和需要的標頭檔案

[email protected]:~$ man 3 open
SYNOPSIS
       #include <sys/stat.h>
       #include <fcntl.h>


       int open(const char *path, int oflag, ...);
       int openat(int fd, const char *path, int oflag, ...);
可以看到open函式需要sys/stat.h,fcntl.h兩個標頭檔案,open函式的第一個入口引數為檔案的路徑,至於第二個引數oflag我們可以繼續翻手冊尋找可以選用的引數
Values for oflag are constructed by a bitwise-inclusive OR of  flags  from  the  following  list,  defined  in
       <fcntl.h>.   Applications  shall specify exactly one of the first five values (file access modes) below in the
       value of oflag:

       O_EXEC        Open for execute only (non-directory files). The result is unspecified if this flag  is  applied
                     to a directory.

       O_RDONLY      Open for reading only.

       O_RDWR        Open for reading and writing. The result is undefined if this flag is applied to a FIFO.

       O_SEARCH      Open  directory  for  search  only.  The result is unspecified if this flag is applied to a non-
                     directory file.

       O_WRONLY      Open for writing only.

       Any combination of the following may be used:

       O_APPEND      If set, the file offset shall be set to the end of the file prior to each write.

       O_CLOEXEC     If set, the FD_CLOEXEC flag for the new file descriptor shall be set.

       O_CREAT       If the file exists, this flag has no effect except as noted under O_EXCL below.  Otherwise,  the
                     file  shall  be  created;  the  user ID of the file shall be set to the effective user ID of the
                     process; the group ID of the file shall be set to the group ID of the file's parent directory or
                     to  the  effective group ID of the process; and the access permission bits (see <sys/stat.h>) of
                     the file mode shall be set to the value of the argument following the oflag  argument  taken  as
                     type mode_t modified as follows: a bitwise AND is performed on the file-mode bits and the corre‐
                     sponding bits in the complement of the process' file mode creation mask. Thus, all bits  in  the
                     file  mode  whose corresponding bit in the file mode creation mask is set are cleared. When bits
                     other than the file permission bits are set, the effect is unspecified. The  argument  following
                     the  oflag  argument does not affect whether the file is open for reading, writing, or for both.
                     Implementations shall provide a way to initialize the file's group ID to the  group  ID  of  the
                     parent  directory.  Implementations  may, but need not, provide an implementation-defined way to
                     initialize the file's group ID to the effective group ID of the calling process.

       O_DIRECTORY   If path resolves to a non-directory file, fail and set errno to [ENOTDIR].

       O_DSYNC       Write I/O operations on the file descriptor shall complete as defined by synchronized  I/O  data
                     integrity completion.

       O_EXCL        If O_CREAT and O_EXCL are set, open() shall fail if the file exists. The check for the existence
                     of the file and the creation of the file if it does not exist shall be atomic  with  respect  to
                     other  threads  executing  open() naming the same filename in the same directory with O_EXCL and
                     O_CREAT set. If O_EXCL and O_CREAT are set, and path names a symbolic link,  open()  shall  fail
                     and set errno to [EEXIST], regardless of the contents of the symbolic link. If O_EXCL is set and
                     O_CREAT is not set, the result is undefined.

       O_NOCTTY      If set and path identifies a terminal device, open() shall not  cause  the  terminal  device  to
                     become  the  controlling  terminal for the process. If path does not identify a terminal device,
                     O_NOCTTY shall be ignored.

       O_NOFOLLOW    If path names a symbolic link, fail and set errno to [ELOOP].

       O_NONBLOCK    When opening a FIFO with O_RDONLY or O_WRONLY set:

                      *  If O_NONBLOCK is set, an open() for reading-only shall return without delay. An  open()  for
                         writing-only shall return an error if no process currently has the file open for reading.

                      *  If  O_NONBLOCK  is  clear, an open() for reading-only shall block the calling thread until a
                         thread opens the file for writing. An open() for writing-only shall block the calling thread
                         until a thread opens the file for reading.

                     When opening a block special or character special file that supports non-blocking opens:

                      *  If O_NONBLOCK is set, the open() function shall return without blocking for the device to be
                         ready or available. Subsequent behavior of the device is device-specific.

                      *  If O_NONBLOCK is clear, the open() function shall block the calling thread until the  device
                         is ready or available before returning.

                     Otherwise,  the O_NONBLOCK flag shall not cause an error, but it is unspecified whether the file
                     status flags will include the O_NONBLOCK flag.
O_RSYNC       Read I/O operations on the file descriptor shall complete at the  same  level  of  integrity  as
                     specified by the O_DSYNC and O_SYNC flags. If both O_DSYNC and O_RSYNC are set in oflag, all I/O
                     operations on the file descriptor shall complete as defined by synchronized I/O  data  integrity
                     completion. If both O_SYNC and O_RSYNC are set in flags, all I/O operations on the file descrip‐
                     tor shall complete as defined by synchronized I/O file integrity completion.

       O_SYNC        Write I/O operations on the file descriptor shall complete as defined by synchronized  I/O  file
                     integrity completion.

                     The  O_SYNC flag shall be supported for regular files, even if the Synchronized Input and Output
                     option is not supported.

       O_TRUNC       If the file exists and is a regular  file,  and  the  file  is  successfully  opened  O_RDWR  or
                     O_WRONLY,  its  length  shall  be  truncated to 0, and the mode and owner shall be unchanged. It
                     shall have no effect on FIFO special files or terminal device files. Its effect  on  other  file
                     types  is  implementation-defined. The result of using O_TRUNC without either O_RDWR or O_WRONLY
                     is undefined.

       O_TTY_INIT    If path identifies a terminal device other than a pseudo-terminal, the  device  is  not  already
                     open  in  any  process,  and either O_TTY_INIT is set in oflag or O_TTY_INIT has the value zero,
                     open() shall set any non-standard termios structure terminal parameters to a state that provides
                     conforming  behavior;  see the Base Definitions volume of POSIX.1‐2008, Section 11.2, Parameters
                     that Can be Set.  It is unspecified whether O_TTY_INIT has any effect if the device  is  already
                     open  in any process. If path identifies the slave side of a pseudo-terminal that is not already
                     open in any process, open() shall set any non-standard termios structure terminal parameters  to
                     a state that provides conforming behavior, regardless of whether O_TTY_INIT is set. If path does
                     not identify a terminal device, O_TTY_INIT shall be ignored.
這裡我選擇了讀寫許可權標誌O_RDWR和非控制終端標誌O_NOCTTY兩個選項,開啟檔案這句程式碼的引數就找齊了,開啟檔案後要記得關閉
#include <termios.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main(void)
{	
	int fd;
	char tty_addr[] = "/dev/ttySAC2";
	fd = open(tty_addr,O_RDWR|O_NOCTTY);
	if(fd < 0)
	{
		printf("開啟%s失敗\r\n",tty_addr);
		return 0;
	}
	printf("開啟%s成功\r\n",tty_addr);
	close(fd);
	return 0;
}

每做完一步先編譯並且放上開發板測試一遍,我用的是nanopc-t1

[email protected]:~/nanopc/usart-test$ arm-linux-gnueabihf-gcc usart-test.c -o usart-test -static
沒有錯誤提示而且生成了usart-test檔案就證明編譯成功了。用自己決覺得方便的方法吧程式下載的板子裡,我比較喜歡用scp方式。執行程式並觀察輸出結果
[email protected]:~# ./usart-test 
開啟/dev/ttySAC2成功
[email protected]:~# 
可以看到,程式順利的運行了,接著進行下一步——獲取串列埠的引數。我們首先看看串列埠的波特率。
#include <termios.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main(void)
{	
	int fd,uart_in_speed,uart_out_speed;
	char tty_addr[] = "/dev/ttySAC2";
	struct termios uart_setting_struct;
	fd = open(tty_addr,O_RDWR|O_NOCTTY);
	if(fd < 0)
	{
		printf("開啟%s失敗\r\n",tty_addr);
		return 0;
	}
	printf("開啟%s成功\r\n",tty_addr);
	tcgetattr(fd,&uart_setting_struct);
	uart_in_speed = cfgetispeed(&uart_setting_struct);
	uart_out_speed = cfgetospeed(&uart_setting_struct);
	printf("串列埠輸入速度:%d,輸出速度:%d\r\n",uart_in_speed,uart_out_speed);
	close(fd);
	return 0;
}
編譯並下載到板子上執行
[email protected]:~# ./usart-test 
開啟/dev/ttySAC2成功
串列埠輸入速度:13,輸出速度:13
[email protected]:~# 
執行之後可以看到串列埠的輸入和輸出的速度都不是常見的波特率,有疑惑就要重新去翻看手冊尋找答案。
Line speed
       The baud rate functions are provided for getting and setting the values of the input and output baud rates  in
       the termios structure.  The new values do not take effect until tcsetattr() is successfully called.

       Setting  the speed to B0 instructs the modem to "hang up".  The actual bit rate corresponding to B38400 may be
       altered with setserial(8).

       The input and output baud rates are stored in the termios structure.

       cfgetospeed() returns the output baud rate stored in the termios structure pointed to by termios_p.

       cfsetospeed() sets the output baud rate stored in the termios structure pointed  to  by  termios_p  to  speed,
       which must be one of these constants:

            B0
            B50
            B75
            B110
            B134
            B150
            B200
            B300
            B600
            B1200
            B1800
            B2400
            B4800
            B9600
            B19200
            B38400
            B57600
            B115200
            B230400

       The  zero  baud  rate,  B0,  is used to terminate the connection.  If B0 is specified, the modem control lines
       shall no longer be asserted.  Normally, this will disconnect the line.  CBAUDEX  is  a  mask  for  the  speeds
       beyond those defined in POSIX.1 (57600 and above).  Thus, B57600 & CBAUDEX is nonzero.

       cfgetispeed() returns the input baud rate stored in the termios structure.

       cfsetispeed()  sets  the  input baud rate stored in the termios structure to speed, which must be specified as
       one of the Bnnn constants listed above for cfsetospeed().  If the input baud rate is set to  zero,  the  input
       baud rate will be equal to the output baud rate.

       cfsetspeed()  is  a  4.4BSD  extension.  It takes the same arguments as cfsetispeed(), and sets both input and
       output speed.

RETURN VALUE
       cfgetispeed() returns the input baud rate stored in the termios structure.

       cfgetospeed() returns the output baud rate stored in the termios structure.

       All other functions return:

       0      on success.

       -1     on failure and set errno to indicate the error.

       Note that tcsetattr() returns success if any of the requested  changes  could  be  successfully  carried  out.
       Therefore,  when  making multiple changes it may be necessary to follow this call with a further call to tcge‐
       tattr() to check that all changes have been performed successfully.
通過手冊,我們發現串列埠的波特率不是直接輸入數字設定的,而是通過一組巨集,剛剛獲取到的速度為13,即指B9600巨集,表示的波特率為9600,那下一步就可以嘗試修改串列埠的波特率了,修改設定後記得使設定生效。
Retrieving and changing terminal settings
       tcgetattr() gets the parameters associated with the object referred by fd  and  stores  them  in  the  termios
       structure  referenced by termios_p.  This function may be invoked from a background process; however, the ter‐
       minal attributes may be subsequently changed by a foreground process.

       tcsetattr() sets the parameters associated with the terminal (unless support is required from  the  underlying
       hardware  that is not available) from the termios structure referred to by termios_p.  optional_actions speci‐
       fies when the changes take effect:

       TCSANOW
              the change occurs immediately.

       TCSADRAIN
              the change occurs after all output written to fd has been transmitted.  This option should be used when
              changing parameters that affect output.

       TCSAFLUSH
              the  change  occurs after all output written to the object referred by fd has been transmitted, and all
              input that has been received but not read will be discarded before the change is made.
在tcsetattr函式的說明後面有幾個生效設定選項,通過各個巨集的說明,可以看到這些巨集代表設定生效的時間,立刻生效,傳送資料完成後生效,傳送資料完成後生效而且接收到的而且沒被程式讀取的資料將被丟棄。按需選擇就好,在當前的簡單應用中,可以選擇任意一個,我選擇了立刻生效。原始碼如下:
#include <termios.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

#define UART_BAUD B115200

int main(void)
{	
	int fd,uart_in_speed,uart_out_speed;
	char tty_addr[] = "/dev/ttySAC2";
	char send_buf[] = "hello";
	struct termios uart_setting_struct;
	fd = open(tty_addr,O_RDWR|O_NOCTTY);
	if(fd < 0)
	{
		printf("開啟%s失敗\r\n",tty_addr);
		return 0;
	}
	printf("開啟%s成功\r\n",tty_addr);
	tcgetattr(fd,&uart_setting_struct);
	uart_in_speed = cfgetispeed(&uart_setting_struct);
	if(uart_in_speed != UART_BAUD)
	{
		cfsetispeed(&uart_setting_struct,UART_BAUD);
	}
	uart_out_speed = cfgetospeed(&uart_setting_struct);
	if(uart_out_speed != UART_BAUD)
	{
		cfsetospeed(&uart_setting_struct,UART_BAUD);
	}
	tcsetattr(fd,TCSANOW,&uart_setting_struct);
	write(fd,send_buf,strlen(send_buf));
	close(fd);
	return 0;
}
以115200的波特率開啟串列埠除錯助手,我用的是picocom,-b表示使用的波特率,/dev/ttyUSB0為usb轉串列埠模組的串列埠號,ctrl+a,ctrl+q可以退出除錯助手
[email protected]:~$ sudo picocom -b 115200 /dev/ttyUSB0
開啟除錯助手之後,把編譯號好的程式下載的板子上並執行,可以在除錯助手中看到輸出的資訊
picocom v1.7

port is        : /dev/ttyUSB0
flowcontrol    : none
baudrate is    : 115200
parity is      : none
databits are   : 8
escape is      : C-a
local echo is  : no
noinit is      : no
noreset is     : no
nolock is      : no
send_cmd is    : sz -vv
receive_cmd is : rz -vv
imap is        : 
omap is        : 
emap is        : crcrlf,delbs,

Terminal ready
hello
Thanks for using picocom
串列埠設定好之後就當做普通檔案來讀寫就好了。

此文章為本人的學習過程,如有錯誤請指出!



相關推薦

linux串列應用程式設計入門一切教程

接觸過linux程式設計的應該都知道,學習linux應用最好的參考資料就是系統自帶的手冊——通過man命令查詢程式設計手冊。 通過搜尋引擎搜尋與linux串列埠程式設計相關的關鍵字,找到與串列埠程式設計相關的結構體或者函式就可以開始自學串列埠應用程式設計了。 學習環境:de

[零]java8 函數語言程式設計入門官方中文版 java.util.stream 中文版 流處理的相關概念

如果行為引數確實有副作用,除非顯式地宣告,否則就無法保證這些副作用對其他執行緒的可見性,也不能保證在同一條管道內的“相同”元素上的不同操作在相同的執行緒中執行。此外,這些影響的排序可能出乎意料。即使管道被限制生成一個與stream源的處理順序一致的結果(例如,IntStream.range(0,5).para

linux查看磁盤大小大小常用方法

查看 inux access host roo 統計 單位 dev 服務器 1.查看磁盤大小使用df 命令df的主要功能是查看linux服務器的磁盤使用情況的,用來查看磁盤使用空間,剩余空間。df 【選項】【文件】顯示指定磁盤文件的可用空間。如果沒有文件名被指定,則所有當前

Linux串列程式設計教程(三)——串列程式設計詳(原始碼)解:http://blog.csdn.net/u011192270/article/details/48174353 Linux下的串列程式設計(二)----(圖文並茂講解深刻)http://blog.csdn.net/w28252

Linux串列埠程式設計教程(三)——串列埠程式設計詳(原始碼)解:http://blog.csdn.net/u011192270/article/details/48174353 Linux下的串列埠程式設計(二)----(圖文並茂,講解深刻)http://blog.csdn.ne

Linux串列程式設計實現不定長收發資料包

一、需求: 需要利用串列埠對兩臺裝置進行資料互動。 要求:資料包大小不定。能夠實現阻塞讀取每一個數據包。粘包,丟包問題在解析資料包中處理。 二、設計 為了實現不定長接收資料包,利用了 struct termios的兩個成員屬性:  newtio.c_cc

Linux串列程式設計詳解 linux串列相關設定函式

tcgetattr    函式用於獲取與終端相關的引數。引數fd為終端的檔案描述符,返回的結果儲存在termios 結構體中 http://baike.baidu.com/view/5644808.htm?fr=aladdin tcset

Linux串列程式設計

串列埠通訊是指一次只傳送一個數據位。雖然在通訊的時候串列埠有 8 位或者 9 位等,但是在物理層面傳輸的時候,它仍然是以單個 bit 的方式傳輸的 一般特指 RS232 標準的介面 在 linux 下串列埠程式設計流程如下: 開啟串列埠 核心是用op

Linux串列程式設計詳解

串列埠本身,標準和硬體 † 串列埠是計算機上的序列通訊的物理介面。計算機歷史上,串列埠曾經被廣泛用於連線計算機和終端裝置和各種外部裝置。雖然乙太網介面和USB介面也是以一個序列流進行資料傳送的,但是串列埠連線通常特指那些與RS-232標準相容的硬體或者調變解調器的介面。雖然現在在很

linux串列程式設計(控制流與終端)

流控制 資料在兩個串列埠之間傳輸時,常常會出現丟失資料的現象,或者兩臺計算機的處理速度不同,如桌上型電腦與微控制器之間的通訊,接收端資料緩衝區已滿,則此時繼續傳送來的資料就會丟失。流控制能解決這個問題,當接收端資料處理不過來時,就發出“不再接收”的訊號,傳送端就停止傳送,直到收到“可以繼續傳送”

linux串列程式設計(termios結構體說明)

termios結構體說明 轉https://www.cnblogs.com/li-hao/archive/2012/02/19/2358158.html termios結構體中,該結構體一般包括如下的成員:tcflag_t       c_iflag;

Linux串列(serial、uart)驅動程式設計

一、核心資料結構串列埠驅動有3個核心資料結構,它們都定義在<#include linux/serial_core.h>1、uart_driveruart_driver包含了串列埠裝置名、串列埠驅動名、主次裝置號、串列埠控制檯(可選)等資訊,還封裝了tty_dri

Linux-串列配置初始化及使用

【檢視串列埠】4412採用 ttySAC*系列串列埠裝置節點 ,即 ttySAC0 , ttySAC1 , ttySAC2 , ttySAC3【開啟串列埠裝置節點】“/dev/ttySAC3”形成fd 與 裝置節點的/dev/ttySAC3連結【初始化配置串列埠】#inclu

【程式碼參考網上的】linux串列程式設計學習筆記

1.串列埠通訊:同步通訊:將很多字元組成一個資訊組進行傳送非同步通訊:一個字元一符的傳送。(可靠性高,但是效率相對降低) 2.通過echo和cat來測試串列埠通訊 echo “Hello” >/dev/ttyS0   cat /dev/ttyS1 3.直接通過read

在嵌入式linux串列終端中如何燒錄核心和上傳檔案?

開發嵌入式linux遇到一些沒有u盤或者網口的時候,怎麼更新核心?更新應用程式? 映像上傳 採用串列埠xmodem協議上傳,串列埠波特率為460800。開發板這裡首先要連線secureCRT,在c

嵌入式Linux基於Qt開發串列應用

By Toradex秦海 1). 簡介 基於Embedded Linux系統的嵌入式裝置使用跨平臺GUI開發工具Qt來開發嵌入式應用已經非常普遍,本文就以分別通過原生C語言方式和使用Qt QSerialPort控制元件方式來進行RS232/RS485串列埠應用的開發示例。

串列通訊程式設計詳解(Linux

rs232是三芯通訊,即DB9的第2引腳RXD(接收)、第3引腳TXD(傳送資料)、第5引腳DG(訊號地)。 rs232是三芯通訊,485是兩芯通訊的,RS-232串列埠線 通常 是 DB9--DB9 的 串列埠通訊線,9芯 RS-485資料線 是 雙絞線或者遮蔽雙絞線,2

linux串列程式設計說明

1.參考文章1 2.linux手冊參考 3.詳解linux下的串列埠通訊開發 在linux下所有的裝置都是檔案,串列埠也不例外,所以對串列埠的操作也是open,close,write,read這幾個操作,只不過串列埠通訊要想正常溝通,還需要設定正確的屬性。

Linux 串列程式設計 使用termios與API進行串列程式開發

在 termios 結構體以及內部終端控制標誌中,並非所有的引數對於實際的物理串列埠都是有效的,在使用過程中也不需要對於所有標誌的作用都有所理解。事實上,快速掌握一項技術的核心點也是一種學習能力。對於

linux之系統編碼python編碼編碼

python 編碼 文件編碼 linux編碼 1 前言如果你對python2和python3的中編解碼很清楚,這裏我認為你很清楚。具體參考文檔:“python2 encode和decode函數說明.docx”“字符編碼——從ASCII開始.docx”以上所有文檔均為本地文檔。2

go語言使用go-sciter創建桌面應用(七) view對象常用方法選擇窗口彈出請求

問題 adf img function jquery stdout view type 改變 view對象的詳細文檔請看: https://sciter.com/docs/content/sciter/View.htm demo9.html代碼如下: &l