研究了一天的linux串口,結果改了樹莓派的系統配置文件config.txt給改了致使系統崩潰。。。。其實我感受網上的大多數方法都是不符合新版本樹莓派的,網上的方法是經過修改系統配置文件後安裝minicom進行串口的調試。爲何須要修改配置文件?由於樹莓派升級後tx與rx引腳是複用的,須要用於串口的話就須要修改配置,讓系統把io口讓給串口。html
這種方法比較麻煩,我採用的是利用兩個usb轉串口,互相鏈接好了,就能夠直接經過linux下的串口通訊函數來實現通訊了。須要注意的是兩個usb轉串口相互鏈接時不只僅要將RXD、TXD相互反接,還須要將GND鏈接在一塊兒。linux
下面講解下具體方法ios
(1)不一樣系統的串口名稱是不同的,以下圖。編程
(2)設置異步
最基本的設置串口包括波特率設置,效驗位和中止位設置.函數
不少系統都支持POSIX終端(串口)接口.程序能夠利用這個接口來改變終端的參數,好比,波特率,字符大小等等.要使用這個端口的話,你必須將<termios.h>頭文件包含到你的程序中.這個頭文件中定義了終端控制結構體和POSIX控制函數.spa
與串口操做相關的最重要的兩個POSIX函數可能就是tcgetattr(3)和tcsetattr(3).顧名思義,這兩個函數分別用來取得設設置終端的屬性.調用這兩個函數的時候,你須要提供一個包含着全部串口選項的termios結構體,串口的設置主要是設置struct termios結構體的各成員值.操作系統
經過termio結構體的c_cflag成員能夠控制波特率,數據的比特數,parity,中止位和硬件流控制,下面這張表列出了全部可使用的常數設計
進行設置時千萬不要直接用使用數字來初始化c_cflag(固然還有其餘標誌),最好的方法是使用位運算的與或非組合來設置或者清除這個標誌.不一樣的操做系統版本會使用不一樣的位模式,使用常數定義和位運算組合來避免重複工做從而提升程序的可移植性.3d
1.1波特率設置
不一樣的操做系統會將波特率存儲在不一樣的位置.舊的編程接口將波特率存儲在上表所示的c_cflag成員中,而新的接口實裝則提供了c_ispeed和c_ospeed成員來保存實際波特率的值.
程序中但是使用cfsetospeed(3)和cfsetispeed(3)函數在termios結構體中設置波特率而不用去管底層操做系統接口.下面的代碼是個很是典型的設置波特率的例子.
struct termios options; tcgetattr(fd,&option); //獲取端口的當前狀態 cfsetispeed(&options,B19200);//設置波特率爲19200 options.c_cflags | =(CLOCK | CREAD);//將設置的參數傳入 tcsetattr(fd,TCSANOW.&options);
函數tcgetattr( )會將當前串口配置回填到termio結構體option中.而後,程序設置了輸入輸出的波特率而且將本地模式(CLOCAL)和串行數據接收(CREAD)設置爲有效,接着將新的配置做爲參數傳遞給函數tcsetattr( ).常量TCSANOW標誌全部改變必須馬上生效而不用等到數據傳輸結束.其餘另外一些常數能夠保證等待數據結束或者刷新輸入輸出以後再生效.
1.2 設置字符大小,設置字符大小的時候,沒有像設置波特率那麼方便的函數.因此,程序中須要一些位掩碼運算來把事情搞定.字符大小以比特爲單位指定:
1 options.c_flag &= ~CSIZE; /* Mask the character size bits */ 2 options.c_flag |= CS8; /* Select 8 data bits */
1.3 與上同理,經過位掩碼來設置校驗位與中止位
無奇偶校驗( no parity)
1 options.c_cflag &= ~PARENB 2 options.c_cflag &= ~CSTOPB 3 options.c_cflag &= ~CSIZE; 4 options.c_cflag |= CS8;
偶校驗(even parity)
1 options.c_cflag |= PARENB 2 options.c_cflag &= ~PARODD 3 options.c_cflag &= ~CSTOPB 4 options.c_cflag &= ~CSIZE;
5 options.c_cflag |= CS7;
奇校驗(odd parity)
1 options.c_cflag |= PARENB 2 options.c_cflag |= PARODD 3 options.c_cflag &= ~CSTOPB 4 options.c_cflag &= ~CSIZE; 5 options.c_cflag |= CS7;
設置奇偶校驗函數
/** *@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; 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] = 150; /* 設置超時15 seconds*/ options.c_cc[VMIN] = 0; /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { perror("SetupSerial 3"); return (FALSE); } return (TRUE); }
1.4 本地設置,本地模式成員變量c_lflag能夠控制串口驅動怎樣控制輸入字符.一般,你可能須要經過c_lflag成員來設置經典輸入和原始輸入模式。
1.4.1 選擇經典模式,經典輸入是以面向行設計的.在經典輸入模式中輸入字符會被放入一個緩衝之中,這樣能夠以與用戶交互的方式編輯緩衝的內容,直到收到CR(carriage return)或者LF(line feed)字符.選擇使用經典輸入模式的時候,你一般須要選擇ICANON,ECHO和ECHOE選項: options.c_lflag |= (ICANON | ECHO | ECHOE);
1.4.2 選擇原始輸入,原始輸入根本不會被處理.輸入字符只是被原封不動的接收.通常狀況中,若是要使用原始輸入模式,程序中須要去掉ICANON,ECHO,ECHOE和ISIG選項:options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
(2)讀寫串口,unix將串口當作文件來處理,直接讀取串口便可,write函數也會返回發送數據的字節數或者在發生錯誤的時候返回-1.一般,發送數據最多見的錯誤就是EIO,當調制解調器或者數據鏈路將Data Carrier Detect(DCD)信號線弄掉了,就會發生這個錯誤.並且,直相當閉端口這個狀況會一直持續.
char buffer[1024];int Length;int nByte;nByte = write(fd, buffer ,Length)
讀取數據:使用文件操做read函數讀取,若是設置爲原始數據模式(Raw Date Mode)傳輸數據,那麼read函數返回的字符數是實際串口收到的字符數,也就是返回從串口輸入緩衝區中實際獲得的字符的個數.在不能獲得數據的狀況下,read(2)系統調用就會一直等着,只到有端口上新的字符能夠讀取或者發生超時或者錯誤的狀況發生.
char buff[1024];int Len;int readByte = read(fd,buff,Len);
若是須要read(2)函數迅速返回的話,可使用操做文件的函數來實現異步讀取,如fcntl,或者select等來操做: fcntl(fd, F_SETFL, FNDELAY);標誌FNDELAY能夠保證read()函數在端口上讀不到字符的時候返回0.須要回到正常(阻塞)模式的時候,須要再次在不帶FNDELAY標誌的狀況下調用fcntl()函數:
(3)函數編程,須要的頭文件以下
#include <stdio.h> /*標準輸入輸出定義*/ #include <stdlib.h> /*標準函數庫定義*/ #include <unistd.h> /*Unix 標準函數定義*/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /*文件控制定義*/ #include <termios.h> /*PPSIX 終端控制定義*/ #include <errno.h> /*錯誤號定義*/
一個樹莓派發送數據數據給電腦串口的程序以下:須要根據具體的狀況修改USB口
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 #include <termios.h> 8 #include <errno.h> 9 #include <string.h> 10 11 //serial port set function 12 void setTermios(struct termios *pNewtio, unsigned short uBaudRate) 13 { 14 bzero(pNewtio,sizeof(struct termios)); 15 pNewtio->c_cflag = uBaudRate|CS8|CREAD|CLOCAL; 16 pNewtio->c_iflag = IGNPAR; 17 pNewtio->c_oflag = 0; 18 pNewtio->c_lflag = 0; 19 pNewtio->c_cc[VINTR] = 0; 20 pNewtio->c_cc[VQUIT] = 0; 21 pNewtio->c_cc[VERASE] = 0; 22 pNewtio->c_cc[VKILL] = 0; 23 pNewtio->c_cc[VEOF] = 4; 24 pNewtio->c_cc[VTIME] = 5; 25 pNewtio->c_cc[VMIN] = 0; 26 pNewtio->c_cc[VSWTC] = 0; 27 pNewtio->c_cc[VSTART] = 0; 28 pNewtio->c_cc[VSTOP] = 0; 29 pNewtio->c_cc[VSUSP] = 0; 30 pNewtio->c_cc[VEOL] = 0; 31 pNewtio->c_cc[VREPRINT] = 0; 32 pNewtio->c_cc[VDISCARD] = 0; 33 pNewtio->c_cc[VWERASE] = 0; 34 pNewtio->c_cc[VLNEXT] = 0; 35 pNewtio->c_cc[VEOL2] = 0; 36 } 37 int main(int argc,char **argv) 38 { 39 int fd; 40 int nCount,nTotal; 41 int i,j,m; 42 int ReadByte = 0; 43 44 int Buffer[512]; 45 struct termios oldtio,newtio; 46 char *dev = "/dev/tq2440_serial0"; 47 48 if((argc!=3)||(sscanf(argv[1],"%d",&nTotal)!=1)) 49 { 50 printf("Usage:COMSend count datat! "); 51 return -1; 52 } 53 54 if((fd=open(dev,O_RDWR|O_NOCTTY|O_NDELAY))<0) //open serial COM2 55 { 56 printf("Can't open serial port! "); 57 return -1; 58 } 59 tcgetattr(fd,&oldtio); 60 setTermios(&newtio,B9600); 61 tcflush(fd,TCIFLUSH); 62 tcsetattr(fd,TCSANOW,&newtio); 63 64 //Send data 65 for(i=0;i<nTotal;i++) 66 { 67 nCount = write(fd,argv[2],strlen(argv[2])); 68 printf("send data OK!count=%d ",nCount); 69 sleep(1); 70 } 71 72 //receive data 73 for(j=0;j<20;j++) 74 { 75 ReadByte = read(fd,Buffer,512); 76 if(ReadByte>0) 77 { 78 printf("readlength=%d ",ReadByte); 79 Buffer[ReadByte]='\0'; 80 printf("%s ",Buffer); 81 sleep(3); 82 } 83 else printf("Read data failure times=%d ",j); 84 } 85 printf("Receive data finished! "); 86 tcsetattr(fd,TCSANOW,&oldtio); 87 close(fd); 88 return 0; 89 }
參考文章:http://blog.sina.com.cn/s/blog_644949120100sc8n.html
http://www.cnblogs.com/jason-lu/articles/3173988.html