号外(相关文章):
【GD32L233C-START评测】01 初识开发板
【GD32L233C-START评测】02 上电及程序下载调试
【GD32L233C-START评测】03 LED操作和普通定时功能
【GD32L233C-START评测】04 外部中断与定时器PWM
前言
由于miniUSB的数据线的缺失,串口功能的体验使用外在的串口转USB工具进行。
目标
串口功能的实现。
分析
软件功能的实现的第一步就是要确保硬件连接正确,也就是RX和TX要和工具的串口连接正确,串口实现通信只要RX、TX和地连接上就可以,电不是必须的,逻辑正确就可以传输,软件功能的实现也是对硬件连接的进一步验证。使用的是PA9和PA10对应的UART0,和板载的资源使用的是同一个。
首先实现串口简单的发数,例如定期发送0x01,以此验证串口配置是否正确和硬件通路是否通畅。
串口配置,包括对应的IO口配置;
//******************************************************************************
//* 函数名称 : gd_USART_init
//* 函数描述 : 外部中断配置
//* 输入参数 :
//* 参数描述 : 外部中断初始化配置
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void gd_USART_init(void)
{
/* enable COM GPIO clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART0);
/* connect port to USART TX */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);
/* connect port to USART RX */
gpio_af_set(GPIOA, GPIO_AF_7, 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);
/* USART configure */
usart_deinit(USART0);
usart_word_length_set(USART0, USART_WL_8BIT);
usart_stop_bit_set(USART0, USART_STB_1BIT);
usart_parity_config(USART0, USART_PM_NONE);
usart_baudrate_set(USART0, 115200U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
/* USART interrupt configuration */
nvic_irq_enable(USART0_IRQn, 0);
/* enable USART TBE interrupt */
// usart_interrupt_enable(USART0, USART_INT_TBE);
usart_enable(USART0);
// usart_interrupt_flag_clear(USART0,USART_INT_FLAG_IDLE);
// usart_interrupt_enable(USART0, USART_INT_IDLE);
// USART0_DMA_Configuration();
}
现象:
然后实现printf功能,我们在第一步已经实现了串口的通信,只要再配置printf重定向就可以了,定期发送字符串。
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t) ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
现象:
在体验了这两种发送方式后就需要来实现串口接收了,printf非常适合调试过程中打印输出调试信息,而在实际的交互过程中是需要使用usart_data_transmit直接进行个性化的发送模式设计。
串口接收为了实现不定长数据的接收处理,避免多次进入中断,准备采用DMA+串口空闲中断的方式,添加DMA配置,通过收到什么回传什么进行测试。DMA的通道映射参考DMAMUX 映射,可是我并没有找到通道请求表,类如GD32F350的这种:
Demo中的串口DMA并没有用到DMAMUX,但是DMAMUX是存在的,中间加了这么一道使DMA的应用更广泛,但是不用时的DMA对应的通道请求时什么样的呢?
DMA配置代码:
void USART0_DMA_Configuration(void)
{
dma_parameter_struct dma_init_struct;
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);
/* initialize DMA channel 1 */
dma_deinit(DMA_CH1);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART0_RX;
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)USART0RecePackBuf;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = DMA_USART0_LEN;
dma_init_struct.periph_addr = (uint32_t)&USART_RDATA(USART0);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH1, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA_CH1);
dma_memory_to_memory_disable(DMA_CH1);
/* disable the DMAMUX_MUXCH1 synchronization mode */
dmamux_synchronization_disable(DMAMUX_MUXCH1);
/* USART DMA enable for reception */
usart_dma_receive_config(USART0, USART_DENR_ENABLE);
/* enable DMA channel 1 */
dma_channel_enable(DMA_CH1);
dma_flag_clear(DMA_CH1, DMA_FLAG_G);
}
现象:在配置完成后会进入一次空闲中断
接下来就是简单的通信协议编制了,根据现有的资源只能是控制LED灯的操作了,目前有两种控制模式是通过按键完成的,现在通过通信协议把这两种控制方式写进去。
规定一下通信协议的格式:
改变展示模式,Data为对应的模式代号:
前导码 (STX)
|
长度
|
命令
|
数据
|
校验和
|
8A F6
|
0x05
|
0x90
|
0x0E
|
Data
|
CHECKSUM
|
例如:8A F6 05 90 0e 02 00 A0
控制呼吸灯,Data为对应的开关(0或者1):
前导码 (STX)
|
长度
|
命令
|
数据
|
校验和
|
8A F6
|
0x05
|
0x91
|
0x0E
|
Data
|
CHECKSUM
|
例如:8A F6 05 91 0e 01 00 A0
现象如下:
|