0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

GD32开发实战指南(基础篇) 第6章 按键

嵌入式大杂烩 来源:嵌入式大杂烩 作者:嵌入式大杂烩 2023-05-11 08:57 次阅读

开发环境:

MDK:Keil 5.30

开发板:GD32F207I-EVAL

MCU:GD32F207IK

1 普通方式

1.1 普通方式工作原理

按键 GPIO 端口有两个方案可以选择,一是采用上拉输入模式,因为按键在没按下的时候,是默认为高电平的,采且内部上拉模式正好符合这个要求。第二个方案是直接采用浮空输入模式,因为按照硬件电路图,在芯片外部接了上拉电阻,其实就没必要再配置成内部上拉输入模式了,因为在外部上拉与内部上拉效果是一样的。

1683728778172wwrwwyb44i

笔者本文将会使用KEY1。

1.2 普通方式实现

主函数代码如下:

/*
    brief      main function
    param[in]  none
    param[out] none
    retval     none
*/
int main(void)
{
    //systick init
    sysTick_init();
	
    /* configure LED1 GPIO port */
    led_init(LED1);

    /* configure LED2 GPIO port */
    led_init(LED2);

    /* configure LED3 GPIO port */
    led_init(LED3);

    /* configure LED4 GPIO port */
    led_init(LED4);

    //key init
    key_init(KEY_WAKEUP);
	
    while(1) 
    {
        delay_ms(100);
        if(key_scan(KEY_WAKEUP))
        {
            /* turn toggle LED */
            led_toggle(LED1);
            led_toggle(LED2);
            led_toggle(LED3);
            led_toggle(LED4);
        }
    }
}
  • GPIO 初始化配置
/*
    brief      configure key
    param[in]  keynum: specify the key to be configured
      arg        KEY_TAMPER: tamper key
      arg        KEY_WAKEUP: wakeup key
      arg        KEY_USER: user key
    param[out] none
    retval     none
*/
void key_init(key_typedef_enum keynum)
{
    /* enable the key clock */
    rcu_periph_clock_enable(KEY_CLK[keynum]);
    rcu_periph_clock_enable(RCU_AF);

    /* configure button pin as input */
    gpio_init(KEY_PORT[keynum], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, KEY_PIN[keynum]);
}

key_init()与 LED 的 GPIO 初始化函数 led_init()类似,区别只是在这个函数中,要开启的 GPIO 的端口时钟不一样,并且把检测按键用的引脚 Pin 的模式设置为适合按键应用的上拉输入模式(由于接了外部上拉电阻,也可以使用浮空输入,读者可自行修改代码做实验)。

  • 按键消抖
/*
    brief      return the key state
    param[in]  keynum: specify the key to be checked
      arg        KEY_TAMPER: tamper key
      arg        KEY_WAKEUP: wakeup key
      arg        KEY_USER: user key
    param[out] none
    retval     the key's GPIO pin value
*/
key_state_enum key_scan(key_typedef_enum keynum)
{
    /* check whether the button is pressed */
    if(RESET == gpio_input_bit_get(KEY_PORT[keynum], KEY_PIN[keynum]))
    {
        delay_ms(100);

        /* check whether the button is pressed */
        if(RESET == gpio_input_bit_get(KEY_PORT[keynum], KEY_PIN[keynum]))
        {
            while(RESET == gpio_input_bit_get(KEY_PORT[keynum], KEY_PIN[keynum]))
            {
                return KEY_ON;
            }
        }
    }
    return KEY_OFF;
}

相信延时消抖的原理大家在学习其他单片机时就已经了解了,本函数的功能就是扫描输入参数中指定的引脚,检测其电平变化,并作延时消抖处理,最终对按键消息进行确认。

  • 利用 gpio_input_bit_get() 读取输入数据,若从相应引脚读取的数据等于 0(KEY_ON),低电平,表明可能有按键按下,调用延时函数。否则返回 KEY_OFF,表示按键没有被按下。
  • 延时之后再次利用 gpio_input_bit_get()读取输入数据,若依然为低电平,表明确实有按键被按下了。否则返回 KEY_OFF,表示按键没有被按下。
  • 循环调用gpio_input_bit_get() 一直检测按键的电平,直至按键被释放,被释放后,返回表示按键被按下的标志 KEY_ON。以上是按键消抖的流程,调用了一个库函数 gpio_input_bit_get()。输入参数为要读取的端口、引脚,返回引脚的输入电平状态,高电平为 1,低电平为 0。

2 EXTI方式

2.1 EXTI的工作原理

EXTI(External Interrupt) 就是指外部中断,通过 GPIO 检测输入脉冲,引起中断事件,打断原来的代码执行流程,进入到中断服务函数中进行处理,处理完后再返回到中断之前的代码中执行。

  • GD32的中断和异常

Cortex内核具有强大的异常响应系统,它把能够打断当前代码执行流程的事件分为异常(exception)和中断(interrupt),并把它们用一个表管理起来,编号为 0 ~ 15 的称为内核异常,而 16 以上的则称为外部中断(外是相对内核而言),这个表就称为中断向量表。

而 GD32 对这个表重新进行了编排,把编号从-3 至 6 的中断向量定义为系统异常,编号为负的内核异常不能被设置优先级,如复位(Reset)、不可屏蔽中断 (NMI)、硬错误(Hardfault)。从编号 7 开始的为外部中断,这些中断的优先级都是可以自行设置的。详细的 GD32中断向量表见下表。

168372877887081545qixac

16837287794042gup5an3bx

……

完整向量表请参考《GD32F20x_User_Manual_EN_Rev2.4》。

GD32的中断如此之多,配置起来并不容易,因此我们需要一个强大而方便的中断控制器 NVIC (Nested Vectored Interrupt Controller)。NVIC 是属于 Cortex 内核的器件,不可屏蔽中断 (NMI)和外部中断都由它来处理,而 SYSTICK 不是由 NVIC 来控制的。

1683728779796q7jzrhgrc4

  • NVIC 结构体成员

当我们要使用 NVIC 来配置中断时,自然想到GD库肯定也已经把它封装成库函数了。查找库帮助文档,发现在 gd32f20x_misc查找到一个nvic_irq_enable() 函数。

/*!
    \\brief      enable NVIC request
    \\param[in]  nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
    \\param[in]  nvic_irq_pre_priority: the pre-emption priority needed to set
    \\param[in]  nvic_irq_sub_priority: the subpriority needed to set
    \\param[out] none
    \\retval     none
*/
void nvic_irq_enable(uint8_t nvic_irq,
                     uint8_t nvic_irq_pre_priority,
                     uint8_t nvic_irq_sub_priority)
{
    uint32_t temp_priority = 0x00U, temp_pre = 0x00U, temp_sub = 0x00U;

    /* use the priority group value to get the temp_pre and the temp_sub */
    switch((SCB->AIRCR) & (uint32_t)0x700U) {
    case NVIC_PRIGROUP_PRE0_SUB4:
        temp_pre = 0U;
        temp_sub = 0x4U;
        break;
    case NVIC_PRIGROUP_PRE1_SUB3:
        temp_pre = 1U;
        temp_sub = 0x3U;
        break;
    case NVIC_PRIGROUP_PRE2_SUB2:
        temp_pre = 2U;
        temp_sub = 0x2U;
        break;
    case NVIC_PRIGROUP_PRE3_SUB1:
        temp_pre = 3U;
        temp_sub = 0x1U;
        break;
    case NVIC_PRIGROUP_PRE4_SUB0:
        temp_pre = 4U;
        temp_sub = 0x0U;
        break;
    default:
        nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
        temp_pre = 2U;
        temp_sub = 0x2U;
        break;
    }

    /* get the temp_priority to fill the NVIC->IP register */
    temp_priority = (uint32_t)nvic_irq_pre_priority << (0x4U - temp_pre);
    temp_priority |= nvic_irq_sub_priority & (0x0FU >> (0x4U - temp_sub));
    temp_priority = temp_priority << 0x04U;
    NVIC->IP[nvic_irq] = (uint8_t)temp_priority;

    /* enable the selected IRQ */
    NVIC->ISER[nvic_irq >> 0x05U] = (uint32_t)0x01U << (nvic_irq & (uint8_t)0x1FU);
}

该函数有三个参数,需要配置的中断向量,中断向量抢占优先级和中断向量的响应优先级。

前面两个结构体成员都很好理解,首先要用 nvic_irq参数来选择将要配置的中断向量。用nvic_irq_pre_priority参数要配置中断向量的抢占优先级,用nvic_irq_sub_priority参数配置中断向量的响应优先级。对于中断的配置,最重要的便是配置其优先级,但 GD32 的同一个中断向量为什么需要设置两种优先级?这两种优先级有什么区别?

  • 抢占优先级和响应优先级

GD32的中断向量具有两个属性,一个为抢占属性,另一个为响应属性,其属性编号越小,表明它的优先级别越高。

抢占,是指打断其他中断的属性,即因为具有这个属性会出现嵌套中断(在执行中断服务函数 A 的过程中被中断 B 打断,执行完中断服务函数 B 再继续执行中断服务函数A),抢占属性由nvic_irq_pre_priority参数配置。

而响应属性则应用在抢占属性相同的情况下,当 两个中断向量的抢占优先级相同时,如 果两个中断同时到达,则先处理响应优先级高的中断,响应属性 由nvic_irq_sub_priority参数配置。例如,现在有三个中断向量,见下表。

中断向量 抢占优先级 响应优先级
A 0 0
B 1 0
C 1 1

若内核正在执行 C 的中断服务函数,则它能被抢占优先级更高的中断 A 打断,由于 B和 C 的抢占优先级相同,所以 C 不能被 B 打断。但如果 B 和 C 中断是同时到达的,内核就会首先响应响应优先级别更高的 B 中断。

  • NVIC 的优先级组

在配置优先级的时候,还要注意一个很重要的问题,即中断种类的数量。NVIC 只可以配置 16 种中断向量的优先级,也就是说,抢占优先级和响应优先级的数量由一个 4 位的数字来决定,把这个 4 位数字的位数分配成抢占优先级部分和响应优先级部分。有 5 组分配方式 :

  • 第 0 组:所有 4 位用来配置响应优先级。即 16 种中断向量具有都不相同的响应优先级。
  • 第 1 组:最高 1 位用来配置抢占优先级,低 3 位用来配置响应优先级。表示有 21=2 种级别的抢占优先级(0 级,1 级),有 23=8 种响应优先级,即在 16 种中断向量之中,有8 种中断,其抢占优先级都为 0 级,而它们的响应优先级分别为 0~7,其余 8 种中断向量的抢占优先级则都为 1 级,响应优先级别分别为 0~7。
  • 第 2 组:2 位用来配置抢占优先级,2 位用来配置响应优先级。即 22=4 种抢占优先级,22=4 种响应优先级。
  • 第 3 组:高 3 位用来配置抢占优先级,最低 1 位用来配置响应优先级。即有 8 种抢占优先级,2 种响应 2 优先级。
  • 第 4 组:所有 4 位用来配置抢占优先级,即 NVIC 配置的 24 =16 种中断向量都是只有抢占属性,没有响应属性。

要配置这些优先级组,可以采用库函数 nvic_priority_group_set(),可输入的参数为NVIC_PRIGROUP_PRE0_SUB4 ~ NVIC_PRIGROUP_PRE4_SUB0,分别为以上介绍的 5 种分配组。

GD32的所有 I/O 端口都可以配置为 EXTI 中断模式,用来捕捉外部信号,可以配置为下降沿中断、上升沿中断和上升下降沿中断这三种模式。它们以图2所示方式连接到外部中断 / 事件线上。

  • EXTI 外部中断

GD32的所有 GPIO 都引入到 EXTI 外部中断线上,使得所有的 GPIO 都能作为外部中断的输入源。GPIO 与 EXTI 的连接方式见下表。

由下表可知,PA0 ~ PI0 连接到 EXTI0 、PA1~ PI1 连接到 EXTI1、……、PA15 ~ PI15 连接到 EXTI15。这里大家要注意的是 :PAx ~ PIx 端口的中断事件都连接到了 EXTIx,即同一时刻 EXTIx 只能响应一个端口的事件触发,不能够同一时间响应所有GPIO 端口的事件,但可以分时复用。它可以配置为上升沿触发、下降沿触发或双边沿触发。EXTI 最普通的应用就是接上一个按键,设置为下降沿触发,用中断来检测按键。

16837287803731iicow74v2

2.2 2 EXTI的寄存器描述

EXTI 寄存器的寄存器主要有6个,下面分别描述。

  • 中断使能寄存器(EXTI_INTEN)

168372878086925fpvkv808

  • 事件使能寄存器(EXTI_EVEN)

1683728781270z65ikushbx

1683728781667lr52pege20

  • 上升沿触发选择寄存器(EXTI_RTEN)

16837287819546y9sa7lt8l

注意: 外部唤醒线是边沿触发的,这些线上不能出现毛刺信号。在写EXTI_RTSR寄存器时,在外部中断线上的上升沿信号不能被识别,挂起位也不会被置位。在同一中断线上,可以同时设置上升沿和下降沿触发。即任一边沿都可触发中断。

  • 下降沿触发选择寄存器(EXTI_FTEN)

1683728782395kdebg1j966

注意: 外部唤醒线是边沿触发的,这些线上不能出现毛刺信号。在写EXTI_FTSR寄存器时,在外部中断线上的下降沿信号不能被识别,挂起位不会被置位。在同一中断线上,可以同时设置上升沿和下降沿触发。即任一边沿都可触发中断。

  • 软件中断事件寄存器(EXTI_SWIEV)

1683728782836102ykdro3b

  • 挂起寄存器(EXTI_PD)

1683728783212gqkpbuuo0g

2.3 EXTI方式实现

主函数代码如下:

/*
    brief      main function
    param[in]  none
    param[out] none
    retval     none
*/
int main(void)
{
    //systick init
    sysTick_init();
	
    /* configure LED1 GPIO port */
    led_init(LED1);

    /* configure LED2 GPIO port */
    led_init(LED2);

    /* configure LED3 GPIO port */
    led_init(LED3);

    /* configure LED4 GPIO port */
    led_init(LED4);
	
    //key init
    key_init(KEY_WAKEUP, KEY_MODE_EXTI);
	
    while(1) 
    {
        delay_ms(100);
    }
}
  • 配置外部中断

现在我们重点分析 key_init() 这个函数,它完成了配置一个 I/O 为 EXTI 中断的一般步骤,主要有以下功能 :

1)使能 EXTIx 线的时钟和第二功能 AFIO 时钟。

2)配置 EXTIx 线的中断优先级。

3)配置 EXTI 中断线 I/O。

4)选定要配置为 EXTI 的 I/O 口线和 I/O 口的工作模式。

5)EXTI 中断线工作模式配置。

/*
    brief      configure key
    param[in]  keynum: specify the key to be configured
      arg        KEY_TAMPER: tamper key
      arg        KEY_WAKEUP: wakeup key
      arg        KEY_USER: user key
    param[in]  keymode: specify button mode
      arg        KEY_MODE_GPIO: key will be used as simple IO
      arg        KEY_MODE_EXTI: key will be connected to EXTI line with interrupt
    param[out] none
    retval     none
*/
void 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_AF);

    /* configure button pin as input */
    gpio_init(KEY_PORT[keynum], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, 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 */
        gpio_exti_source_select(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]);
    }
}

key_init()代码中,不仅配置了NVIC ,还对按键的GPIO进行了初始化,这部分和按键轮询的设置类似。

接下来,调用 gpio_exti_source_select () 函数把 GPIOA、Pin0 与EXTI连接起来。

最后调用 exti_init() 把 EXTI 初始化,函数如下:

/*!
    \\brief      initialize the EXTI
    \\param[in]  linex: EXTI line number, refer to exti_line_enum
                only one parameter can be selected which is shown as below:
      \\arg        EXTI_x (x=0..19): EXTI line x
    \\param[in]  mode: interrupt or event mode, refer to exti_mode_enum
                only one parameter can be selected which is shown as below:
      \\arg        EXTI_INTERRUPT: interrupt mode
      \\arg        EXTI_EVENT: event mode
    \\param[in]  trig_type: interrupt trigger type, refer to exti_trig_type_enum
                only one parameter can be selected which is shown as below:
      \\arg        EXTI_TRIG_RISING: rising edge trigger
      \\arg        EXTI_TRIG_FALLING: falling trigger
      \\arg        EXTI_TRIG_BOTH: rising and falling trigger
      \\arg        EXTI_TRIG_NONE: without rising edge or falling edge trigger
    \\param[out] none
    \\retval     none
*/
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)
{
    /* reset the EXTI line x */
    EXTI_INTEN &= ~(uint32_t)linex;
    EXTI_EVEN &= ~(uint32_t)linex;
    EXTI_RTEN &= ~(uint32_t)linex;
    EXTI_FTEN &= ~(uint32_t)linex;

    /* set the EXTI mode and enable the interrupts or events from EXTI line x */
    switch(mode) {
    case EXTI_INTERRUPT:
        EXTI_INTEN |= (uint32_t)linex;
        break;
    case EXTI_EVENT:
        EXTI_EVEN |= (uint32_t)linex;
        break;
    default:
        break;
    }

    /* set the EXTI trigger type */
    switch(trig_type) {
    case EXTI_TRIG_RISING:
        EXTI_RTEN |= (uint32_t)linex;
        EXTI_FTEN &= ~(uint32_t)linex;
        break;
    case EXTI_TRIG_FALLING:
        EXTI_RTEN &= ~(uint32_t)linex;
        EXTI_FTEN |= (uint32_t)linex;
        break;
    case EXTI_TRIG_BOTH:
        EXTI_RTEN |= (uint32_t)linex;
        EXTI_FTEN |= (uint32_t)linex;
        break;
    case EXTI_TRIG_NONE:
    default:
        break;
    }
}
  • AFIO 时钟

代码中调用rcu_periph_clock_enable(RCU_AF)表示开启 AFIO的时钟。

AFIO (alternate-function I/O),指 GPIO 端口的复用功能,GPIO 除了用作普通的输入输出(主功能),还可以作为片上外设的复用输入输出,如串口、ADC,这些就是复用功能。大多数 GPIO 都有一个默认复用功能,有的 GPIO 还有重映射功能。重映射功能是指把原来属于 A 引脚的默认复用功能,转移到B引脚进行使用,前提是 B 引脚具有这个重映射功能。

当把 GPIO 用作 EXTI 外部中断或使用重映射功能的时候,必须开启 AFIO 时钟,而在使用默认复用功能的时候,就不必开启 AFIO 时钟了。

  • 编写中断服务函数

在这个 EXTI 设置中我们把 PA0 连接到内部的 EXTI0,GPIO 配置为上拉输入,工作在下降沿中断。在外围电路上我们将 PA0 接到了 key上。当按键没有按下时,PA0 始终为高,当按键按下时 PA0 变为低,从而 PA0 上产生一个下降沿跳变,EXTI0 会捕捉到这一跳变,并产生相应的中断,中断服务程序在 gd32f20x_it.c 中实现。gd32f20x_it.c 文件是专门用来存放中断服务函数的。文件中默认只有几个关于系统异常的中断服务函数,而且都是空函数,在需要的时候自行编写。那么中断服务函数名是不是可以自己定义呢?不可以。中断服务函数的名字必须要与启动文件startup_gd32f20x_cl.s 中的中断向量表定义一致。

16837287836368hav0m3p26

EXTI0_IRQHandler 表示为 EXTI0 中断向量的服务函数名。于是,我们就可以在 gd32f20x_it.c文件中加入名为 EXTI0_IRQHandler() 的函数。

/*!
    \\brief      this function handles external lines 0 interrupt request
    \\param[in]  none
    \\param[out] none
    \\retval     none
*/
void EXTI0_IRQHandler(void)
{
    if(RESET != exti_interrupt_flag_get(EXTI_0))
    {
        /* turn toggle LED */
        led_toggle(LED1);
        led_toggle(LED2);
        led_toggle(LED3);
        led_toggle(LED4);

       exti_interrupt_flag_clear(EXTI_0);
   }
}

其内容比较容易理解,进入中断后,调用exti_interrupt_flag_get() 库函数来重新检查是否产生了 EXTI_Line 中断,接下来把 LED 取反,操作完毕后,调用 exti_interrupt_flag_clear()清除中断标志位再退出中断服务函数。

3 实验现象

编译好程序后,下载到板子上,不管是普通方式还是中断方式,当按在按键KEY1时,LED或亮或灭。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16024

    浏览量

    343717
  • 按键
    +关注

    关注

    4

    文章

    220

    浏览量

    57346
  • 开发板
    +关注

    关注

    25

    文章

    4441

    浏览量

    94097
  • Cortex-M
    +关注

    关注

    2

    文章

    224

    浏览量

    29574
  • GD32
    +关注

    关注

    7

    文章

    336

    浏览量

    23748
收藏 人收藏

    评论

    相关推荐

    GD32开发实战指南(基础篇) 第7章 定时器

    系统滴答定时器一般用来提供“心跳”作用,而GD32定时器最基本功能也是定时,可以设置不同时间长度的定时。定时器除了最基本的定时功能外,定时器与GPIO有挂钩使得它可以发挥强大的作用,比如可以输出
    的头像 发表于 05-11 09:00 9252次阅读
    <b class='flag-5'>GD32</b><b class='flag-5'>开发</b><b class='flag-5'>实战</b><b class='flag-5'>指南</b>(基础篇) 第7章 定时器

    GD32开发实战指南(基础篇) 第8章 定时器

    开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 1 PWM输出的工作原理 脉冲宽度调制(PWM) ,是英文“Pulse Wi
    的头像 发表于 05-12 22:14 6384次阅读
    <b class='flag-5'>GD32</b><b class='flag-5'>开发</b><b class='flag-5'>实战</b><b class='flag-5'>指南</b>(基础篇) 第8章 定时器

    GD32开发实战指南(基础篇) 第14章 内部温度传感器

    GD32 有一个内部的温度传感器,可以用来测量 CPU 及周围的温度(TA)。该温度传感器在内部和 ADCx_IN16 输入通道相连接,此通道把传感器输出的电压转换成数字值。温度传感器模拟输入
    的头像 发表于 05-17 08:58 4043次阅读
    <b class='flag-5'>GD32</b><b class='flag-5'>开发</b><b class='flag-5'>实战</b><b class='flag-5'>指南</b>(基础篇) 第14章 内部温度传感器

    GD32开发实战指南(基础篇) 第16章 RTC

    开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 1 RTC工作原理 1.1 RTC简介
    的头像 发表于 05-18 22:14 5759次阅读
    <b class='flag-5'>GD32</b><b class='flag-5'>开发</b><b class='flag-5'>实战</b><b class='flag-5'>指南</b>(基础篇) 第16章 RTC

    【图书分享】《STM32库开发实战指南

    GPIO入门之流水灯 4 深入分析流水灯例程 5 调试程序第二部分 库开发中级 
    发表于 03-13 17:01

    好书分享】入门经典:STM32库开发实战指南

    灯例程 5 调试程序 第二部分 库开发中级 6
    发表于 06-24 20:53

    Arduino开发实战指南 AVR

    第一基础1初识Arduino2编写Arduino程序
    发表于 08-03 16:14

    Arduino开发实战指南 AVR

    Arduino开发实战指南AVR
    发表于 04-04 12:20

    GD32和STM32有哪些不同的地方

    一、前言GD32是国内开发的一款单片机,据说开发的人员是来自ST公司的,GD32也是以STM32作为模板做出来的。所以GD32和STM32有
    发表于 08-09 07:03

    什么是GD32

    一、前言什么GD32GD32是国内开发的一款单片机,据说开发的人员是来自ST公司的,GD32也是以STM32作为模板做出来的。所以
    发表于 08-12 07:46

    每日推荐 | STM32Cube高效开发教程,电源系统管理设计系列知识

    指南(基于RT-Thread系统)》3 GPIO使用和《嵌入式系统 – GD32应用开发实战
    发表于 05-09 10:38

    GD32 MCU原理及固件库开发指南》 + 初读感悟

    GD32 MCU原理固件库开发指南这本书内容丰富,囊括了GD32中的所有外设,书中首先介绍了如何使用MDK或IAR软件搭建GD32工程环境,让初学者能快速基于工程上手编程。书中主要对
    发表于 03-31 22:11

    GD32 MCU原理及固件库开发指南》+读后感

    2介绍GD32 MCU快速入门与开发平台搭建的方法,包括对软硬件开发平台、调试工具、GD32
    发表于 06-06 21:52

    GD32移植到STM32开发平台

    GD32移植到STM32开发平台
    发表于 12-02 14:51 27次下载
    <b class='flag-5'>GD32</b>移植到STM32<b class='flag-5'>开发</b>平台

    GD32开发实战指南(基础篇) 第19章 程序加密

    GD32通过读取芯片唯一ID号来实现程序的保护,防止被抄袭。96位的产品唯一身份标识所提供的参考号码对任意一个GD32微控制器
    的头像 发表于 05-20 09:10 3397次阅读
    <b class='flag-5'>GD32</b><b class='flag-5'>开发</b><b class='flag-5'>实战</b><b class='flag-5'>指南</b>(基础篇) 第19章 程序加密