近期需要在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)硬件电路
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_USART3RCC_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)实验结果