STM32实现RS485通讯_stm32 485收发数据
先展示一下我的成果图:
数据收发截图:有时会有点错误,所以说485要加个CRC校验才是最稳妥的方案,校验失败就重发。
再来看看RS485转换芯片,感觉大部分的芯片都是一样的,都是互相抄袭的结果吧!
这个芯片按照下面的接线方式就能用了:
线路连接好后,剩下的就是软件方面的事情了;直接贴代码吧,RS485.c文件:
#include \"RS485.h\"void RS485_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 9600;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_InitStruct.USART_Parity = USART_Parity_No;USART_InitStruct.USART_StopBits = USART_StopBits_1;USART_InitStruct.USART_WordLength = USART_WordLength_8b;USART_Init(USART2,&USART_InitStruct);USART_Cmd(USART2,ENABLE);USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStruct);RS485_TX_EN=0;}u8 RS485_RX_Buf[64];u8 RS485_RX_Len=0;void USART2_IRQHandler(void){u8 res=0;if(USART_GetITStatus(USART2,USART_IT_RXNE)){if(RS485_RX_Len < 64){res = USART_ReceiveData(USART2);RS485_RX_Buf[RS485_RX_Len] = res;RS485_RX_Len++;}USART_ClearITPendingBit(USART2,USART_IT_RXNE);}}/*RS485发送数据的函数。 参数一:要发送的数组首地址。 参数二:要发送的数组中字节的个数*/void RS485_Send_Data(u8 *buf, u8 len){u8 i=0;RS485_TX_EN=1; //首先要使能485芯片,转为发送模式for(i=0; i<len; i++){USART_SendData(USART2,buf[i]); while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET); //等待每个字节发送完成}RS485_RX_Len=0; // 将接收的字节数置零,等待下次接收RS485_TX_EN=0; // 485芯片切换置接收使能}/*RS485接收数据的函数。参数一:接收的数据要保存的数组首地址。 参数二:接受了多少个字节的数量*/void RS485_Receive_Data(u8 *buf,u8 *len){u8 rxlen = RS485_RX_Len; //首先把中断中接收的字节数赋值给rxlen。u8 i=0;Delay_ms(10); //等待10毫秒,程序在此耗时但是接收仍会产生中断,如果正在接收那字节数在不断增加if(rxlen == RS485_RX_Len && rxlen) //如果字节数和中断中的字节数相同,且字节数不是0,那证明接收完成了{for(i=0;i<rxlen;i++) //把中断中接收的字节转存到新的数组中{buf[i]=RS485_RX_Buf[i];}*len = rxlen+1; //把接收的字节数转存到新的变量中,并把中断中的字节数置0,准备下次接收RS485_RX_Len = 0;}}
RS485.h文件:
#ifndef _RS485_H#define _RS485_H#include \"system.h\"#include \"Delay.h\"#define RS485_TX_EN PBout(12)extern u8 RS485_RX_Buf[];extern u8 RS485_RX_Len;void RS485_Init(void);void RS485_Send_Data(u8 *buf, u8 len);void RS485_Receive_Data(u8 *buf,u8 *len);#endif
主函数:
#include \"led.h\"#include \"Serail1.h\"#include \"OLED.h\"#include \"RS485.h\"u8 dat[5] = {6,7,8,9,10};u8 len=0;int main(void){Serail1_Init();Serail2_Init();led_Init();OLED_Init();RS485_Init();RS485_Send_Data(dat,6);while(1){RS485_Receive_Data(dat,&len);if(len){led1 = ~led1;RS485_Send_Data(dat,len);}OLED_ShowHexNum(1,1,dat[0],2);OLED_ShowHexNum(1,4,dat[1],2);OLED_ShowHexNum(1,7,dat[2],2);OLED_ShowHexNum(1,10,dat[3],2);OLED_ShowHexNum(1,13,dat[4],2);len = 0;}}
工程编译后,用串口调试助手通过232转485转换器像SP485芯片的AB线发送数据就能触发程序像串口调试助手返回发送的数据了。软件部分和串口的收发是一样的,没有什么区别,唯一的区别就是要有一个发送接收的转换,我用的是PB12口,使用的是位带操作,发送时置1,平常时置0.