📄 serial.c
字号:
#include <stdio.h> /*printf*/
#include <fcntl.h> /* open */
#include <string.h> /* bzero */
#include <stdlib.h> /*exit */
#include <sys/times.h> /* times*/
#include <sys/types.h> /* pid_t*/
#include <termios.h> /*termios, tcgetattr(), tcsetattr()*/
#include <unistd.h>
#include <sys/ioctl.h> /* ioctl*/
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>
#include <minigui/control.h>
#include <signal.h> //异步通讯信号处理
#include <pthread.h>
#include "common.h"
#include "meter.h"
#include "serial.h"
#define TTY_DEV "/dev/ttyS" /*端口路径*/
#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2) /*接收超时*/
#define TIMEOUT_USEC 0
/*******************************************
* 获得端口名称
********************************************/
unsigned char *get_ptty(pportinfo_t pportinfo)
{
unsigned char *ptty;
switch(pportinfo->tty){
case '0':{
ptty = TTY_DEV"0";
}break;
case '1':{
ptty = TTY_DEV"1";
}break;
case '2':{
ptty = TTY_DEV"2";
}break;
}
return(ptty);
}
/*******************************************
* 波特率转换函数(请确认是否正确)
********************************************/
int convbaud(unsigned long int baudrate)
{
switch(baudrate){
case 2400:
return B2400;
case 4800:
return B4800;
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
default:
return B9600;
}
}
void signal_handler_IO (int status)
{
//printf("signal_handler_IO \n");
wait_flag=0;
}
/*******************************************
* Setup comm attr
* fdcom: 串口文件描述符,pportinfo: 待设置的端口信息(请确认)
*
********************************************/
int PortSet_normal(int fdcom, const pportinfo_t pportinfo)
{
struct termios termios_old, termios_new;
int baudrate, tmp;
unsigned char databit, stopbit, parity, fctl;
bzero(&termios_old, sizeof(termios_old));
bzero(&termios_new, sizeof(termios_new));
cfmakeraw(&termios_new);
tcgetattr(fdcom, &termios_old); /*get the serial port attributions*/
/*------------设置端口属性----------------*/
/*baudrates*/
baudrate = convbaud(pportinfo -> baudrate);
cfsetispeed(&termios_new, baudrate); /*填入串口输入端的波特率*/
cfsetospeed(&termios_new, baudrate); /*填入串口输出端的波特率*/
termios_new.c_cflag |= CLOCAL; /*控制模式,保证程序不会成为端口的占有者*/
termios_new.c_cflag |= CREAD; /*控制模式,使能端口读取输入的数据*/
/* 控制模式,flow control*/
fctl = pportinfo-> fctl;
switch(fctl){
case '0':{
termios_new.c_cflag &= ~CRTSCTS; /*no flow control*/
}break;
case '1':{
termios_new.c_cflag |= CRTSCTS; /*hardware flow control*/
}break;
case '2':{
termios_new.c_iflag |= IXON | IXOFF |IXANY; /*software flow control*/
}break;
}
/*控制模式,data bits*/
termios_new.c_cflag &= ~CSIZE; /*控制模式,屏蔽字符大小位*/
databit = pportinfo -> databit;
switch(databit){
case '5':
termios_new.c_cflag |= CS5;
case '6':
termios_new.c_cflag |= CS6;
case '7':
termios_new.c_cflag |= CS7;
default:
termios_new.c_cflag |= CS8;
}
/*控制模式 parity check*/
parity = pportinfo -> parity;
switch(parity){
case '0':{
termios_new.c_cflag &= ~PARENB; /*no parity check*/
}break;
case '1':{
termios_new.c_cflag |= PARENB; /*odd check*/
termios_new.c_cflag &= ~PARODD;
}break;
case '2':{
termios_new.c_cflag |= PARENB; /*even check*/
termios_new.c_cflag |= PARODD;
}break;
}
/*控制模式,stop bits*/
stopbit = pportinfo -> stopbit;
if(stopbit == '2'){
termios_new.c_cflag |= CSTOPB; /*2 stop bits*/
}
else{
termios_new.c_cflag &= ~CSTOPB; /*1 stop bits*/
}
/*other attributions default*/
termios_new.c_oflag &= ~OPOST; /*输出模式,原始数据输出*/
termios_new.c_cc[VMIN] = 1; /*控制字符, 所要读取字符的最小数量*/
termios_new.c_cc[VTIME] = 2; /*控制字符, 读取第一个字符的等待时间 unit: (1/10)second*/
tcflush(fdcom, TCIFLUSH); /*溢出的数据可以接收,但不读*/
tmp = tcsetattr(fdcom, TCSANOW, &termios_new); /*设置新属性,TCSANOW:所有改变立即生效*/
tcgetattr(fdcom, &termios_old);
return(tmp);
}
void set_speed( int speed){
int i;
int fd;
int status;
struct termios Opt;
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, };
fd=Commfd2;
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);
}
}
}
int SetBourate(int baudrate )
{
set_speed(baudrate);
/*
int tmp;
struct termios termios_old2, termios_new2;
int fd;
fd=Commfd2;
bzero(&termios_old2, sizeof(termios_old2));
bzero(&termios_new2, sizeof(termios_new2));
cfmakeraw(&termios_new2);
tcgetattr(fd, &termios_old2);
termios_new2=termios_old2;
baudrate = convbaud( baudrate);
cfsetispeed(&termios_new2, baudrate);
cfsetospeed(&termios_new2, baudrate);
tcflush(fd, TCIFLUSH);
tmp = tcsetattr(fd, TCSANOW, &termios_new2); //设定新 波特率
return(tmp);
*/
}
/*******************************************
* Setup comm attr
* fdcom: 串口文件描述符,pportinfo: 待设置的端口信息(请确认)
*
********************************************/
int PortSet(int fdcom, const pportinfo_t pportinfo)
{
struct termios termios_old, termios_new;
int baudrate, tmp;
unsigned char databit, stopbit, parity, fctl;
struct sigaction saio;
wait_flag = 1;
bzero(&termios_old, sizeof(termios_old));
bzero(&termios_new, sizeof(termios_new));
cfmakeraw(&termios_new);
tcgetattr(fdcom, &termios_old); /*get the serial port attributions*/
/*------------设置端口属性----------------*/
/*baudrates*/
baudrate = convbaud(pportinfo -> baudrate);
cfsetispeed(&termios_new, baudrate); /*填入串口输入端的波特率*/
cfsetospeed(&termios_new, baudrate); /*填入串口输出端的波特率*/
termios_new.c_cflag |= CLOCAL; /*控制模式,保证程序不会成为端口的占有者*/
termios_new.c_cflag |= CREAD; /*控制模式,使能端口读取输入的数据*/
/* 控制模式,flow control*/
fctl = pportinfo-> fctl;
switch(fctl){
case '0':{
termios_new.c_cflag &= ~CRTSCTS; /*no flow control*/
}break;
case '1':{
termios_new.c_cflag |= CRTSCTS; /*hardware flow control*/
}break;
case '2':{
termios_new.c_iflag |= IXON | IXOFF |IXANY; /*software flow control*/
}break;
}
/*控制模式,data bits*/
termios_new.c_cflag &= ~CSIZE; /*控制模式,屏蔽字符大小位*/
databit = pportinfo -> databit;
switch(databit){
case '5':
termios_new.c_cflag |= CS5;
case '6':
termios_new.c_cflag |= CS6;
case '7':
termios_new.c_cflag |= CS7;
default:
termios_new.c_cflag |= CS8;
}
/*控制模式 parity check*/
parity = pportinfo -> parity;
switch(parity){
case '0':{
termios_new.c_cflag &= ~PARENB; /*no parity check*/
}break;
case '1':{
termios_new.c_cflag |= PARENB; /*odd check*/
termios_new.c_cflag &= ~PARODD;
}break;
case '2':{
termios_new.c_cflag |= PARENB; /*even check*/
termios_new.c_cflag |= PARODD;
}break;
}
//install the signal handler before making the device asynchronous
// 在进行设备异步传输前,安装信号处理程序
saio.sa_handler = signal_handler_IO;
// saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
// allow the process to receive SIGIO
// 允许进程接收 SIGIO 信号
fcntl(fdcom, F_SETOWN, getpid());
// Make the file descriptor asynchronous (the manual page says only
//O_APPEND and O_NONBLOCK, will work with F_SETFL...)
// 设置串口的文件描述符为异步,man上说,只有 O_APPEND 和 O_NONBLOCK 才能使用F_SETFL
fcntl(fdcom, F_SETFL, FASYNC);
/*控制模式,stop bits*/
stopbit = pportinfo -> stopbit;
if(stopbit == '2'){
termios_new.c_cflag |= CSTOPB; /*2 stop bits*/
}
else{
termios_new.c_cflag &= ~CSTOPB; /*1 stop bits*/
}
/*other attributions default*/
termios_new.c_oflag &= ~OPOST; /*输出模式,原始数据输出*/
termios_new.c_cc[VMIN] = 2; /*控制字符, 所要读取字符的最小数量*/
termios_new.c_cc[VTIME] = 1; /*控制字符, 读取第一个字符的等待时间 unit: (1/10)second*/
tcflush(fdcom, TCIFLUSH); /*溢出的数据可以接收,但不读*/
tmp = tcsetattr(fdcom, TCSANOW, &termios_new); /*设置新属性,TCSANOW:所有改变立即生效*/ tcgetattr(fdcom, &termios_old);
return(tmp);
}
/*******************************************
* Open serial port
* tty: 端口号 ttyS0, ttyS1, ....
* 返回值为串口文件描述符
********************************************/
int PortOpen(pportinfo_t pportinfo)
{
int fdcom; /*串口文件描述符*/
unsigned char *ptty;
ptty = get_ptty(pportinfo);
printf("%s\n",ptty);
/*fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);*/
fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);
return (fdcom);
}
/*******************************************
* Close serial port
********************************************/
void PortClose(int fdcom)
{
close(fdcom);
}
/********************************************
* send data
* fdcom: 串口描述符,data: 待发送数据,datalen: 数据长度
* 返回实际发送长度
*********************************************/
int PortSend(int fdcom, unsigned char *data, int datalen)
{
int len = 0;
len = write(fdcom, data, datalen); /*实际写入的长度*/
if(len == datalen){
return (len);
}
else{
tcflush(fdcom, TCOFLUSH);
return -1;
}
}
/*******************************************
* receive data
* 返回实际读入的字节数
*
********************************************/
int PortRecv(int fdcom, unsigned char *data, int datalen, int baudrate)
{
int readlen, fs_sel;
fd_set fs_read;
struct timeval tv_timeout;
int bytes;
FD_ZERO(&fs_read);
FD_SET(fdcom, &fs_read);
tv_timeout.tv_sec = 0;//TIMEOUT_SEC(datalen, baudrate);
tv_timeout.tv_usec =2;//TIMEOUT_USEC;
//printf("TIMEOUT_USEC=%d\n",TIMEOUT_USEC);
// printf("TIMEOUT_SEC(datalen, baudrate)=%d\n",TIMEOUT_SEC(datalen, baudrate));
fs_sel = select(fdcom+1, &fs_read,NULL, NULL, &tv_timeout);
if(fs_sel){
// ioctl(fdcom, FIONREAD, &bytes);
//printf( "bytes can read:%d\n",bytes);
readlen = read(fdcom, data, datalen);
return(readlen);
}
else{
return(-1);
}
return (readlen);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -