通过232从外部读取数据

本文介绍了作者在通过串口232接收数据时遇到的问题,即接收到的FF数据变成了7F。经过排查,发现是termio结构体中设置导致数据的最高位丢失。通过修改termios结构体的配置,成功解决了问题。文章强调了嵌入式系统中细节的重要性,提醒读者在复用和修改程序时要注意硬件设置是否符合需求。
AI助手已提取文章相关产品:

出现的问题及解决思路

问题:当在终端数数据 FFFFFF010203040AFE 时,直接打印输入的信息,FF都变成 7F ,百思不得其解,尝试了几种办法:

  1. 考虑到数据类型,就去查了一下,char类型数据的取值范围是(-128~127),按照这个考虑,输入的最大数值是7F,就去考虑了其他原因。
    注:当时没有有考虑到如果是因为最大表示的数是127,那么FF表示的数也应该是-1而不是7F.

  2. 做了下面这样一个尝试:

	char a =0xff;
	unsigned char b =0xff;
	printf("\na=%x",a);
	printf("\na=%d",a);
	printf("\na=%x",b);
	printf("\na=%d",b);

得到如下结果:

	a=ff
	a=255
	a=ff
	a=255

这就证实了unsigned char是(0-255),无论char还是unsigned char 都可以输出FF这样一个数据,这说明系统是没有问题的。神奇的就是接收到的数据的最高位的 1 不见了,就开始捋程序,不再只关注receive232函数,从头开始捋。
3. 从头捋程序,程序的内容不多,能出问题的就在程序的设置上,看到了termio结构体,里面有这一句:

	newtermios.c_iflag |= (INPCK | ISTRIP);//启动输入就校验,去掉第八位

看到这一句思路就清晰了,八位数据位最高位失踪的原因找到了,就去查termios结构体的设置
https://blog.youkuaiyun.com/vevenlcf/article/details/51096122
把那一行代码进行了修改,如下:

	newtermios.c_iflag |= INPCK;

问题就这样解决了

心得总结

这个程序写起来不难,难在细节,不是别的程序设置好了就可以直接套用过来的,就比如这次的最高位失踪问题,起因就归结于直接使用的前面的程序模板,在其基础上进行修改的同时没有注意到一些设置是否依旧符合要求。

细节

termios结构体很有脾气,不同于软件自定义的起始、数据、校验、停止,这个结构体相当于设置了串口的硬件读写规则,数据的接收先通过硬件接受,接受到了才能被软件所使用,嵌入式的软硬件结合可能这就是初显端倪。

代码

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#define SERIAL_DEV_DIR "/dev/ttyS2"
/*
	程序要求:
		起始位:0xff0xff0xff(三位起始)
		数据位:四位
		校验位:数据相加取低两位(十六进制)
		停止位:0xfe
*/
int set232port(int fd )
{
	struct termios newtermios,	oldtermios ;
	memset(&oldtermios,0,sizeof(oldtermios));	//初始化oldtermios
	if(tcgetattr(fd,&oldtermios)!=0){			//如果没有成功获取fd的参数,打印错误信息(待测试)	
		perror("set232port/tcgetattr");
		return -1;
	}
	memset(&newtermios,0,sizeof(newtermios));
	newtermios.c_cflag = newtermios.c_cflag |=CLOCAL | CREAD ;	//待测试
	newtermios.c_cflag &=~CSIZE  ;		//屏蔽其他标志
	newtermios.c_cflag |= CS8    ;		//设置字符长度为8
	newtermios.c_cflag &= ~PARENB ;		//设置为奇校验
//	newtermios.c_iflag |= (INPCK | ISTRIP);//启动输入就校验,去掉第八位
	newtermios.c_iflag |= INPCK;
	newtermios.c_cflag &= ~CSTOPB;		//设置停止位
	cfsetospeed(&newtermios, B115200);	//设置波特率
	cfsetispeed(&newtermios, B115200);
	newtermios.c_cc[VTIME] = 0;			//设置特殊控制字元
	newtermios.c_cc[VMIN]  = 0;			//设置特殊控制字元
	tcflush(fd , TCIFLUSH);
	if((tcsetattr(fd, TCSANOW, &newtermios))!=0)	//tcsetattr函数用于设置终端参数。函数在成功的时候返回0,失败的时候返回-1,并设置errno的值
	{
		perror("set232port/tcsetattr");
		return -1;
	}
	
	return 0;
	
}

int open232port(char *dir)
{
	int fd;
	fd = open(dir , O_RDWR);
	return fd ;
}

void print232usage(FILE *stream, int exit_code)
{
	fprintf(stream, "first step , come on !\n try again!\n");
	fprintf(stream, 
					"\t-h  --help     Display this usage information.\n"
					"\t-d  --device   The device ttyS[0-3] or ttySCMA[0-1]\n"
	   				"\t-b  --baudrate Set the baud rate you can select\n" 
	       			"\t-s  --string   Write the device data\n");
	exit(exit_code);
}

int receive232(int fd ,unsigned char buff232[]	){
//	printf("\nreceive函数调用了1");
	int readflag , relong ,renum,resum,nread ;
	unsigned char reword[9];
	unsigned char recheck[1];
//	printf("\nreceive函数调用了2");
//	memset(reword, 0, sizeof(reword)+2);
//	memset(buff232, 0, sizeof(buff232)+2);

	readflag = 0;
	do{
	//	printf("\nreceive函数调用了%s",reword);
		nread = read(fd,reword,sizeof(reword));
		sleep(1);
		if((reword[0] == 0xff)&&(reword[1] == 0xff)&&(reword[2] == 0xff))
			readflag = 1;
	//	else
	//		printf("收到的数据是:%d",reword);
	}while(readflag == 0 );
		printf("\n receive函数调用了4");
		printf("\n 收到的数据是: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ",reword[0],reword[1],reword[2],reword[3],reword[4],reword[5],reword[6],reword[7],reword[8]);
	renum = 3;
	resum = 0 ;
	recheck[0] = 0x00;
	while(renum < 7){
		printf("\n receive函数调用了5");
		buff232[resum] = reword[renum];
		recheck[0] = reword[renum] + recheck[0];
		resum ++;
		renum ++;
	}
	recheck[0] = recheck[0]&0xff;
	printf("\n 收到的校验数值为:%x,计算得到的校验数值为:%x",reword[7],recheck[0]);
	if((recheck[0] == reword[7])&&(reword[9]=0xfe)){
		printf("\n 收到数据: 0x%x 0x%x 0x%x 0x%x(已通过校验)",buff232[0],buff232[1],buff232[2],buff232[3]);
	}else{
		printf("\n 收到的数据无效,未保存");
	}
	return 0;
}


int main(int argc , char *argv[])
{
	unsigned char readbuff[4];
	int fd ,i  ,nread,wrnum,renum,resum;
	int nextoption,havearg = 0;;
	extern struct termios oldtermios;	//修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”
	int speed ;
	char *device;
	int speeflag = 0, deviceflag = 0;
	const char *const shortoptions = "hd:s:b:";
	const struct option longoptions[] = {
		{"help",	0,NULL,'h'},
		{"device",	1,NULL,'d'},
		{"string",	1,NULL,'s'},
		{"baudrate",1,NULL,'b'},
		{NULL,		0,NULL,	0}
	};
		
	if(argc < 2){
		print232usage (stdout, 0);
		exit(0);
	}
	while (1) {
		nextoption = getopt_long (argc, argv, shortoptions, longoptions, NULL);	//用来解析命令行选项参数的
		if (nextoption < 0)	//解析命令行选项参数失败则退出while(1)
			break;
		switch(nextoption){
			case 'h':
				print232usage (stdout, 0);
				break;
			case 'd':
				device = optarg;
				deviceflag = 1;
				break;
			case 'b':
				speed = atoi(optarg);
				speeflag = 1 ;
				break;
			case '?':
				print232usage (stderr, 1);
				break ;
			default:
				abort ();
		}
			
	}	
	if ((!deviceflag)||(!speeflag)) {		//如果device跟speed都没有设置,则输出错误信息
		print232usage (stderr, 1);
		exit(0);	
	}	
	fd = open232port(device);                     
	if (fd < 0){
		perror("open failed");
		return -1;
	}
	i = set232port(fd);		//设置串口的各种参数
	if (i < 0) {							//如果串口设置失败,就打印错误信息
		perror("set232port failed");
		return -1;	
	}
/*	char a =0xff;
	unsigned char b =0xff;
	printf("\na=%x",a);
	printf("\na=%d",a);
	printf("\na=%x",b);
	printf("\na=%d",b);*/
	printf("\nwhile函数之前正常\n成功进入while程序");
	receive232(fd, readbuff);
	printf("\n成功完成while程序\n");
	exit(0);
	tcsetattr(fd,TCSANOW,&oldtermios);
	close(fd);
	return 0;
}

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值