找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5561|回复: 13
收起左侧

请问如何利用单片机+RS485总线进行多机通信?

  [复制链接]
回帖奖励 100 黑币 回复本帖可获得 100 黑币奖励! 每人限 1 次
ID:541653 发表于 2019-5-28 17:50 | 显示全部楼层 |阅读模式
现在,我已经会1对1的数据通信了,比如 能把从机1的温度传感器的读数发给主机。但是目前的问题是,如何用主机的LCD 把 如图两个从机 的温度读数都显示出来(根据主机地址输入显示 或者 同时显示)?请各位前辈指点指点。另外,关于地址选择,我看书百度,还是都不怎么会,现在想的是能不能两个从机的温度,同时显示在LCD屏幕上?拜托各位前辈了。谢谢!

这是1对1时的485部分单片机代码:

//////////////////
发送端(从机):
/////////////////

sbit UART_EN=P3^3;

void UART_init() //串口初始化
{
TMOD=0x20;
SCON=0x50;
TH1=0xFD;
TL1=0xFD;
TR1=1;
UART_EN=1;    //485一直在写
}
/***
**函数名:UART_sent()
**功能:  串口发送一个字节
****/
void send(unsigned char str)
{
if(TI==0)
{
  SBUF=str;
  while(TI==0);
  TI=0;
}
}

//////////////////

接收端(主机):

/////////////////

unsigned int sdata; // LCD将要显示的温度

sbit UART_EN=P3^3;
void uart_init() //串口初始化
{
TMOD=0x20;  //9600bps
SCON=0x50;
TH1=0xFD;
TL1=0xFD;
TR1=1;
ES=1;
EA=1;
UART_EN=0;    //串口一直处于接收状态
}
void receive(void) //接收数据函数
{
while(RI==0);
RI=0;
sdata=SBUF;     
}
3 (1).png
1.png
4 (1).png
4 (2).png
5 (1).png
回复

使用道具 举报

ID:548878 发表于 2019-6-5 13:13 | 显示全部楼层
你有完成的程序吗?我也在做一个多机通行的设计,怎么实现无线远程的多机通信?
回复

使用道具 举报

ID:415123 发表于 2019-6-5 17:10 | 显示全部楼层
一对多通信,那么就有地址问题,将从机编号啊,按你的图,你就将从机编为1号和3号。现在你要改的是通信程序,有两种方法:主机发起,从机响应。二、从机定时上传,主机接收。你来决定用哪一个方法。主机发起,从机响应的思路是这样的:你需要定义一个帧结构,至少要包含从机地址。比如说,你定义一个两字节的帧,第一个字节表示地址,如1,第二个字节表示命令。那么从机接收到这两个字节后,各自判读,如果1号机读到后响应返回温度值,那么主机就读到了啊,由于是1号机,2号机其实也读到了相同的命令,由于地址不对,所以2号机不响应。定时响应的方法,你自己思考一下
回复

使用道具 举报

ID:93224 发表于 2019-6-5 17:42 | 显示全部楼层
我做过这个相关的仿真,多从机的,实在不行你加我的QQ 1014461948
回复

使用道具 举报

ID:541653 发表于 2019-6-9 16:46 | 显示全部楼层
涛涛涛涛12138 发表于 2019-6-5 13:13
你有完成的程序吗?我也在做一个多机通行的设计,怎么实现无线远程的多机通信?

没有欸
回复

使用道具 举报

ID:541653 发表于 2019-6-9 16:57 | 显示全部楼层
honey_teck 发表于 2019-6-5 17:10
一对多通信,那么就有地址问题,将从机编号啊,按你的图,你就将从机编为1号和3号。现在你要改的是通信程序 ...

谢谢。这个流程就是地址确认,然后再传输数据,大方向我能理解,但是细节的代码部分,漏洞百出。请问一下,中断方式是第一种方法还是第二种方法?
回复

使用道具 举报

ID:762124 发表于 2020-6-4 15:53 | 显示全部楼层
学习了,谢谢楼主,太棒了
回复

使用道具 举报

ID:18297 发表于 2020-6-6 09:40 | 显示全部楼层
多机通讯需要一个可靠的协议:
可以参考其他通讯的协议,自己给他搞个简单的协议。
比如你这个可以这样定义。
主机发送:命令+地址+校验。等待对应的地址进行返回。
从机返回:地址+数据+校验。
例如:主机发送0a(cmd)+01(address)+0b(sum)     //采用简单的求和,也可以采用其他的检验方式)
address的从机发送:01(address)+88(数据)+89(sum)。
其他地址的从机不处理。
这个只是最简单的一种协议,当然可以拓展成更复杂的。
通过CMD可以对从机决心参数设定,校准等待。
仅供参考。
回复

使用道具 举报

ID:767423 发表于 2020-6-6 10:45 | 显示全部楼层
honey_teck 发表于 2019-6-5 17:10
一对多通信,那么就有地址问题,将从机编号啊,按你的图,你就将从机编为1号和3号。现在你要改的是通信程序 ...

第二个方法不好实现,会出现多个从机同时发的冲突。
回复

使用道具 举报

ID:767423 发表于 2020-6-6 10:53 | 显示全部楼层
产品上用的部分程序,可以参考,modbus协议
/********485通讯接收处理*******/
void com_recv(void)
{
        recv_ok=0;
        red_addr_flg=0;
        /*读寄存器功能码03H处理*/
        if(recv_data[1]==0x03)        //读寄存器(功能码03H)处理
        {
                if((recv_data[0]==0)&&(recv_data[3]==17))
                {
                        red_addr_flg=1;
                }
                if((recv_data[0]!=0)||(red_addr_flg!=0))//地址不为0,或为0读地址
                {
                        send_data[0]=ADDR_s1;                        //本机地址
                        send_data[1]=0x03;                                //功能码
                        send_data[2]=recv_data[5]<<1;        //字节数
                        send_count=send_data[2];
                        while(send_count!=0)
                        {
                                send_data[send_i+3]=(ram_data[recv_data[3]+send_j]&0xff00)>>8;        //取变量高字节
                                send_i++;
                                send_data[send_i+3]=ram_data[recv_data[3]+send_j]&0x00ff;                //取变量低字节
                                send_i++;
                                send_j++;
                                send_count--;
                        }
                        CRC_string(send_data[2]+3);                                                //发送数据串CRC校验
                        send_data[send_data[2]+3]=(CRC_data&0x00ff);        //CRC校验码低字节
                        send_data[send_data[2]+4]=(CRC_data&0xff00)>>8;        //CRC校验码高字节
                        send_count=send_data[2]+5;
                        p1_6=1;                        //485设为输出
                        re_u0c1=0;                //不允许接收
                        tx_count=1;
                        send_count--;
                        u0tb=send_data[0];
                        CRC_data=0xffff;
                        send_i=0;
                        send_j=0;
                        red_addr_flg=0;
                }
                else
                {
                        re_u0c1=1;        //允许串口接收       
                }
        }
        else
        {
                if((status.stu.far_near==1)&&(recv_data[0]!=0))        //为远程和地址不为0才能设置
                {                       
        /*功能码10H处理*/                                       
                        if(recv_data[1]==0x10)        //写寄存器(功能码10H)处理
                        {
                        /********10H功能给主机返馈***********/
                                send_data[0]=ADDR_s1;                        //本机地址
                                send_data[1]=0x10;                                //功能码
                                send_data[2]=recv_data[2];                //变量起始地址高字节
                                send_data[3]=recv_data[3];                //变量起始地址低字节
                                send_data[4]=recv_data[4];                //变量个数高字节
                                send_data[5]=recv_data[5];                //变量个数低字节
                                CRC_string(6);                                        //发送数据串CRC校验
                                send_data[6]=(CRC_data&0x00ff);        //CRC校验码低字节
                                send_data[7]=(CRC_data&0xff00)>>8;//CRC校验码高字节
                                p1_6=1;                                                        //485设为输出
                                re_u0c1=0;                                                //不允许接收
                                tx_count=1;                                                //指向第二个字节
                                send_count=7;                                        //后续字节在发送中断中发
                                u0tb=send_data[0];                                //发第一个字节
                                CRC_data=0xffff;
                        /**************************************/       
                        /**********装载收到的数据*************/
                                               
                                load_count=recv_data[5];//变量个数
                                send_i=7;                                //recv_data[7]开始为数据
                                while(load_count!=0)
                                {
                                        ram_data[recv_data[3]+send_j]=recv_data[send_i]<<8;
                                        send_i++;
                                        ram_data[recv_data[3]+send_j]=ram_data[recv_data[3]+send_j]|recv_data[send_i];
                                        send_i++;
                                        send_j++;
                                        load_count--;
                                }
                                ram_data[1]=status.stus;//状态不能写
                                if((ram_data[16]==0x0008)||(ram_data[16]==0x0009)||(ram_data[16]==0x000a))
                                {
                                        ram_data[16]=0x0008;
                                }
                                send_i=0;
                                send_j=0;
                                //time_spke=0;            //声音延时时间清零
                                //delay_spke_flg=1;   //声音延时标志
                        }
                }
                re_u0c1=1;        //允许串口接收
        }
}
回复

使用道具 举报

ID:772431 发表于 2020-6-8 09:47 | 显示全部楼层
关于主从机,他是咋分配的
回复

使用道具 举报

ID:793949 发表于 2020-11-11 08:29 来自手机 | 显示全部楼层
老哥做出来多机通信了吗?
回复

使用道具 举报

ID:313791 发表于 2020-11-12 17:28 | 显示全部楼层
就是主机发送的数据需要有地址
回复

使用道具 举报

ID:546729 发表于 2020-11-17 08:53 | 显示全部楼层
有人做出来了吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表