Linux 串列埠程式設計
在linux中,所有的裝置檔案一般位於"/dev"目錄下,其中串列埠對應的名稱為"/dev/ttySx",(因驅動不同,該裝置名也會有所不同),可也檢視在"/dev"下的檔案以確認。在linux下對裝置的操作方法與對檔案操作方法一樣,因此,對串列埠的讀寫就可以使用簡單的read,write等函式來完成,所不同的只是需要對串列埠的其他引數另做配置。
串列埠的設定主要是設定structtermios結構體中的成員,如下所示.
struct termios
{
tcflag_t c_iflag; //輸入模式標誌
tcflag_t c_oflag; //輸出模式標誌
tcflag_t c_cflag; //控制模式標誌
tcflag_t c_lflag; //本地模式標誌
cc_t c_line; //線路規則
cc_t c_cc[NCC]; //控制特性
}
C_iflag支援的常量名稱如下表所示,其用於控制埠接收端的字元輸入處理。
鍵 值 |
說 明 |
IGNBRK |
忽略BREAK鍵輸入 |
BRKINT |
如果設定了IGNBRK,BREAK鍵的輸入將被忽略,如果設定了BRKINT ,將產生SIGINT中斷 |
IGNPAR |
忽略奇偶校驗錯誤 |
PARMRK |
標識奇偶校驗錯誤 |
INPCK |
允許輸入奇偶校驗 |
ISTRIP |
去除字元的第8個位元 |
INLCR |
將輸入的NL(換行)轉換成CR(回車) |
IGNCR |
忽略輸入的回車 |
ICRNL |
將輸入的回車轉化成換行(如果IGNCR未設定的情況下) |
IUCLC |
將輸入的大寫字元轉換成小寫字元(非POSIX) |
IXON |
允許輸入時對XON/XOFF流進行控制 |
IXANY |
輸入任何字元將重啟停止的輸出 |
IXOFF |
允許輸入時對XON/XOFF流進行控制 |
IMAXBEL |
當輸入佇列滿的時候開始響鈴,Linux在使用該引數而是認為該引數總是已經設定 |
C_oflag支援的常量名稱如下表所示,其用於控制終端埠傳送出去的字元處理。
鍵 值 |
說 明 |
OPOST |
處理後輸出 |
OLCUC |
將輸入的小寫字元轉換成大寫字元(非POSIX) |
ONLCR |
將輸入的NL(換行)轉換成CR(回車)及NL(換行) |
OCRNL |
將輸入的CR(回車)轉換成NL(換行) |
ONOCR |
第一行不輸出回車符 |
ONLRET |
不輸出回車符 |
OFILL |
傳送填充字元以延遲終端輸出 |
OFDEL |
以ASCII碼的DEL作為填充字元,如果未設定該引數,填充字元將是NUL(‘\0’)(非POSIX) |
NLDLY |
換行輸出延時,可以取NL0(不延遲)或NL1(延遲0.1s) |
CRDLY |
回車延遲,取值範圍為:CR0、CR1、CR2和 CR3 |
TABDLY |
水平製表符輸出延遲,取值範圍為:TAB0、TAB1、TAB2和TAB3 |
BSDLY |
空格輸出延遲,可以取BS0或BS1 |
VTDLY |
垂直製表符輸出延遲,可以取VT0或VT1 |
FFDLY |
換頁延遲,可以取FF0或FF1 |
C_cflag支援的常量名稱如下表所示,其是結構中最重要的一個,通過對他的賦值,使用者可以設定波特率,字元大小,資料位,停止位,奇偶校驗位和硬體流控等。但是c_cflag中的成員不能直接對其初始化,需要將其通過“或”、“與”操作使用其中的某些選項。
鍵 值 |
說 明 |
CBAUD |
波特率(4+1位)(非POSIX) |
CBAUDEX |
附加波特率(1位)(非POSIX) |
CSIZE |
字元長度,取值範圍為CS5、CS6、CS7或CS8 |
CSTOPB |
設定兩個停止位 |
CREAD |
使用接收器 |
PARENB |
使用奇偶校驗 |
PARODD |
對輸入使用奇偶校驗,對輸出使用偶校驗 |
HUPCL |
關閉裝置時掛起 |
CLOCAL |
忽略調變解調器線路狀態 |
CRTSCTS |
使用RTS/CTS流控制 |
C_lflag支援的常量名稱如下表所示,其用於控制終端的本地資料處理和工作模式。
鍵 值 |
說 明 |
ISIG |
當輸入INTR、QUIT、SUSP或DSUSP時,產生相應的訊號 |
ICANON |
使用標準輸入模式 |
XCASE |
在ICANON和XCASE同時設定的情況下,終端只使用大寫。如果只設定了XCASE,則輸入字元將被轉換為小寫字元,除非字元使用了轉義字元(非POSIX,且Linux不支援該引數) |
ECHO |
顯示輸入字元 |
ECHOE |
如果ICANON同時設定,ERASE將刪除輸入的字元,WERASE將刪除輸入的單詞 |
ECHOK |
如果ICANON同時設定,KILL將刪除當前行 |
ECHONL |
如果ICANON同時設定,即使ECHO沒有設定依然顯示換行符 |
ECHOPRT |
如果ECHO和ICANON同時設定,將刪除列印出的字元(非POSIX) |
TOSTOP |
向後臺輸出傳送SIGTTOU訊號 |
C_cc[nccs]支援的常量名稱如下表所示
巨集 |
說 明 |
巨集 |
說 明 |
VINTR |
Interrupt字元 ,對應鍵 “ctrl+c” |
VEOL |
附加的End-of-file字元 |
VQUIT |
Quit字元 ,”ctrl+z” |
VTIME |
非規範模式讀取時的超時時間 |
VERASE |
Erase字元 , “backspace” |
VSTOP |
Stop字元 |
VKILL |
Kill字元 ,”ctrl+u” |
VSTART |
Start字元 |
VEOF |
End-of-file字元 ,”ctrl+d” |
VSUSP |
Suspend字元 |
VMIN |
非規範模式讀取時的最小字元數 |
操作串列埠的控制函式
函式名 |
說明 |
Tcgetattr |
獲取屬性(termios結構) |
Tcsetattr |
設定屬性(termios結構) |
Tcsendbreak |
傳送break字元 |
Tcdrain |
等待所有輸出都被傳輸(使程式阻塞,直到輸出緩衝區中的資料全部傳送完畢) |
tcflow |
掛起傳輸或接收(用於暫停或重新開始輸出) |
Tcflush |
用於清空輸入/輸出緩衝區 |
cfmakeraw |
設定串列埠模式為原始模式 |
Cfgetispeed |
獲取輸入波特率 |
Cfgetospeed |
獲取輸出波特率 |
Cfsetispeed |
設定輸入波特率 |
Cfsetospeed |
設定輸出波特率 |
cfsetspeed |
設定波特率 |
Linux串列埠實現-uart.c
/*************************************************************************************************************
* 檔名: uart.c
* 功能: Linux串列埠操作函式
* 作者: oxp_edward@163.com
* 建立時間: 2014年12月31日
* 最後修改時間: 2014年12月31日
* 詳細: 無
*************************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <strings.h>
static int SerialPortFd = 0; //儲存串列埠的檔案描述符
/*************************************************************************************************************************
*函式 : int SerialIsValid(void)
*功能 : 檢查串列埠檔案描述符的有效性
*引數 : 無
*返回 : 0:有效
-1:無效
*依賴 : 無
*作者 : edward
*時間 : 20141231
*最後修改時間: 20141231
*說明 : 無
*************************************************************************************************************************/
static int SerialIsValid(void)
{
//SerialPortFd 安全檢查
if(0 == SerialPortFd)
{
perror("SerialPortFd is invalid");
return -1;
}
return 0;
}
/*************************************************************************************************************************
*函式 : int SerialIsValid(void)
*功能 : 檢查串列埠檔案描述符的有效性
*引數 : 無
*返回 : 0:有效
-1:無效
*依賴 : 無
*作者 : edward
*時間 : 20141231
*最後修改時間: 20141231
*說明 : 無
*************************************************************************************************************************/
int SerialOpen(const char *devicePath)
{
SerialPortFd = open(devicePath,O_RDWR | O_NOCTTY | O_NDELAY);
if(SerialPortFd < 0)
{
perror(devicePath);
printf("%s open failed\n",devicePath);
return -1;
}
return 0;
}
/*************************************************************************************************************************
*函式 : int SerialConfig(int nSpeed,int nBits,char nEvent,int nStop)
*功能 : 串列埠引數設定
*引數 : nSpeed:波特率
nBits :資料位
nEvent:奇偶校驗位
nStop :停止位
*返回 : 0:設定成功
-1:設定失敗
*依賴 : 無
*作者 : edward
*時間 : 20141231
*最後修改時間: 20141231
*說明 : 無
*************************************************************************************************************************/
int SerialConfig(int nSpeed,int nBits,char nEvent,int nStop)
{
int rtn = 0;
int speed = 0;
struct termios NewConfig,OldConfig;
//SerialPortFd 安全檢查
if(SerialIsValid())
return -1;
//1、儲存原串列埠配置
/*tcgetattr(serialPortFd,&options)得到與SerialFd指向物件的相關引數,
並將它們儲存於oldtio,該函式,還可以測試配置是否正確,該串列埠是否
可用等。若呼叫成功,函式返回值為0,若呼叫失敗,函式返回值為1.*/
rtn = tcgetattr(SerialPortFd,&OldConfig);
if(0 != rtn)
{
perror("Error on tcgetattr");
return -1;
}
bzero(&NewConfig,sizeof(NewConfig));
//2、啟用選項
//CLOCAL:修改控制模式,保證程式不會佔用串列埠
//CREAD:修改控制模式,接收使能,使得能夠從串列埠中讀取輸入資料
NewConfig.c_cflag |= CLOCAL | CREAD;
//3、設定資料位
//在設定資料位時,需要先使用CSIZE位清空資料位設定,然後再設定相應的資料位
NewConfig.c_cflag &= ~CSIZE;
switch(nBits)
{
case 8: NewConfig.c_cflag |= CS8;break;
case 7: NewConfig.c_cflag |= CS7;break;
case 6: NewConfig.c_cflag |= CS6;break;
case 5: NewConfig.c_cflag |= CS5;break;
default:
printf("Error on nBits\n");
return -1;
}
//4、設定奇偶校驗位
//設定奇偶校驗需要使用到termiso中的兩個成員:c_cflag和c_iflag,
//首先啟用c_cflag中的校驗位使能標誌PARENB,這樣會對輸出資料產生校驗位,
//而輸入資料進行校驗檢測。同時還要啟用c_iflag中的對於輸入資料的奇偶校驗使能INPCK
//c_cflag中的PARODD為1時使用奇校驗,為0時使用偶校驗
switch(nEvent)
{
case 'o':
case 'O': //設定為奇校驗
NewConfig.c_cflag |=(PARODD|PARENB);
NewConfig.c_iflag |= INPCK;
break;
case 'e':
case 'E': //設定為偶校驗
NewConfig.c_cflag |=PARENB;
NewConfig.c_cflag &= ~PARODD;
NewConfig.c_iflag |= INPCK;
break;
case 's':
case 'S': /*as no parity*/
NewConfig.c_cflag &=~PARENB;
NewConfig.c_cflag &= ~CSTOPB;
break;
case 'n':
case 'N': //設定無奇偶校驗位
NewConfig.c_cflag &= ~PARENB;
NewConfig.c_iflag &= ~INPCK;
break;
default:
printf("Error on nEvent\n");
return -1;
}
//5、設定波特率
switch(nSpeed)
{
case 2400: speed = B2400; break;
case 4800: speed = B4800; break;
case 9600: speed = B9600; break;
case 19200: speed = B19200; break;
case 38400: speed = B38400; break;
case 115200: speed = B115200; break;
default:
printf("Error on nSpeed\n");
return -1;
}
cfsetispeed(&NewConfig,speed);
cfsetospeed(&NewConfig,speed);
//6、設定停止位
//設定停止位是通過啟用c_cflag中的CSTOPB而實現的。若停止位為1個,這清除CSTOPB,若停止位為2個,則啟用CSTOPB
switch(nStop)
{
case 1: NewConfig.c_cflag &= ~CSTOPB;break;
case 2: NewConfig.c_cflag |= CSTOPB;break;
default:
printf("Error on nStop\n");
return;
}
//7、設定等待時間和最小接收字元
NewConfig.c_cc[VTIME] = 0;//讀取一個字元等待1*(1/10)s
NewConfig.c_cc[VMIN] = 0;//讀取字元的最少個數
//8、清除串列埠緩衝
//在串列埠重新設定後,需要對當前的串列埠裝置進行適當的處理,
//這時可以呼叫tcdrain,tcflow,tcflush等函式來處理目前串列埠緩衝區中的資料
//tcdrain 函式使程式阻塞,直到輸出緩衝區中的資料全部傳送完畢
//tcflow 函式用於暫停或重新開始輸出
//tcflush 函式用於清空輸入/輸出緩衝區
//如果發生資料溢位,接收資料,但是不再讀取
tcflush(SerialPortFd,TCIFLUSH);
//9、啟用配置
//在串列埠配置完成後,需要使用tcsetattr函式啟用配置。
rtn = tcsetattr(SerialPortFd,TCSANOW,&NewConfig);
if(0 != rtn)
{
perror("Error on tcsetattr");
return -1;
}
printf("Serial Set Done\n");
return 0;
}
/*************************************************************************************************************************
*函式 : int SerialReceive(unsigned char *buf,int size)
*功能 : 串列埠接收資料
*引數 : buf: 接收緩衝區
size:緩衝區大小
*返回 :錯誤-1,返回接收資料的大小
*依賴 : 無
*作者 : edward
*時間 : 20141231
*最後修改時間: 20141231
*說明 : 無
*************************************************************************************************************************/
int SerialReceive(unsigned char *buf,int size)
{
int rtn ;
//SerialPortFd 安全檢查
if(SerialIsValid())
return -1;
rtn = read(SerialPortFd,buf,size);
// printf("ReadLength = %d\n",rtn);
return rtn;
}
/*************************************************************************************************************************
*函式 : int SerialSend(unsigned char *buf,int DataLength)
*功能 : 串列埠傳送資料
*引數 : buf:傳送緩衝區
DataLength:需要傳送的位元組數
*返回 : rtn:成功傳送的位元組數
-1:傳送失敗
*依賴 : 無
*作者 : edward
*時間 : 20141231
*最後修改時間: 20141231
*說明 : 無
*************************************************************************************************************************/
int SerialSend(unsigned char *buf,int DataLength)
{
int rtn ;
//SerialPortFd 安全檢查
if(SerialIsValid())
return -1;
#if 0
int remain = DataLength;
int offset = 0;
int sub = 0;
while(remain > 0 )
{
sub = (remain >= 8? 8:remain);
write(SerialPortFd,buf+offset,sub);
tcflush(SerialPortFd,TCOFLUSH);
remain -= 8;
offset += 8;
}
#else
rtn = write(SerialPortFd,buf,DataLength);
#endif
return rtn;
}
/*************************************************************************************************************************
*函式 : int SerialIsValid(void)
*功能 : 關閉串列埠
*引數 : 無
*返回 : 0:關閉成功
*依賴 : 無
*作者 : edward
*時間 : 20141231
*最後修改時間: 20141231
*說明 : 無
*************************************************************************************************************************/
int SerialClose(void)
{
//SerialPortFd 安全檢查
if(SerialIsValid())
return -1;
close(SerialPortFd);
return 0;
}
uart.h標頭檔案
#ifndef __UART_H__
#define __UART_H__
int SerialOpen(const char *devicePath);
int SerialConfig(int nSpeed,int nBits,char nEvent,int nStop);
int SerialReceive(unsigned char *buf,int size);
int SerialSend(unsigned char *buf,int DataLength);
int SerialClose(void);
#endif
uart-test測試檔案,固定傳送字元,並接收,硬體上將串列埠的RX與TX相連線
#include <stdio.h>
#include <string.h>
#include "uart.h"
int main(int argc,char**argv)
{
int rtn;
int Count = 0;
unsigned char *send = "Hello Uart";
unsigned char buf[1024] ={0};
if(2 > argc){
printf("Input error\n");
printf("Usage: %s <Device>\n",argv[0]);
printf("Eample: %s /dev/ttyS0\n",argv[0]);
return -1;
}
//開啟串列埠
rtn = SerialOpen(argv[1]);
if(0 > rtn)
return -1;
//配置串列埠
rtn = SerialConfig(115200,8,'n',1);
if(0 > rtn)
return -1;
//迴圈傳送與接收
while(1)
{ //傳送資料
rtn = SerialSend(send,strlen(send));
if(0 < rtn){
printf("[Send]: %s\n",send);
}
sleep(1);
//接收資料
rtn = SerialReceive(buf,sizeof(buf));
if(0 < rtn){
printf("[Recv]: %s\n",buf);
}
}
}
相關文章
- Linux串列埠程式設計Linux串列埠程式設計
- Linux 串列埠程式設計 串列埠裝置程式開發Linux串列埠程式設計
- Linux下串列埠程式設計基礎Linux串列埠程式設計
- Linux 串列埠程式設計 使用termios與API進行串列埠程式開發Linux串列埠程式設計iOSAPI
- Linux 串列埠程式設計 一些背景Linux串列埠程式設計
- POSIX 串列埠程式設計指南串列埠程式設計
- Linux 串列埠程式設計 深入瞭解 termiosLinux串列埠程式設計iOS
- Android之串列埠程式設計Android串列埠程式設計
- ROS串列埠程式設計學習筆記ROS串列埠程式設計筆記
- VC++串列埠通訊程式設計詳解C++串列埠程式設計
- Windows下的Win32串列埠程式設計WindowsWin32串列埠程式設計
- Linux下串列埠通訊詳解(下)讀寫串列埠及關閉串列埠Linux串列埠
- Linux下PCI轉串列埠卡及USB轉串列埠Linux串列埠
- linux 串列埠通訊Linux串列埠
- android串列埠程式Android串列埠
- VC++串列埠程式設計之簡訊應用開發(轉)C++串列埠程式設計
- UART串列埠及Linux實現串列埠Linux
- linux串列埠命令列除錯Linux串列埠命令列除錯
- 使用串列埠連線到Linux串列埠Linux
- 基於多串列埠ETH005裝置的Socket網路程式設計串列埠程式設計
- 沒有真實串列埠裝置時使用"虛擬串列埠驅動"除錯你的串列埠程式碼串列埠除錯
- 串列埠UART串列埠
- 帶內串列埠 在串列埠中輸入命令串列埠
- Linux串列埠程式收發16進位制資料錯誤Linux串列埠
- 串列埠資料抓取及串列埠通訊模擬串列埠
- 你真的瞭解串列埠嗎(示波器串列埠波形分析)串列埠
- tty,串列埠,控制檯與驅動程式串列埠
- C#串列埠通訊程式SerialPort類C#串列埠
- 串列埠流控串列埠
- 串列埠通訊串列埠
- 串列埠blog串列埠
- IBM串列埠線序以及串列埠線的做法(轉)IBM串列埠
- 【linux學習--工具篇】串列埠除錯工具Linux串列埠除錯
- gdbserver連線Ubuntu除錯程式(使用串列埠)ServerUbuntu除錯串列埠
- 序列通訊的基本原理及用MFC實現串列埠通訊程式設計 (轉)串列埠程式設計
- QT實現串列埠助手中串列埠名的實時更新QT串列埠
- 【STM32】串列埠串列埠
- 串列埠小工具串列埠