基于485总线的评分系统双机实验报告详解

本来还想着做多机的,但老师已经打分了就算了。为了压缩到6页删减了很多内容,将就看吧

基于485总线的评分系统实验报告

实验目标:

通过本案例加深理解RS485通信方式,实现上位机的主控制器与所有的下位机进行通信。

B级任务

实验要求:

使用两块STC板分别下载上一节所提供的.hex文件,搭建485双机通信电路,在linux中编程实现打分程序代码。

实验资源:Windows10电脑,Ubuntu18.04,单片机,杜邦线

实验步骤:

  1. 阅读程序系统流程框图,明确双机通信的功能需求。

  2. 熟悉上一节中模拟MODBUS协议的数据包结构,相关功能码及附加数据定义

  3. 回顾485总线数据收发实验,搭建双机通信电路。

  4. PC端串口设置如下:串口波特率:9600 数据位:8位 校验位:无 停止位:

5.所编写的PC端程序应参考上一节中的通信协议完成一次完整的评分过程:

  • 需要包含串口的设置

  • 主节点发起从机检测过程:发送指定从机编号正常检测数据包,判断回应查询数据包是否符合上一节中的通信协议。

  • 主机获取从机评分过程:发送指定从机评分相关数据包,判断回应查询数据包是否符合上一节中的通信协议。

  • 主机发起结束评分的过程,若复位成功,STC从机上第1位和第8位LED 灯会熄灭。

  • 展示串口相关信息,展示检测到的从机编号和从机的评分等。

  • 代码设计思路:

    1.定义了几个本次实验要用到的函数:

    string format(const vector<uchar> &data);		  //数据处理为字符串
    int check(serial &pipe, int addr);				 //设备检测
    int get_score(serial &pipe, int addr);			  //获取分数
    void reset(serial &pipe);				         //从机复位
    

    2.接下来是主函数,首先从单片机读入数据,波特率设为9600(题目已给出)

    serial pipe("/dev/ttyUSB0", B9600);
    

    3.接着根据题目的要求根据用户输入来选择想要的功能。第一个是根据单片机的编号查找对应的分数,第二个是将从机复位,第三个是退出程序,通过设置循环来重复用户的选择。具体代码如下:

        while(1){
            cout<<"--------------------基于RS485总线的评分系统-------------------------"<<endl;
            cout<<"输入说明:\n1. 输入合法从机地址查询分数\n2. 输入-2将从机复位\n3. 输入-1退出程序\n请输入指令:";
            cin>>addr;
            if(addr == -1) break;
            if(addr == -2) {
                reset(pipe);
                continue;
            }
            check_ret = check(pipe, addr);
            if(check_ret == 1){
                cout<<"设备检测正常"<<endl;
                sleep(1);
        	    if(!(score = get_score(pipe, addr)))
        	        cout<<"获取分数失败"<<endl;
        	    else 
        	        cout<<"分数:"<<score<<endl;
            }
            else if(check_ret == 0){
                cout<<"地址错误,请输入地址重试"<<endl;
                continue;
            }
    	else{
    	    cout<<"数据传输错误,请重启从机"<<endl;
    	}        
    
            //reset(pipe);
            cout<<"从机已复位,输入-1退出"<<endl;
        }
    

    可以看到,输入-1时退出循环,然后return 0退出程序。输入-2时调用reset函数使从机复位。输入正确的从机编号后就会输出对应的成绩,主要是通过调用check函数来检测从机编号是否正确,调用get_score来获得成绩,下面具体再分析一下这三个函数的实现思路。

    4.reset函数完整代码:

    void reset(serial &pipe){
    	vector<uchar> code = {0x5a, 0x00, 0x01,0x00,0x5b};
    	//cout <<"reset:"<< format(code) << endl;				
    	/* 发送数据包 */
    	for(int i=0;i<600;i++) {
    	    pipe.myWrite(code);
    	}
    	return;	    
    }
    

    参数值是serial串口的数据,根据实验指导可以知道,当主机要发送复位信号给从机时,其序列号应为5a + 广播地址00 + 复位功能码01 + 00 +校验字节,所以实现思路就是定义一个字符串序列号,然后通过主机不断向从机发送数据包,最终实现从机复位。

    5.check函数完整代码:

    int check(serial &pipe,int addr){
    	int check_code = 117 + addr, ret;				//校验码为累加和
    	vector<uchar> code = {0x5a, 0x08, 0x13};
    	vector<uchar> rec;
    	code.insert(code.begin()+1, (uchar)addr);			//插入从机地址
    	code.push_back((uchar)check_code);				//插入校验码
    	//cout << format(code) << endl;					
    	/* 写入并接收回应数据包 */
    	pipe.myWrite(code);
    	sleep(1);
    	rec = pipe.myRead(5);
    	if(format(rec) == format(code))				//检验接收数据包是否与发送相同,相同则从机地址正确
    	    ret = 1;
    	else{
    	    if(rec[3] == 0x6f) ret = 0;
    	    else ret = -1;
    	}
    	return ret;	    
    }
    

    函数的参数为串口数据和从机地址。主机发送进行数据检测的序列号为5a + 从机地址 + 检测功能码08 + 13 + 校验码 。实现思路就是将数据检测序列号写入,然后根据收到的数据包来判断从机地址是否正确。如果返回1说明地址正确,返回0说明地址错误,返回-1说明数据错误。

    6.get_score函数完整代码:

    int get_score(serial &pipe, int addr){
    	int check_code = 93 + addr, ret;				//校验码为累加和
    	vector<uchar> code = {0x5a, 0x00, 0x03};
    	vector<uchar> rec;
    	code.insert(code.begin()+3, (uchar)addr);			//插入从机地址
    	code.push_back((uchar)check_code);				//插入校验码
    	//cout << format(data) << endl;					
    	/* 写入并接收回应数据包 */
    	pipe.myWrite(code);
    	sleep(1);
    	rec = pipe.myRead(5);
    	if(rec[3] == 0x6f) ret = -1;					//检验是否错误
    	else {
    	    ret = (int)rec[3];						//转为数字
    	    if(ret < 0 || ret > 100) ret =-2;				//检测数字是否合法
    	}
    	return ret;	    
    }
    

    函数的参数为串口数据和从机地址。主机发送进行分数获取序列号为5a + 00 + 读取功能码03 + 从机地址 + 校验码 。实现思路和上一个函数一样,将数据检测序列号写入,然后根据收到的数据包来获得分数,同时要对分数的合法性进行判断。如果正确则返回正确分数,返回-1说明从机未准备好,返回-2说明从机错误。

    7.format函数完整代码如下:

    string format(const vector<uchar> &data) {
        std::string str(2 * data.size() + 1, '\x00');
        for (int i = 0; i < data.size(); i++) {
            sprintf(&str[i * 2], "%02X", data[i]);
        }
        return str;
    }
    

    函数的功能主要是将数据处理为字符串,在check函数中使用

    验证及结果分析:

    这里设置下位机的编号为2号,分数为66分

    打开程序,运行后输入从机编号2可得成绩,输入-2可复位从机,输入-1可退出程序

    可以看到,结果正确,当输入正确的从机地址2时,输出了分数66。当输入了-2时,从机就会复位,效果如第一张图所示,单片机上的第一个和第八个灯熄灭。当输入-1时,直接退出程序。

    实验总结:

  • 人文:认识到交流的重要性。很多不懂的问题通过和同学交流都得到了有效解决。同时遇到问题时可以向老师虚心求问。
  • 知识:掌握了基于485总线的评分系统的工作原理和具体实现。学会了如何获取串口数据,并利用串口数据进行一些判断。还学会了如何使用c++来实现基于485总线的评分系统的双机评分。
  • 技能:能够较快的编写出c++代码,同时对于单片机的使用和串口助手软件的使用更加得心应手,对于单片机的一些按键能够简单使用。
  • 物联沃分享整理
    物联沃-IOTWORD物联网 » 基于485总线的评分系统双机实验报告详解

    发表评论