[MCU] 兆易GD32H759I-EVAL UART

御坂10032号   2024-5-26 01:03 楼主

题外话

 

原本今天的帖子是打算写ADC功能的。但是想了下,写ADC功能的话没有串口或者屏幕的话不是很好能够观察到现象。所以今天的内容是关于串口。

不知道官方是出于什么考虑,在MCU附近针孔预留的都是2.0MM的。很不方便。我已经下单买了一些2.0MM的排母。和一些排针。突然意识到这个杜邦线也必须要使用2.0MM的。不然根本插不到排母里面去。 

 

本文参考如下资料:

1- GD32H759I-EVAL-V1.3.pdf

2- GD32H759I-EVAL评估板使用指南_Rev1.2.pdf

3- GD32H737_757_759_User_Manual_Rev1.3_CN.pdf

4- GD32H759xx_Datasheet_Rev1.5.pdf

 

正文

 

这款GD32H759IMK6 一共支持8个串口同时工作。这款芯片非常强大。引脚数太多了。如果需要详细的引脚定义的话,请查看 GD32H759xx_Datasheet_Rev1.5.pdf

 

image.png  

本文主要实现用户手册的4.19章已经引出为Mini-usb接口的USART0

 

image.png  

 

数据手册PIN定义如下:

 

image.png  

 

接下来开始编码,复制上一章的工程,重命名为03-UART

#include "gd32h7xx.h"
#include "systick.h"
static void cache_enable(void)
{
    /* Enable I-Cache */
    SCB_EnableICache();

    /* Enable D-Cache */
    SCB_EnableDCache();
}




int main(void)
{
    /* Enable the CPU Cache */
    cache_enable();

    /* Configure systick */
    systick_config();

		
    while(1) {
       
    }
}

 

下面是借助ChatGPT翻译的关于串口function 定义的中文注释

 

/* 函数声明 */
/* 初始化函数 */
/* 复位 USART */
void usart_deinit(uint32_t usart_periph);
/* 配置 USART 波特率值 */
void usart_baudrate_set(uint32_t usart_periph, uint32_t baudval);
/* 配置 USART 校验功能 */
void usart_parity_config(uint32_t usart_periph, uint32_t paritycfg);
/* 配置 USART 字长 */
void usart_word_length_set(uint32_t usart_periph, uint32_t wlen);
/* 配置 USART 停止位长度 */
void usart_stop_bit_set(uint32_t usart_periph, uint32_t stblen);
/* 使能 USART */
void usart_enable(uint32_t usart_periph);
/* 禁用 USART */
void usart_disable(uint32_t usart_periph);
/* 配置 USART 发送器 */
void usart_transmit_config(uint32_t usart_periph, uint32_t txconfig);
/* 配置 USART 接收器 */
void usart_receive_config(uint32_t usart_periph, uint32_t rxconfig);

/* USART 正常模式通信 */
/* 数据按 LSB/MSB 顺序传输/接收 */
void usart_data_first_config(uint32_t usart_periph, uint32_t msbf);
/* USART 反转配置 */
void usart_invert_config(uint32_t usart_periph, usart_invert_enum invertpara);
/* 使能 USART 过载功能 */
void usart_overrun_enable(uint32_t usart_periph);
/* 禁用 USART 过载功能 */
void usart_overrun_disable(uint32_t usart_periph);
/* 配置 USART 过采样模式 */
void usart_oversample_config(uint32_t usart_periph, uint32_t oversamp);
/* 配置采样位方法 */
void usart_sample_bit_config(uint32_t usart_periph, uint32_t osb);
/* 使能接收超时 */
void usart_receiver_timeout_enable(uint32_t usart_periph);
/* 禁用接收超时 */
void usart_receiver_timeout_disable(uint32_t usart_periph);
/* 配置接收超时阈值 */
void usart_receiver_timeout_threshold_config(uint32_t usart_periph, uint32_t rtimeout);
/* USART 发送数据函数 */
void usart_data_transmit(uint32_t usart_periph, uint16_t data);
/* USART 接收数据函数 */
uint16_t usart_data_receive(uint32_t usart_periph);
/* 使能 USART 命令 */
void usart_command_enable(uint32_t usart_periph, uint32_t cmdtype);

/* 多处理器通信 */
/* 使能地址 0 匹配模式 */
void usart_address_0_match_mode_enable(uint32_t usart_periph);
/* 禁用地址 0 匹配模式 */
void usart_address_0_match_mode_disable(uint32_t usart_periph);
/* 使能地址 1 匹配模式 */
void usart_address_1_match_mode_enable(uint32_t usart_periph);
/* 禁用地址 1 匹配模式 */
void usart_address_1_match_mode_disable(uint32_t usart_periph);
/* 配置 USART 地址 0 */
void usart_address_0_config(uint32_t usart_periph, uint8_t addr);
/* 配置 USART 地址 1 */
void usart_address_1_config(uint32_t usart_periph, uint8_t addr);
/* 配置地址 0 检测模式 */
void usart_address_0_detection_mode_config(uint32_t usart_periph, uint32_t addmod);
/* 配置地址 1 检测模式 */
void usart_address_1_detection_mode_config(uint32_t usart_periph, uint32_t addmod);
/* 使能静默模式 */
void usart_mute_mode_enable(uint32_t usart_periph);
/* 禁用静默模式 */
void usart_mute_mode_disable(uint32_t usart_periph);
/* 配置静默模式下的唤醒方法 */
void usart_mute_mode_wakeup_config(uint32_t usart_periph, uint32_t wmethod);

/* LIN 模式通信 */
/* 使能 LIN 模式 */
void usart_lin_mode_enable(uint32_t usart_periph);
/* 禁用 LIN 模式 */
void usart_lin_mode_disable(uint32_t usart_periph);
/* LIN 断字符检测长度 */
void usart_lin_break_detection_length_config(uint32_t usart_periph, uint32_t lblen);

/* 半双工通信 */
/* 使能半双工模式 */
void usart_halfduplex_enable(uint32_t usart_periph);
/* 禁用半双工模式 */
void usart_halfduplex_disable(uint32_t usart_periph);

/* 同步通信 */
/* 使能时钟 */
void usart_clock_enable(uint32_t usart_periph);
/* 禁用时钟 */
void usart_clock_disable(uint32_t usart_periph);
/* 配置 USART 同步模式参数 */
void usart_synchronous_clock_config(uint32_t usart_periph, uint32_t clen, uint32_t cph, uint32_t cpl);

/* 智能卡通信 */
/* 配置智能卡模式的守卫时间值 */
void usart_guard_time_config(uint32_t usart_periph, uint32_t guat);
/* 使能智能卡模式 */
void usart_smartcard_mode_enable(uint32_t usart_periph);
/* 禁用智能卡模式 */
void usart_smartcard_mode_disable(uint32_t usart_periph);
/* 使能智能卡模式中的 NACK */
void usart_smartcard_mode_nack_enable(uint32_t usart_periph);
/* 禁用智能卡模式中的 NACK */
void usart_smartcard_mode_nack_disable(uint32_t usart_periph);
/* 使能智能卡模式中的早期 NACK */
void usart_smartcard_mode_early_nack_enable(uint32_t usart_periph);
/* 禁用智能卡模式中的早期 NACK */
void usart_smartcard_mode_early_nack_disable(uint32_t usart_periph);
/* 配置智能卡自动重试次数 */
void usart_smartcard_autoretry_config(uint32_t usart_periph, uint32_t scrtnum);
/* 配置块长度 */
void usart_block_length_config(uint32_t usart_periph, uint32_t bl);

/* IrDA 通信 */
/* 使能 IrDA 模式 */
void usart_irda_mode_enable(uint32_t usart_periph);
/* 禁用 IrDA 模式 */
void usart_irda_mode_disable(uint32_t usart_periph);
/* 配置 IrDA 低功耗或智能卡模式下的外设时钟预分频器 */
void usart_prescaler_config(uint32_t usart_periph, uint32_t psc);
/* 配置 IrDA 低功耗模式 */
void usart_irda_lowpower_config(uint32_t usart_periph, uint32_t irlp);

/* 硬件流控制 */
/* 配置硬件流控制 RTS */
void usart_hardware_flow_rts_config(uint32_t usart_periph, uint32_t rtsconfig);
/* 配置硬件流控制 CTS */
void usart_hardware_flow_cts_config(uint32_t usart_periph, uint32_t ctsconfig);

/* 一致性控制 */
/* 配置硬件流控制一致性模式 */
void usart_hardware_flow_coherence_config(uint32_t usart_periph, uint32_t hcm);

/* 使能 RS485 驱动 */
void usart_rs485_driver_enable(uint32_t usart_periph);
/* 禁用 RS485 驱动 */
void usart_rs485_driver_disable(uint32_t usart_periph);
/* 配置驱动使能断言时间 */
void usart_driver_assertime_config(uint32_t usart_periph, uint32_t deatime);
/* 配置驱动使能取消断言时间 */
void usart_driver_deassertime_config(uint32_t usart_periph, uint32_t dedtime);
/* 配置驱动使能极性模式 */
void usart_depolarity_config(uint32_t usart_periph, uint32_t dep);

/* USART DMA */
/* 配置 USART DMA 接收 */
void usart_dma_receive_config(uint32_t usart_periph, uint32_t dmacmd);
/* 配置 USART DMA 发送 */
void usart_dma_transmit_config(uint32_t usart_periph, uint32_t dmacmd);
/* 禁用接收错误的 DMA */
void usart_reception_error_dma_disable(uint32_t usart_periph);
/* 使能接收错误的 DMA */
void usart_reception_error_dma_enable(uint32_t usart_periph);

/* 使能 USART 从深度睡眠模式唤醒 MCU */
void usart_wakeup_enable(uint32_t usart_periph);
/* 禁用 USART 从深度睡眠模式唤醒 MCU */
void usart_wakeup_disable(uint32_t usart_periph);
/* 配置 USART 从深度睡眠模式唤醒模式 */
void usart_wakeup_mode_config(uint32_t usart_periph, uint32_t wum);

/* USART FIFO */
/* 使能 FIFO */
void usart_fifo_enable(uint32_t usart_periph);
/* 禁用 FIFO */
void usart_fifo_disable(uint32_t usart_periph);
/* 配置发送 FIFO 阈值 */
void usart_transmit_fifo_threshold_config(uint32_t usart_periph, uint32_t txthreshold);
/* 配置接收 FIFO 阈值 */
void usart_receive_fifo_threshold_config(uint32_t usart_periph, uint32_t rxthreshold);
/* 读取接收 FIFO 计数器数量 */
uint8_t usart_receive_fifo_counter_number(uint32_t usart_periph);

/* 标志和中断函数 */
/* 获取 STAT/FCS 寄存器中的标志 */
FlagStatus usart_flag_get(uint32_t usart_periph, usart_flag_enum flag);
/* 清除 USART 状态 */
void usart_flag_clear(uint32_t usart_periph, usart_flag_enum flag);
/* 使能 USART 中断 */
void usart_interrupt_enable(uint32_t usart_periph, usart_interrupt_enum interrupt);
/* 禁用 USART 中断 */
void usart_interrupt_disable(uint32_t usart_periph, usart_interrupt_enum interrupt);
/* 获取 USART 中断和标志状态 */
FlagStatus usart_interrupt_flag_get(uint32_t usart_periph, usart_interrupt_flag_enum int_flag);
/* 清除 USART 中断标志 */
void usart_interrupt_flag_clear(uint32_t usart_periph, usart_interrupt_flag_enum int_flag);

 

其实并不需要关注那么多,让我来移除那些不在本章节讨论内容外的函数定义

 

/* 函数声明 */
/* 初始化函数 */
/* 复位 USART */
void usart_deinit(uint32_t usart_periph);
/* 配置 USART 波特率值 */
void usart_baudrate_set(uint32_t usart_periph, uint32_t baudval);
/* 配置 USART 校验功能 */
void usart_parity_config(uint32_t usart_periph, uint32_t paritycfg);
/* 配置 USART 字长 */
void usart_word_length_set(uint32_t usart_periph, uint32_t wlen);
/* 配置 USART 停止位长度 */
void usart_stop_bit_set(uint32_t usart_periph, uint32_t stblen);
/* 使能 USART */
void usart_enable(uint32_t usart_periph);
/* 禁用 USART */
void usart_disable(uint32_t usart_periph);
/* 配置 USART 发送器 */
void usart_transmit_config(uint32_t usart_periph, uint32_t txconfig);
/* 配置 USART 接收器 */
void usart_receive_config(uint32_t usart_periph, uint32_t rxconfig);

/* USART 正常模式通信 */
/* 数据按 LSB/MSB 顺序传输/接收 */
void usart_data_first_config(uint32_t usart_periph, uint32_t msbf);
/* USART 反转配置 */
void usart_invert_config(uint32_t usart_periph, usart_invert_enum invertpara);
/* 使能 USART 过载功能 */
void usart_overrun_enable(uint32_t usart_periph);
/* 禁用 USART 过载功能 */
void usart_overrun_disable(uint32_t usart_periph);
/* 配置 USART 过采样模式 */
void usart_oversample_config(uint32_t usart_periph, uint32_t oversamp);
/* 配置采样位方法 */
void usart_sample_bit_config(uint32_t usart_periph, uint32_t osb);
/* 使能接收超时 */
void usart_receiver_timeout_enable(uint32_t usart_periph);
/* 禁用接收超时 */
void usart_receiver_timeout_disable(uint32_t usart_periph);
/* 配置接收超时阈值 */
void usart_receiver_timeout_threshold_config(uint32_t usart_periph, uint32_t rtimeout);
/* USART 发送数据函数 */
void usart_data_transmit(uint32_t usart_periph, uint16_t data);
/* USART 接收数据函数 */
uint16_t usart_data_receive(uint32_t usart_periph);
/* 使能 USART 命令 */
void usart_command_enable(uint32_t usart_periph, uint32_t cmdtype);




/* 半双工通信 */
/* 使能半双工模式 */
void usart_halfduplex_enable(uint32_t usart_periph);
/* 禁用半双工模式 */
void usart_halfduplex_disable(uint32_t usart_periph);



/* 标志和中断函数 */
/* 获取 STAT/FCS 寄存器中的标志 */
FlagStatus usart_flag_get(uint32_t usart_periph, usart_flag_enum flag);
/* 清除 USART 状态 */
void usart_flag_clear(uint32_t usart_periph, usart_flag_enum flag);
/* 使能 USART 中断 */
void usart_interrupt_enable(uint32_t usart_periph, usart_interrupt_enum interrupt);
/* 禁用 USART 中断 */
void usart_interrupt_disable(uint32_t usart_periph, usart_interrupt_enum interrupt);
/* 获取 USART 中断和标志状态 */
FlagStatus usart_interrupt_flag_get(uint32_t usart_periph, usart_interrupt_flag_enum int_flag);
/* 清除 USART 中断标志 */
void usart_interrupt_flag_clear(uint32_t usart_periph, usart_interrupt_flag_enum int_flag);

 

这样看起来代码就简介很多了。接下来让我们来初始化这个USART0

 

按照如下步骤

1 - 开启时钟

	
/************************Clock Start ***************************/	
	/* Turn on GPIO A clock */
	rcu_periph_clock_enable(GPIO_PORT_A);
	/* Turn on USART0 clock*/
	rcu_periph_clock_enable(USART0_CLOCK);	
/************************Clock end ***************************/

2- 重映射GPIOA的PIN9 和PIN 10 作为Usart0

/************************GPIO re-maping start ***************************/
	/* TX */
	gpio_af_set(GPIOA, GPIO_AF_7, USART0_TX_PIN);
	/* RX */
	gpio_af_set(GPIOA, GPIO_AF_7, USART0_RX_PIN);
/************************GPIO re-maping end ***************************/

3- 初始化GPIO, 注意! 这里初始化GPIO的时候就不能选择输入或者输出模式了。需要配置当前的PIN为复用模式GPIO_MODE_AF

/************************Init GPIO start ***************************/
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART0_TX_PIN);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, USART0_TX_PIN);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART0_RX_PIN);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, USART0_RX_PIN);
/************************Init GPIO end ***************************/

4- 初始化USART0

		
/************************Init USART0 start ***************************/
	usart_deinit(USART0);
	/*配置波特率*/
	usart_baudrate_set(USART0, 115200U);
	/*配置数据长度*/
    usart_word_length_set(USART0, USART_WL_8BIT);
	/*配置停止位长度*/
    usart_stop_bit_set(USART0, USART_STB_1BIT);
	/*配置校验*/
    usart_parity_config(USART0, USART_PM_NONE);
	/*开启接收*/
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
	/*开启发送*/
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
	/*开启USART0*/
    usart_enable(USART0);
/************************Init USART0 end ***************************/

程序到这里,USART的初始化已经完成了。

 

接下来我们简单的进行测试, 通过调用usart_data_transmit 函数间隔一秒向上位机发送数据

 

#include "gd32h7xx.h"
#include "systick.h"
#include "bsp_usart.h"
static void cache_enable(void)
{
    /* Enable I-Cache */
    SCB_EnableICache();

    /* Enable D-Cache */
    SCB_EnableDCache();
}




int main(void)
{
    /* Enable the CPU Cache */
    cache_enable();

    /* Configure systick */
    systick_config();
	
	usart_init();
		
    while(1) {
			delay_1ms(1000);
            usart_data_transmit(USART0, 0x41);
    }
}

 

你也许会注意到,这样的方式很不友好,且每次只能发送一个字符。

 

image.png  

让我们简单的对这个发送函数做一下封装。使其可以支持发送字符串。

 

void usart_send_string(uint32_t usart_periph, const char *str) {
    // 循环直到字符串结束(即遇到空字符 '\0')
    while (*str) {
        // 发送当前字符
        usart_data_transmit(usart_periph, (uint8_t)*str);
        // 这确保当前字符已经传输完成,可以发送下一个字符
        while (usart_flag_get(usart_periph, USART_FLAG_TBE) == RESET);
        // 移动到下一个字符
        str++;
    }
}

 

再次测试,发现串口可以正常的发送字符串。

 

image.png  

 

同时我也提供了另外一种发送字符串的方式,即重写fputchar函数,使其用户调用printf函数可以直接把消息发送到上位机

 

// 重写 fputchar 函数,使其通过 USART 发送字符
int fputc(int ch, FILE *f) {
    // 发送字符
    usart_data_transmit(USART0, (uint8_t)ch);
    // 等待发送缓冲区为空
    while (usart_flag_get(USART0, USART_FLAG_TBE) == RESET);
    return ch;
}

 

代码如下:

 

image.png  

接下来我们对代码进行一点点小小的修改,使其能够支持串口接收中断,并且将接收到的数据转发出去。

 

增加初始化串口接收中断方法

void usart_receive_init(void) {
	nvic_irq_enable(USART0_IRQn, 0, 0);
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
    usart_interrupt_enable(USART0, USART_INT_RBNE);
}

串口中断回调函数

void USART0_IRQHandler(void) {
    if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) {
        // 读取接收缓冲区中的数据并打印
        uint16_t received_data = usart_data_receive(USART0);
        printf("Received data: %c\r\n", (char)received_data);
        // 清除接收缓冲区非空中断标志
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
    }
}

 

测试效果:

 

4d17663fb752170ebf2cbaf90318742f

 

 

注意: 千万千万千万要再中断中调用usart_data_receive 函数,否则会一直触发中断!

 

代码如下:

 

03_UART.zip (46.08 KB)
(下载次数: 0, 2024-5-26 04:01 上传)
本帖最后由 御坂10032号 于 2024-5-26 04:04 编辑

回复评论 (1)

太晚了,大脑降频了。原本没有在中断里接受数据导致数据接收寄存器一直不为空一直进中断。自己找不到原因。 后来找资料看手册。最后也是找到了解决办法。睡觉了

点赞  2024-5-26 04:06
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复