出现的问题及解决思路
问题:当在终端数数据 FFFFFF010203040AFE 时,直接打印输入的信息,FF都变成 7F ,百思不得其解,尝试了几种办法:
-
考虑到数据类型,就去查了一下,char类型数据的取值范围是(-128~127),按照这个考虑,输入的最大数值是7F,就去考虑了其他原因。
注:当时没有有考虑到如果是因为最大表示的数是127,那么FF表示的数也应该是-1而不是7F. -
做了下面这样一个尝试:
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;
}
本文介绍了作者在通过串口232接收数据时遇到的问题,即接收到的FF数据变成了7F。经过排查,发现是termio结构体中设置导致数据的最高位丢失。通过修改termios结构体的配置,成功解决了问题。文章强调了嵌入式系统中细节的重要性,提醒读者在复用和修改程序时要注意硬件设置是否符合需求。
1842

被折叠的 条评论
为什么被折叠?



