1.优劣

优势:RS485的可靠传输距离远,接线简单成为了相对于RS232的最大优势。

不足:RS485总线是一种常规的通信总线,它不能够做总线的自动仲裁,也就是不能够同时发送数据以避免总线竞争,所以整个系统的通信效率必然较低,数据冗余量较大,对于速度要求高的应用场所不适应用RS485总线。同时由于RS485总线上通常只有一台主机,所以这种总线方式是典型的集中—分散型控制系统。一旦主机出现故障,会使整个系统的通信限于瘫痪状态,因此做好主机的在线备份是一个重要措施。

2. 硬件层协议

通讯协议主要是实现两个设备之间的数据交换功能,通讯协议分硬件层协议和软件层协议。硬件层协议决定数据如何传输问题,比如要在设备1向设备2发送0x63,0x63的二进制数为0110 0011,这8个二进制数从设备1传输到设备2,涉及到1怎么传,0怎么传的问题,这就是硬件层要解决的问题。 
硬件层协议目前比较多见的有RS-232、RS-485、SPI、IIC等。RS-232规定,线上的电压为x伏都表示传输的是0,y伏传输的则是1。再者,比如要选择多少条线传输数据,选择什么材质的线传输输入,这些也属于硬件层协议约束的。

3.RS-485通讯协议

MCU管脚输出TTL电平,TTL电平的意思是,当MCU管脚输出0电平时,一般情况下电压是0V,当MCU管脚输出1电平时,电压是5V。因TTL电平的是由一条信号线,一条地线产生,信号线上的干扰信号会跟随有效信号传送到接收端,使得有效信号受到干扰,485通讯实际上是把MCU出来的TTL电平通过硬件层的一个转换器芯片进行转换:

把MCU出来的一条的TTL信号经过芯片转换为两根线(线A、线B)上的信号。当MCU给转换器输入低TTL电平时,转换器会使得B的电压比A的电压高,反之,A的电压比B的电压高。 
485协议规约两条电平线上差值为多少表示0或者1,电压是通过仪表可以测量得到的,所以说RS-485是硬件层协议。 
485协议的接收端可能是另一个MCU,MCU管脚也只接受TTL电平,转换芯片过来的是两条线的电压,所以需要对此两条线差分电压转换为TTL电平。

把TTL转为485,实质是一个集成芯片,其间无任何程序代码,纯粹硬件逻辑。同理,将485电平转为TTL也是如此。现在很多芯片把接收和转换都集成到一块IC,注意,转换器和接收器依旧是没有同时工作的,常见的转换芯片是MAX485。 
可以这样理解,硬件层协议是公路,路的目的是为了让车辆能够过去。

4.半双工通讯

首先了解什么是单工通讯,单工通讯是指数据只能朝着一个方向传输的通讯方式。而半双工通讯则是指对于通讯两端,不能同时相对方法发送数据,必须错开时间段发送。

RS-485的通讯线只有2条,且这两条通讯线在一次传输中都需要用到,因此485只可实现半双工通讯。485实现半双工通讯,会遇到一个问题,MCU1向MCU2发数据时,并不知道线上是否正传来MCU2数据,因为没有其他线可用来判断对方的收发状态,那么可能也会导致数据冲突。因此,RS-485要实现半双工通讯,就需要上层的软件协议加以规约,也就是做到”不能你想发数据就发数据”。可以理解,软件层协议就好像交通规则,它能让数据有序传输。

5.基本电路

三种常用电路如下:

5.1 基本的RS485电路

上图是最基本的RS485电路,R/D为低电平时,发送禁止,接收有效,R/D为高电平时,则发送有效,接收截止。上拉电阻R7和下拉电阻R8,用于保证无连接的SP485R芯片处于空闲状态,提供网络失效保护,提高RS485节点与网络的可靠性,R7,R8,R9这三个电阻,需要根据实际应用改变大小,特别是使用120欧或更小的终端电阻时,R9就不需要了,此时R7,R8使用680欧电阻。正常情况下,一般R7=R8=4.7K,R9不要。

图中钳位于6.8V的管V4,V5,V6,都是为了保护RS485总线的,避免受外界干扰,也可以选择集成的总线保护原件。另外图中的L1,L2,C1,C2为可选安装原件,用于提高电路的EMI性能.

5.2 带隔离的RS485电路

根本原理与基本电路的原理相似。使用DC-DC器件可以产生1组与微处理器电路完全隔离的电源输出,用于向RS485收发器提供+5V电源。电路中的光耦器件速率会影响RS485电路的通信速率。上图中选用了NEC的光耦PS2501,受其影响,该电路的通讯速率控制在19200bps下。

5.3 自动切换电路

上图中,TX,RX引脚均需要上拉电阻,这一点特别重要。
接收:默认没有数据时,TX为高电平,三极管导通,RE为低电平使能,RO收数据有效,MAX485为接收态。
发送:发送数据1时,TX为高电平时,三极管导通,DE为低电平,此时收发器处于接收状态,驱动器就变成了高阻态,也就是发送端与A\B断开了,此时A\B之间的电压就取决于A\B的上下拉电阻了,A为高电平、B为低电平,也就成为了逻辑1了。
发送数据0时,TX为低电平,三极管截止,DE为高电平,驱动器使能,此时正好DI是接地的,也就是低电平,驱动器也就会驱动输出B为1,A为0,也就是所谓的逻辑0了。
理解自收发的作用,关键是要理解RE和DE的作用,尤其是DE为0时,驱动器与A\B之间就是高阻态,也就是断开状态,而且A\B都要有上下拉电阻。然后就有了逻辑0-1之间的切换了。所以很巧妙,但是这里也有一个很明显的bug,也就是只适用于“半双工”,如果是全双工,就不行了,因为TX为1时,接收使能,此时从机如果回复数据,那么也就乱了。
基本原理了解了,除了使用三极管实现,还可以使用施密特触发器,也就是所谓的“非”门,来显现,如下图所示:
基本原理与三极管相同,TX为1时,经过施密特触发器进行“非”运算,DE为0,则接收使能,驱动器呈高阻态,此时A\B的电平就是上下拉电阻的电平,也就是逻辑1。TX为0时,DE为1,发送使能,由于DI接地,也就是0,A\B输出也是0.

6.SP3485内部结构图:

 
图中: 
A、B总线接口,用于连接485总线。RO是接收输出端,DI是发送数据收入端,RE是接收使能信号(低电平有效),DE是发送使能信号(高电平有效)。

SP3485硬件连接: 
 
注意: 
R55和R56是两个偏置电阻,用来保证总线空闲时,AB之间的电压差都会大约200mV,避免总线空闲时压差不定逻辑混乱。

7. RS485串口编程

7.1 编程思路

使用RS485实现两个MCU之间的通信,把接收到的数据通过串口助手显示在超级终端上。首先对Usart1和Usart2进行初始化,Usart1负责与串口助手通信,Usart2与RS485连接进行两个MCU之间的通信。然后编写发送和接收函数,接收函数在Usart2的中断服务函数中实现。最后把接收到的数据和必要的提示信息发送到超级终端上显示。

7.2 功能模块代码

①串口初始化

void Uart1_Init(void)
{//USART1 初始化GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);        //开启GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);       //开启USART1时钟//串口1对应引脚复用映射GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);     //GPIOA9复用为USART1GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);    //GPIOA10复用为USART1//USART1端口配置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;     //GPIOA9,GPIOA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                //复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;           //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP;              //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                //上拉GPIO_Init(GPIOA,&GPIO_InitStructure);                       //初始化PA9,PA10//USART1 端口配置USART_InitStructure.USART_BaudRate      = 115200;USART_InitStructure.USART_WordLength    = USART_WordLength_8b;USART_InitStructure.USART_StopBits      = USART_StopBits_1;USART_InitStructure.USART_Parity        = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode          = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE);  //使能串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);          //开启相关中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;       NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;       NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         NVIC_Init(&NVIC_InitStructure);
}void Uart2_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);       //串口2对应引脚复用映射GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);     GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;               GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                    GPIO_Init(GPIOA,&GPIO_InitStructure);                                   //USART2 端口配置USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, &USART_InitStructure); USART_Cmd(USART2, ENABLE);  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);      //Usart2 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     NVIC_Init(&NVIC_InitStructure);
}

②接收数据

void USART2_IRQHandler(void)
{static u32 rx_i=0;if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){     USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除标志位rx_buf[rx_i++] = USART_ReceiveData(USART2);    //rx_buf是在main.c定义的全局变量while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); }rx_flag = 1;
}

③RS485初始化

(SP3485的RE,DE引脚与MCU的PG8引脚相连接)

void Rs485_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);   GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_8;        GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP;  GPIO_Init(GPIOG, &GPIO_InitStruct);     //  RS485_TX_EN = 0; //默认为接收模式
}

④主函数

int main(void)
{char *tx_buf = "I believe I can fly!";u8 len;Led_Init();Key_Init();Systick_Init();Uart1_Init();Uart2_Init();Rs485_Init();printf("Usart test succeeded!\r\n");while(1){if(!KEY0)            //KEY1按键按下{                    delay_ms(10);    //消抖动if(!KEY0){while(!KEY0);RS485_TX_EN = 1; //发送模式,RS485_TX_EN是自定义的一个宏,即对PG8进行置位复位len = strlen(tx_buf);while(len--){USART_SendData(USART2, *tx_buf++);while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);}printf("Send data succeeded!\r\n"); //printf函数已经重定义}}if(!KEY1)              //KEY1按键按下{delay_ms(10);      //消抖动if(!KEY1)          //等待按键松开{while(!KEY1);RS485_TX_EN = 0;    //接收模式if(rx_flag){rx_flag = 0; //清除标志printf("Receive data: %s\r\n", rx_buf);}}}}
}

RS485——RS485通信基础理论与STM32测试相关推荐

  1. python实现485通讯_Python编程实现USB转RS485串口通信

    ---作者疆,未经允许,严禁转载,违权必究--- ---欢迎指正,需要源码和文件可站内私信联系--- -----------点击此处链接至博客园原文----------- 功能说明:Python编程实 ...

  2. fx5u怎么与计算机通讯,两个FX5U系列PLC如何用RS485进行通信幻灯片

    <两个FX5U系列PLC如何用RS485进行通信幻灯片>由会员分享,可在线阅读,更多相关<两个FX5U系列PLC如何用RS485进行通信幻灯片(17页珍藏版)>请在人人文库网上 ...

  3. 【正点原子FPGA连载】 第十七章 RS485串口通信实验 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  4. 【STC8A8K64S4A12开发板】—RS485总线通信

    版权声明:本文为博主原创文章,转载请附上原文出处链接. 文章目录 前言 一.硬件设计 1.开发板串口硬件电路 2.RS485电气性能 3.RS485通信协议 4.RS485电路设计 二.软件设计 1. ...

  5. Arduino与Proteus仿真实例-两个Arduino通过RS485协议通信仿真

    两个Arduino通过RS485协议通信仿真 1.RS485通信协议介绍 RS485 串行通信协议能够传输数字串行数据,最远距离可达 4000 米或 4 公里. 但通常在 1200 米之后,信号开始下 ...

  6. FlexRay汽车通信总线介绍及测试环境

    FlexRay汽车通信总线介绍及测试环境 原文链接:http://www.ulantec.cn/a/xinwen/xingyezixun/8.html 综述 FlexRay通信总线是由多个汽车制造商和 ...

  7. # 项目一:‍‍‍STM32+串口DMA+RS485+MODBUS+传感器实现SO2的测试

    ✨简介: 通过STM32控制传感器实现气体浓度的测量:RS485+MODBUS+串口DMA+定时器. 其中,USART2负责控制数据的发送和接受,USART3负责将询问帧.应答帧以及处理后数据打印出来 ...

  8. RS-485总线通信应用

    概述: 掌握总线基础知识 了解Modbus通讯协议基本知识 能够进行基于Modbue串行通信协议软件开发 能够搭建RS-485总线并编程实现组网通信 一.Modbus概述 1.什么是Modbus通信协 ...

  9. UART串口通信(回环测试)

    一 UART串口通信简介 UART(Universal Asynchronous Receiver-Transmitter)是采用异步串行通信方式的通用异步收发传输器,在发送数据时将并行数据转换为串行 ...

最新文章

  1. 关于wxpy,使用Python玩转微信的问题
  2. python 字典排序
  3. python零基础能学吗 知乎-Python零基础学习能学好吗?老男孩Python面授班
  4. 屏幕录像软件Bandicam和oCam
  5. SpringMVC-@RequestMapping的参数和用法
  6. 虚拟环境下对SQL Server安全性的考虑
  7. xx是一个类型 这在给定的上下文_#PaperCarrier | CoSeRNN :为你解释序列化与上下文在会话推荐中的作用...
  8. 威纶触摸屏EB8000编程软件V4.65.14 官方最新版
  9. python数据框列命名_python-按列名称处理pandas数据框值
  10. 微信小程序开发常用功能
  11. DevOps工具图谱分析(一)
  12. 算法竞赛命题指南(命题流程、Polygon的使用等)
  13. fantastic组需求分析
  14. 阿里云人脸对比API使用
  15. 在用argparse的add_argument添加运行参数时,(bool类型)参数不生效
  16. SpringBoot+Layui 打印PDF
  17. Lawnmower(洛谷 CF115B)
  18. 机器学习——基础概念
  19. vim配置参考备忘-------嵌入式
  20. Webpack配置区分开发环境和生产环境

热门文章

  1. Techo TVP物联网开发者峰会青润的总结
  2. 借助栈将一个带头节点的单链表倒置
  3. 计算机的未来无可限量英文,(整理笔记)Day86【BBC】无人驾驶5:无人驾驶已是大势所趋 The trend of driverless cars is unstoppable...
  4. 基于JAVA第二课堂选课系统计算机毕业设计源码+系统+lw文档+部署
  5. android判断一个控件是否获得光标,Android View获取焦点
  6. 26、python数据表透视分析、交叉分析、实现透视表功能
  7. 第一次面试(厦门西联电子)
  8. 二维点集求外轮廓Java_从二维点集重建平面形状-浅议凹包算法
  9. 零基础学习人工智能如何入门?
  10. 手机上PDF怎么编辑?这个办公APP必须装!