基于STM32实现 Modbus协议调试笔记 --利用485通信实现单个字符的接收与发送

近期需要在STM32上实现Modbus协议的传输,传输的具体接口使用的是RS485。
接下来将自己的调试过程记录如下,首先关于RS-485的介绍如下:
1)何为RS485通信
RS-485通信属于半双工通信,相较于RS232,RS-485通信接收和发送需要额外增加一个控制引脚。
RS-485采用平衡发送和差分接收,因此具有抑制共模干扰的能力。RS-485采用半双工工作方式,任何时候只能有一点处于发送状态,因此,发送电路须由使能信号加以控制。RS-485用于多点互连时非常方便,可以省掉许多信号线。
应用RS-485可以联网构成分布式系统,其允许最多并联32台驱动器和32台接收器。在RS232或RS485设备联成的设备网中,如果设备数量超过2台,就必须使用RS485做通讯介质,RS485网的设备间要想互通信息只有通过“主(Master)”设备中转才能实现,这个主设备通常是PC,而这种设备网中只允许存在一个主设备,其余全部是从(Slave)设备。
RS-485 接口具有良好的抗噪声干扰性、长的传输距离和多站能力等。上述优点就使其成为首选的串行接口。因为工业RS485 通讯接口组成的半双工网络,一般只需二根连线,所以工业RS485 通讯接口均采用屏蔽双绞线传输。
2)硬件电路

实验用485通信电路
3)实验内容
通过电脑上位机向STM32发送一个字符,STM32接收到数据,并回传到电脑上位机
4)源代码
所包含的核心文件主要RS485.C RS485.H main.c
4-1:宏定义相应的端口
RS485.H
端口宏定义
#define RS485_TX_Pin GPIO_Pin_11
#define RS485_TX_Port GPIOB

#define RS485_RX_Pin GPIO_Pin_10
#define RS485_RX_Port GPIOB

#define RS485_EN_Pin GPIO_Pin_12
#define RS485_EN_Port GPIOB
/控制端电平定义/
#define RS485_EN(x) x ? GPIO_SetBits(RS485_EN_Port,RS485_EN_Pin):GPIO_ResetBits(RS485_EN_Port,RS485_EN_Pin)

4-2:所用到的IO配置函数

RS485.C
/**

  • 函数功能: 初始化配置485通讯GPIO引脚

  • 输入参数: 无

  • 返 回 值: 无

  • 说 明:无
    */
    void RS485_GPIO_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    /初始化RCC_485_Pin 485控制引脚端口时钟/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//RCC_APB2Periph_GPIOB
    /初始化RCC_485_RTX 485串口通讯功能端口时钟/
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//RCC_APB1Periph_USART3

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//端口复用功能开启
    /初始化控制端口/
    GPIO_InitStructure.GPIO_Pin=RS485_EN_Pin;//EN_485
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
    GPIO_Init(RS485_EN_Port,&GPIO_InitStructure);
    /初始化TX端口/
    GPIO_InitStructure.GPIO_Pin=RS485_TX_Pin;//TX
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(RS485_TX_Port,&GPIO_InitStructure);
    /初始化RX端口/
    GPIO_InitStructure.GPIO_Pin=RS485_RX_Pin;//对应于STM32的USART3_TX
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//推挽复用输出
    GPIO_Init(RS485_RX_Port,&GPIO_InitStructure);
    }

/**

  • 函数功能: 初始化配置485通讯功能

  • 输入参数: USART_TypeDef* USARTx:USART功能通道;uint32_t BaudRate:波特率

  • 返 回 值: 无

  • 说 明:无
    */
    void USART_Configuration(uint32_t BaudRate)
    {
    USART_InitTypeDef USART_InitStructure;

    RS485_GPIO_Configuration();//初始化RS485 GPIO引脚

    USART_InitStructure.USART_BaudRate=BaudRate;//系统USART波特率设置
    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_Tx|USART_Mode_Rx;//发送和接受均使能

    USART_Init(RS485,&USART_InitStructure);
    USART_ITConfig(RS485,USART_IT_RXNE,ENABLE);
    USART_Cmd(RS485,ENABLE);
    USART_ClearFlag(RS485,USART_FLAG_TC);//清空发送成功标志位
    RS485_EN(0);//初始化为接收状态
    RS485_TX_EN=0;//接收状态
    }
    4-3:接收中断
    void USART3_IRQHandler(void)
    {
    u8 temp=0;
    if(USART_GetITStatus(RS485,USART_IT_RXNE)!=RESET)//检查USART3的接收中断是否被触发
    {
    temp=USART_ReceiveData(RS485);//将USART中接收到的数据保存到临时变量temp中

    RS485_EN(1);//初始化为发送状态
    delay_ms(1);
    USART_SendData(RS485,temp);
    while(USART_GetFlagStatus(RS485, USART_FLAG_TXE)==RESET);
    delay_ms(2);				
    RS485_EN(0);//初始化为发送状态	 
    

    }
    }
    4-4:主函数,初始化完成后,则等待中断执行
    int main()
    {

    SystemInit();//72m
    USART_Configuration(9600);//初始化USART 9600 N 8 1
    NVIC_RS485_Configuration();
    USART_232_Configuration(9600);
    NVIC_RS232_Configuration();
    while(1)
    {

    }
    }
    5)实验结果
    实验结果

发布了9 篇原创文章 · 获赞 5 · 访问量 3005

猜你喜欢

转载自blog.csdn.net/WHL_YSU/article/details/87864362