先展示一下我的成果图:
数据收发截图:有时会有点错误,所以说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.