国产MCU的GD32E230串口通信

之前一直使用st的stm32f031单片机,但是由于疫情还是啥啥原因,st的芯片价格涨得没法看,因为我们是做产品,而且量比较大,st的芯片就无法再用了,这个成本真的扛不起。
于是在很多国产mcu里面做了甄选,最终gd的因为新能优越,价格便宜获选。gd32e230对标的stm32f031,实现了pin to pin兼容,寄存器不是完全兼容,但是gd的主频可以实现72m,这就很恐怖,stm32f031才48m,之前还得超频到56m使用。不得不说,gd强!
仅仅对比固件库,gd的库函数封装的比st的库要好很多,当然,st现在主推hal库,这个hal库确实也很好。
在使用串口之前同样要配置引脚,时钟。
gpio引脚配置
void com_gpio_init(void){rcu_periph_clock_enable(rcu_gpioa);gpio_af_set(gpioa, gpio_af_1, gpio_pin_9);gpio_af_set(gpioa, gpio_af_1, gpio_pin_10);
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);
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;}
串口使用usart0,对应pa9和pa10,相当于stm32的usart1;
配置usart时需要先复用pa9和pa10,使用gpio_mode_set()配置io口的工作模式、输入输出类型。gpio_output_options_set()配置速度等参数。pa8为rs485的使能引脚。串口配置
void com_usart_init(void){ /* 使能usart时钟*/ rcu_periph_clock_enable(rcu_usart0);
/* usart 配置*/ 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);}
使能usart的时钟,设置波特率,使能接收和发送。串口中断配置串口中断的配置只需要一个api函数,相当简单。
nvic_irq_enable(usart0_irqn, 0);
下面是中断服务函数,被屏蔽的代码为直接操作寄存器,加快代码的速度,因为我的项目对串口的速度要求较高。
串口接收数据进入中断后首先获取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); } }}
运行结果
到此已经实现了usart接收中断,接收判断之后回复数据。
dma配置
void usart_dma_init(void){ dma_parameter_struct dma_init_struct; /* enable dma clock */ rcu_periph_clock_enable(rcu_dma); rcu_periph_clock_enable(rcu_cfgcmp); syscfg_dma_remap_enable(syscfg_dma_remap_usart0tx); /* deinitialize dma channel1 */ dma_deinit(dma_ch3); dma_init_struct.direction = dma_memory_to_peripheral; dma_init_struct.memory_addr = (uint32_t)rs485_tx_buf; dma_init_struct.memory_inc = dma_memory_increase_enable; dma_init_struct.memory_width = dma_memory_width_8bit; dma_init_struct.number = 11; dma_init_struct.periph_addr = usart0_tdata_address; dma_init_struct.periph_inc = dma_periph_increase_disable; dma_init_struct.periph_width = dma_peripheral_width_8bit; dma_init_struct.priority = dma_priority_medium; dma_init(dma_ch3,&dma_init_struct); /* configure dma mode */ dma_circulation_disable(dma_ch3); dma_memory_to_memory_disable(dma_ch3);}
dma的配置过程和stm32差不多,同样是配置dma的时钟,配置数据方向,基地址,外设地址,数据宽度,数据量等等。dma发送数据因为我只用到dma的发送,这里只介绍dma的发送。
void mydma_send(uint8_t *buffer,uint16_t size){ dma_chctl(dma_ch3) &= ~dma_chxctl_chen;//失能dma dma_chmaddr(dma_ch3) = (uint32_t)buffer; //设置要发送的数据地址 dma_chcnt(dma_ch3) = size ; //设置要发送的字节数目 dma_chctl(dma_ch3) |= dma_chxctl_chen;//使能dma}
void rs_485_send(uint8_t *psrc_data,int num){ gpio_bop(gpioa) = (uint32_t)gpio_pin_8; mydma_send(psrc_data,num); while(reset == usart_flag_get(usart0, usart_flag_tc)); gpio_bc(gpioa) = (uint32_t)gpio_pin_8;}
当需要发送数据时直接调用rs_485_send即可。psrc_data为发送数组,num为发送数量。
原文标题:不会用国产单片机?看这里:gd32e230串口通信
文章出处:【微信公众号:嵌入式arm】欢迎添加关注!文章转载请注明出处。


5G对于智慧医疗的贡献是什么
无线耳机性价比的推荐,无线蓝牙耳机哪个好
你的新能源汽车做路试了吗
什么是中央控制系统电力输入/电力输出
驭势对于《让大象飞》的解读
国产MCU的GD32E230串口通信
芯片生产工艺流程图
智能家居生态体系如何去构建
人脸识别应用的安全性隐患还存在
解密RF信号链:特性和性能指标
iOS11正式版今晚一点推送:即使不用iPhoneX也能体验到新功能,哪些设备可以升级呢?
保存图片的最佳方式是是硬盘还是移动硬盘与刻录光盘
纺织品气流阻力测试仪的测试范围说明
皮肤缝合线线径测量仪的详细介绍
2013年全球便携式军用电子市场将达27.7亿美元
国星光电2.2亿元增资子公司国星半导体
英特尔布局非硅基半导体集成氮化镓基功率器件
LCD液晶显示模块的分类,三种类型的介绍
人工智能产业发展势头强劲
如何将HTTP里面的Header信息记录到访问日志里