基于GD32F4XX串口环形缓冲区,北斗2.1协议,RD模块数据解析代码

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

以下是基于GD32F4XX串口,使用sscanf函数、strstrstrcmp,并结合环形缓冲区在中断中写数据,主函数处理发送接收的代码示例:

串口初始化与环形缓冲区定义

#include <gd32f4xx.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUF_SIZE 256 // 环形缓冲区大小

// 环形缓冲区结构体
typedef struct {
    uint8_t buffer[BUF_SIZE];
    uint16_t write_idx;
    uint16_t read_idx;
} RingBuffer;

RingBuffer rx_ring_buf;

// 初始化串口
void usart_init(uint32_t baudrate) {
    rcu_periph_clock_enable(RCU_USART0);
    rcu_periph_clock_enable(RCU_GPIOA);

    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    usart_deinit(USART0);
    usart_baudrate_config(USART0, baudrate);
    usart_word_length_config(USART0, USART_WL_8BIT);
    usart_stop_bit_config(USART0, USART_SBT_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

    // 开启中断
    usart_interrupt_enable(USART0, USART_INT_RBNE);
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_2);
    nvic_irq_enable(USART0_IRQn, 0, 0);
}

// 初始化环形缓冲区
void ring_buffer_init(RingBuffer *ring_buf) {
    ring_buf->write_idx = 0;
    ring_buf->read_idx = 0;
}

// 写入环形缓冲区
void ring_buffer_write(RingBuffer *ring_buf, uint8_t data) {
    ring_buf->buffer[ring_buf->write_idx] = data;
    ring_buf->write_idx = (ring_buf->write_idx + 1) % BUF_SIZE;
}

// 从环形缓冲区读取数据
uint8_t ring_buffer_read(RingBuffer *ring_buf) {
    uint8_t data = ring_buf->buffer[ring_buf->read_idx];
    ring_buf->read_idx = (ring_buf->read_idx + 1) % BUF_SIZE;
    return data;
}

// 环形缓冲区是否为空
uint8_t ring_buffer_is_empty(RingBuffer *ring_buf) {
    return (ring_buf->read_idx == ring_buf->write_idx);
}

串口接收中断处理

// 串口中断服务函数
void USART0_IRQHandler(void) {
    if (usart_flag_get(USART0, USART_FLAG_RBNE) != RESET) {
        uint8_t received_data = usart_data_receive(USART0);
        ring_buffer_write(&rx_ring_buf, received_data);
    }
}

北斗协议解析与发送

// 北斗协议解析函数
void parse_bds_sentence() {
    static char sentence_buf[256];
    static uint8_t sentence_idx = 0;
    char *token;

    while (!ring_buffer_is_empty(&rx_ring_buf)) {
        uint8_t data = ring_buffer_read(&rx_ring_buf);
        sentence_buf[sentence_idx++] = data;

        if (data == '\n' || sentence_idx >= sizeof(sentence_buf)) {
            sentence_buf[sentence_idx] = '\0';
            sentence_idx = 0;

            // 找到开头的$符号
            char *start_pos = strstr(sentence_buf, "$");
            if (start_pos) {
                // 提取指令关键字
                char command[16];
                sscanf(start_pos, "$%[^,*]", command);

                // 判断指令类型并进行解析
                if (strcmp(command, "BDICI") == 0) {
                    parse_bds_card(start_pos);
                } else if (strcmp(command, "BDBSI") == 0) {
                    parse_bds_signal(start_pos);
                } else if (strcmp(command, "BDDWR") == 0) {
                    parse_bds_position(start_pos);
                } else if (strcmp(command, "BDTXR") == 0) {
                    parse_bds_message(start_pos);
                }
            }
        }
    }
}

// 解析北斗卡号
void parse_bds_card(char *sentence) {
    char card_number[16];
    sscanf(sentence, "$BDICI,%[^,]", card_number);
    printf("Beidou Card Number: %s\n", card_number);
}

// 解析信号状态
void parse_bds_signal(char *sentence) {
    char signal_values[50];
    sscanf(sentence, "$BDBSI,%4s,%4s,%[^,*]", NULL, NULL, signal_values);
    printf("Signal Values: %s\n", signal_values);
}

// 解析定位信息
void parse_bds_position(char *sentence) {
    char time[16], latitude[16], longitude[16], altitude[16];
    sscanf(sentence, "$BDDWR,%*[^\r\n],%[^,],%[^,],%[^,],%[^,],%[^,],", time, latitude, longitude, altitude);
    printf("Position - Time: %s, Latitude: %s, Longitude: %s, Altitude: %s\n", time, latitude, longitude, altitude);
}

// 解析接收到的消息
void parse_bds_message(char *sentence) {
    char message_content[100];
    sscanf(sentence, "$BDTXR,%*[^,],%*[^,],%[^,]", message_content);
    printf("Received Message: %s\n", message_content);
}

主函数与发送功能

//送 发北斗指令
void send_bds_sentence(const char *sentence) {
    uint8_t len = strlen(sentence);
    for (uint8_t i = 0; i < len; i++) {
        usart_data_transmit(USART0, sentence[i]);
        while (usart_flag_get(USART0, USART_FLAG_TBE) == RESET);
    }
}

// 主函数
int main(void) {
    rcu_clock_prescale_config(RCU_APB2_RTCPrescale, 1);
    rcu_clock_configuration();
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_USART0);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_AF);

    // 初始化串口
    usart_init(9600);

    // 初始化环形缓冲区
    ring_buffer_init(&rx_ring_buf);

    while (1) {
        // 解析接收到的数据
        parse_bds_sentence();

        // 发送北斗指令示例
        static uint8_t send_flag = 0;
        send_flag++;
        if (send_flag > 100) { // 模拟发送频率控制
            send_flag = 0;
            // 发送读取卡号指令
            send_bds_sentence("$CCICA,0,00*7B\r\n");
            delay_1ms(100); // 简单延时函数
        }
    }
}

异或校验字节计算

// 计算异或校验字节
char calculate_checksum(const char *sentence) {
    char *start = strstr(sentence, "$") + 1;
    char *end = strstr(start, "*");
    if (!end) return 0x00;

    uint8_t checksum = 0;
    while (start < end) {
        checksum ^= *start++;
    }
    return checksum;
}

说明

  1. 本代码示例适用于GD32F4XX系列MCU,需要根据具体型号调整引脚和时钟配置。
  2. 环形缓冲区大小可以根据实际应用需求调整。
  3. sscanf函数用于解析北斗协议中的字段,strstrstrcmp用于指令识别。
  4. 在实际应用中,需要添加有效的延时函数delay_1ms和错误处理机制。
  5. 异或校验字节在发送指令时需要正确计算,可调用calculate_checksum函数。
  6. 根据需求,可以扩展解析和发送更多类型的北斗短报文协议指令。

网站公告

今日签到

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