RS485通信应注意的几点细节
1. 关于控制位问题
#define TX_485GPIO_SetBits(GPIOF,GPIO_Pin_11)
#define RX_485GPIO_ResetBits(GPIOF,GPIO_Pin_11)
是给控制位高电平为发送模式还是给低电平为发送模式,看电路原理图的时候一定要看清楚。改变控制位时应该有一定的时间延迟。
2. 关于连续发送或接受一个字节或多个字节时问题
关于发送一个字节很简单:
void USART3_SendByte(unsigned char senddata)
{
Delay();
USART_SendData(USART3,(uint8_t)senddata);
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)== RESET);
RX_485;
Delay();
}
开始我这么想的,连续发送多个字节和发送一个字节不都是一样的?就是多调用几次这个函数不就行那,可是,我调试了一个下午,连续调用这个函数发送一组命令过去,就是没收到接受设备的发聩,用485转232将命令发送到pc的串口助手上,没错误。后来我想到既然都是发送字节,干脆将TX_485和RX_485放到函数外面来,变成如下结构
TX_485;
---
---
USART3_SendByte();
RX_485;
Delay();
然后将发送函数改成
void USART3_SendByte(unsigned charsenddata)
{
USART_SendData(USART3,(uint8_t)senddata);
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)== RESET);
}
这样就收到了接受命令设备发回来的设备,通过这个现象是不是当发送大于一个字节的的数据时候,应该是不能多次改变485的控制位的,这样得到的将不会是一个整体的命令序列。接受数据也是一样的,当接受的数据大于一个字节的时候,只需要将485控制位设置为接受一次就行了。不然会出现没发送一组命令数据,却只会收到一个字节,因为在改变控制位的时候后面的数据还没来得及接受就丢弃了。调试了一天终于将485通信调试通了,唉,主要是第一次接触485,里面出现很多问题都不知道为什么,在网络上也很少说到这些应该注意的细节。因此将它记录下来。
附串口初始化函数:
void bsp_InitUart(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
USART_InitTypeDefUSART_InitStructure;
NVIC_InitTypeDefNVIC_InitStructure;
// USART_ClockInitTypeDefUSART_ClockInitStructure;
/*第1步:打开GPIO和USART部件的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOF| RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
/*第2步:将USART Tx的GPIO配置为推挽复用模式 */
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
/*第3步:将USART Rx的GPIO配置为浮空输入模式
由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
*/
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU;
GPIO_Init(GPIOB,&GPIO_InitStructure);
/* 第3步已经做了,因此这步可以不做
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
*/
//GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOF,&GPIO_InitStructure);
/*第4步:配置USART参数
- 波特率 = 9600 baud
- 数据长度 = 8 Bits
- 1个停止位
- 无校验
- 禁止硬件流控(即禁止RTS和CTS)
- 使能接收和发送
*/
USART_InitStructure.USART_BaudRate= 9600;
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(USART3,&USART_InitStructure);
/*第5步:使能 USART, 配置完毕 */
/*
CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
如下语句解决第1个字节无法正确发送出去的问题:
清发送完成标志,Transmission Complete flag*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel= USART3_IRQn;
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init(&NVIC_InitStructure);
//
USART_Cmd(USART3,ENABLE);
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
USART_ClearFlag(USART3,USART_FLAG_TC);
}