日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux与开发板串口通信

發(fā)布時(shí)間:2025/3/21 linux 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux与开发板串口通信 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

研究了一天的linux串口,結(jié)果改了樹莓派的系統(tǒng)配置文件config.txt給改了導(dǎo)致系統(tǒng)崩潰。。。。其實(shí)我感覺網(wǎng)上的大多數(shù)方法都是不符合新版本樹莓派的,網(wǎng)上的方法是通過修改系統(tǒng)配置文件后安裝minicom進(jìn)行串口的調(diào)試。為什么需要修改配置文件?因?yàn)闃漭缮?jí)后tx與rx引腳是復(fù)用的,需要用于串口的話就需要修改配置,讓系統(tǒng)把io口讓給串口。

?

這種方法比較麻煩,我采用的是利用兩個(gè)usb轉(zhuǎn)串口,互相連接好了,就可以直接通過linux下的串口通信函數(shù)來實(shí)現(xiàn)通信了。需要注意的是兩個(gè)usb轉(zhuǎn)串口相互連接時(shí)不僅僅要將RXD、TXD相互反接,還需要將GND連接在一起。

?

下面講解下具體方法

(1)不同系統(tǒng)的串口名稱是不一樣的,如下圖。

?

(2)設(shè)置

最基本的設(shè)置串口包括波特率設(shè)置,效驗(yàn)位和停止位設(shè)置.

很多系統(tǒng)都支持POSIX終端(串口)接口.程序可以利用這個(gè)接口來改變終端的參數(shù),比如,波特率,字符大小等等.要使用這個(gè)端口的話,你必須將<termios.h>頭文件包含到你的程序中.這個(gè)頭文件中定義了終端控制結(jié)構(gòu)體和POSIX控制函數(shù).

與串口操作相關(guān)的最重要的兩個(gè)POSIX函數(shù)可能就是tcgetattr(3)和tcsetattr(3).顧名思義,這兩個(gè)函數(shù)分別用來取得設(shè)設(shè)置終端的屬性.調(diào)用這兩個(gè)函數(shù)的時(shí)候,你需要提供一個(gè)包含著所有串口選項(xiàng)的termios結(jié)構(gòu)體,串口的設(shè)置主要是設(shè)置struct termios結(jié)構(gòu)體的各成員值.

通過termio結(jié)構(gòu)體的c_cflag成員可以控制波特率,數(shù)據(jù)的比特?cái)?shù),parity,停止位和硬件流控制,下面這張表列出了所有可以使用的常數(shù)

進(jìn)行設(shè)置時(shí)千萬不要直接用使用數(shù)字來初始化c_cflag(當(dāng)然還有其他標(biāo)志),最好的方法是使用位運(yùn)算的與或非組合來設(shè)置或者清除這個(gè)標(biāo)志.不同的操作系統(tǒng)版本會(huì)使用不同的位模式,使用常數(shù)定義和位運(yùn)算組合來避免重復(fù)工作從而提高程序的可移植性.

1.1波特率設(shè)置

不同的操作系統(tǒng)會(huì)將波特率存儲(chǔ)在不同的位置.舊的編程接口將波特率存儲(chǔ)在上表所示的c_cflag成員中,而新的接口實(shí)裝則提供了c_ispeed和c_ospeed成員來保存實(shí)際波特率的值.

程序中可是使用cfsetospeed(3)和cfsetispeed(3)函數(shù)在termios結(jié)構(gòu)體中設(shè)置波特率而不用去管底層操作系統(tǒng)接口.下面的代碼是個(gè)非常典型的設(shè)置波特率的例子.

struct termios options; tcgetattr(fd,&option); //獲取端口的當(dāng)前狀態(tài) cfsetispeed(&options,B19200);//設(shè)置波特率為19200 options.c_cflags | =(CLOCK | CREAD);//將設(shè)置的參數(shù)傳入 tcsetattr(fd,TCSANOW.&options);

函數(shù)tcgetattr( )會(huì)將當(dāng)前串口配置回填到termio結(jié)構(gòu)體option中.然后,程序設(shè)置了輸入輸出的波特率并且將本地模式(CLOCAL)和串行數(shù)據(jù)接收(CREAD)設(shè)置為有效,接著將新的配置作為參數(shù)傳遞給函數(shù)tcsetattr( ).常量TCSANOW標(biāo)志所有改變必須立刻生效而不用等到數(shù)據(jù)傳輸結(jié)束.其他另一些常數(shù)可以保證等待數(shù)據(jù)結(jié)束或者刷新輸入輸出之后再生效.

1.2 設(shè)置字符大小,設(shè)置字符大小的時(shí)候,沒有像設(shè)置波特率那么方便的函數(shù).所以,程序中需要一些位掩碼運(yùn)算來把事情搞定.字符大小以比特為單位指定:

1 options.c_flag &= ~CSIZE; /* Mask the character size bits */ 2 options.c_flag |= CS8; /* Select 8 data bits */

1.3? 與上同理,通過位掩碼來設(shè)置校驗(yàn)位與停止位

無奇偶校驗(yàn)( no parity)

1 options.c_cflag &= ~PARENB 2 options.c_cflag &= ~CSTOPB 3 options.c_cflag &= ~CSIZE; 4 options.c_cflag |= CS8;

偶校驗(yàn)(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;

奇校驗(yàn)(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;

設(shè)置奇偶校驗(yàn)函數(shù)

/** *@brief 設(shè)置串口數(shù)據(jù)位,停止位和效驗(yàn)位 *@param fd 類型 int 打開的串口文件句柄 *@param databits 類型 int 數(shù)據(jù)位 取值 為 7 或者8 *@param stopbits 類型 int 停止位 取值為 1 或者2 *@param parity 類型 int 效驗(yàn)類型 取值為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) /*設(shè)置數(shù)據(jù)位數(shù)*/{ 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); /* 設(shè)置為奇效驗(yàn)*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* 轉(zhuǎn)換為偶效驗(yàn)*/ 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); } /* 設(shè)置停止位*/ 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; /* 設(shè)置超時(shí)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 本地設(shè)置,本地模式成員變量c_lflag可以控制串口驅(qū)動(dòng)怎樣控制輸入字符.通常,你可能需要通過c_lflag成員來設(shè)置經(jīng)典輸入和原始輸入模式。

1.4.1? 選擇經(jīng)典模式,經(jīng)典輸入是以面向行設(shè)計(jì)的.在經(jīng)典輸入模式中輸入字符會(huì)被放入一個(gè)緩沖之中,這樣可以以與用戶交互的方式編輯緩沖的內(nèi)容,直到收到CR(carriage return)或者LF(line feed)字符.選擇使用經(jīng)典輸入模式的時(shí)候,你通常需要選擇ICANON,ECHO和ECHOE選項(xiàng):?? options.c_lflag |= (ICANON | ECHO | ECHOE);

?1.4.2 選擇原始輸入,原始輸入根本不會(huì)被處理.輸入字符只是被原封不動(dòng)的接收.一般情況中,如果要使用原始輸入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG選項(xiàng):options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

?

(2)讀寫串口,unix將串口當(dāng)做文件來處理,直接讀取串口即可,write函數(shù)也會(huì)返回發(fā)送數(shù)據(jù)的字節(jié)數(shù)或者在發(fā)生錯(cuò)誤的時(shí)候返回-1.通常,發(fā)送數(shù)據(jù)最常見的錯(cuò)誤就是EIO,當(dāng)調(diào)制解調(diào)器或者數(shù)據(jù)鏈路將Data Carrier Detect(DCD)信號(hào)線弄掉了,就會(huì)發(fā)生這個(gè)錯(cuò)誤.而且,直至關(guān)閉端口這個(gè)情況會(huì)一直持續(xù).

char buffer[1024];int Length;int nByte;nByte = write(fd, buffer ,Length)

  讀取數(shù)據(jù):使用文件操作read函數(shù)讀取,如果設(shè)置為原始數(shù)據(jù)模式(Raw?Date Mode)傳輸數(shù)據(jù),那么read函數(shù)返回的字符數(shù)是實(shí)際串口收到的字符數(shù),也就是返回從串口輸入緩沖區(qū)中實(shí)際得到的字符的個(gè)數(shù).在不能得到數(shù)據(jù)的情況下,read(2)系統(tǒng)調(diào)用就會(huì)一直等著,只到有端口上新的字符可以讀取或者發(fā)生超時(shí)或者錯(cuò)誤的情況發(fā)生.

char buff[1024];int Len;int readByte = read(fd,buff,Len);

  如果需要read(2)函數(shù)迅速返回的話,可以使用操作文件的函數(shù)來實(shí)現(xiàn)異步讀取,如fcntl,或者select等來操作: fcntl(fd, F_SETFL, FNDELAY);標(biāo)志FNDELAY可以保證read()函數(shù)在端口上讀不到字符的時(shí)候返回0.需要回到正常(阻塞)模式的時(shí)候,需要再次在不帶FNDELAY標(biāo)志的情況下調(diào)用fcntl()函數(shù):

(3)函數(shù)編程,需要的頭文件如下

#include <stdio.h> /*標(biāo)準(zhǔn)輸入輸出定義*/ #include <stdlib.h> /*標(biāo)準(zhǔn)函數(shù)庫定義*/ #include <unistd.h> /*Unix 標(biāo)準(zhǔn)函數(shù)定義*/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /*文件控制定義*/ #include <termios.h> /*PPSIX 終端控制定義*/ #include <errno.h> /*錯(cuò)誤號(hào)定義*/

?

?

一個(gè)樹莓派發(fā)送數(shù)據(jù)數(shù)據(jù)給電腦串口的程序如下:需要根據(jù)具體的情況修改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

轉(zhuǎn)載于:https://www.cnblogs.com/lflj/p/7280877.html

總結(jié)

以上是生活随笔為你收集整理的linux与开发板串口通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。