STM32
直播中

贾小龙

7年用户 1572经验值
私信 关注
[问答]

如何使用RS485实现两个MCU之间的通信?

如何使用RS485实现两个MCU之间的通信

回帖(1)

王桂荣

2021-10-22 16:18:51
1. RS485基础知识

a. 485接口

485(一般称作RS485/EIA-485)是隶属于OSI模型物理层的电气特性规定为2线,半双工,多点通信的标准。它的电气特性和RS-232大不一样。用缆线两端的电压差值来表示传递信号。RS485仅仅规定了接受端和发送端的电气特性。它没有规定或推荐任何数据协议。
b. RS485的特点

① 接口电平低,不易损坏芯片。RS485的电气特性:逻辑“1”以两线间的电压差为+(2~6)V 表示;辑“0”以两线间的电压差为-(2~6)V表示。接口信号电平比RS232降低了,不易损坏 接口电路的芯片。
② 传输速率高。10米时,RS485的数据最高传输速率可达35Mbps,在1200m时,传输速度可达100Kbps。
③ 抗干扰能力强。RS485接口是采用平衡驱动器和差分接收器的组合,抗共模干 扰能力增强,即抗噪声干扰性好。
④传输距离远,支持节点多。RS485总线最长可以传输1200m以上(速率≤100Kbps)一般最大支持32个节点,如果使用特制的485芯片,可以达到128个或者256个节点,最大的可以支持到400个节点。
c. RS485的接口原理

RS485推荐使用在点对点网络中,线型,总线型,不能是星型,环型网络。理想情况下RS485需要2个匹配电阻,其阻值要求等于传输电缆的特性阻抗(一般为120Ω)。没有特性阻抗的话,当所有的设备都静止或者没有能量的时候就会产生噪声,而且线移需要双端的电压差。没有终接电阻的话,会使得较快速的发送端产生多个数据信号的边缘,导致数据传输出错。
485推荐的连接方式:





在上面的连接中,如果需要添加匹配电阻,我们一般在总线的起止端加入,也就是主机和设备4上面各加一个120Ω的匹配电阻。
SP3485内部结构图:





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





注意:
R55和R56是两个偏置电阻,用来保证总线空闲时,AB之间的电压差都会大约200mV,避免总线空闲时压差不定逻辑混乱。
2. RS485串口编程

a. 编程思路

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


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复用为USART1
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);    //GPIOA10复用为USART1


    //USART1端口配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;     //GPIOA9,GPIOA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                //复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;           //速度50MHz
    GPIO_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);  //使能串口1


    USART_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);
}
c. 工程说明

把程序分别下载到两个MCU后,一方按下发送键后,另一方按下接收键即可接收数据。
效果图




















现场调试图





说明:本次调试使用的是两个不同的工程,所以双方发送的数据和提示信息不一样。其实也可以两个MCU用同一个程序,其发送的数据就会一致。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分