1. 程式人生 > >【程式碼參考網上的】linux串列埠程式設計學習筆記

【程式碼參考網上的】linux串列埠程式設計學習筆記

1.串列埠通訊:
同步通訊:將很多字元組成一個資訊組進行傳送
非同步通訊:一個字元一符的傳送。(可靠性高,但是效率相對降低)


2.通過echo和cat來測試串列埠通訊 echo “Hello” >/dev/ttyS0   cat /dev/ttyS1


3.直接通過read/write函式來讀寫串列埠  用select()函式來監聽


4.struct termios opt;/*定義指向termios結構型別的指標opt*/
cfsetispeed(&opt,B9600);/*制定輸入波特率 ,9600bps*/
cfsetospeed(&opt,B9600);/*制定輸出波特率,9600bps*/


5.fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY);/*以讀寫方式開啟裝置*/
int read(int fd,*buffer,length);
int write(int fd,*buffer,length);
int close(int fd);


6.串列埠操作需要的標頭檔案:
#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>/*錯誤號定義*/


7.RTS/CTS請求資料傳送/清楚資料傳送


8.設定串列埠流程
1.儲存運來串列埠配置使用tcgetattr(fd,&oldtio)函式
struct termios newtio,oldtio;
tcgetattr(fd,&oldtio);
2.啟用選項有CLOCAL和CREAD,用於本地連線和接收使能
newtio.c_cflag |= CLOCAL|CREAD;
3.設定波特率,使用函式cfsetispeed,cfsetospeed
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
4.設定資料位,需使用掩碼設定
newtio.c_cflag&=~CSIZE;
newtio.c_cflag|=CS8;
5.設定奇偶校驗位,使用c_cflag和c_iflag.
設定奇校驗:
newtio.c_cflag|=PARENB;
newtio.c_cflag|=PARODD;
newtio.c_iflag|=(INPACK|ISTRIP);
設定偶校驗:
newtio.c_iflag|=(INPACK|ISTRIP);
newtio.c_cflag|=PARENB;
newtio.c_cflag&=~PARODD;
7.設定停止位,通過啟用c_cflag中的CSTOPB實現,若停止位為1,則
清除CSTOPB,若停止位為2,則啟用
newtio.c-cfalg&~CSTOPB;
8。設定最少字元和等待時間,對於接收字元和等待時間沒有特別要求時,可設為0;
newtio.c_cc[VTIME]=0;
newtio.c_cc[VMIN]=0;
9.處理要寫入的引用物件
tcflush函式刷清(拋棄)輸入快取(終端驅動程式已經接收到但是使用者程式尚未讀)或者輸出快取
int tcflush(int filedes,int queue);
queue數應當是下列三個常數之一:TCIFLUSH刷清輸入佇列,TCOFLUSH抒情輸出佇列,TCIOFLUSH刷清輸入輸出佇列
比如:tcflush(fd,TCIFLUSH);

10啟用配置。用tsettattr();比如:tcsetattr(fd,TCSANOW,&newtio);

</pre><pre name="code" class="cpp"><span style="font-size:18px;"><strong>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>

/*
**@名稱:open_port
**@功能:開啟串列埠
**@引數 fd 型別 int 含義 檔案標號
**@引數 comport 型別 int 含義 使用者選擇的串列埠號
**@返回值: -1 開啟串列埠失敗
**@返回值: 0 開啟串列埠成功
*/
int open_port(int fd,int comport)
{
	char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};
	long vdisable;
	if(1==comport)
	{
		fd=open(dev[0],O_RDWR|NOCTTY|NDELAY);
		if(-1==fd)
		{
			perror("can`t open serial port!!!\n");
			return -1;
		}
		else
		{
			printf("open ttyS0");
		}
	}
	   else if(comport==2)
    {    fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);
        if (-1 == fd)
        {
            perror("Can't Open Serial Port");
            return(-1);
        }
        else 
        {
            printf("open ttyS1 .....\n");
        }    
    }
    else if (comport==3)
    {
        fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);
        if (-1 == fd)
        {
            perror("Can't Open Serial Port");
            return(-1);
        }
        else 
        {
            printf("open ttyS2 .....\n");
        }
    }
/*然後恢復串列埠的狀態為阻塞狀態,用於等待串列埠資料的讀入,用fcntl函式:
**fcntl(fd,F_SETFL,0);  //F_SETFL:設定檔案flag為0,即預設,即阻塞狀態****
** 接著測試開啟的檔案描述符是否應用一個終端裝置,以進一步確認串列埠是否正確開啟.
**isatty(STDIN_FILENO);
*/
  
	if(fcntl(fd,F_SETFL,0)<0)
	{
		printf("fcntl failed!!!\n");
	}
	else
	{
		printf("fcntl=%d\n",fcntl(fd,F_SETFL,0));
	}
	if(0==isatty(STDIN_FILENO))
	{
		printf("standard input is not a terminal device!!!\n");
	}
	else
	{
		printf("isatty success!!\n");
	}
	printf("fd-open%d\n",fd);
	return fd;
}

/*
**@名稱:set_port
**@功能:設定串列埠
**@引數 fd 型別 int 含義 檔案標號
**@引數 nSpeed 型別 int 含義 速度
**@引數 nBits 型別 int 含義 資料位
**@引數 nEvent型別 int 含義 奇偶校驗
**@引數 nStop型別 int 含義 停止位
**@返回值: -1 設定串列埠失敗
**@返回值: 0 設定串列埠成功
*/
int set_port(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));//值前n個位元組為0
/*
** 2>啟用選項有CLOCAL和CREAD,用於本地連線和接收使用
** newtio.c_cflag | = CLOCAL | CREAD;
*/
	newtio.c_cflag|=CLOACAL|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'://奇校驗
		case 'O':
			newtio.c_cflag|=PARENB;
			newtio.c_cflag|=PARODD;
			newtio.c_iflag|=(INPCK|ISTRIP);
		case 'e'://偶校驗
		case 'E':
			newtio.c_iflag|=(INPCK|ISTRIP);
			newtio.c_cflag|=PARENB;
			newtio.c_cflag&=~PARODD;
			break;
		case 'n'://無校驗
		case 'N':
			newtio.c_cflag&=~PARENB;
			break;
		
	}
	
	switch(nSpeed)
	{
		case 4800:
			cfsetispeed(&newtio, B4800);
			cfsetospeed(&newtio, B4800);
			break;
		case 115200:
			cfsetispeed(&newtio,B115200);
			cfsetospeed(&newtio,B115200);
			break;
		default:
			printf("set error!!!\n");
	}
	switch(nStop)
	{
		case 1:
			newtio.c_cflag&=~CSTOPB;
			break;
		case 2:
			newtio.c_cflag|=CSTOPB;
			break;
	}
	
	newtio.c_cc[VTIME]=0;
	newtio.c_cc[VMIN]=0;
	
	tcflush(fd,TCIFLUSH);
	if((tcsetattr(fd,TCSANOW,&newtio))!=0)
	{
		perror("com set error!!!\n");
		return -1;
	}
	printf("set done!!!\n");
	return 0;
}

int main()
{
	int fd;//用於接收開啟串列埠的狀態
	int i;//用於接收設定串列埠的狀態
	int nread;//用於接收read的返回值
	char buff[]="zhang lei\n";
	if((fd=open_port(fd,1))<0)
	{//開啟串列埠不成功
		perror("open_port error!!!\n");
		return -1;
	}
	if((i=set_port(fd,115200,8,'N',1))<0)
	{//設定串列埠不成功
		perror("set_port error!!!\n");
		return -1;
	}
	printf("fd=%d",fd);
	nread=read(fd,buff,8);
	close(fd);
	return 0;
}</strong></span>