Linux串列埠程式設計
開發環境
開發板:A33-Vstar
開發板系統:Linux
Ubuntu版本:Ubuntu14.04
-------------------------------------------
串列埠2(Ubuntu)
串列埠1(A33)
Ubuntu和A33都執行uart_test程式(見附件)。
一、串列埠設定
最基本的串列埠設定包括波特率、校驗位和停止位設定,且串列埠設定主要使用termios.h標頭檔案中定義的termios結構,如下:
struct termios
{
tcflag_t c_iflag; //輸入模式標誌
tcflag_t c_oflag; //輸出模式標誌
tcflag_t c_cflag; //控制模式標誌
tcflag_t c_lflag; //本地模式標誌
cc_t c_line; //line discipline
cc_t c_cc[NCC]; //control characters
}
1. 重要配置函式
1)獲取終端對應的termios結構:
int tcgetattr(int fd, struct termios *termios_p);
2)重新配置串列埠
int tcsetattr(int fd , int actions , const struct termios *termios_h);
引數actions控制修改方式,共有三種修改方式,如下所示。
TCSANOW:立刻對值進行修改
TCSADRAIN:等當前的輸出完成後再對值進行修改。
TCSAFLUSH:等當前的輸出完成之後,再對值進行修改,但丟棄還未從read呼叫返回的當前的可用的任何輸入。
2. 控制符VTIME和VMIN
VTIME定義要求等待的時間(百毫秒,通常是unsigned char變數),而VMIN定義了要求等待的最小位元組數(相比之下,read函式的第三個引數指定了要求讀的最大位元組數)。
1)如果VTIME=0,VMIN=要求等待讀取的最小位元組數,read必須在讀取了VMIN個位元組的資料或者收到一個訊號才會返回。
2)如果VTIME=時間量,VMIN=0,不管能否讀取到資料,read也要等待VTIME的時間量。
3)如果VTIME=時間量,VMIN=要求等待讀取的最小位元組數,那麼將從read讀取第一個位元組的資料時開始計時,並會在讀取到VMIN個位元組或者VTIME時間後返回。
4)如果VTIME=0,VMIN=0,不管能否讀取到資料,read都會立即返回
二、使用過程中遇到的一些問題
1. 串列埠2到串列埠1:在傳送資料時沒有鍵入回車,資訊就傳送不出去,鍵入回車傳送後,前面沒有傳送出去的資料會和本次一起全部傳送出去。這主要是因為我們在輸入輸出時是按照規範模式接收到回車或換行才傳送,而更多情況下我們是不必鍵入回車或換行的。此時將對方串列埠(串列埠1)設定如下:
Opt.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);
主要是:ICANON
注:當A33使用cat(開機後串列埠1未經過程式設定),Ubuntu使用uart_test會出現此問題即A33收不到,Ubuntu使用echo傳送資料時可以收到(echo 應該是傳送了回車),win7使用串列埠助手不加回車傳送資料時A33收不到,加了回車可以收到。
2. 回顯問題:在串列埠2往串列埠1傳送資料時,串列埠2能接收到傳送出去的資料。此時,關閉串列埠1的回顯即可。設定如下:
Opt.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);
主要是:ECHO | ECHOE
3. 未經測試(未遇到的問題,網上摘錄)
1)還存在這樣的情況:傳送字元0X0d的時候,往往接收端得到的字元是0X0a,原因是因為在串列埠設定中c_iflag和c_oflag中存在從NL-CR和CR-NL的對映,即串列埠能把回車和換行當成同一個字元,可以進行如下設定遮蔽之:
Opt.c_iflag &= ~ (INLCR | ICRNL | IGNCR);
Opt.c_oflag &= ~(ONLCR | OCRNL);
2)c_cc陣列的VSTART和VSTOP元素被設定成DC1和DC3,代表ASCII標準的XON和XOFF字元,如果在傳輸這兩個字元的時候就傳不過去,需要把軟體流控制遮蔽,即:
Opt.c_iflag &= ~ (IXON | IXOFF | IXANY);
三、附錄
1. c_cflag用於設定控制引數,除了波特率外還包含以下內容:
EXTA External rate clock
EXTB External rate clock
CSIZE Bit mask for data bits
CS5 5個資料位
CS6 6個資料位
CS7 7個資料位
CS8 8個資料位
CSTOPB 2個停止位(清除該標誌表示1個停止位
PARENB 允許校驗位
PARODD 使用奇校驗(清除該標誌表示使用偶校驗)
CREAD Enable receiver
HUPCL Hangup (drop DTR) on last close
CLOCAL Local line – do not change “owner” of port
LOBLK Block job control outpu
c_cflag標誌可以定義CLOCAL和CREAD,這將確保該程式不被其他埠控制和訊號干擾,同時串列埠驅動將讀取進入的資料。CLOCAL和CREAD通常總是被是能的。
2. c_lflag用於設定本地模式,決定串列埠驅動如何處理輸入字元,設定內容如下:
ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
ICANON Enable canonical input (else raw)
XCASE Map uppercase \lowercase (obsolete)
ECHO Enable echoing of input characters
ECHOE Echo erase character as BS-SP-BS
ECHOK Echo NL after kill character
ECHONL Echo NL
NOFLSH Disable flushing of input buffers after interrupt or quit characters
IEXTEN Enable extended functions
ECHOCTL Echo control characters as ^char and delete as ~?
ECHOPRT Echo erased character as character erased
ECHOKE BS-SP-BS entire line on line kill
FLUSHO Output being flushed
PENDIN Retype pending input at next read or input char
TOSTOP Send SIGTTOU for background output
3. c_iflag用於設定如何處理串列埠上接收到的資料,包含如下內容:
INPCK Enable parity check
IGNPAR Ignore parity errors
PARMRK Mark parity errors
ISTRIP Strip parity bits
IXON Enable software flow control (outgoing)
IXOFF Enable software flow control (incoming)
IXANY Allow any character to start flow again
IGNBRK Ignore break condition
BRKINT Send a SIGINT when a break condition is detected
INLCR Map NL to CR
IGNCR Ignore CR
ICRNL Map CR to NL
IUCLC Map uppercase to lowercase
IMAXBEL Echo BEL on input line too long
4. c_oflag用於設定如何處理輸出資料,包含如下內容:
OPOST Postprocess output (not set = raw output)
OLCUC Map lowercase to uppercase
ONLCR Map NL to CR-NL
OCRNL Map CR to NL
NOCR No CR output at column 0
ONLRET NL performs CR function
OFILL Use fill characters for delay
OFDEL Fill character is DEL
NLDLY Mask for delay time needed between lines
NL0 No delay for NLs
NL1 Delay further output after newline for 100 milliseconds
CRDLY Mask for delay time needed to return carriage to left column
CR0 No delay for CRs
CR1 Delay after CRs depending on current column position
CR2 Delay 100 milliseconds after sending CRs
CR3 Delay 150 milliseconds after sending CRs
TABDLY Mask for delay time needed after TABs
TAB0 No delay for TABs
TAB1 Delay after TABs depending on current column position
TAB2 Delay 100 milliseconds after sending TABs
TAB3 Expand TAB characters to spaces
BSDLY Mask for delay time needed after BSs
BS0 No delay for BSs
BS1 Delay 50 milliseconds after sending BSs
VTDLY Mask for delay time needed after VTs
VT0 No delay for VTs
VT1 Delay 2 seconds after sending VTs
FFDLY Mask for delay time needed after FFs
FF0 No delay for FFs
FF1 Delay 2 seconds after sending FFs
5. c_cc定義了控制字元,包含以下內容:
VINTR Interrupt CTRL-C
VQUIT Quit CTRL-Z
VERASE Erase Backspace (BS)
VKILL Kill-line CTRL-U
VEOF End-of-file CTRL-D
VEOL End-of-line Carriage return (CR)
VEOL2 Second end-of-line Line feed (LF)
VMIN Minimum number of characters to read
VSTART Start flow CTRL-Q (XON)
VSTOP Stop flow CTRL-S (XOFF)
VTIME Time to wait for data (tenths of seconds)
測試原始碼:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE 9600
char *uart_device = "/dev/ttyUSB1";
#define FALSE -1
#define TRUE 0
char rec_buf[100];
int fd;
////////////////////////////////////////////////////////////////////////////////
/**
*@brief 設定串列埠通訊速率
*@param fd 型別 int 開啟串列埠的檔案控制程式碼
*@param speed 型別 int 串列埠速度
*@return void
*/
int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,
B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300,
115200, 38400, 19200, 9600, 4800, 2400, 1200, 300, };
void set_speed(int fd, int speed){
int i;
int status;
struct termios Opt;
tcgetattr(fd, &Opt);
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
if (speed == name_arr[i]) {
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0) {
perror("tcsetattr fd1");
return;
}
tcflush(fd,TCIOFLUSH);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/**
*@brief 設定串列埠資料位,停止位和效驗位
*@param fd 型別 int 開啟的串列埠檔案控制程式碼
*@param databits 型別 int 資料位 取值 為 7 或者8
*@param stopbits 型別 int 停止位 取值為 1 或者2
*@param parity 型別 int 效驗型別 取值為N,E,O,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{
struct termios options;
if ( tcgetattr( fd,&options) != 0) {
perror("SetupSerial 1");
return(FALSE);
}
options.c_cflag &= ~CSIZE;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
options.c_oflag &= ~OPOST; /*Output*/
switch (databits) /*設定資料位數*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr,"Unsupported data size\n"); return (FALSE);
}
switch (parity)
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 設定為奇效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 轉換為偶效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;break;
default:
fprintf(stderr,"Unsupported parity\n");
return (FALSE);
}
/* 設定停止位*/
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return (FALSE);
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME] = 0; /* 設定超時0 seconds*/
options.c_cc[VMIN] = 1; //至少接收了1個位元組資料才可以返回
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}
void *read_thread(void *argv)
{
int res = 0;
while(1){
res = read(fd, rec_buf, 50);
if(res <= 0){
printf("\nrev faild, try rev again.\n");
continue;
}
rec_buf[res]=0;
printf("rev data:%s\n", rec_buf);
}
}
int main(int argc, char *argv[])
{
int res;
pthread_t a_thread;
char buf[256];
if(argc == 2){
uart_device = argv[1];
}
printf("open %s\n", uart_device);
fd = open(uart_device, O_RDWR);
if (fd < 0) {
perror(uart_device);
exit(1);
}
printf("setting...\n");
set_speed(fd, BAUDRATE);
if (set_Parity(fd,8,1,'N') == FALSE) {
printf("Set Parity Error\n");
exit (0);
}
res = pthread_create(&a_thread, NULL, read_thread, NULL); /*啟動執行緒函式*/
if (res != 0){
perror("Thread creation failed");
exit(0);
}
printf("read thread is created.\n");
while(1) {
printf("input the data: ");
gets(buf);
res = write(fd, buf, strlen(buf));
if(res > 0) printf("write sucess. length:%d.\n", res);
}
printf("Close...\n");
close(fd);
return 0;
}
相關文章
- Android之串列埠程式設計Android串列埠程式設計
- ROS串列埠程式設計學習筆記ROS串列埠程式設計筆記
- linux 串列埠通訊Linux串列埠
- Linux下串列埠監視Linux串列埠
- UART串列埠及Linux實現串列埠Linux
- linux串列埠命令列除錯Linux串列埠命令列除錯
- 沒有真實串列埠裝置時使用"虛擬串列埠驅動"除錯你的串列埠程式碼串列埠除錯
- 【linux學習--工具篇】串列埠除錯工具Linux串列埠除錯
- 串列埠blog串列埠
- 串列埠UART串列埠
- 帶內串列埠 在串列埠中輸入命令串列埠
- 串列埠資料抓取及串列埠通訊模擬串列埠
- 你真的瞭解串列埠嗎(示波器串列埠波形分析)串列埠
- 串列埠通訊串列埠
- gdbserver連線Ubuntu除錯程式(使用串列埠)ServerUbuntu除錯串列埠
- 【Linux】 Linux網路程式設計Linux程式設計
- Linux jpeg程式設計Linux程式設計
- Linux Bash程式設計Linux程式設計
- linux程式和埠檢視Linux
- 【linux】系統呼叫版串列埠分析&原始碼實戰Linux串列埠原始碼
- QT實現串列埠助手中串列埠名的實時更新QT串列埠
- Android 串列埠通訊Android串列埠
- 串列埠小工具串列埠
- 【STM32】串列埠串列埠
- RHEL6.8程式單印表機串列埠檢查串列埠
- 程式碼隨想錄:設計連結串列
- 【程式碼隨想錄】二、連結串列:2、設計連結串列
- linux 下根據埠kill 程式Linux
- Linux之shell程式設計Linux程式設計
- Linux Shell程式設計(1)Linux程式設計
- Linux Shell程式設計(2)Linux程式設計
- 【Linux】Linux系統程式設計入門Linux程式設計
- Rust 程式設計,用連結串列實現棧Rust程式設計
- Linux單裝置多路USB串列埠的實現方法介紹Linux串列埠
- 11. 串列埠通訊串列埠
- (10)uart串列埠通訊串列埠
- 串列埠通訊型別串列埠型別
- 串列埠,COM口,UART,USART串列埠