/*串口設備無論是在工控領域,還是在嵌入式設備領域,應用都非常廣泛。而串口編程也就顯得必不可少。
偶然的一次機會,需要使用串口,而且操作系統還要求是Linux,因此,趁着這次機會,綜合別人的代碼,
進行了一次整理和封裝。具體的封裝格式爲C代碼,這樣做是爲了很好的移植性,使它可以在C和C++環境下,
都可以編譯和使用。代碼的頭文件如下: */
///////////////////////////////////////////////////////////////////////////////
//filename:stty.h
#ifndef __STTY_H__
#define __STTY_H__
//包含頭文件
#include
<stdio.h>
#include
<stdlib.h>
#include
<unistd.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<fcntl.h>
#include
<termios.h>
#include
<errno.h>
#include
<pthread.h>
//
// 串口設備信息結構
typedef struct tty_info_t
{
int fd;
// 串口設備ID
pthread_mutex_t mt;
// 線程同步互斥對象
char name[24];
// 串口設備名稱,例:"/dev/ttyS0"
struct termios ntm;
// 新的串口設備選項
struct termios otm;
// 舊的串口設備選項
} TTY_INFO;
//
// 串口操作函數
TTY_INFO *readyTTY(int id);
int setTTYSpeed(TTY_INFO
*ptty,
int speed);
int setTTYParity(TTY_INFO
*ptty,int databits,int parity,int
stopbits);
int cleanTTY(TTY_INFO
*ptty);
int sendnTTY(TTY_INFO
*ptty,char
*pbuf,int size);
int recvnTTY(TTY_INFO
*ptty,char
*pbuf,int size);
int lockTTY(TTY_INFO
*ptty);
int unlockTTY(TTY_INFO
*ptty);
#endif
/*從頭文件中的函數定義不難看出,函數的功能,使用過程如下:
(1) 打開串口設備,調用函數setTTYSpeed();
(2) 設置串口讀寫的波特率,調用函數setTTYSpeed();
(3) 設置串口的屬性,包括停止位、校驗位、數據位等,調用函數setTTYParity();
(4) 向串口寫入數據,調用函數sendnTTY();
(5) 從串口讀出數據,調用函數recvnTTY();
(6) 操作完成後,需要調用函數cleanTTY()來釋放申請的串口信息接口;
其中,lockTTY()和unlockTTY()是爲了能夠在多線程中使用。在讀寫操作的前後,需要鎖定和釋放串口資源。
具體的使用方法,在代碼實現的原文件中,main()函數中進行了演示。下面就是源代碼文件: */
////////////////////////////////////////////////////////////////////////////////
//stty.c
#include
<stdio.h>
#include
<sys/ioctl.h>
#include
"stty.h"
///////////////////////////////////////////////////////////////////////////////
// 初始化串口設備並進行原有設置的保存
TTY_INFO *readyTTY(int id)
{
TTY_INFO *ptty;
ptty = (TTY_INFO
*)malloc(sizeof(TTY_INFO));
if(ptty
==
NULL)
return NULL;
memset(ptty,0,sizeof(TTY_INFO));
pthread_mutex_init(&ptty->mt,NULL);
sprintf(ptty->name,"/dev/ttyS%d",id);
//
// 打開並且設置串口
ptty->fd
= open(ptty->name, O_RDWR
| O_NOCTTY |O_NDELAY);
if (ptty->fd
<0)
{
free(ptty);
return NULL;
}
//
// 取得並且保存原來的設置
tcgetattr(ptty->fd,&ptty->otm);
return ptty;
}
///////////////////////////////////////////////////////////////////////////////
// 清理串口設備資源
int cleanTTY(TTY_INFO
*ptty) {
//
// 關閉打開的串口設備
if(ptty->fd>0)
{
tcsetattr(ptty->fd,TCSANOW,&ptty->otm);
close(ptty->fd);
ptty->fd
= -1;
free(ptty);
ptty = NULL;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// 設置串口通信速率
// ptty 參數類型(TTY_INFO *),已經初始化的串口設備信息結構指針
// speed 參數類型(int),用來設置串口的波特率
// return 返回值類型(int),函數執行成功返回零值,否則返回大於零的值
///////////////////////////////////////////////////////////////////////////////
int setTTYSpeed(TTY_INFO
*ptty,
int speed) {
int i;
//
// 進行新的串口設置,數據位爲8位
bzero(&ptty->ntm,
sizeof(ptty->ntm));
tcgetattr(ptty->fd,&ptty->ntm);
ptty->ntm.c_cflag
= /*CS8 |*/ CLOCAL
| CREAD;
switch(speed)
{
case 300:
ptty->ntm.c_cflag
|= B300;
break;
case 1200:
ptty->ntm.c_cflag
|= B1200;
break;
case 2400:
ptty->ntm.c_cflag
|= B2400;
break;
case 4800:
ptty->ntm.c_cflag
|= B4800;
break;
case 9600:
ptty->ntm.c_cflag
|= B9600;
break;
case 19200:
ptty->ntm.c_cflag
|= B19200;
break;
case 38400:
ptty->ntm.c_cflag
|= B38400;
break;
case 115200:
ptty->ntm.c_cflag
|= B115200;
break;
}
ptty->ntm.c_iflag
= IGNPAR;
ptty->ntm.c_oflag
= 0;
//
//
tcflush(ptty->fd, TCIFLUSH);
tcsetattr(ptty->fd,TCSANOW,&ptty->ntm);
//
//
return 0;
} // 設置串口數據位,停止位和效驗位
// ptty 參數類型(TTY_INFO *),已經初始化的串口設備信息結構指針
// databits 參數類型(int), 數據位,取值爲7或者8
// stopbits 參數類型(int),停止位,取值爲1或者2
// parity 參數類型(int),效驗類型 取值爲N,E,O,,S
// return 返回值類型(int),函數執行成功返回零值,否則返回大於零的值
///////////////////////////////////////////////////////////////////////////////
int setTTYParity(TTY_INFO
*ptty,int databits,int parity,int
stopbits) {
//
// 取得串口設置
if( tcgetattr(ptty->fd,&ptty->ntm)
!= 0)
{
printf("SetupSerial [%s]\n",ptty->name);
return 1;
}
bzero(&ptty->ntm,
sizeof(ptty->ntm));
ptty->ntm.c_cflag
= CS8 | CLOCAL
| CREAD;
ptty->ntm.c_iflag
= IGNPAR;
ptty->ntm.c_oflag
= 0;
//
// 設置串口的各種參數
ptty->ntm.c_cflag
&=
~CSIZE;
switch (databits)
{ //設置數據位數
case 7:
ptty->ntm.c_cflag
|= CS7;
break;
case 8:
ptty->ntm.c_cflag
|= CS8;
break;
default:
printf("Unsupported data size\n");
return 5;
}
//
//
switch (parity)
{ // 設置奇偶校驗位數
case n:
case N:
ptty->ntm.c_cflag
&=
~PARENB; /* Clear parity enable */
ptty->ntm.c_iflag
&=
~INPCK; /* Enable parity checking */
break;
case o:
case O:
ptty->ntm.c_cflag
|=
(PARODD|PARENB);
/* 設置爲奇效驗*/
ptty->ntm.c_iflag
|= INPCK;
/* Disnable parity checking */
break;
case e:
case E:
ptty->ntm.c_cflag
|= PARENB;
/* Enable parity */
ptty->ntm.c_cflag
&=
~PARODD; /* 轉換爲偶效驗*/
ptty->ntm.c_iflag
|= INPCK;
/* Disnable parity checking */
break;
case S:
case s:
/*as no parity*/
ptty->ntm.c_cflag
&=
~PARENB;
ptty->ntm.c_cflag
&=
~CSTOPB;
break;
default:
printf("Unsupported parity\n");
return 2;
}
//
// 設置停止位
switch (stopbits)
{
case 1:
ptty->ntm.c_cflag
&=
~CSTOPB;
break;
case 2:
ptty->ntm.c_cflag
|= CSTOPB;
break;
default:
printf("Unsupported stop bits\n");
return 3;
}
//
//
ptty->ntm.c_lflag
= 0;
ptty->ntm.c_cc[VTIME]
= 0;
// inter-character timer unused
ptty->ntm.c_cc[VMIN]
= 1;
// blocking read until 1 chars received
tcflush(ptty->fd, TCIFLUSH);
if (tcsetattr(ptty->fd,TCSANOW,&ptty->ntm)
!= 0)
{
printf("SetupSerial \n");
return 4;
}
return 0;
}
int recvnTTY(TTY_INFO
*ptty,char
*pbuf,int size)
{
int ret,left,bytes;
left = size;
while(left>0)
{
ret = 0;
bytes = 0;
pthread_mutex_lock(&ptty->mt);
ioctl(ptty->fd, FIONREAD,
&bytes);
if(bytes>0)
{
ret =
read(ptty->fd,pbuf,left);
}
pthread_mutex_unlock(&ptty->mt);
if(ret
>0)
{
left -= ret;
pbuf += ret;
}
usleep(100);
}
return size -
left; }
int sendnTTY(TTY_INFO
*ptty,char
*pbuf,int size)
{
int ret,nleft;
char *ptmp;
ret = 0;
nleft = size;
ptmp = pbuf;
while(nleft>0)
{
pthread_mutex_lock(&ptty->mt);
ret = write(ptty->fd,ptmp,nleft);
pthread_mutex_unlock(&ptty->mt);
if(ret
>0)
{
nleft -= ret;
ptmp += ret;
}
//usleep(100);
}
return size - nleft;
}
int lockTTY(TTY_INFO
*ptty) {
if(ptty->fd
< 0)
{
return 1;
}
return flock(ptty->fd,LOCK_EX);
} int unlockTTY(TTY_INFO
*ptty) {
if(ptty->fd
< 0)
{
return 1;
}
return flock(ptty->fd,LOCK_UN);
}
#ifdef LEAF_TTY_TEST
///////////////////////////////////////////////////////////////////////////////
// 接口測試
int main(int argc,char
**argv)
{
TTY_INFO *ptty;
int nbyte,idx;
unsigned char cc[16];
ptty = readyTTY(0);
if(ptty
==
NULL)
{
printf("readyTTY(0) error\n");
return 1;
}
//
//
lockTTY(ptty);
if(setTTYSpeed(ptty,9600)>0)
{
printf("setTTYSpeed() error\n");
return -1;
}
if(setTTYParity(ptty,8,N,1)>0)
{
printf("setTTYParity() error\n");
return -1;
}
//
idx = 0;
while(1)
{
cc[0]
= 0xFA;
sendnTTY(ptty,&cc[0],1);
nbyte = recvnTTY(ptty,cc,1);
printf("%d:%02X\n",idx++,cc[0]);
}
cleanTTY(ptty);
} #endif
|