STM32实现RS485通讯

发布于:2025-05-20 ⋅ 阅读:(20) ⋅ 点赞:(0)

先展示一下我的成果图:

数据收发截图:有时会有点错误,所以说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.


网站公告

今日签到

点亮在社区的每一天
去签到