RS-485总线是一种串行通信标准,支持多点通信,传输距离远、抗干扰能力强,常用于工业自动化和楼宇控制。我们在用GD32做项目的时候经常会碰到连接各类485传感器的情况。GD32和485连接一般需要3个脚,TX、RX、控制脚。以GD32的串口2为例,串口2接485电路。将串口2接收到的数据发送到串口1。串口1发送指令后串口2就会发送485指令,然后将串口2接收到的数据发送到串口1上,方便调试。

图中左边给串口1发送指令sh20test。右边可以显示串口2发送的数据。然后串口2设置了定时发送数据,串口1每条数据都可以收到。
以下是串口2的h文件
#ifndef USART2_H_
#define USART2_H_
#include “gd32f30x.h”
#define U2_485_DR GPIO_PIN_7
#define U2_485_Recedata gpio_bit_reset(GPIOB, GPIO_PIN_7);
#define U2_485_trandata gpio_bit_set(GPIOB, GPIO_PIN_7)
extern uint8_t sh20test_flag;
void init_usart2(uint32_t baudRate);
void usart2_send_byte(uint8_t byte);
void usart2_send_bytes(uint8_t *bytes,int len);
void usart2_send_string(char *string);
#endif
以下是串口2的C文件
#include "usart2.h"
#include "Sys_Config.h"
#if MD_USD_SALVE
#include "MDS_RTU_Serial.h"
#else
#include "MDM_RTU_Serial.h"
#include "MD_RTU_SysInterface.h"
#include "MDM_RTU_Fun.h"
#endif
extern uint8_t sh20test_flag=0;
#define USART2_RX_BUF_SIZE 128 // 串口2接收缓冲区大小
#define HEX_STR_BUF_SIZE 384 // 十六进制字符串缓冲区大小(每个字节转2个字符+空格)
uint8_t usart2_rx_buf[USART2_RX_BUF_SIZE]; // 串口2接收缓冲区
uint16_t usart2_rx_len = 0; // 串口2接收数据长度
uint8_t usart2_rx_complete = 0; // 串口2接收完成标志
void usart1_send_hex_data(uint8_t *data, uint16_t len);
void hex_to_string(uint8_t *hex_buf, uint16_t hex_len, char *str_buf);
void usart2_send_hex(uint8_t *hex_buf, uint16_t len);
//uint8_t send_hex_485_memsdata[] = {0x01,0x03,0x00,0x04,0x00,0x01,0xC5,0xCB}; //MEMS传感器指令
uint8_t send_hex_485_sh20tdata[] = {0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x60 ,0x0A}; //Sh20温度指令
void RS485RWConvInit(void)
{
//收发引脚配置
rcu_periph_clock_enable(RCU_GPIOB);
gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,U2_485_DR);
gpio_bit_reset(GPIOB,U2_485_DR);
}
//串口1配置
void init_usart2(uint32_t baudRate)
{
/* Enable GPIO clock */
rcu_periph_clock_enable(RCU_USART2);
rcu_periph_clock_enable(RCU_GPIOB);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_10);//
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ,GPIO_PIN_11);//
usart_baudrate_set(USART2,baudRate);
usart_word_length_set(USART2,USART_WL_8BIT);
usart_stop_bit_set(USART2,USART_STB_1BIT);
usart_parity_config(USART2,USART_PM_NONE);
usart_hardware_flow_cts_config(USART2,USART_CTS_DISABLE);
usart_hardware_flow_rts_config(USART2,USART_RTS_DISABLE);
usart_transmit_config(USART2,USART_TRANSMIT_ENABLE);
usart_receive_config(USART2,USART_RECEIVE_ENABLE);
/* Configure USARTz */
usart_interrupt_enable(USART2,USART_INT_RBNE);
nvic_irq_enable(USART2_IRQn,0,0);
usart_enable(USART2);
RS485RWConvInit();
}
void usart2_send_byte(uint8_t byte)
{
while(usart_flag_get(USART2,USART_FLAG_TC )==RESET);
usart_data_transmit(USART2,byte);
while(usart_flag_get(USART2,USART_FLAG_TC )==RESET);
}
void usart2_send_bytes(uint8_t *bytes,int len)
{
int i;
for(i=0;i<len;i++){
usart2_send_byte(bytes);
}
}
void usart2_send_string(char *string)
{
while(*string)
{
usart2_send_byte(*string++);
}
}
void usart2_485run()
{
if(sh20test_flag==1)
{
U2_485_trandata;
usart2_send_hex(send_hex_485_sh20tdata,8);
sh20test_flag=0;
U2_485_Recedata;
}
if(usart2_rx_complete)
{
//usart1_send_string("收到数据:");
// 将十六进制数据以字符串形式发送到串口1
usart1_send_hex_data(usart2_rx_buf, usart2_rx_len);
// 重置接收缓冲区和标志
memset(usart2_rx_buf, 0, USART2_RX_BUF_SIZE);
usart2_rx_len = 0;
usart2_rx_complete = 0;
usart_interrupt_enable(USART2, USART_INT_RBNE);
}
}
// 十六进制数据转字符串(如0x1A转为"1A ")
void hex_to_string(uint8_t *hex_buf, uint16_t hex_len, char *str_buf)
{
if(hex_buf == NULL || str_buf == NULL || hex_len == 0)
return;
const char hex_digits[] = "0123456789ABCDEF";
uint16_t str_idx = 0;
for(uint16_t i = 0; i < hex_len && str_idx < HEX_STR_BUF_SIZE - 3; i++)
{
// 高4位
str_buf[str_idx++] = hex_digits[(hex_buf >> 4) & 0x0F];
// 低4位
str_buf[str_idx++] = hex_digits[hex_buf & 0x0F];
// 空格分隔
str_buf[str_idx++] = ' ';
}
// 字符串结束符
str_buf[str_idx] = '\0';
}
// 将十六进制数据转换为字符串形式发送
void usart1_send_hex_data(uint8_t *data, uint16_t len)
{
if(data == NULL || len == 0)
return;
char hex_str[HEX_STR_BUF_SIZE];
hex_to_string(data, len, hex_str);
usart1_send_string(hex_str);
}
void usart2_send_hex(uint8_t *hex_buf, uint16_t len)
{
if (hex_buf == NULL || len == 0)
return; // 空指针或长度为0时直接返回,避免错误
for (uint16_t i = 0; i < len; i++)
{
// 等待发送缓冲区为空(TBE:Transmit Buffer Empty)
while (RESET == usart_flag_get(USART2, USART_FLAG_TBE));
// 发送1字节16进制数据(直接写入硬件发送寄存器)
usart_data_transmit(USART2, hex_buf);
}
// 可选:等待最后1字节发送完成(TC:Transmission Complete)
while (RESET == usart_flag_get(USART2, USART_FLAG_TC));
}
void USART2_IRQHandler(void)
{
uint8_t data;
// 接收非空中断
if(usart_interrupt_flag_get(USART2, USART_INT_FLAG_RBNE) != RESET)
{
// 读取接收的数据
data = usart_data_receive(USART2);
// 检查缓冲区是否已满
if(usart2_rx_len < USART2_RX_BUF_SIZE)
{
usart2_rx_buf[usart2_rx_len++] = data;
// 接收完成条件: 接收到10个字节或检测到0xAA作为结束符
// 可根据实际需求修改
if(usart2_rx_len >= 7 || data == 0xAA)
{
usart2_rx_complete = 1;
// 暂时关闭接收中断, 避免数据覆盖
usart_interrupt_disable(USART2, USART_INT_RBNE);
}
}
else
{
// 缓冲区已满, 置位完成标志
usart2_rx_complete = 1;
usart_interrupt_disable(USART2, USART_INT_RBNE);
}
usart_interrupt_flag_clear(USART2, USART_INT_FLAG_RBNE);
}
}
具体的实现可以看下下面的链接
https://download.csdn.net/download/c781918946/91888414
————————————————
版权声明:本文为CSDN博主「-黑起-」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/c781918946/article/details/151262652
|
|