分类: 嵌入式
2012-11-01 11:18:02
/**
* 串口模块
* 模块功能:串口的基本操作,打开和关闭操作,
* 同时支持四个串口操作
* Author:Lzy
* Greate Date:2012.10.18
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "uart.h"
static int fd_uart[MAXNUM_UART] = {-1, -1, -1, -1}; // 保存串口打开的文件句柄
/**
* 打开串口
* 返回:0成功 1失败 ff已经打开
*/
int appuart_open(unsigned int port)
{
if (port >= MAXNUM_UART)
return 1;
if(fd_uart[port]==-1)
{
if(port==0) fd_uart[port]= open("/dev/ttyS0", O_RDWR | O_NONBLOCK);
else if(port==1) fd_uart[port] = open("/dev/ttyS1", O_RDWR | O_NONBLOCK);
else fd_uart[port]= open("/dev/ttyS2", O_RDWR | O_NONBLOCK);
}
// if(fd_uart[port] == -1)
// fd_uart[port] = open(UART_DEV[port], O_RDWR | O_NONBLOCK); // 不阻塞打开串口
if (-1 == fd_uart[port]) // 检查串口打开是否成功
return 1;
return 0;
}
/**
* 关闭串口
*/
void appuart_close(unsigned int port)
{
if ((port >= MAXNUM_UART) || (-1 == fd_uart[port]))
return;
close(fd_uart[port]);
fd_uart[port] = -1;
}
/**
* 设置串口通信速率
* port->打开串口的文件句柄 speed->串口速度
*/
void appuart_set_speed(unsigned int port, int speed)
{
int speed_arr[] ={ B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B600, B300, };
int name_arr[] ={ 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 600, 300, };
int i, status, fd;
struct termios Opt;
if (port >= MAXNUM_UART)
return;
fd = fd_uart[port];
if (fd < 0)
return;
tcgetattr(fd, &Opt);
for (i = 0; i < sizeof(speed_arr) / sizeof(int); i++)
{
if (speed == name_arr[i])
{
/**
* tcflush函数刷清(抛弃)输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送)。
* queue参数应是下列三个常数之一:
* TCIFLUSH刷清输入队列。
* TCOFLUSH刷清输出队列。
* TCIOFLUSH刷清输入、输出队列。
*/
tcflush(fd, TCIOFLUSH); //设置前flush
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
/**
*通过tcsetattr函数把新的属性设置到串口上。
* tcsetattr(串口描述符,立即使用或者其他标示,指向termios的指针)
*/
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0)
{
perror("tcsetattr fd1");
return;
}
tcflush(fd, TCIOFLUSH); //设置后flush
}
}
}
/**
* 设置串口数据位,停止位和效验位
* fd-> 打开的串口文件句柄
* databits 数据位 取值 为 7 或者8
* stopbits 停止位 取值为 1 或者2
* parity 效验类型 取值为N,E,O,,S
*/
int appuart_set_parity(unsigned int port, int databits, int stopbits, char parity)
{
struct termios options;
int fd;
if (port >= MAXNUM_UART)
return -1;
fd = fd_uart[port];
if (fd < 0)
return -1;
if (tcgetattr(fd, &options) != 0)
return -1;
options.c_iflag = 0;
options.c_cflag &= ~CSIZE;
/*设置数据位数*/
switch (databits)
{
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
return -1;
}
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:
return -1;
}
/* 设置停止位*/
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
return -1;
}
options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IUCLC); /* 输入参数的设置 */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* 不需要回车直接发送*/
options.c_oflag &= ~OPOST; /* 输出参数的设置 */
tcflush(fd, TCIFLUSH);
options.c_cc[VTIME] = 0; /* 设置超时15 seconds*/
options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
if (tcsetattr(fd, TCSANOW, &options) != 0)
{
perror("SetupSerial 3");
return -1;
}
return 0;
}
/**
* 设置串口
* 参数:串口 速度 数据位 停止位 奇偶较检位
*/
void appuart_set(unsigned int port, int speed, int databits, int stopbits, char parity)
{
appuart_set_speed(port, speed);
appuart_set_parity(port, databits, stopbits, parity);
}
/**
* 数据发送
*/
int appuart_send(unsigned int port, char *buf, int len)
{
int fd;
if (port >= MAXNUM_UART)
return 1;
fd = fd_uart[port];
if (fd < 0)
return 1;
write(fd, buf, len);
return 0;
}
/**
* 接收字符串数据
*/
int appuart_recv(unsigned int port, unsigned char *buf, int len)
{
int fd, rtn;
if (port >= MAXNUM_UART)
return -1;
fd = fd_uart[port];
if (fd < 0)
return -1;
rtn = read(fd, buf, len);
if (rtn <= 0)
return 0;
return rtn;
}
/**
* 获得串口的文件句柄
*/
int appuart_getfd(unsigned int port)
{
if (port > MAXNUM_UART)
return -1;
return fd_uart[port-1];
}
/**
* 函数功能: 打开串口模块
* pcComName( 入口):"COM1","COM2","COM3","COM4",串口名称
* phDevHandel( 出口):设备句柄
* 返回值: 0x00-->打开成功
* : 0x89-->设备已经打开
* : 0x8E-->内存分配失败
* : 0x01-->其它错误
*/
int ST_OpenRS232 ( char * pcComName, int *phDevHandel)
{
int port, ret;
port = atoi(pcComName + 3) - 1;
if(port>=0 && port < MAXNUM_UART)
{
if(fd_uart[port]<0)
fd_uart[port]=appuart_open(port);
else
return 0x89;
*phDevHandel = port;
}
else
return 0x8e;
return 0x00;
}
/**
* 函数功能: 关闭串口模块
* pcComName( 入口):设备句柄
* phDevHandel( 出口):设备句柄
* 返回值: 0x00-->关闭成功
*/
int ST_CloseRS232 (int *phDevHandle)
{
appuart_close(*phDevHandle);
*phDevHandle = -1;
return 0x00;
}
/**
* 函数功能:设置RS232口的通讯方式
* hDevHandel:设备名称
* ucBPS: 0x01-->对应1200波特率 * : 0x02-->对应2400波特率 * : 0x03-->对应4800波特率
* : 0x04-->对应9600波特率 * : 0x05-->对应14400波特率 * : 0x06-->对应28800波特率
* : 0x07-->对应19200波特率 * : 0x08-->对应57600波特率 * : 0x09-->对应115200波特率
* : 0x0A-->对应38400波特率
* ucPAR:'N'-->无效验(缺省) :'E'-->偶效验 :'O'-->奇效验
* ucDBS: 0x07-->7位数据位, 0x08-->8位数据位(缺省)
* 返回值: 0x00-->成功 : 0x8C-->设备未打开 : 0x8B-->参数错误(ucBPS,ucPAR或者ucDBS值错误)
* : 0x8D-->串口无法使用 : 0x01-->其他错误(操作系统错误等)
*/
int ST_InitRS232(int hDevHandel, unsigned char ucBPS, unsigned char ucPAR, unsigned char ucDBS)
{
int gprs_baudrate[] = {1200, 2400, 4800, 9600, 14400, 28800, 19200, 57600, 115200, 38400 };
int baud, port;
port=hDevHandel;
baud = gprs_baudrate[ucBPS - 1];
appuart_set(port, baud, 8, 1, 'N');
return 0;
}
/**
* 函数功能:清除RS232的接收缓冲区
* hDevHandel:设备句柄
* 返回值: 0x00-->成功 : 0x8C-->设备未打开 : 0x8D-->串口无法使用 : 0x01-->其他错误(操作系统错误等)
*/
int ST_ClearRS232(int hDevHandel)
{
char buf[1024];
appuart_recv(hDevHandel, buf, 1024);
return 0x00;
}
/**
* 函数功能:从指定设备读数据。提供毫秒级读写,当时时间的精度为10Ms,即小于10Ms按照0处理
* 入口hDevHandel:设备句柄 uiLength:计划接收长度,若接收长度为0默认接收成功
* uiTimeout:超时时间(单位:毫秒):0表示按缺省的超时等待时间。若为负数,则一直等待。缺省的超时为1小时
* 出口pvBuf:接收缓冲区 *puiRetLen:实际接收的长度
* 返回值: 0x00-->读设备或接收成功 : 0x8C-->设备未打开 : 0x8B-->参数错误(pvBuf或puiRetLen为空指针) : 0x01-->读设备或接收失败或打开方式错误
*/
int ST_ReadRS232Ms (int hDevHandel, unsigned int uiLength, int uiTimeOut, char *pvBuf, unsigned int *puiRetLen)
{
int port = hDevHandel;
int rtn = 0, i, len=0;
int times = uiTimeOut;
if(uiTimeOut==0)
times=3600*60;
for (i = 0; i < times; i++)
{
if (len >= uiLength)
break;
while ((rtn = appuart_recv(port, pvBuf, uiLength)) > 0)
{
*pvBuf += rtn;
len += rtn;
if (len >= uiLength)
break;
usleep(1000*1);
}
usleep(1000 *1);
}
*puiRetLen = len;
if (len == 0)
return 1;
return 0;
}
/**
* 函数功能:往指定设备写数据
* hDevHandel:设备句柄
* pvBuf:发送缓冲区
* uiLength:发送长度;若发送长度为0默认成功
* uiTimeout:超时时间(单位:毫秒) :0表示按缺省的超时等待时间。若为负数,则一直等待。缺省的超时为1小时
* 返回值: 0x00-->写设备或发送成功 : 0x8C-->设备未打开 : 0x8B-->参数错误(pvBuf为空) : 0x01-->写设备或发送失败或打开方式错误
* : 'G'---->发送成功未确认
*/
int ST_WriteRS232Ms(int hDevHandel, unsigned int uiLength, int uiTimeOut,char *pvBuf)
{
int port = hDevHandel;
int rtn = 0;
int len = strlen(pvBuf);
if(len > uiLength)
len = uiLength;
print_hexbuf(pvBuf, uiLength); // 按16进制格式打印 字符数据 至屏幕
rtn = appuart_send(port, pvBuf, len);
return rtn;
}
源码: uart.zip