【前言】
GD32H759拥有最多8个通用同步异步收发器(USART),其中USART0、USART5是挂载在APB2总线上,而其余6个是挂载在APB1总线之上。具体见下如:
![image.png image.png](https://static.assets-stash.eet-china.com/forum/202403/01/152804e7gu142frss1bjhe.png)
根据开发板原理图,USART0通过PA9、PA10的端口接到了板载的CH340上面,可以用来打印参数等。其原理图如下:
![image.png image.png](https://static.assets-stash.eet-china.com/forum/202403/01/153308nyrgryc9ug2maelc.png)
因此,从USART0进行试用。
【工程以及具体配置】
1、在工程中,在bsp下面新建uart.h、uart.c,用于uart的业务。
由于要开启UART总线时钟,在lugl_gd32h7xx.h头文件中定时RCU_APB2EN的地址:
//APB2EN 串口挂载在 APB2 使能寄存器(RCU_APB2EN)偏移 0x44
#define LU_RCU_APB2EN (*(volatile uint32_t *)(uint32_t)(0x58024444))
复制代码![image.png image.png](https://static.assets-stash.eet-china.com/forum/202403/01/160242c3c5d565bza35d78.png)
3、在PIN9、PIN10,备用选择寄存器为GPIOx_AFSEL1,偏移地址为:0x24,因此在lugl_gd32h7xx.h中定义:
#define LU_GPIOA_AFSEL1 (*(volatile uint32_t *)(uint32_t)0x58020024)
配置为:
//配置 GPIOA9、10复用模式。为输出高速上拉,
LU_GPIOA_AFSEL1 &= ~((uint32_t)0b1111<<4);
LU_GPIOA_AFSEL1 |= ((uint32_t)0b0111<<4);
LU_GPIOA_AFSEL1 &= ~((uint32_t)0b1111<<8);
LU_GPIOA_AFSEL1 |= ((uint32_t)0b0111<<8);
复制代码//APB2EN 串口挂载在 APB2 使能寄存器(RCU_APB2EN)偏移 0x44
#define LU_RCU_APB2EN (*(volatile uint32_t *)(uint32_t)(0x58024444))
//打开USART0总线时钟
LU_RCU_APB2EN |= ((uint32_t)0x01 << 4);
复制代码然后配置GPIO的AF复用,PA9 为推挽输出,上拉,60M速度
LU_GPIOA_CTL &= ~((uint32_t)0b11<<(2U*9));
LU_GPIOA_CTL |= ((uint32_t)0b10<<(2U*9)); //10
LU_GPIOA_OMODE &= ~((uint32_t)0x01<<9); //0输出模式 输出推挽模式(复位值)
LU_GPIOA_OSPD &= ~((uint32_t)0b11<<(2U*9)); //清零
LU_GPIOA_OSPD |= ((uint32_t)0b01<<(2U*9)); //01:输出最大速度60M
LU_GPIOA_PUD &= ~((uint32_t)0b11<<(2U*9)); //清零
LU_GPIOA_PUD |= ((uint32_t)0b01<<(2U*9)); //01:端口上拉模式
复制代码 LU_GPIOA_CTL &= ~((uint32_t)0b11<<(2U*10)); //
LU_GPIOA_CTL |= ((uint32_t)0b10<<(2U*9));
LU_GPIOA_OSPD &= ~((uint32_t)0b11<<(2U*9)); //清零
LU_GPIOA_OSPD |= ((uint32_t)0b01<<(2U*9)); //01:最大速度60M
LU_GPIOA_PUD &= ~((uint32_t)0b11<<(2U*9)); //清零
LU_GPIOA_PUD |= ((uint32_t)0b01<<(2U*9)); //01:端口上拉模式
复制代码1)首先重置USART0,经学习官方示例,他就是先开启睡眠模式,然后关闭,代码如下:
/* 关闭睡眠时钟使能 USART0SPEN 在睡眠模式下 USART0 时钟使能
由软件置位或复位
0:关闭在睡眠模式下 USART0 时钟
1:开启在睡眠模式下 USART0 时钟
4bit
*/
LU_RCU_ADDAPB2SPEN |= ((uint32_t)0x01<<4U);
LU_RCU_ADDAPB2SPEN &= ~((uint32_t)0x01<<4U);
复制代码 /* 关闭USART */
/*
USART使能
0:USART预分频器和输出禁用
1:USART预分频器和输出被使能
*/
LU_USART0_CTL0 &= ~((uint32_t)0x01<<0);
复制代码![image.png image.png](https://static.assets-stash.eet-china.com/forum/202403/01/210608cz7eon1asobqp7re.png)
因此我位配置代码如下:
LU_USART0_CTL0 &= ~(((uint32_t)0x01<<12) | ((uint32_t)0x01<<28)); //定义为00 即8数据位
/* configure USART word length */
LU_USART0_CTL0 |= (((uint32_t)0x00<<12) | ((uint32_t)0x00<<28)); //8bit为00
复制代码![image.png image.png](https://static.assets-stash.eet-china.com/forum/202403/01/210837x66u6lp9kc1wlcpg.png)
我们配置为1位停止位时,给这两个BIT写0x00,代码如下:
LU_USART0_CTL1 &= ~((uint32_t)0b11<<12); //请除【13:12】位 STB
LU_USART0_CTL1 |= ((uint32_t)0b00<<12); // STOP位长 00:1停止位
复制代码 //设置波特率 这里定为115200 总线频率为300M,先不计算先,写死0x00000A2C
LU_USART0_BAUD = 0x00000A2C;
复制代码 LU_USART0_CTL0 &= ~((uint32_t)0x01<<2); //先清除REN 位
LU_USART0_CTL0 |= ((uint32_t)0x01<<2); //接收使能
LU_USART0_CTL0 &= ~((uint32_t)0x01<<3); //先清除REN 位
LU_USART0_CTL0 |= ((uint32_t)0x01<<3); //接收使能
LU_USART0_CTL0 |= 0x01; //1:USART预分频器和输出被使能
复制代码5、接着编写串口阻塞式的发送一个Byte的函数,非常简单,就是往USART0_TDATA的[9:0]位写入需要发送的数据就行了。
void usart0_data_transmit(uint16_t data)
{
LU_USART0_TDATA = ((uint32_t)0x3FF & (uint32_t)data); //0-9位
}
复制代码/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart0_data_transmit((uint8_t)ch);
while(RESET == ((LU_USART0_STAT >>6) & 0x01));
return ch;
}
复制代码![image.png image.png](https://static.assets-stash.eet-china.com/forum/202403/01/211830m086amp16anb69n1.png)
【实现效果】
当然配置好后,需要进行验证,在TobudOS的工程中,添加uart.c进来,并在任务中添回printf,其任务函数如下:
void test_task(void *Parameter)
{
while(1)
{
TG_LED1;
printf("\r\ntask1\r\n\r\n");
tos_task_delay(2000);
}
}
void led_task_entry(void *Parameter)
{
while(1)
{
TG_LED2;
printf("\r\ntask2\r\n\r\n");
tos_task_delay(500);
}
}
复制代码![image.png image.png](https://static.assets-stash.eet-china.com/forum/202403/01/212201l3953z55loalnjf1.png)
【总结】
经过一天的学习,熟悉了USART0的几个普通寄存器,以及相关的配置与应用,并成功的编写好了应用,实现了printf。
使用寄存器配置,相比库函数,代码要简洁,运行速度也要快!
附:基于TobudOS的工程源码:
![](static/image/filetype/zip.gif)
全部回复 0