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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

七、Linux串口编程

發布時間:2025/4/5 linux 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 七、Linux串口编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

相關程序代碼和資源我都已經給大家打包好了。可以到https://download.csdn.net/download/qq_28938511/13080045下載。

不方便下載的,可以給我留言,我直接分享給你。

Linux下的串口編程過程如下(我就不給大家再講串口是什么了,不懂得朋友自行補上串口相關知識):

目錄

一、打開串口

二、初始化串口

1、 串口的初始化結構介紹

2、串口的初始化常用函數介紹?

函數 tcgetattr

波特率相關的函數?cfsetispeed 和 cfsetospeed、cfgetispeed 、cfgetospeed

函數 tcflush

函數 tcsetattr

3、初始化流程分析

4、串口初始化代碼

三、串口發送數據

四、串口接收數據

五、關閉串口

六、補充:開機自啟動


一、打開串口

先來學習一下如何打開串口,在幾乎所有的 Linux 系統中,在 dev 目錄下都會有 tty*的設備節點,如下圖所示,啟動開發板,在超級終端中,進入 dev 目錄,輸入查找命令“ls tty*”。

如上圖所示,有多種形式的設備節點,在 4412 開發板中,設備節點使用的是 ttySAC*系列,即 ttySAC0ttySAC1ttySAC2ttySAC3。?

iTOP-4412 開發板可以支持 4 個串口,如下圖所示,方便用戶使用的除了控制臺(超級終端使用的串口)以外,精英版靠近麥克和耳機的串口,也是可以直接拿來使用的。精英版靠近耳機和麥克的串口對應的設備節點是“ttySAC3”(就是串口3的意思)。后面的實驗都已這個操作這個串口為例子來講解。

還是那句話,linux下一切皆文件,那么我們要打開串口,就要打開串口對應的文件,也就是我們剛剛提到的ttySAC3文件,如何打開呢?還是我們之前用的open函數,具體代碼如下:

#include <stdio.h>#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h>void main(){int fd;char *uart3 = "/dev/ttySAC3"; //串口3文件路徑if((fd = open(uart3,O_RDWR|O_CREAT,0777))<0){// O_RDWR 讀、寫打開,沒有就創建,權限0777 printf("open %s failed!\n",uart3);}else{printf("open %s is success!\n",uart3);}close(fd); }

二、初始化串口

1、 串口的初始化結構介紹

串口編程的最大的難度就是初始化,用的參數非常多。如下圖所示,使用 source insight 打開內核源碼,串口的初始化最終要將參數傳遞到內核中的,搜索“termios.h”,如下所示。

? ? ? ? ? ? ? ? ?

如上圖所示,打開“arch\arm\include\asm”目錄下的“termios.h”頭文件。如下圖所示,可以看到這個 termio 結構體的定義。?

? ? ? ? ? ? ? ? ? ? ? ? ? ??

分析一下上圖中幾個常用的參數。

  • 成員 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]:控制字符

2、串口的初始化常用函數介紹?

在給串口初始化之前必須讀取串口的句柄,也就是先要使用 open 函數,在前面的實驗中已經測試過,可以正常返回 fd 了。

函數 tcgetattr

  • 函數 tcgetattr 用于讀取當前串口的參數值,在實際應用中,一般用于先確認該串口是否能夠配置,做檢測用。
  • 需要用到頭文件 “#include <termios.h>”和“#include <unistd.h>”。
  • 函數原型為 int tcgetattr(int fd, struct termios *termios_p)。
  • 參數 1:fd 是 open 返回的文件句柄。
  • 參數 2:*termios_p 是前面介紹的結構體。
  • 使用這個函數前可以先定義一個 termios 結構體,用于存儲舊的參數。?

波特率相關的函數?cfsetispeed 和 cfsetospeed、cfgetispeed 、cfgetospeed

函數 cfsetispeed 和 cfsetospeed 用于修改串口的波特率,函數 cfgetispeed 和cfgetospeed 可以用于獲取當前波特率。在實際應用中,這個經常需要用到,例如修改默認的波特率。
波特率相關的函數需要用到頭文件“#include <termios.h>”和“#include <unistd.h>”。

先介紹設置波特率的函數。
函數原型 int cfsetispeed(struct termios *termios_p, speed_t speed); // 這個是輸入的波特率
參數 1:*termios_p 是前面介紹的結構體。
參數 2:speed 波特率,常用的 B2400,B4800,B9600,B115200,B460800 等等。
執行成功返回 0,失敗返回-1

函數原型 int cfsetospeed(struct termios *termios_p, speed_t speed);?// 這個是輸出的波特率
參數 1:*termios_p 是前面介紹的結構體。
參數 2:speed 波特率,常用的 B2400,B4800,B9600,B115200,B460800 等等。
執行成功返回 0,失敗返回-1

下面介紹獲取波特率的函數。
函數原型為 speed_t cfgetispeed(const struct termios *termios_p)。用于讀取當前串口輸入的波特率。
參數 1:*termios_p 是前面介紹的結構體。
返回值為 speed_t。
函數 speed_t cfgetospeed(const struct termios *termios_p)。這個函數用于讀取當前輸出的波特率。
參數 1:*termios_p 是前面介紹的結構體。
返回值為 speed_t 類型,當前波特率。

函數 tcflush

函數 tcflush 用于清空串口中沒有完成的輸入或者輸出數據。在接收或者發送數據的時候,串口寄存器會緩存數據,這個函數用于清除這些數據。
原型為 int tcflush(int fd, int queue_selector);
參數 1:fd 是 open 返回的文件句柄。
參數 2:控制 tcflush 的操作。
有三個常用數值,TCIFLUSH 清除正收到的數據,且不會讀取出來;TCOFLUSH 清除正
寫入的數據,且不會發送至終端
TCIOFLUSH 清除所有正在發生的 I/O 數據。
執行成功返回 0,失敗返回-1?

函數 tcsetattr

前面介紹了讀取串口配置參數的函數,tcsetattr 函數是設置參數的函數。
原型為 int tcsetattr(int fd, int optional_actions,const struct termios *termios_p);
參數 1:fd 是 open 返回的文件句柄。
參數 2:optional_actions 是參數生效的時間。
有三個常用的值:TCSANOW:不等數據傳輸完畢就立即改變屬性;TCSADRAIN:等待所有數據傳輸結束才改變屬性;TCSAFLUSH:清空輸入輸出緩沖區才改變屬性
參數 3:*termios_p 在舊的參數基礎上修改的后的參數。
執行成功返回 0,失敗返回-1
一般在初始化最后會使用這個函數。?

3、初始化流程分析

如下圖所示,是串口初始化的流程圖。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

4、串口初始化代碼

下面寫一個函數,包括串口的基本的配置,函數里面的參數還可以添加,也可以單獨拿出來配置。如下圖所示,首先定義一個初始化函數int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)。然后定義結構體變量 newtio (新串口參數)和 oldtio(舊串口參數)。

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop) {struct termios newtio,oldtio;if ( tcgetattr( fd,&oldtio) != 0) { perror("SetupSerial 1");return -1;}bzero( &newtio, sizeof( newtio ) );newtio.c_cflag |= CLOCAL | CREAD;newtio.c_cflag &= ~CSIZE;switch( nBits ){case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;}switch( nEvent ){case 'O':newtio.c_cflag |= PARENB;newtio.c_cflag |= PARODD;newtio.c_iflag |= (INPCK | ISTRIP);break;case 'E': newtio.c_iflag |= (INPCK | ISTRIP);newtio.c_cflag |= PARENB;newtio.c_cflag &= ~PARODD;break;case 'N': newtio.c_cflag &= ~PARENB;break;}switch( nSpeed ){case 2400:cfsetispeed(&newtio, B2400);cfsetospeed(&newtio, B2400);break;case 4800:cfsetispeed(&newtio, B4800);cfsetospeed(&newtio, B4800);break;case 9600:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;case 115200:cfsetispeed(&newtio, B115200);cfsetospeed(&newtio, B115200);break;case 460800:cfsetispeed(&newtio, B460800);cfsetospeed(&newtio, B460800);break;default:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;}if( nStop == 1 )newtio.c_cflag &= ~CSTOPB;else if ( nStop == 2 )newtio.c_cflag |= CSTOPB;newtio.c_cc[VTIME] = 0;newtio.c_cc[VMIN] = 0;tcflush(fd,TCIFLUSH);if((tcsetattr(fd,TCSANOW,&newtio))!=0){perror("com set error");return -1;} // printf("set done!\n\r");return 0; }

?

三、串口發送數據

口發送類似文件操作,非常簡單。使用 write 函數即可,三個參數分別是句柄,傳輸的buffer 以及,傳輸的長度。這個函數前面介紹文件 IO 的時候已經介紹過了,這里就不再重復。

#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <errno.h>int set_opt(int,int,int,char,int); void main() {int fd,wr_static,i=10;char *uart3 = "/dev/ttySAC3";char *buffer = "hello world!\n";printf("\r\nitop4412 uart3 writetest start\r\n");if((fd = open(uart3, O_RDWR|O_NOCTTY|O_NDELAY))<0){printf("open %s is failed",uart3);}else{printf("open %s is success\n",uart3);set_opt(fd, 115200, 8, 'N', 1); while(i--){wr_static = write(fd,buffer, strlen(buffer));if(wr_static<0)printf("write failed\n");else{printf("wr_static is %d\n",wr_static);}sleep(1);}}close(fd); }int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop) {struct termios newtio,oldtio;if ( tcgetattr( fd,&oldtio) != 0) { perror("SetupSerial 1");return -1;}bzero( &newtio, sizeof( newtio ) );newtio.c_cflag |= CLOCAL | CREAD;newtio.c_cflag &= ~CSIZE;switch( nBits ){case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;}switch( nEvent ){case 'O':newtio.c_cflag |= PARENB;newtio.c_cflag |= PARODD;newtio.c_iflag |= (INPCK | ISTRIP);break;case 'E': newtio.c_iflag |= (INPCK | ISTRIP);newtio.c_cflag |= PARENB;newtio.c_cflag &= ~PARODD;break;case 'N': newtio.c_cflag &= ~PARENB;break;}switch( nSpeed ){case 2400:cfsetispeed(&newtio, B2400);cfsetospeed(&newtio, B2400);break;case 4800:cfsetispeed(&newtio, B4800);cfsetospeed(&newtio, B4800);break;case 9600:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;case 115200:cfsetispeed(&newtio, B115200);cfsetospeed(&newtio, B115200);break;case 460800:cfsetispeed(&newtio, B460800);cfsetospeed(&newtio, B460800);break;default:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;}if( nStop == 1 )newtio.c_cflag &= ~CSTOPB;else if ( nStop == 2 )newtio.c_cflag |= CSTOPB;newtio.c_cc[VTIME] = 0;newtio.c_cc[VMIN] = 0;tcflush(fd,TCIFLUSH);if((tcsetattr(fd,TCSANOW,&newtio))!=0){perror("com set error");return -1;} // printf("set done!\n\r");return 0; }

四、串口接收數據

串口接收使用 read 函數,在文件 io 中已經介紹過了。

#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <errno.h>int set_opt(int,int,int,char,int); //"/dev/ttySAC3"是con2,靠近耳機接口的串口 void main() {int fd,nByte;char *uart3 = "/dev/ttySAC3";char buffer[512];char *uart_out = "please input\r\n";memset(buffer, 0, sizeof(buffer));if((fd = open(uart3, O_RDWR|O_NOCTTY))<0)printf("open %s is failed",uart3);else{set_opt(fd, 115200, 8, 'N', 1);write(fd,uart_out, strlen(uart_out));while(1){while((nByte = read(fd, buffer, 512))>0){buffer[nByte+1] = '\0'; write(fd,buffer,strlen(buffer));memset(buffer, 0, strlen(buffer));nByte = 0;}}} }int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop) {struct termios newtio,oldtio;if ( tcgetattr( fd,&oldtio) != 0) { perror("SetupSerial 1");return -1;}bzero( &newtio, sizeof( newtio ) );newtio.c_cflag |= CLOCAL | CREAD;newtio.c_cflag &= ~CSIZE;switch( nBits ){case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;}switch( nEvent ){case 'O':newtio.c_cflag |= PARENB;newtio.c_cflag |= PARODD;newtio.c_iflag |= (INPCK | ISTRIP);break;case 'E': newtio.c_iflag |= (INPCK | ISTRIP);newtio.c_cflag |= PARENB;newtio.c_cflag &= ~PARODD;break;case 'N': newtio.c_cflag &= ~PARENB;break;}switch( nSpeed ){case 2400:cfsetispeed(&newtio, B2400);cfsetospeed(&newtio, B2400);break;case 4800:cfsetispeed(&newtio, B4800);cfsetospeed(&newtio, B4800);break;case 9600:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;case 115200:cfsetispeed(&newtio, B115200);cfsetospeed(&newtio, B115200);break;case 460800:cfsetispeed(&newtio, B460800);cfsetospeed(&newtio, B460800);break;default:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;}if( nStop == 1 )newtio.c_cflag &= ~CSTOPB;else if ( nStop == 2 )newtio.c_cflag |= CSTOPB;newtio.c_cc[VTIME] = 0;newtio.c_cc[VMIN] = 0;tcflush(fd,TCIFLUSH);if((tcsetattr(fd,TCSANOW,&newtio))!=0){perror("com set error");return -1;}// printf("set done!\n\r");return 0; }

五、關閉串口

close(fd);

六、補充:開機自啟動

打開開發板控制臺,按照如下命令,配置rcS文件

進入rcS,移動到最后一行,添加如下:

?

?

?

總結

以上是生活随笔為你收集整理的七、Linux串口编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。