评估板: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

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐