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

歡迎訪問 生活随笔!

生活随笔

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

linux

linux下串口通信程序,关于Linux下串口通信的一点心得

發(fā)布時間:2025/4/16 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux下串口通信程序,关于Linux下串口通信的一点心得 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.

打開串口

與其他的關(guān)于設(shè)備編程的方法一樣,在

Linux

下,操作、控制串口也是通過操作起設(shè)備文件進行的。在

Linux

下,串口的設(shè)備文件是

/dev/ttyS0

/dev/ttyS1

等。因此要讀些串口,我們首先要打開串口:

char *dev= "/dev/ttyS0"; //

串口

1

intfd = open( dev, O_RDWR );

//| O_NOCTTY | O_NDELAY

if (-1 == fd)

{

perror("Can't Open Serial Port");

return -1;

}

else

return fd;

2.

設(shè)置串口速度

打開串口成功后,我們就可以對其進行讀寫了。首先要設(shè)置串口的波特率:

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){

inti;

intstatus;

struct termiosOpt;

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 fd");

return;

}

tcflush(fd,TCIOFLUSH);

}

}

}

3.

設(shè)置串口信息

這主要包括:數(shù)據(jù)位、停止位、奇偶校驗位這些主要的信息。

/**

*@brief

設(shè)置串口數(shù)據(jù)位,停止位和效驗位

*@paramfd

類型

int

打開的串口文件句柄

*@paramdatabits

類型

int

數(shù)據(jù)位

取值

7

或者

8

*@paramstopbits

類型

int

停止位

取值為

1

或者

2

*@paramparity

類型

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) /*

設(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è)置為奇效驗

*/

options.c_iflag |= INPCK;/* Disnable parity checking */

break;

case 'e':

case 'E':

options.c_cflag |= PARENB;/* Enable parity */

options.c_cflag &= ~PARODD;/*

轉(zhuǎ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] = 0; /*

設(shè)置超時

0 seconds*/

options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

if (tcsetattr(fd,TCSANOW,&options) != 0)

{

perror("SetupSerial 3");

return (FALSE);

}

return (TRUE);

}

在上述代碼中,有兩句話特別重要:

options.c_cc[VTIME] = 0; /*

設(shè)置超時

0 seconds*/

options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

這兩句話決定了對串口讀取的函數(shù)

read()

的一些功能。我將著重介紹一下他們對

read()

函數(shù)的影響。

對串口操作的結(jié)構(gòu)體是

Struct{

tcflag_t c_iflag;/*

輸入模式標(biāo)記

*/

tcflag_t c_oflag;/*

輸出模式標(biāo)記

*/

tcflag_t c_cflag;/*

控制模式標(biāo)記

*/

tcflag_t c_lflag;/*

本地模式標(biāo)記

*/

cc_tc_line;/*

線路規(guī)程

*/

cc_tc_cc[NCCS];/*

控制符號

*/

}

其中

cc_tc_line

只有在一些特殊的系統(tǒng)程序

(

比如,設(shè)置通過

tty

設(shè)備來通信的網(wǎng)絡(luò)協(xié)議

)

中才會用。在數(shù)組

c_cc

中有兩個下標(biāo)

(VTIME

VMIN)

對應(yīng)的元素不是控制符,并且只是在原始模式下有效。只有在原始模式下,他們決定了

read()

函數(shù)在什么時候返回。在標(biāo)準(zhǔn)模式下,除非設(shè)置了

O_NONBLOCK

選項,否則只有當(dāng)遇到文件結(jié)束符或各含的字符都已經(jīng)編輯完畢后才返回。

控制符

VTIME

VMIN

之間有著復(fù)雜的關(guān)系。

VTIME

定義要求等待的零到幾百號妙的是間量

(

通常是一個

8

位的

unsigned char

變量,取值不能大于

cc_t)

VMIN

定義了要求等待的最小字節(jié)數(shù)

(

不是要求讀的字節(jié)數(shù)——

read()

的第三個參數(shù)才是指定要求讀的最大字節(jié)數(shù)

)

,這個字節(jié)數(shù)可能是

0

l

如果

VTIME

0

VMIN

定義了要求等待讀取的最小字節(jié)數(shù)。函數(shù)

read()

只有在讀取了

VMIN

個字節(jié)的數(shù)據(jù)或者收到一個信號的時候才返回。

l

如果

VMIN

0

VTIME

定義了即使沒有數(shù)據(jù)可以讀取,

read()

函數(shù)返回前也要等待幾百毫秒的時間量。這時,

read()

函數(shù)不需要像其通常情況那樣要遇到一個文件結(jié)束標(biāo)志才返回

0

l

如果

VTIME

VMIN

等不取

0

VTIME

定義的時當(dāng)接收到底一個自己的數(shù)據(jù)后開始計算等待的時間量。如果當(dāng)調(diào)用

read

函數(shù)時可以得到數(shù)據(jù),計時器馬上開始計時。如果但調(diào)用

read

函數(shù)時還沒有任何數(shù)據(jù)可讀,則等接收到底一個字節(jié)的數(shù)據(jù)后,計時器開始計時。函數(shù)

read

可能會在讀取到

VMIN

個字節(jié)的數(shù)據(jù)后返回,也可能在計時完畢后返回,這主要取決于哪個條件首先實現(xiàn)。不過函數(shù)至少會讀取到一個字節(jié)的數(shù)據(jù),因為計時器是在讀取到第一個數(shù)據(jù)時開始計時的。

l

如果

VTIME

VMIN

都取

0

,即使讀取不到任何數(shù)據(jù),函數(shù)

read

也會立即返回。同時,返回值

0

表示

read

函數(shù)不需要等待文件結(jié)束標(biāo)志就返回了。

這就是這兩個變量對

read

函數(shù)的影響。我使用的讀卡器每次傳送的數(shù)據(jù)是

13

個字節(jié),一開始,我把它們設(shè)置成

options.c_cc[VTIME] = 150

options.c_cc[VMIN] = 0;

結(jié)果,每次讀取的信息只有

8

個字節(jié),剩下的

5

個字節(jié)要等到下一次打卡時才能收到。就是由于這個原因造成的。根據(jù)上面規(guī)則的第一條,我把

VTIME

0

VMIN=13

,也就是正好等于一次需要接收的字節(jié)數(shù)。這樣就實現(xiàn)了一次讀取

13

個字節(jié)值。同時,得出這樣的結(jié)論,如果讀卡器送出的數(shù)據(jù)為

n

個字節(jié),那么就把

VMIN=n

,這樣一次讀取的信息正好為讀卡器送出的信息,并且讀取的時候不需要進行循環(huán)讀取。

4.

讀取數(shù)據(jù)

有了上面的函數(shù)后,我們設(shè)置了串口的基本信息,根據(jù)我們自己的實際情況,設(shè)置了相應(yīng)的參數(shù),就可以讀取數(shù)據(jù)了。

void getcardinfo(char *buff){

int fd;

int nread,count=0;

char tempbuff[13];

char *dev= "/dev/ttyS0"; //

串口

1

fd = OpenDev(dev);

set_speed(fd,9600);

if (set_Parity(fd,8,1,'N') == FALSE){

printf("Set Parity Error\n");

//return -1;

}

while (1) //

循環(huán)讀取數(shù)據(jù)

{

count=0;

//sleep(5000);

while(1)

{

if((nread = read(fd, tempbuff, 13))>0)

{

//printf("\nLen %d\n",nread);

memcpy(&buff[count],tempbuff,nread);

count+=nread;

}

if(count==13)

{

buff[count+1] = '\0';

//printf( "\n%s", buff);

break;

}

}

//break;

}

//return buff;

close(fd);

pthread_exit(NULL);

//close(fd);

// exit (0);

}

這是我原來的程序,其實把

VMIN

設(shè)置以后,可以改成:

void getcardinfo(char *buff){

int fd;

int nread,count=0;

char tempbuff[13];

char *dev= "/dev/ttyS0"; //

串口

1

fd = OpenDev(dev);

set_speed(fd,9600);

if (set_Parity(fd,8,1,'N') == FALSE){

printf("Set Parity Error\n");

//return -1;

}

nread = read(fd, buff, 13)

close(fd);

}

5.

程序完整代碼:

#include/*

標(biāo)準(zhǔn)輸入輸出定義

*/

#include/*

標(biāo)準(zhǔn)函數(shù)庫定義

*/

#include/*Unix

標(biāo)準(zhǔn)函數(shù)定義

*/

#include

#include

#include/*

文件控制定義

*/

#include/*PPSIX

終端控制定義

*/

#include/*

錯誤號定義

*/

#define FALSE-1

#define TRUE0

/**

*@brief

設(shè)置串口通信速率

*@paramfd

類型

int

打開串口的文件句柄

*@paramspeed

類型

int

串口速度

*@returnvoid

*/

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){

inti;

intstatus;

struct termiosOpt;

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 fd");

return;

}

tcflush(fd,TCIOFLUSH);

}

}

}

/**

*@brief

設(shè)置串口數(shù)據(jù)位,停止位和效驗位

*@paramfd

類型

int

打開的串口文件句柄

*@paramdatabits

類型

int

數(shù)據(jù)位

取值

7

或者

8

*@paramstopbits

類型

int

停止位

取值為

1

或者

2

*@paramparity

類型

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) /*

設(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è)置為奇效驗

*/

options.c_iflag |= INPCK;/* Disnable parity checking */

break;

case 'e':

case 'E':

options.c_cflag |= PARENB;/* Enable parity */

options.c_cflag &= ~PARODD;/*

轉(zhuǎ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] = 0; /*

設(shè)置超時

15 seconds*/

options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

if (tcsetattr(fd,TCSANOW,&options) != 0)

{

perror("SetupSerial 3");

return (FALSE);

}

return (TRUE);

}

/**********************************************************************

代碼說明:使用串口一測試的,發(fā)送的數(shù)據(jù)是字符,

但是沒有發(fā)送字符串結(jié)束符號,所以接收到后,后面加上了結(jié)束符號

**********************************************************************/

/*********************************************************************/

int OpenDev(char *Dev)

{

intfd = open( Dev, O_RDWR );

//| O_NOCTTY | O_NDELAY

if (-1 == fd)

{

perror("Can't Open Serial Port");

return -1;

}

else

return fd;

}

void getcardinfo(char *buff){

int fd;

int nread,count=0;

char tempbuff[13];

char *dev= "/dev/ttyS0"; //

串口

1

fd = OpenDev(dev);

set_speed(fd,9600);

if (set_Parity(fd,8,1,'N') == FALSE){

printf("Set Parity Error\n");

//return -1;

}

while (1) //

循環(huán)讀取數(shù)據(jù)

{

count=0;

//sleep(5000);

while(1)

{

if((nread = read(fd, tempbuff, 13))>0)

{

//printf("\nLen %d\n",nread);

memcpy(&buff[count],tempbuff,nread);

count+=nread;

}

if(count==13)

{

buff[count+1] = '\0';

//printf( "\n%s", buff);

break;

}

}

//break;

}

//return buff;

close(fd);

pthread_exit(NULL);

//close(fd);

// exit (0);

}

總結(jié)

以上是生活随笔為你收集整理的linux下串口通信程序,关于Linux下串口通信的一点心得的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 国产精选一区 | 91大片在线观看 | 午夜国产在线 | 麻豆影视在线 | 国产精选视频 | 亚洲情区 | www,xxx69 japan| 中文字幕精品视频在线 | 无码国产精品高潮久久99 | 午夜福利电影一区二区 | 中文字幕第2页 | 一级视频黄色 | 欧美日韩在线播放三区四区 | 四虎国产精品免费 | 黄色操人视频 | 人妻久久一区二区 | 美女黄色一级 | 日本欧美黄色 | 色人天堂 | 日本成人一区二区 | 永久免费不卡在线观看黄网站 | 黄视频免费在线看 | 中文字幕一区二区三区门四区五区 | 草久影院 | 人人草超碰 | 93看片淫黄大片一级 | 国产精品日日摸夜夜爽 | 免费观看黄色 | 日韩中文字幕在线看 | 中文字幕xxxx | 黄色一级大片 | 午夜极品 | 丰满大乳露双乳呻吟 | 国产页 | 国产日本欧美在线 | 日本少妇作爱视频 | 国产精品一区在线观看你懂的 | 男女视频在线观看免费 | 国产亚洲精品久久久久久青梅 | 91精品国产一区 | 一区二区xxx | 亚洲国产999 | 中国一级特黄毛片大片 | 在线一二区 | 中国免费毛片 | 色欲色香天天天综合网www | 色欧美视频 | 五月天婷婷丁香花 | 狼人综合网| 亚洲国产精品视频 | 欧美日韩国产免费观看 | 国产日韩视频 | 小视频在线看 | 久久久夜色精品亚洲 | 成年黄色片 | 国模私拍一区二区三区 | 天堂av网址 | 在线免费小视频 | 精品无码免费视频 | 少妇毛片一区二区三区 | 在线手机av | 国产成人短视频 | 亚洲一本在线 | 亚洲精品乱码久久久久久蜜桃不卡 | 久久精品国产精品 | 小泽玛丽亚在线观看 | 男男啪啪无遮挡 | 狠狠操综合网 | 天天操天天操天天操天天 | 91国语对白 | 涩涩小网站 | 欧美freesex黑人又粗又大 | 日本乱码一区 | 91九色porny视频 | 六月丁香综合 | 黄在线网站 | 婷婷射 | 国产在线中文 | 97久草 | 大地资源在线观看免费高清版粤语 | 中文字幕免 | 极品人妻videosss人妻 | 国产愉拍 | 亚洲看片网 | 日韩深夜视频 | 久久99精品久久久久久园产越南 | 18禁裸乳无遮挡啪啪无码免费 | 亚洲成人生活片 | 日韩 中文字幕 | 久插网 | 嘿咻视频在线观看 | a毛片毛片av永久免费 | 国产一级二级毛片 | 香蕉久久国产 | 秋霞在线一区 | 精品999久久久一级毛片 | 久在线播放 | 日本免费电影一区二区三区 | 激情综合网婷婷 |