GD32F350固件库解析(⼀)
GD32F350固件库解析(⼀)
前⾔
从事嵌⼊式的学习和⼯作有3年的时间了,中间⼀直是⽤到什么学什么,慢慢探索,最近由于感到进步很慢,⽽且学的很不系统,很多东西都是⼀知半解,移植成了,能⽤就不管了。于是我决定认真的对库函数进⾏⼀次解析,⼀可以充实⾃⼰的⽣活,⼆能巩固⾃⼰的专业技能,不⽩⽩浪费时光。
为什么不是stm32
按照道理来讲,我应该写stm32相关的解析才对,但是stm32的库函数解析的⽂章太多了,我想来研究⼀次其他芯⽚,正好公司⽤gd32⽤的⽐较多。
GPIO
⾸先,做这⼀⾏的对这个东西都⽐较熟悉了,在认真看库函数之前,我对gpio的理解有⼀下⼏点:
1. ⼯作模式
模式备注
推挽输出51单⽚机、LED很多都是这个模式,⼀般单个引脚能推出20mA电流
开漏输出单⽚机本⾝没有推挽模式下的电流输出能⼒,其类似于MOS的控制端,控制外部电路的电平⾼低,需要外接上拉电阻。
浮空输⼊按键、外部中断、外部电平状态要求的模式
模拟输⼊ADC要求的模式
基本输⼊输出模式就上边4种,但是有的单⽚机可以设置内部的弱上拉和弱下拉电阻。具体应⽤环境还不太清楚。
模式备注
复⽤推挽串⼝USART等外设需要⽤到的引脚模式,即其控制权在外设模块⼿中。
复⽤开漏II2等接⼝要求的输出模式,需外接上拉电阻,控制权也在相应的外设模块⼿中。
3. 速率问题
不同芯⽚gpio速率不同,GD32F350有50MHz、10MHz、2MHz(复位值)三种模式。
相应的,速率越快,功耗越⼤,在低功耗应⽤的需要配置为低速率。
4. GD32有端⼝锁定功能,能够锁定端⼝的配置,防⽌意外修改寄存器。
5. GD32F350有输出翻转寄存器,这个寄存器功能很好⽤啊,不知道stm32后来的有没有这个寄存器,以前写程序都是:
// 这是以前⽤的做法
gpio_state =gpio_bit_read(GPIOA,GPIO_PIN_1);
if(gpio_state){
gpio_bit_reset(GPIOA,GPIO_PIN_1);
}else{
gpio_bit_set(GPIOA,GPIO_PIN_1);
}
// 这是以前⽤的做法
gpio_state =gpio_bit_read(GPIOA,GPIO_PIN_1);
if(gpio_state){
GPIOA->BSRR=1<<32;
}else{
GPIOA->BSRR=1<<0;
}
或者上边的做法太笨了,读⼀次,判断⼀次,执⾏⼀次,⽽且语句多,还带有分⽀,更好的做法还可以这么做:// 这是更好的做法
GPIOA->ODR^=GPIO_PIN_1;
上边⽤⼀条语句就操作了,在GD32中还可以这么做:
这样做,没有异或操作,会快⼀些?
eval是做什么的// 这是操作翻转寄存器的做法
//GPIOA->GPIO_TG = GPIO_PIN_15;
GPIO_TG(GPIOA)=GPIO_PIN_15;//GD32F350库改变了写法
GD32 GPIO例程
可以看到gd32的库中,只有这两个例程:
⼀个是键盘的轮询。
int main(void)
{
systick_config();
gd_eval_led_init(LED1);
gd_eval_key_init(KEY_TAMPER,KEY_MODE_GPIO);
while(1){
/* check whether the button is pressed */
if(RESET==gd_eval_key_state_get(KEY_TAMPER)){
delay_1ms(100);
/* check whether the button is pressed */
if(RESET==gd_eval_key_state_get(KEY_TAMPER)){
gd_eval_led_toggle(LED1);
}
}
}
}
⼀个是⾛马灯。
int main(void)
{
systick_config();
gd_eval_led_init(LED1);
gd_eval_led_init(LED2);
gd_eval_led_init(LED3);
gd_eval_led_init(LED4);
while(1){
/* turn on led1, turn off led4*/
gd_eval_led_on(LED1);
gd_eval_led_off(LED4);
delay_1ms(1000);
/* turn on led2, turn off led1*/
gd_eval_led_on(LED2);
gd_eval_led_off(LED1);
delay_1ms(1000);
/* turn on led3, turn off led2*/
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
delay_1ms(1000);
/
* turn on led4, turn off led3*/
gd_eval_led_on(LED4);
gd_eval_led_off(LED3);
delay_1ms(1000);
}
}
可以看到,例程中操作灯和读端⼝状态的时候⽤的都是BSP中封装好的函数,再以后的开发过程中,我们也要注意避免在mian中直接调⽤库函数,破坏移植性。
内⾏⼈看这个例程是肯定有⼤问题的,阻塞,长按检测等,但是如果要实现那些功能,就需要timer等外设的使⽤,所以这⾥就不纠结啦。EXTI
GPIO是最最基础的。下⾯说和GPIO直接关联的外部中断。这个常常被⽤作外部按键的检测。关于按键长按双击检测的⽂章,。
配置外部中断主要分为以下⼏个步骤:
1. 开时钟
2. 配置端⼝为输⼊模式
3. 配置nvic相应中断使能
4. 配置exti线路映射
5. exti初始化
6. 清除中断标志位
在外部中断中不适合做纯延时去抖,会造成很⼤的阻塞
void gd_eval_key_init(key_typedef_enum keynum, keymode_typedef_enum keymode)
{
/* enable the key clock */
rcu_periph_clock_enable(KEY_CLK[keynum]);
rcu_periph_clock_enable(RCU_CFGCMP);
/* configure button pin as input */
gpio_mode_set(KEY_PORT[keynum],GPIO_MODE_INPUT,GPIO_PUPD_NONE,KEY_PIN[keynum]);
if(keymode ==KEY_MODE_EXTI){
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(KEY_IRQn[keynum],2U,0U);
/* connect key EXTI line to key GPIO pin */
syscfg_exti_line_config(KEY_PORT_SOURCE[keynum],KEY_PIN_SOURCE[keynum]);
/* configure key EXTI line */
exti_init(KEY_EXTI_LINE[keynum],EXTI_INTERRUPT,EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(KEY_EXTI_LINE[keynum]);
}
}
1. 这个以后查⼀下资料再来修正。GD32⼿册上说是单周期翻转,以前是⼏个周期?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论