LINUX_RS232/RS485通信
#include <stdio.h>
#include <pthread.h>
#include “RS485.h”
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <linux/serial.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <stdint.h>
/**
- @brief: set the properties of serial port
- @Param: fd: file descriptor
- @Param: nSpeed: Baud Rate
- @Param: nBits: character size
- @Param: nEvent: parity of serial port
- @Param: nStop: stop bits
*/
typedef enum {DISABLE = 0, ENABLE} RS485_ENABLE_t;
int Set_Uart(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio, oldtio;
memset(&oldtio, 0, sizeof(oldtio));
/* save the old serial port configuration */
if(tcgetattr(fd, &oldtio) != 0) {
perror("set_port/tcgetattr");
return -1;
}
memset(&newtio, 0, sizeof(newtio));
/* ignore modem control lines and enable receiver */
newtio.c_cflag = newtio.c_cflag |= CLOCAL | CREAD;// 开启读取模式和本地连接模式
newtio.c_cflag &= ~CSIZE;// 数据位掩码
/* set character size */
switch (nBits) {
case 8:
newtio.c_cflag |= CS8;// 8个数据位
break;
case 7:
newtio.c_cflag |= CS7;
break;
case 6:
newtio.c_cflag |= CS6;
break;
case 5:
newtio.c_cflag |= CS5;
break;
default:
newtio.c_cflag |= CS8;
break;
}
/* set the parity */
switch (nEvent) {
case 'o':
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'e':
case 'E':
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'n':
case 'N':
newtio.c_cflag &= ~PARENB;// 无奇偶校验
break;
default:
newtio.c_cflag &= ~PARENB;
break;
}
/* set the stop bits */
switch (nStop) {
case 1:
newtio.c_cflag &= ~CSTOPB;// 1个停止位
break;
case 2:
newtio.c_cflag |= CSTOPB;
break;
default:
newtio.c_cflag &= ~CSTOPB;
break;
}
/* set output and input baud rate */
switch (nSpeed) {
case 0:
cfsetospeed(&newtio, B0);
cfsetispeed(&newtio, B0);
break;
case 50:
cfsetospeed(&newtio, B50);
cfsetispeed(&newtio, B50);
break;
case 75:
cfsetospeed(&newtio, B75);
cfsetispeed(&newtio, B75);
break;
case 110:
cfsetospeed(&newtio, B110);
cfsetispeed(&newtio, B110);
break;
case 134:
cfsetospeed(&newtio, B134);
cfsetispeed(&newtio, B134);
break;
case 150:
cfsetospeed(&newtio, B150);
cfsetispeed(&newtio, B150);
break;
case 200:
cfsetospeed(&newtio, B200);
cfsetispeed(&newtio, B200);
break;
case 300:
cfsetospeed(&newtio, B300);
cfsetispeed(&newtio, B300);
break;
case 600:
cfsetospeed(&newtio, B600);
cfsetispeed(&newtio, B600);
break;
case 1200:
cfsetospeed(&newtio, B1200);
cfsetispeed(&newtio, B1200);
break;
case 1800:
cfsetospeed(&newtio, B1800);
cfsetispeed(&newtio, B1800);
break;
case 2400:
cfsetospeed(&newtio, B2400);
cfsetispeed(&newtio, B2400);
break;
case 4800:
cfsetospeed(&newtio, B4800);
cfsetispeed(&newtio, B4800);
break;
case 9600:
cfsetospeed(&newtio, B9600);
cfsetispeed(&newtio, B9600);
break;
case 19200:
cfsetospeed(&newtio, B19200);
cfsetispeed(&newtio, B19200);
break;
case 38400:
cfsetospeed(&newtio, B38400);
cfsetispeed(&newtio, B38400);
break;
case 57600:
cfsetospeed(&newtio, B57600);
cfsetispeed(&newtio, B57600);
break;
case 115200:
cfsetospeed(&newtio, B115200);
cfsetispeed(&newtio, B115200);
break;
case 230400:
cfsetospeed(&newtio, B230400);
cfsetispeed(&newtio, B230400);
break;
default:
cfsetospeed(&newtio, B115200);
cfsetispeed(&newtio, B115200);
break;
}
/* set timeout in deciseconds for non-canonical read */
newtio.c_cc[VTIME] = 0;
/* set minimum number of characters for non-canonical read */
newtio.c_cc[VMIN] = 0;
/* flushes data received but not read */
tcflush(fd, TCIFLUSH);
/* set the parameters associated with the terminal from
the termios structure and the change occurs immediately */
if((tcsetattr(fd, TCSANOW, &newtio))!=0)
{
perror("set_port/tcsetattr");
return -1;
}
return 0;
}
/**
- @brief: open serial port
- @Param: dir: serial device path
*/
int Open_Uart(char *dir)
{
int fd ;
fd = open(dir, O_RDWR);
if(fd < 0) {
perror(“open_port”);
}
return fd;
}
/*******************************************************************
*名称: UART_Close
*功能: 关闭串口并返回串口设备文件描述
*入口参数: fd 文件描述符
*出口参数:void
*******************************************************************/
void Close_Port(int fd)
{
close(fd);
}
/*******************************************************************
-
名称: UART0_Recv
-
功能: 接收串口数据
-
入口参数: fd 文件描述符
-
rcv_buf 接收串口中数据存入rcv_buf缓冲区中
-
data_len 一帧数据的长度
-
出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int Uart_Recv(int fd, char *rcv_buf,int data_len)
{
int len,fs_sel;len = read(fd,rcv_buf,data_len);
return len;
}
/********************************************************************
-
名称: UART0_Send
-
功能: 发送数据
-
入口参数: fd 文件描述符
-
send_buf 存放串口发送数据
-
data_len 一帧数据的个数
-
出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int Uart_Send(int fd, char *send_buf,int data_len)
{
int len = 0;len = write(fd,send_buf,data_len);
if (len == data_len )
{
//printf(“send data is %s\n”,send_buf);
return len;
}
else
{tcflush(fd,TCOFLUSH); return 0;
}
}
uint16_t GetCRC16(uint8_t *buff,uint8_t len)
{
uint8_t i=0;
uint8_t j=0;
uint16_t wtmp=0xffff;
uint16_t out=0;
for(i=0; i<len; i++)
{
wtmp = wtmp ^ buff[i];
for(j=0; j<8; j++)
{
if((wtmp & 0x0001) == 0)
{
wtmp=wtmp>>1;
out=wtmp;
}
else
{
wtmp=wtmp>>1;
wtmp ^= 0xa001;
out=wtmp;
}
}
}
return out;
}
//封装请求码
int buildRequest(int sid,int func, int addr, int nb, uint8_t *req)
{
//这里控制的就是外部定义的req数组。下面按RTU的数据格式填充
req[0] = sid; //从机地址
req[1] = func; //功能码
req[2] = (uint8_t)(addr >> 8); //理论上,有要分大小端存储的数,都可以拆分开。
req[3] = (uint8_t)(addr & 0xff);
if (func == 3)
{
req[4] = (uint8_t)(nb >> 8); //当功能码是03时完成的任务
req[5] = (uint8_t)(nb & 0xff);
}
uint16_t crc = GetCRC16(req, 6); //这里是一个CRC校验,形成两字节的校验位
req[6] = (uint8_t)(crc & 0xff);
req[7] = (uint8_t)(crc >> 8); //上返回的unsigned short类型,转为uint8_t
return 8;
}