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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux下串口编程基础

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

串口知識
串行接口 (SerialInterface) 是指數據一位一位地順序傳送,其特點是通信線路簡單,只要一對傳輸線就可以實現雙向通信(可以直接利用電話線作為傳輸線),從而大大降低了成本,特別適用于遠距離通信,但傳送速度較慢。
1. 波特率
表示每秒傳輸的比特數,串口通信的雙方必須保持一致才能通信數據位,若波特率為115200,它表示什么呢?
對于發送斷,即每秒鐘發送115200bit。
對于接收端,115200波特率意味著串口通信在數據線上的采樣率為115200Hz.
2. 數據位
這是衡量通信中實際數據位的參數。當計算機發送一個信息包,實際的數據不會是8位的,標準的值是5、6、7和8位。如何設置取決于你想傳送的信息。比如,標準的ASCII碼是0~127(7位)。擴展的ASCII碼是0~255(8位)。如果數據使用簡單的文本(標準 ASCII碼),那么每個數據包使用7位數據。每個包是指一個字節,包括開始/停止位,數據位和奇偶校驗位。由于實際數據位取決于通信協議的選取,術語“包”指任何通信的情況。7位或8位數據中不僅僅是數據,還包括開始/停止位,數據位以及奇偶校驗位等
3. 停止位
用于表示單個包的最后一位。典型的值為1,1.5和2位。由于數據是在傳輸線上定時的,并且每一個設備有其自己的時鐘,很可能在通信中兩臺設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,并且提供計算機校正時鐘同步的機會。適用于停止位的位數越多,不同時鐘同步的容忍程度越大,但是數據傳輸率同時也越慢。
4. 奇偶校驗
一般奇偶校驗位的應用是由硬件完成的,軟件只需要在初始化的時候對MCU的串口外設設置一下
奇偶校驗的形式一般是在數據位后面跟一個奇偶校驗位,如果數據位是8位的,那么加上校驗位就是9位數據;如果數據位是7位的,那么加上校驗位就是8位數據,校驗位和數據之間沒有任何意義上的關聯,它不是數據的一部分,它只是關心數據中的“1”的個數是否為奇數(奇校驗),或者偶數(偶校驗)。奇校驗,奇校驗就是控制器在發送的一個字節或者一個數據幀里面含有的“1”的個數進行奇數個的修正調整,這里采用8位數據位+1位奇校驗位的形式舉個簡單的例子,A發送數據0x35到B,后面緊跟一個奇校驗位X, 0x35的二進制 = 0011 0101,可以看出8個數據位中一共有4個‘1’,那此時硬件會根據“1”的個數來設置X,這里會將奇校驗位X調整為“1”,為什么呢? 因為數據位的“1”的個數是偶數,而我們用的是奇校驗,所以為了達到有奇數個“1”的目的,調整奇偶校驗位X為“1”,那么這9個位發出去就有奇數個“1”啦,當B接收的時候,B的硬件同樣會對接收到“數據+X”中“1”的個數進行計數判斷,如果是奇數個“1”,則認為數據接收正確,否則認為數據錯誤。而當A發送數據0x25( 0010 0101)到B的時候,則X應該就是“0”了,因為要保證發送出去的數據位+X位一共有奇數個“1”。
串口編程
串口編程的步驟:

a) 打開串口
這里是串口操作需要的一些頭文件

#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> /*錯誤號定義*/

Linux下一切皆文件,所以串口操作也是對文件進行操作的
Linux的串口文件位于 /dev下的

/dev/ttyS0 /* 串口0 */ /dev/ttyS1 /* 串口1 */

這里我們通過標準的文件打開操作嘗試打開串口 1
在這之前先建立一個 .c 文件 這里是 uatr2.c

#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> /*錯誤號定義*/int main() {int fd;/*以讀寫方式打開串口*/fd = open( "/dev/ttyS1", O_RDWR);if (-1 == fd)/* 不能打開串口一*/perror(" 提示錯誤!");elseprintf("success\n");close(fd);}

編譯 .c 文件

gcc -o uart2.o uart2.c

運行

./uart2.o

這里輸出success 說明串口能成功打開

調用open()函數來代開串口設備,對于串口的打開操作,必須使用O_NOCTTY參數。
O_NOCTTY:表示打開的是一個終端設備,程序不會成為該端口的控制終端。如果不使用此標志,任務一個輸入(eg:鍵盤中止信號等)都將影響進程。
O_NDELAY:表示不關心DCD信號線所處的狀態(端口的另一端是否激活或者停止)。

1、 串口波特率設置
串口的設置主要是設置 struct termios 結構體的各成員值。

struct termio { unsigned short c_iflag; /* 輸入模式標志 */ unsigned short c_oflag; /* 輸出模式標志 */ unsigned short c_cflag; /* 控制模式標志*/ unsigned short c_lflag; /* local mode flags */ unsigned char c_line; /* line discipline */ unsigned char c_cc[NCC]; /* control characters */ };

設置這個結構體很復雜,這里就只說說常見的一些設置:
波特率設置
下面是修改波特率的代碼:

struct termios Opt; tcgetattr(fd, &Opt); cfsetispeed(&Opt,B19200); /*設置為19200Bps*/ cfsetospeed(&Opt,B19200); tcsetattr(fd,TCANOW,&Opt);

設置波特率的例子函數:

/** *@brief 設置串口通信速率 *@param fd 類型 int 打開串口的文件句柄 *@param speed 類型 int 串口速度 *@return void */ int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 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); } } }

3、校驗位和停止位的設置
設置效驗的函數:

/** *@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); }

4、 讀寫串口
設置好串口之后,讀寫串口就很容易了,把串口當作文件讀寫就是。
發送數據

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

讀取串口數據
使用文件操作read函數讀取,如果設置為原始模式(Raw Mode)傳輸數據,那么read函數返回的字符數是實際串口收到的字符數。
可以使用操作文件的函數來實現異步讀取,如fcntl,或者select等來操作。

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

5、 關閉串口
關閉串口就是關閉文件。
close(fd);

下面是串口1的一個簡單的讀取與發送的例子

#include <stdio.h> /*標準輸入輸出定義*/ #include <stdlib.h> /*標準函數庫定義*/ #include <unistd.h> /*Unix標準函數定義*/ #include <sys/types.h> /**/ #include <sys/types.h> /**/ #include <sys/stat.h> /**/ #include <fcntl.h> /*文件控制定義*/ #include <termios.h> /*PPSIX終端控制定義*/ #include <errno.h> /*錯誤號定義*/#define FALSE 0 #define TRUE 1/***@brief 設置串口通信速率 *@param fd 類型 int 打開串口的文件句柄 *@param speed 類型 int 串口速度 *@return void*/int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300,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);} } /** { int fd = open( Dev, O_RDWR | O_NOCTTY | O_NDELAY); //| O_NOCTTY | O_NDELAYif (-1 == fd){ /*設置數據位數*/perror("Can't Open Serial Port");return -1;}elsereturn fd;} /** *@breif main() */ int main(int argc, char **argv) {int fd , n;int nread;char buff[512];char *dev ="/dev/ttyS1";fd = OpenDev(dev);if (fd>0)set_speed(fd,19200);else{printf("Can't Open Serial Port!\n");exit(0);}if (set_Parity(fd,8,1,'N')== FALSE){printf("Set Parity Error\n");exit(1);}while(1){while((nread = read(fd,buff,512))>0){printf("\nLen %d\n",nread);buff[nread+1]='\0';printf("\n%s",buff);n = write(fd, "I get\r", 4) //如果收到數據則向串口發送I Get if (n < 0)fputs("write() of 4 bytes failed!\n", stderr);}}//close(fd);//exit(0); }

總結

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

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