欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

STM32实现RS485半双工通信方法指南

最编程 2024-07-20 11:37:48
...

典型的串口通信标准有 RS232 和 RS485,RS232 是全双工点对点的通信,而 RS485 是半双工通信(2 线制),可以一点对多点进行组网,而且 RS485 是用缆 线两端的电压差值来表示传递信号,这与 RS232 电气特性大不一样。RS485 仅仅 规定了接受端和发送端的电气特性,并没有规定或推荐任何数据协议,因此 RS485 的协议层可以和 RS232 一样。


连接方式

发送数据时,串口控制器的 TX 信号经过 收发器转换成差分信号传输到总线上,而接收数据时,收发器把总线上的差分信 号转化成 TTL 信号通过 RX 引脚传输到串口控制器中


SP3485

SP3485是板子上的收发器。对收发器,RO是接收输出端,DI是发送数据输入端, RE 是接收使能信号(低电平有效), DE 是发送使能信 号(高电平有效)

开发板把RE和DE共同连接到了PG3,用高低电平来表示是输出有效还是接收有效。


本次列程是用USART2

rs485.c

#include "rs485.h"
#include "SysTick.h"

/*******************************************************************************
* 函 数 名         : RS485_Init
* 函数功能         : USART2初始化函数
* 输    入         : bound:波特率
* 输    出         : 无
*******************************************************************************/  
void RS485_Init(u32 bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG|RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA\G时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
    
    /*  配置GPIO的模式和IO口 */
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; //TX-485    //串口输出PA2
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;         //复用推挽输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 
    GPIO_Init(GPIOA,&GPIO_InitStructure);       /* 初始化串口输入IO */
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3; //RX-485       //串口输入PA3
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;     //模拟输入
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3; //CS-485
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;     //推挽输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOG,&GPIO_InitStructure);
    
    //USART2 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    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); //初始化串口2
    
    USART_Cmd(USART2, ENABLE);  //使能串口 2
    
    USART_ClearFlag(USART2, USART_FLAG_TC);
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启接受中断

    //Usart2 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;       //子优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
    
    RS485_TX_EN=0;              //默认为接收模式   
}

/*******************************************************************************
* 函 数 名         : USART2_IRQHandler
* 函数功能         : USART2中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/ 
void USART2_IRQHandler(void)
{
    u8 res;     
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据
    {       
        res =USART_ReceiveData(USART2);//;读取接收到的数据USART2->DR
        RS485_TX_EN=1; //发送模式,RS232是全双工发送读取可同时,不需要这样转换模式分时
        delay_ms(1);
        USART_SendData(USART2,res);
        while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=1);
        delay_ms(2);
        RS485_TX_EN=0;//接受模式
    }  
    USART_ClearFlag(USART2,USART_FLAG_TC);  
}   


rs485.h

#ifndef _rs485_H
#define _rs485_H

#include "system.h"


//模式控制
#define RS485_TX_EN     PGout(3)    //485模式控制.0,接收;1,发送.
                                                         
void RS485_Init(u32 bound);


#endif

main.c



#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "rs485.h"


/*******************************************************************************
* 函 数 名         : main
* 函数功能         : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
int main()
{
    u8 i=0;

    SysTick_Init(72);
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
    LED_Init();
    USART1_Init(9600);
    RS485_Init(9600);
    
    while(1)
    {
        i++;
        if(i%20==0)
        {
            led1=!led1;
        }
        
        delay_ms(10);
    }
}