GD32H759I-EVAL 通过USB转RS485,和RS485转TTL(MAX13487EESA自动换向)进行RS485通信
【代码】RS485通信(待改)
·
评估板:GD32H759I-EVAL
USB转RS485,和RS485转TTL:

与评估板连接:

那个RS485转TTL有四根杜邦线,UCC连板子3.3V,GND连板子GND。那个RXD焊在了PD9,TXD焊在了PD8。(PD8是485TX ,PD9是485RX,用的是MCU的USART2,通信模块支持的通信波特率最大115200)
工程文件:在评估板配套资料的19上直接修改main.c代码

跳线帽配置:
和之前CAN通信没有变,应该只要注意把JP68跳到USART 就行,不然没办法打印结果。
main.c代码:(在keil5中编译生成bin文件,使用评估板配套的GD-Link Programmer烧录(这两个别的帖子都有教程))
#include "gd32h7xx.h"
#include <stdio.h>
#include "gd32h759i_eval.h"
#include "systick.h"
#include "string.h"
/* RS485配置参数 */
#define RS485_USART USART2
#define RS485_BAUDRATE 115200 // 与COM6实际波特率一致
#define MAX_RX_BUFFER_SIZE 64 // 最大接收缓冲区大小
#define RESPONSE_TIMEOUT_MS 5000 // 等待电脑发送数据的超时时间
/* 全局变量 */
uint8_t rx_buffer[MAX_RX_BUFFER_SIZE]; // 接收缓冲区
volatile uint8_t rx_len = 0; // 接收数据长度
volatile FlagStatus rx_complete = RESET; // 接收完成标志
/* 函数声明 */
void rs485_gpio_config(void);
void rs485_usart_config(void);
void wait_for_pc_data(void);
void send_response_to_pc(void);
void cache_enable(void);
/* 使能Cache */
void cache_enable(void) {
SCB_EnableICache();
SCB_EnableDCache();
}
/* 配置RS485 GPIO引脚 */
void rs485_gpio_config(void) {
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_USART2);
/* PD8 (TX) 配置为复用功能 */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_8); // 确认AF值(参考数据手册)
/* PD9 (RX) 配置为复用功能 */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_9); // 确认AF值
}
/* 配置USART2(新增IDLE中断) */
void rs485_usart_config(void) {
usart_deinit(USART2);
/* 基本参数配置 */
usart_baudrate_set(USART2, RS485_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_receive_config(USART2, USART_RECEIVE_ENABLE);
usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);
/* 使能接收中断和IDLE中断 */
usart_interrupt_enable(USART2, USART_INT_RBNE);
usart_interrupt_enable(USART2, USART_INT_IDLE); // 新增IDLE中断
nvic_irq_enable(USART2_IRQn, 1U, 0U);
usart_enable(USART2);
}
/* 等待电脑发送数据 */
void wait_for_pc_data(void) {
printf("\n[评估板] 等待电脑发送数据(%d秒超时)...\n", RESPONSE_TIMEOUT_MS/1000);
printf("[操作指引] 请在电脑串口助手中发送任意十六进制数据(最大%d字节)\n", MAX_RX_BUFFER_SIZE);
// 重置接收状态
rx_len = 0;
rx_complete = RESET;
uint32_t timeout = 0;
// 等待接收数据或超时
while (!rx_complete && timeout < RESPONSE_TIMEOUT_MS) {
delay_1ms(1);
timeout++;
}
if (rx_complete) {
printf("[评估板] ✅ 成功接收 %d 字节数据:", rx_len);
for (uint8_t i = 0; i < rx_len; i++) {
printf("0x%02X ", rx_buffer[i]);
}
printf("\n");
} else {
printf("[评估板] ❌ 接收超时!未收到电脑数据\n");
}
}
/* USART2接收中断 */
void USART2_IRQHandler(void) {
if (usart_interrupt_flag_get(USART2, USART_INT_FLAG_RBNE) == SET) {
// 接收数据字节
uint8_t data = usart_data_receive(USART2);
if (rx_len < MAX_RX_BUFFER_SIZE) {
rx_buffer[rx_len++] = data;
}
usart_interrupt_flag_clear(USART2, USART_INT_FLAG_RBNE);
}
else if (usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE) == SET) {
// IDLE中断:表示一帧数据接收完毕
usart_interrupt_flag_clear(USART2, USART_INT_FLAG_IDLE); // 清除IDLE标志
uint8_t temp = usart_data_receive(USART2); // 读取DR寄存器以清除IDLE条件
rx_complete = SET; // 标记接收完成
}
}
/* 将接收到的数据通过RS485返回给电脑 */
void send_response_to_pc(void) {
if (!rx_complete || rx_len == 0) return;
printf("[评估板] 正在通过RS485将数据返回给电脑...\n");
// 通过RS485(USART2)发送数据
for (uint8_t i = 0; i < rx_len; i++) {
usart_data_transmit(RS485_USART, rx_buffer[i]);
while (usart_flag_get(RS485_USART, USART_FLAG_TBE) == RESET); // 等待发送缓冲区为空
}
while (usart_flag_get(RS485_USART, USART_FLAG_TC) == RESET); // 等待所有数据发送完成
printf("[评估板] ✅ 数据已通过RS485成功返回\n");
}
int main(void) {
/* 系统初始化 */
cache_enable();
systick_config();
gd_eval_com_init(EVAL_COM); // 调试串口
/* 初始化RS485 */
rs485_gpio_config();
rs485_usart_config();
printf("===== RS485通信测试(电脑→评估板→电脑)=====\n");
printf("硬件连接:电脑 → USB转RS485 → TTL转RS485 → 评估板\n");
printf("波特率:%d,数据格式:8N1\n", RS485_BAUDRATE);
/* 主循环:等待电脑数据 → 通过RS485返回相同数据 */
while (1) {
wait_for_pc_data(); // 等待电脑发送数据
send_response_to_pc(); // 通过RS485将数据返回给电脑
printf("\n----------------------------------------\n");
printf("等待下一次数据...\n");
}
}
/* 重定向printf到调试串口 */
int fputc(int ch, FILE *f) {
usart_data_transmit(EVAL_COM, (uint8_t)ch);
while (usart_flag_get(EVAL_COM, USART_FLAG_TBE) == RESET);
return ch;
}
串口调试助手:微软那个,百度一搜微软调试助手就能下载 。
打开两个,一个发数据,一个收数据。

测极限速率
#include "gd32h7xx.h"
#include <stdio.h>
#include <stdbool.h>
#include "gd32h759i_eval.h"
#include "systick.h"
#include "string.h"
/* RS485配置参数 */
#define RS485_USART USART2
#define RS485_BAUDRATE 115200 // 波特率
#define MAX_RX_BUFFER_SIZE 256 // 最大接收缓冲区大小
#define TEST_TIMEOUT_MS 3000 // 无数据超时时间
#define MAX_FRAME_SAMPLES 100 // 最大帧采样数
/* 全局变量 */
uint8_t rx_buffer[MAX_RX_BUFFER_SIZE]; // 接收缓冲区
volatile uint8_t rx_len = 0; // 接收数据长度
volatile FlagStatus rx_complete = RESET;// 接收完成标志
volatile FlagStatus tx_complete = SET; // 发送完成标志
/* 测试统计变量 */
// 接收统计
volatile uint32_t rx_total_bytes = 0; // 总接收字节数
volatile uint32_t rx_frame_count = 0; // 接收帧总数
volatile uint32_t rx_frame_intervals[MAX_FRAME_SAMPLES]; // 接收帧间隔
volatile uint8_t rx_interval_idx = 0; // 接收间隔索引
// 发送统计
volatile uint32_t tx_total_bytes = 0; // 总发送字节数
volatile uint32_t tx_frame_count = 0; // 发送帧总数
// 时间戳
volatile uint32_t test_start_time = 0; // 测试开始时间
volatile uint32_t last_rx_time = 0; // 最后接收时间
volatile uint32_t last_tx_time = 0; // 最后发送时间
volatile bool test_in_progress = false; // 测试状态
/* 函数声明 */
void rs485_gpio_config(void);
void rs485_usart_config(void);
void send_response(void); // 发送响应数据
void cache_enable(void);
uint32_t get_tick_count(void);
void print_test_results(void);
/* 使能Cache */
void cache_enable(void) {
SCB_EnableICache();
SCB_EnableDCache();
}
/* 配置RS485 GPIO引脚 */
void rs485_gpio_config(void) {
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_USART2);
/* PD8 (TX) 配置为复用功能 */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_8);
/* PD9 (RX) 配置为复用功能 */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_9);
}
/* 配置USART2 */
void rs485_usart_config(void) {
usart_deinit(USART2);
/* 基本参数配置 */
usart_baudrate_set(USART2, RS485_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_receive_config(USART2, USART_RECEIVE_ENABLE);
usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);
/* 使能接收中断和IDLE中断 */
usart_interrupt_enable(USART2, USART_INT_RBNE);
usart_interrupt_enable(USART2, USART_INT_IDLE);
nvic_irq_enable(USART2_IRQn, 1U, 0U);
usart_enable(USART2);
}
/* 发送响应数据 */
void send_response(void) {
if (rx_len == 0) return;
tx_complete = RESET;
uint32_t current_time = get_tick_count();
// 通过USART2发送数据
for (uint8_t i = 0; i < rx_len; i++) {
usart_data_transmit(RS485_USART, rx_buffer[i]);
while (usart_flag_get(RS485_USART, USART_FLAG_TBE) == RESET);
}
while (usart_flag_get(RS485_USART, USART_FLAG_TC) == RESET);
// 更新发送统计
tx_frame_count++;
tx_total_bytes += rx_len;
last_tx_time = current_time;
tx_complete = SET;
}
/* USART2接收中断 */
void USART2_IRQHandler(void) {
static uint32_t last_idle_time = 0;
uint32_t current_time = get_tick_count();
if (usart_interrupt_flag_get(USART2, USART_INT_FLAG_RBNE) == SET) {
// 接收数据字节
uint8_t data = usart_data_receive(USART2);
// 长度校验:固定8字节,超过则丢弃
if (rx_len < 8) {
rx_buffer[rx_len++] = data;
// 当收到第8个字节时,立即标记接收完成
if (rx_len == 8) {
// 记录接收帧间隔(当前时间 - 上一次接收时间)
if (rx_frame_count > 0 && rx_interval_idx < MAX_FRAME_SAMPLES) {
rx_frame_intervals[rx_interval_idx++] = current_time - last_idle_time;
}
if (!test_in_progress) {
// 开始新测试
test_in_progress = true;
test_start_time = current_time;
last_rx_time = current_time;
last_tx_time = current_time;
rx_frame_count = 1;
rx_total_bytes = rx_len;
} else {
rx_frame_count++;
rx_total_bytes += rx_len;
}
last_idle_time = current_time;
last_rx_time = current_time;
rx_complete = SET;
}
}
usart_interrupt_flag_clear(USART2, USART_INT_FLAG_RBNE);
}
else if (usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE) == SET) {
// IDLE中断:处理异常情况
usart_interrupt_flag_clear(USART2, USART_INT_FLAG_IDLE);
uint8_t temp = usart_data_receive(USART2);
// 仅当数据长度为8时认为有效
if (rx_len == 8) {
// 记录接收帧间隔
if (rx_frame_count > 0 && rx_interval_idx < MAX_FRAME_SAMPLES) {
rx_frame_intervals[rx_interval_idx++] = current_time - last_idle_time;
}
if (!test_in_progress) {
test_in_progress = true;
test_start_time = current_time;
last_rx_time = current_time;
last_tx_time = current_time;
rx_frame_count = 1;
rx_total_bytes = rx_len;
} else {
rx_frame_count++;
rx_total_bytes += rx_len;
}
last_idle_time = current_time;
last_rx_time = current_time;
rx_complete = SET;
} else {
// 丢弃不完整帧
printf("警告: 收到不完整帧,长度=%d (期望8字节)\n", rx_len);
rx_len = 0;
}
}
}
/* 打印测试结果(统计最大接收速率) */
void print_test_results(void) {
uint32_t total_time_ms = last_rx_time - test_start_time;
if (total_time_ms == 0) total_time_ms = 1; // 避免除零
float total_time_sec = total_time_ms / 1000.0f;
// 计算最大接收速率(基于最小帧间隔)
float rx_max_rate = 0.0f;
for (uint8_t i = 0; i < rx_interval_idx; i++) {
if (rx_frame_intervals[i] > 0) {
float rate = (float)8 * 1000.0f / rx_frame_intervals[i]; // 8字节/帧
if (rate > rx_max_rate) rx_max_rate = rate;
}
}
// 计算平均接收速率
float rx_avg_rate = rx_total_bytes / total_time_sec;
// 输出接收统计结果
printf("\n[测试结束] 接收统计结果:\n");
printf(" - 总测试时间:%.2f 秒\n", total_time_sec);
printf(" - 总接收帧数:%lu\n", rx_frame_count);
printf(" - 总接收字节数:%lu\n", rx_total_bytes);
printf(" - 平均接收速率:%.2f 字节/秒\n", rx_avg_rate);
printf(" - 最大接收速率:%.2f 字节/秒\n", rx_max_rate);
printf(" - 测试波特率:%d\n", RS485_BAUDRATE);
printf("----------------------------------------\n");
printf("等待下一次测试...\n\n");
}
int main(void) {
/* 系统初始化 */
cache_enable();
systick_config();
gd_eval_com_init(EVAL_COM); // 调试串口
/* 初始化RS485 */
rs485_gpio_config();
rs485_usart_config();
printf("===== RS485接收速率测试初始化完成 =====\n");
printf("请通过串口发送8字节数据,设备将回传并统计接收性能\n\n");
/* 主循环 */
while (1) {
// 接收完成后立即发送响应
if (rx_complete) {
// 打印接收到的8字节数据
printf("收到有效帧: ");
for (int i = 0; i < rx_len; i++) {
printf("%02X ", rx_buffer[i]);
}
printf("\n");
send_response(); // 回传数据
rx_complete = RESET;
rx_len = 0; // 清空接收缓冲区
}
// 超时判断
if (test_in_progress && (get_tick_count() - last_rx_time > TEST_TIMEOUT_MS)) {
print_test_results();
// 重置测试参数
test_in_progress = false;
rx_total_bytes = 0;
rx_frame_count = 0;
rx_interval_idx = 0;
memset((void*)rx_frame_intervals, 0, sizeof(rx_frame_intervals));
tx_total_bytes = 0;
tx_frame_count = 0;
}
delay_1ms(10);
}
}
/* 获取系统滴答时间 */
uint32_t get_tick_count(void) {
static uint32_t tick_count = 0;
tick_count++;
return tick_count;
}
/* 重定向printf到调试串口 */
int fputc(int ch, FILE *f) {
usart_data_transmit(EVAL_COM, (uint8_t)ch);
while (usart_flag_get(EVAL_COM, USART_FLAG_TBE) == RESET);
return ch;
}

完整工程文件:时叶彤/MyTest - Gitee.com
更多推荐



所有评论(0)