GD32F350固件库解析(一)

GD32F350固件库解析(一)

前言

从事嵌入式的学习和工作有3年的时间了,中间一直是用到什么学什么,慢慢探索,最近由于感到进步很慢,而且学的很不系统,很多东西都是一知半解,移植成了,能用就不管了。于是我决定认真的对库函数进行一次解析,一可以充实自己的生活,二能巩固自己的专业技能,不白白浪费时光。

为什么不是stm32

按照道理来讲,我应该写stm32相关的解析才对,但是stm32的库函数解析的文章太多了,我想来研究一次其他芯片,正好公司用gd32用的比较多。

GPIO

首先,做这一行的对这个东西都比较熟悉了,在认真看库函数之前,我对gpio的理解有一下几点:

  1. 工作模式
模式备注
推挽输出51单片机、LED很多都是这个模式,一般单个引脚能推出20mA电流
开漏输出单片机本身没有推挽模式下的电流输出能力,其类似于MOS的控制端,控制外部电路的电平高低,需要外接上拉电阻。
浮空输入按键、外部中断、外部电平状态要求的模式
模拟输入ADC要求的模式

基本输入输出模式就上边4种,但是有的单片机可以设置内部的弱上拉和弱下拉电阻。具体应用环境还不太清楚。

模式备注
复用推挽串口USART等外设需要用到的引脚模式,即其控制权在外设模块手中。
复用开漏II2等接口要求的输出模式,需外接上拉电阻,控制权也在相应的外设模块手中。
  1. 速率问题
    不同芯片gpio速率不同,GD32F350有50MHz、10MHz、2MHz(复位值)三种模式。
    相应的,速率越快,功耗越大,在低功耗应用的需要配置为低速率。
  2. GD32有端口锁定功能,能够锁定端口的配置,防止意外修改寄存器。
  3. 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中还可以这么做:
这样做,没有异或操作,会快一些1

// 这是操作翻转寄存器的做法
//GPIOA->GPIO_TG = GPIO_PIN_15; 
GPIO_TG(GPIOA) = GPIO_PIN_15; //GD32F350库改变了写法

GD32 GPIO例程

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手册上说是单周期翻转,以前是几个周期? ↩︎

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值