出现的问题及解决思路
变量名相近,比如wrnum,wrsum,在具体的使用过程中,很容易就出现问题,而且因为相近,这个问题出现在数组(例wrbuff[wrnum],wrbuff[sum])中时,不容易被发现:
解决:https://blog.youkuaiyun.com/u012314708/article/details/52130961
心得总结
程序的书写应该遵循层层递进的原则,比如说这次的232程序中的发送程序要包含起始位、数据位、校验位、停止位。如果一上来就直接把这些东西都包括进来,可能出现问题的地方太多,不利于问题的定位。所以,可以层层递进,先保证数据可以完整的被发送与接受,然后在增加起始位,停止位,把最容易出现问题的校验位的设置放到最后。
在使用while()死循环,很容易就让就让CPU跑到100%,适当加入一些sleep函数或者是usleep函数,可以在不影响程序运行的情况下,使得CPU的占用率降下来,一般还是使用usleep函数多一点。
fork()绝对是一个神奇的函数,可以被用来创建子进程,相当于把一个CPU一分为二,通过fork的不同返回值,只需要一个简单的if进行判断就可以进入到不同的程序中,让232的发送与接受做到了同时进行。
细节
异或运算:按照abcdefgh进行异或得到的结果,跟按照hgfedcba进行异或得到的结果是不相同的。
printf:多使用printf函数,把各种参数在程序运行过程中的变化显示出来,方便判断问题出在哪里,前面的renum、resum的问题就是通过这样的方法检查出来。
ASCII:控制字符虽然会影响到printf()函数的输出显示,但控制字符本身在内存还是占据存储空间的。只影响显示,不影响存储。
程序
#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"
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_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 send232(int fd,char buff232[]){
int wrlong,i,wrnum;
char wrword[11];
sleep(3);
memset(wrword,0,sizeof(wrword)+2);
wrlong = strlen(buff232);
i = wrlong;
wrword[0] = '<';
wrword[10] = '>';
wrword[9] = 0x00;
wrnum = 8;
while(wrnum > 0){
wrword[wrnum] = (i % 10 + 0x30);
i = i / 10;
wrword[9] = wrword[9] ^ wrword[wrnum] ;
wrnum --;
}
write(fd, wrword, sizeof(wrword));
printf("\n****一共>>>>发送的数据:%s,这是%d数据**",wrword,0);
// printf("\n发送函数这里正常");
sleep(1);
i = 0;
while(i < wrlong){
wrnum = 1 ;
wrword[9] = 0x00;
// sleep(1);
while(wrnum < 9){
wrword[wrnum] = buff232[i];
wrword[9] = wrword[9]^wrword[wrnum] ;
i++ ;
wrnum++;
// printf("\n发送函数这里正常%d",i);
if(wrnum == 9){
write(fd, wrword,sizeof(wrword));
sleep(1);
printf("\n>>>>发送数据:%s,这是%d数据 Test:wrword[9] = %d",wrword,i,wrword[9]);
}
}
}
// sleep(10);
return 0;
}
int receive232(int fd ,char buff232[] ){
int readflag = 0 , relong ,renum,resum = 0,nread,i;
char reword[11],recheck[1];
memset(buff232, 0, sizeof(buff232)+2);
// printf("\nreceive函数调用了1");
do{
nread = read(fd,reword,sizeof(reword));
usleep(10);
}while(nread < 1 );
printf("\nreceive函数调用了2");
recheck[0] = 0x00;
renum = 1;
relong = 0;
while(renum < 9){
relong = relong * 10 + reword[renum] - 0x30;
recheck[0] = recheck[0]^reword[renum];
renum ++;
}
printf("\n 数字Test:reword[9] = %d,recheck[0] = %d",reword[9],recheck[0]);
printf("\nreceive函数调用了3");
printf("\n****一共<<<<收到的数据大小为:%d",relong);
do{
usleep(100);
nread = read(fd,reword,sizeof(reword));
}while(nread < 1 );
printf("\nreceive函数调用了%d",relong);
if(reword[0]=='<'){
while(resum < relong)
renum = 1;
recheck[0] = 0x00 ;
while(renum < 9){
buff232[resum] = reword[renum];
recheck[0] = recheck[0]^reword[renum];
renum ++ ;
resum ++ ;
printf("\nreceive函数调用了num=%d,sum=%d,relong=%d",renum,resum ,relong);
}
printf("\n num=%d,sum=%d,relong=%d",renum,resum ,relong);
if(recheck[0] != reword[9]){
relong = relong - 8 ;
resum = resum - 8 ;
printf("\n Test:reword[9] = %d,recheck[0] = %d",reword[9],recheck[0]);
}
if(resum < relong){
do{
nread = read(fd,reword,sizeof(reword));
usleep(10);
}while(nread < 1);
}
}
}
printf("\n <<<<收到的数据为:%s , final总共:%d\n",buff232,relong);
return 0;
}
int main(int argc , char *argv[])
{
char writebuff[] = "abcdefghijklmnopqrstuvwxcdefghijklmnopqrstuvwxyzcdefghijklmnopqrstuvwxyz";
char readbuff[strlen(writebuff)];
// char recheck[1] ;
int fd ,i ,len ,nread,wrlong,relong,wrnum,renum,resum,wrsum,readflag = 0;
int pid ;
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:";
// char *xmit = "1234567890";
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;
}
pid = fork();
if (pid < 0){
perror("fork");
return -1;
}else if (pid == 0){
//发送数据:起始位——数据——校验位——停止位
//用于发送一共写了多少数据,把数字转化成了字符
send232(fd, writebuff);
sleep(10);
exit(0);
}else{
//接受数据:起始位——数据——校验位——停止位
receive232(fd,readbuff);
sleep(10);
exit(0);
}
sleep(100);
tcsetattr(fd,TCSANOW,&oldtermios);
close(fd);
return 0;
}
本文总结了在开发232通信程序时遇到的变量混淆问题及其解决方案,强调了程序书写应遵循的层次递进原则,分享了如何避免CPU高占用率的技巧,并探讨了fork()函数在并发执行中的应用。此外,还提到了异或运算的特性以及在调试中使用printf函数的重要性。
346

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



