一、开发背景
因为疫情的原因,导致stm32的价格上涨,且货期也不稳定。所以需要从国内寻找新的芯片厂商,经过多家对比,最终选择了GD的单片机,之前使用的是stm32f031系列芯片,在GD的代理商引导下选择了GD32E230单片机,可以与stm32f031 pin to pin 兼容,之前准备直接用ST的代码直接烧录使用,但是存在一些问题,索性使用GD的库直接重写代码。后面的博文会持续更新GD的各种外设使用。此次开篇先来一个基础的USART配置和使用,涉及到串口的接收中断和发送。
二、串口配置
GPIO引脚配置
GD的API函数和ST略有差异,但是配置过程基本相同。
首先配置GPIO,包括时钟和IO口配置。
PA8为RS485使能引脚。
PA9和PA10是USART0,相当于STM32的USART1。
void com_gpio_init(void)
{
/* enable COM GPIO clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* connect port to USARTx_Tx */
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);
/* connect port to USARTx_Rx */
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
GPIO_BOP(GPIOA) = (uint32_t)GPIO_PIN_8;
GPIO_BC(GPIOA) = (uint32_t)GPIO_PIN_8;
}
串口配置
同样是使能串口,配置串口的相关参数。
void com_usart_init(void)
{
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART0);
/* USART configure */
usart_deinit(USART0);
usart_baudrate_set(USART0,2500000U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
}
串口中断配置
串口中断的配置只需要一个API函数,相当简单。nvic_irq_enable(USART0_IRQn, 0);
下面是中断服务函数,被屏蔽的代码为直接操作寄存器,加快代码的速度,因为我的项目对串口的速度要求较高,看我的波特率就知道了2.5M的波特率。
串口接收数据进入中断后首先获取USART中断标志位状态,通过usart_interrupt_flag_get(EVAL_COM, USART_INT_FLAG_RBNE)判断。然后用数组接收串口数据,判断数据是否是0x1A,符合条件进入if函数。判断串口数据接收标志位是否为RESET,然后通过函数发送数据,发送完失能串口中断,以便下一次进入中断,这里和st的库函数处理方法有所不同。我在测试的时候想用usart_flag_clear()函数清除掉中断标志位,但是在手册里没有清除中断标志位的选项,GD是采用失能串口中断的方式退出中断。
void USART0_IRQHandler(void)
{
// if(RESET != (USART_STAT(USART0)&0x00000010))
// {
// GPIO_BOP(GPIOA) = (uint32_t)GPIO_PIN_8;
// receiver_buffer[0] = (uint16_t)(GET_BITS(USART_RDATA(USART0), 0U, 8U));
// USART_REG_VAL(USART0, USART_INT_TBE) |= BIT(USART_BIT_POS(USART_INT_TBE));
//
// }
//
// if(RESET != (USART_STAT(USART0)&0x00000040))
// {
// USART_TDATA(USART0) = (USART_TDATA_TDATA & transmitter_buffer[txcount++]);
// if(txcount == transfersize){
// USART_REG_VAL(USART0, USART_INT_TBE) &= ~BIT(USART_BIT_POS(USART_INT_TBE));
// GPIO_BC(GPIOA) = (uint32_t)GPIO_PIN_8;
// txcount = 0 ;
// }
// }
if(RESET != usart_interrupt_flag_get(EVAL_COM, USART_INT_FLAG_RBNE)){
/* receive data */
receiver_buffer[0] = usart_data_receive(EVAL_COM);
usart_interrupt_enable(EVAL_COM, USART_INT_TBE);
if(receiver_buffer[0] == 0x1A)
{
/* transmit data */
gpio_bit_set(GPIOA,GPIO_PIN_8);
while(usart_flag_get(USART0,USART_FLAG_TC)==RESET);
usart_data_transmit(EVAL_COM, transmitter_buffer[4]);
while(usart_flag_get(USART0,USART_FLAG_TC)==RESET);
gpio_bit_reset(GPIOA,GPIO_PIN_8);
// usart_flag_clear(USART0,USART_FLAG_TC);
usart_interrupt_disable(EVAL_COM, USART_INT_TBE);
}
}
}
主函数
主函数就非常简单,配置串口中断,初始化时钟和串口,使能串口中断。
int main(void)
{
/* 串口中断配置*/
nvic_irq_enable(USART0_IRQn, 0);
systick_config() ;
/* 初始化串口 */
com_gpio_init();//GPIO初始化
com_usart_init();//串口初始化
printf("please test Usart recevie transfersize\n") ;
delay_1ms(300) ;
usart_interrupt_enable(USART0, USART_INT_RBNE);
while (1);
}
三、运行结果
发送1A,返回transmitter_buffer[4]的值。
GD的库因为不熟悉,刚用起来有点费劲,但是用过一次就会发现比ST的要简单和方便,代码集成度更高,用起来代码更简单。单片机的性能也进行过测试,怎么说呢,对标比较:更快,更强,更便宜。希望国产芯片越来越强。