C语言实现串口通信(运行于各LINUX系统上)

代码配置如下:

/*********************************************************************
* 文件名称:serial_config
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月10日
* 包含的模块名称:
* 主要功能描述:实现串口信息配置和和线程创建。
* 运行环境要求:运行于各LINUX系统上,设备至少具备一路网口和路串口,运行内存不小于512M,存储空间不小于4G。
* 修改内容1:
* 修改人1:
* 修改时间1:
* ...
* 修改内容n:
* 修改人n:
* 修改时间n:
**********************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>         //包含文件控件,像O_RDWR
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>       // 错误代码和strerror()函数
#include <sys/socket.h>
#include <unistd.h>		// write(), read(), close()
#include <termios.h>	

#define	SERIA_SITE	"/dev/ttyS7"	//定义LINUX下所调用串口端口位置及名称

int serialfd;
void Seria_initialization(void); 	//串口初始化函数
/*********************************************************************
* 函数名称:set_baudrate
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月10日
* 功能描述:实现串口波特率设置	
* 函数输入:opt(串口配置结构体指针)、baudrate(波特率,可选范围B0,  B50,  B75,  B110, 
			B134,  B150,  B200, B300, B600, B1200, B1800, B2400, B4800, B9600, B19200,
			B38400, B57600, B115200, B230400, B460800)
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:
**********************************************************************/
static void set_baudrate(struct termios *opt,unsigned int baudrate)
{
    cfsetispeed(opt, baudrate);
    cfsetospeed(opt, baudrate);
}
/*********************************************************************
* 函数名称:set_data_bit
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月10日
* 功能描述:实现串口收/发数据位数的设置	
* 函数输入:opt(串口配置结构体指针)、databit(数据位数,可选范围CS5,CS6,CS7,CS8)
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:
**********************************************************************/
static void set_data_bit (struct termios *opt,unsigned int databit)
{
    switch (databit) {
    case 8:
        opt->c_cflag |= CS8;
        break;
    case 7:
        opt->c_cflag |= CS7;
        break;
    case 6:
        opt->c_cflag |= CS6;
        break;
    case 5:
        opt->c_cflag |= CS5;
        break;
    default:
        opt->c_cflag |= CS8;
        break;
    }
}
/*********************************************************************
* 函数名称:set_parity
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月10日
* 功能描述:实现串口收/发数据校验方式的设置	
* 函数输入:opt(串口配置结构体指针)、parity(校验,选值范围N,E,O)
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:
**********************************************************************/
static void set_parity (struct termios *opt, char parity)
{
    switch (parity) {
    case 'N':                  /* 无校验 */
        opt->c_cflag &= ~PARENB;
        break;
    case 'E':                  /* 偶校验 */
        opt->c_cflag |= PARENB;
        opt->c_cflag &= ~PARODD;
        break;
    case 'O':                  /* 奇校验 */
        opt->c_cflag |= PARENB;
        opt->c_cflag |= ~PARODD;
        break;
    default:                   /* 无校验 */
        opt->c_cflag &= ~PARENB;
        break;
    }
}
/*********************************************************************
* 函数名称:set_stopbit
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月10日
* 功能描述:实现串口收/发停止位数的设置	
* 函数输入:opt(串口配置结构体指针)、stopbit(选值范围1或2)
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:
**********************************************************************/
static void set_stopbit (struct termios *opt, const char *stopbit)
{
    if (0 == strcmp (stopbit, "1")) {
        opt->c_cflag &= ~CSTOPB; /* 1 stop bit */
    }  
	else if (0 == strcmp (stopbit, "2")) {
        opt->c_cflag |= CSTOPB;  /* 2 stop bits */
    } 
	else {
        opt->c_cflag &= ~CSTOPB; /* 1 stop bit */
    }
}
/*********************************************************************
* 函数名称:set_serial_attr
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月10日
* 功能描述:实现串口收/发所有属性的设置	
* 函数输入:fd(打开串口返回编号)、baudrate(波特率)、databit(数据位)
			stopbit(停止位)、parity(校验)、
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:
**********************************************************************/
static void set_serial_attr (int fd, int  baudrate, int  databit, const char *stopbit, char parity,int vtime,int vmin)
{
    struct termios opt;
    tcgetattr(fd, &opt);					//读取现有设置
    set_baudrate(&opt, baudrate);			//设置波特率
    set_data_bit(&opt, databit);			//设置数据位
    set_parity(&opt, parity);				//设置校验位
    set_stopbit(&opt, stopbit);				//设置停止位
	//其它设置
	opt.c_cflag |= CLOCAL | CREAD;			//打开READ,并忽视调制状态,禁用调制解调器特定的信号线
	opt.c_cflag &= ~CRTSCTS;				//禁用硬件RTS/CTS流控制
//    opt.c_lflag |= 0;
	opt.c_lflag &= ~ICANON;					//禁用规范模式
	opt.c_lflag &= ~ECHO; 					//禁用发送字符回显,Disable echo
	opt.c_lflag &= ~ECHOE; 					// Disable erasure
	opt.c_lflag &= ~ECHONL; 				// Disable new-line echo
	opt.c_lflag &= ~ISIG; 					// Disable interpretation of INTR, QUIT and SUSP
	opt.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制(IXOFF,IXON,IXANY)
	opt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);//禁用接收时字节的特殊处理
//	opt.c_oflag = 0;
    opt.c_oflag &= ~OPOST;					//禁用输出字符的特殊处理
	opt.c_oflag &= ~ONLCR;
    opt.c_cc[VTIME] = vtime;				//VMIN = 0,VTIME = 0:无阻塞,立即返回可用值,VMIN> 0,VTIME = 0:这将read()始终等待字节(确切地由决定多少个字节VMIN),因此read()可以无限期地阻塞。
    opt.c_cc[VMIN]  = vmin;					//VMIN = 0,VTIME> 0:这是对最大超时(由给出VTIME)的任何数字字符的阻塞读取。read()将阻塞直到有大量数据可用或发生超时为止。
											//VMIN> 0,VTIME> 0:阻塞直到VMIN接收到任何字符或VTIME第一个字符过去后超时。请注意,VTIME直到收到第一个字符,超时才会开始。
    tcflush (fd, TCIFLUSH);					//刷新输入缓存,丢弃接收的缓存数据
    if(tcsetattr (fd, TCSANOW, &opt)!= 0) {	//保存配置
		printf("Error %i from tcsetattr: %s ヘ(_ _ヘ)\n", errno, strerror(errno));
	}
}

/*********************************************************************
* 函数名称:Seria_initialization
* 版本标识:v3.00
* 创建人:
* 创建时间:2024年4月10日
* 功能描述:实现串口的初始化配置和对串口收发数据缓存清空
* 函数输入:无
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:
**********************************************************************/
void Seria_initialization(void)
{
	serialfd = open(SERIA_SITE,O_RDWR|O_NOCTTY);				//打开串口
	if (serialfd < 0) {														
		printf("Open Serial port failed, code %i from open: %s \n", errno, strerror(errno));
	}
	else printf("Open Serial port succeed!\n");
	set_serial_attr(serialfd,B115200,8,"1",'N',0,0);				//串口参数配置
}

调用方式:

extern void Seria_initialization(void); 		  //串口初始化函数
extern int serialfd;
/*********************************************************************
* 函数名称:serialDataTX
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月13日
* 功能描述:实现串口机箱管理数据帧的组包发送
* 函数输入:无
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:
**********************************************************************/
static void *serialDataTX(void *arg)
{
	int wireId = 0;
	hasSentData = false;
	makeSerialSendData(1);
	while(1)
	{
		/*wireId = write(serialfd, &TxSerialData, sizeof(struct serialChassisSend));		//串口发送数据
		if(wireId < 0) printf("Write serial port failed!!!!\n");
		else 
		memset(&tx_test_serial,0,sizeof(struct serialTest));
		
		if(rx_test_serial.command == 0xAA)// 添加条件判断语句以检查是否已发送过数据 && !hasSentData
		{
			makeSerialSendData(2);
			write(serialfd,&tx_test_serial,sizeof(struct serialTest));//发送串口测试数据
			//hasSentData = true; // 设置已发送数据标志为真
			printf("serial data has send! \n");
		}
		*/
		makeSerialSendData(2);
		write(serialfd,&tx_test_serial,sizeof(struct serialTest));//发送串口测试数据
		printf("serial data has send! \n");
	usleep(45*1000);//延时 45 毫秒
    }
	
	close(serialfd);
    return NULL;
	
}
/*********************************************************************
* 函数名称:serialDataRX
* 版本标识:v3.00
* 创建人:	
* 创建时间:2024年4月13日
* 功能描述:实现串口数据帧的接收
* 函数输入:无
* 函数输出:无
* 修改内容1:
* 修改人1:
* 修改时间1:			
**********************************************************************/
static void *serialDataRX(void *arg)
{
	unsigned int usartRXlen = 0;							//读取串口返回字节长度
	unsigned char usartbuf[1024] = {0};						//串口接收数据缓存
	Seria_initialization();									//初始化串口
	while(1)
	{
		usartRXlen = 0;
		RxSerialData.frameHead = 0;
		RxFanSerialData.frameHead = 0;
        usartRXlen = read(serialfd, usartbuf, sizeof(usartbuf));
		/*if(usartRXlen <= 0) 						//未接收到串口数据
		{
			printf("Read the CHMC serial port data failure! ヘ(_ _ヘ)\n"); 
		}*/
		
		if(usartRXlen == sizeof(struct serialChassisRecv))
		{
			memcpy(&RxSerialData, usartbuf, usartRXlen);
			if(RxSerialData.frameHead == 0x0FF0 && RxSerialData.frameEnd == 0xE00E)
			{
				if(queryFlag == 1)
				{
					memcpy(singleBoardBuffer, RxSerialData.chmcData, sizeof(RxSerialData.chmcData));//数据缓存至singleBoardBuffer
					//将singleBoardBuffer中的数据存入udp返回chassis_back_health中的boardHealthAttribute数组中
					memcpy(&back_single_board.boardAttribute, singleBoardBuffer, sizeof(singleBoardBuffer));
					backUdpQueryData(1);
                }
                else if(queryFlag == 2)
				{
				    memcpy(healthManageBuffer,RxSerialData.chmcData,sizeof(RxSerialData.chmcData));//数据缓存至healthManageBuffer
					//将healthManageBuffer中的数据存入udp返回chassis_back_health中的healthAttribute数组中
					memcpy(&chassis_back_health.healthAttribute, healthManageBuffer, sizeof(healthManageBuffer));
					backUdpQueryData(2);
				}
                else
				{
					memset(&RxSerialData,0,sizeof(struct serialChassisRecv));//清零0缓存
					queryFlag =0;
				}				
			}
				
		}else if(usartRXlen == sizeof(struct serialFanData))
		{
		    memcpy(&RxFanSerialData,usartbuf,usartRXlen);
			if(RxFanSerialData.frameHead == 0x0FF0 && RxFanSerialData.frameEnd == 0xE00E)
			{
			    if(queryFlag == 3){
				memcpy(fanManageBuffer,&RxFanSerialData,sizeof(struct serialFanData));//数据缓存至fanManageBuffer
			    //将fanManageBuffer中的数据存入udp返回back_fan_state中的fanState数组中
				memcpy(&back_fan_state.fanState, fanManageBuffer, sizeof(fanManageBuffer));
				backUdpQueryData(3);
			    printf("fanManageBuffer:%hhn \n",fanManageBuffer);
			   }
			   else memset(&back_fan_state,0,sizeof(struct backFanState));
			}
		}else if(usartRXlen == sizeof(struct serialTest))//测试串口
		{
			memcpy(&rx_test_serial,usartbuf,usartRXlen);
			printf("the usartRXlen is: %d \n",usartRXlen);
			if(rx_test_serial.frameHead == 0xF00F && rx_test_serial.frameEnd == 0x0EE0)
			{
				printf("the frameHead data is: %hd \n",rx_test_serial.frameHead);
				printf("the frameEnd data is: %hd \n",rx_test_serial.frameEnd);
				backUdpQueryData(4);
				if(rx_test_serial.command == 0xAA)
				{
					printf("the command data is: %hhu \n",rx_test_serial.command);
				}
				else if(rx_test_serial.command == 0x55)
				{
				  printf("the command data is: %hhu \n",rx_test_serial.command);
				}
			}
		}
		else
		{
			memset(usartbuf,0,sizeof(usartRXlen));
		}		
	    usleep(47.5 *1000);
	}
	close(serialfd);
	return NULL;
}
int main(void)
{
if(pthread_create(&serialRecvId,NULL,serialDataRX,NULL) == -1) //创建串口数据接收线程			
	{
		printf("create CManagement serialDataRX pthread failed!\n");
		return 0;
	}else printf("create CManagement serialDataRX pthread succeed!! \n");
	
	if(pthread_create(&serialSendId,NULL,serialDataTX,NULL) == -1) //创建串口数据发送处理线程			
	{
		printf("create CManagement serialDataTX pthread failed! \n");
		return 0;
	}
	else printf("create CManagement serialDataTX pthread succeed!\n");
	pthread_join(serialRecvId, NULL);
	pthread_join(serialSendId, NULL);
	while(1)
	{
	usleep(50*1000);
   }
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九点两刻

你的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值