【FR801xH】富芮坤FR801xH之按键控制LED闪烁模式

00. 目录

01. FR801xH概述

在这里插入图片描述

FR801xH 系列芯片是面向SOC(片上系统),易于快速开发的低功耗蓝牙芯片。基于 Freqchip 的蓝牙智能固件和协议栈的支持,完全兼容蓝牙 V5.3(LE 模式)协议。同时用户可以基于芯片内置的 ARM CorteM3 嵌入式 32 位高性能单片机开发各种应用程序。

蓝牙智能固件包括 L2CAP 服务层协议、安全管理器 (SM)、属性协议(ATT)、通用属性配置文件 (GATT)和通用访问配置文件(GAP)。此外,还 支持应用程序配置文件,例如接近度、健康温度计、 心率、血压、血糖、人机界面设备(HID)和 SDK (包括驱动程序、OS-API 等)。SDK 还集成了用于网络应用程序的 SIG Mesh 协议。

采用 Freqchip 的创新技术,将 PMU(锂电池充电 器+LDO)、带 XIP 模式的 QSPI FLASH ROM、 I2C、UART、GPIO、ADC、PWM 集成在一块芯片中,为客户提供:

  • 竞争力的功耗
  • 稳定的蓝牙连接
  • 极低的 BOM 成本

02. FR801xH功能框图

在这里插入图片描述

03. GPIO相关类型

位于 components\driver\include\driver_gpio.h。

3.1 system_port_t

enum system_port_t
{
    GPIO_PORT_A,
    GPIO_PORT_B,
    GPIO_PORT_C,
    GPIO_PORT_D,
};

3.2 system_port_bit_t

enum system_port_bit_t
{
    GPIO_BIT_0,
    GPIO_BIT_1,
    GPIO_BIT_2,
    GPIO_BIT_3,
    GPIO_BIT_4,
    GPIO_BIT_5,
    GPIO_BIT_6,
    GPIO_BIT_7,
};

3.3 DIR

#define GPIO_DIR_IN             1
#define GPIO_DIR_OUT            0

04. GPIO相关函数

4.1 gpio_portX_write

/*********************************************************************
 * @fn      gpio_porta_write
 *
 * @brief   set gpio PORTA output value.
 *
 * @param   value   - output value.
 *
 * @return  None.
 */
__INLINE void gpio_porta_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTA_DATA, value);
}

/*********************************************************************
 * @fn      gpio_portb_write
 *
 * @brief   set gpio PORTB output value.
 *
 * @param   value   - output value.
 *
 * @return  None.
 */
__INLINE void gpio_portb_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTB_DATA, value);
}

/*********************************************************************
 * @fn      gpio_portc_write
 *
 * @brief   set gpio PORTC output value.
 *
 * @param   value   - output value.
 *
 * @return  None.
 */
__INLINE void gpio_portc_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTC_DATA, value);
}

/*********************************************************************
 * @fn      gpio_portd_write
 *
 * @brief   set gpio PORTD output value.
 *
 * @param   value   - output value.
 *
 * @return  None.
 */
__INLINE void gpio_portd_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTD_DATA, value);
}

void gpio_portX_write(uint8_t value)
功能:
	设置一组 IO 由大数字控制时的输出值,x 为 a、b、c、d
参数:
	value  IO 的输出值
返回值:

4.2 gpio_portX_read

/*********************************************************************
 * @fn      gpio_porta_read
 *
 * @brief   get current value of gpio PORTA.
 *
 * @param   None.
 *
 * @return  current value of gpio PORTA.
 */
__INLINE uint8_t gpio_porta_read(void)
{
    return REG_PL_RD(GPIO_PORTA_DATA);
}

/*********************************************************************
 * @fn      gpio_portb_read
 *
 * @brief   get current value of gpio PORTB.
 *
 * @param   None.
 *
 * @return  current value of gpio PORTB.
 */
__INLINE uint8_t gpio_portb_read(void)
{
    return REG_PL_RD(GPIO_PORTB_DATA);
}

/*********************************************************************
 * @fn      gpio_portc_read
 *
 * @brief   get current value of gpio PORTC.
 *
 * @param   None.
 *
 * @return  current value of gpio PORTC.
 */__INLINE uint8_t gpio_portc_read(void)
{
    return REG_PL_RD(GPIO_PORTC_DATA);
}

 /*********************************************************************
  * @fn      gpio_portd_read
  *
  * @brief   get current value of gpio PORTD.
  *
  * @param   None.
  *
  * @return  current value of gpio PORTD.
  */
__INLINE uint8_t gpio_portd_read(void)
{
    return REG_PL_RD(GPIO_PORTD_DATA);
}

uint8_t gpio_portX_read(void)
功能:
	获取一组 IO 由大数字控制时的当前值,x 为 a、b、c、d
参数:
	无
返回值:
	IO 的当前值
    
    

4.3 gpio_portX_set_dir

/*********************************************************************
 * @fn      gpio_porta_set_dir
 *
 * @brief   set gpio works in output or input mode.
 *
 * @param   dir - the in-out direction of gpio, each bit represent one channel,
 *                0: output, 1:input.
 *
 * @return  None.
 */
__INLINE void gpio_porta_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTA_DIR, dir);
}

/*********************************************************************
 * @fn      gpio_portb_set_dir
 *
 * @brief   set gpio works in output or input mode.
 *
 * @param   dir - the in-out direction of gpio, each bit represent one channel,
 *                0: output, 1:input.
 *
 * @return  None.
 */
__INLINE void gpio_portb_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTB_DIR, dir);
}

/*********************************************************************
 * @fn      gpio_portc_set_dir
 *
 * @brief   set gpio works in output or input mode.
 *
 * @param   dir - the in-out direction of gpio, each bit represent one channel,
 *                0: output, 1:input.
 *
 * @return  None.
 */
__INLINE void gpio_portc_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTC_DIR, dir);
}

/*********************************************************************
 * @fn      gpio_portd_set_dir
 *
 * @brief   set gpio works in output or input mode.
 *
 * @param   dir - the in-out direction of gpio, each bit represent one channel,
 *                0: output, 1:input.
 *
 * @return  None.
 */
__INLINE void gpio_portd_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTD_DIR, dir);
}

void gpio_portX_set_dir(uint8_t dir)
功能:
	设置一组 IO 由大数字控制时的输入输出,x 为 a、b、c、d
参数:
	dir  输入输出,每一位对应一个 IO,0:输出;1:输入
返回值:

4.4 gpio_portX_get_dir

/*********************************************************************
 * @fn      gpio_porta_set_dir
 *
 * @brief   get current gpio PORTA in-out setting.
 *
 * @param   None.
 *
 * @return  current setting.
 */
__INLINE uint8_t gpio_porta_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTA_DIR);
}

/*********************************************************************
 * @fn      gpio_portb_set_dir
 *
 * @brief   get current gpio PORTB in-out setting.
 *
 * @param   None.
 *
 * @return  current setting.
 */
__INLINE uint8_t gpio_portb_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTB_DIR);
}

/*********************************************************************
 * @fn      gpio_portc_set_dir
 *
 * @brief   get current gpio PORTC in-out setting.
 *
 * @param   None.
 *
 * @return  current setting.
 */
__INLINE uint8_t gpio_portc_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTC_DIR);
}

/*********************************************************************
 * @fn      gpio_portd_set_dir
 *
 * @brief   get current gpio PORTD in-out setting.
 *
 * @param   None.
 *
 * @return  current setting.
 */
__INLINE uint8_t gpio_portd_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTD_DIR);
}

uint8_t gpio_portX_get_dir(void)
功能:
	获取一组 IO 由大数字控制时的输入输出设置,x 为 a、b、c、d
参数:
	无
返回值:
	当前的输入输出配置
    

4.5 gpio_set_dir

/*********************************************************************
 * @fn      gpio_set_dir
 *
 * @brief   set specific gpio channel working mode: output or input.
 *
 * @param   port    - which port this channel belongs to. @ref system_port_t
 *          bit     - channel number. @ref system_port_bit_t
 *          dir     - in-out selection, should be GPIO_DIR_IN or GPIO_DIR_OUT.
 *
 * @return  None.
 */
void gpio_set_dir(enum system_port_t port, enum system_port_bit_t bit, uint8_t dir);
功能:
	设置 IO 由大数字控制时的输入输出,一次设置一个 IO
参数:
	port IO 所属的端口组
	bit  IO 的 channel 编号
	dir  输入或者输出
返回值:

示例

gpio_set_dir(GPIO_PORT_A, GPIO_BIT_0, GPIO_DIR_OUT);

05. 低功耗模式GPIO接口

5.1 pmu_set_gpio_value

/*********************************************************************
 * @fn      pmu_set_gpio_value
 *
 * @brief   set value of IOs which are controlled by PMU.
 *          example usage:
 *          pmu_set_gpio_value(GPIO_PORT_A, (1<<GPIO_BIT0)|((1<<GPIO_BIT1), 1)
 *
 * @param   port    - which group the io belongs to, @ref system_port_t
 *          bits    - the numbers of io
 *          value   - 1: set the IO to high, 0: set the IO to low.
 *
 * @return  None.
 */
void pmu_set_gpio_value(enum system_port_t port, uint8_t bits, uint8_t value);
功能:
	当某个 pin 脚被配置为 pmu gpio 控制,并且是输出模式时,设置该 pin 脚的值
参数:
	port 选择 pin 脚对应的 port 口,一共有 4 个 port 口,PA,PB,PC,PD。参见 enum system_port_t 定义。
	bits 选择 pin 脚对应的 pin 号码,bit7~bit0 分别代表每个 port 口的 pin7~pin0。每个 bit 位表示该 pin 被选中。
	Value 设置 pin 脚输出值。只能填以下二值:1,该 pin 输出为高。0,该 pin 输出为低。
返回值:

示例

void pmu_gpio_test(void)
{
    pmu_set_port_mux(GPIO_PORT_A,GPIO_BIT_0,PMU_PORT_MUX_GPIO);
    pmu_set_port_mux(GPIO_PORT_A,GPIO_BIT_1,PMU_PORT_MUX_GPIO);
    pmu_set_pin_to_PMU(GPIO_PORT_A,BIT(0)|BIT(1) );
    pmu_set_pin_dir(GPIO_PORT_A,BIT(0)|BIT(1), GPIO_DIR_OUT);
    pmu_set_pin_pull(GPIO_PORT_A, BIT(0)|BIT(1), true);
    pmu_set_gpio_value(GPIO_PORT_A, BIT(0)|BIT(1), 1);
    co_delay_100us(10);
    
	pmu_set_gpio_value(GPIO_PORT_A, BIT(0)|BIT(1), 0);
}    

5.2 pmu_get_gpio_value

/*********************************************************************
 * @fn      pmu_get_gpio_value
 *
 * @brief   get value of IO which are controlled by PMU and in GPIO mode.
 *          example usage:
 *          pmu_get_gpio_value(GPIO_PORT_A, GPIO_BIT_0)
 *
 * @param   port    - which group the io belongs to, @ref system_port_t
 *          bit     - the number of io
 *
 * @return  1: the IO is high, 0: the IO is low..
 */
uint8_t pmu_get_gpio_value(enum system_port_t port, uint8_t bit);
功能:
	当某个 pin 脚被配置为 pmu gpio 控制,并且是输入模式时,获取该 pin 脚的值。
参数:
	port 选择 pin 脚对应的 port 口,一共有 4 个 port 口,PA,PB,PC,PD。参见 enum system_port_t 定义。
	bit 选择 pin 脚对应的 pin 号码,参见 enum system_port_bit_t 定义
返回值:
	IO口的值

示例

void pmu_gpio_test(void)
{
    pmu_set_port_mux(GPIO_PORT_A,GPIO_BIT_2,PMU_PORT_MUX_GPIO);
    pmu_set_port_mux(GPIO_PORT_A,GPIO_BIT_3,PMU_PORT_MUX_GPIO);
    pmu_set_pin_to_PMU(GPIO_PORT_A,BIT(2)|BIT(3) );
    pmu_set_pin_dir(GPIO_PORT_A,BIT(2)|BIT(3), false);
    co_printf("PA2:%d,PA3:%d\r\n",pmu_get_gpio_value(GPIO_PORT_A,GPIO_BIT_2)
    	,pmu_get_gpio_value(GPIO_PORT_A,GPIO_BIT_3) );
}

06. 按键控制LED闪烁模式(非阻塞)

6.1 定时器实现非阻塞式程序

•程序功能:按键控制LED,使其切换不同的点亮模式

•程序要求:按键灵敏,每次按键按下都能准确切换模式

​ 模块要高度封装,主程序调用要简洁

​ 在任何时候模块代码都不能阻塞主程序

在这里插入图片描述

6.2 阻塞和非阻塞

•阻塞:执行某段程序时,CPU因为需要等待延时或者等待某个信号而被迫处于暂停状态一段时间,程序执行时间较长或者时间不定

•非阻塞:执行某段程序时,CPU不会等待,程序很快执行结束

在这里插入图片描述

6.3 定时器扫描按键-单按键

•定时中断,每隔20ms读取一次本次引脚值和上次引脚值

•判断,如果本次是1,上次是0,则表示按键按下且当前处于刚松手的状态

•置键码标志位,向主程序报告此事件

在这里插入图片描述

6.4 定时器扫描按键-多按键

•先写一个获取键码值的子函数(非阻塞式)

•定时中断,每隔20ms读取一次本次键码值和上次键码值

•判断,如果本次是0,上次非0,则表示按键按下且当前处于刚松手的状态

•置键码标志位,向主程序报告此事件

在这里插入图片描述

6.5 定时器实现LED闪烁

•定时中断,每隔1ms计次变量自增

•计次变量计到周期值时,归零

•判断,如果计次变量小于一个比较值,开灯,否则,关灯

在这里插入图片描述

07. 程序示例

led.h

#ifndef __LED_H__
#define __LED_H__


// PA1
void led_init(void);
void led_set_mode(uint8_t mode);
void led_tick(void);


#endif

led.c


#include <stdio.h>

#include "os_timer.h"
#include "co_printf.h"
#include "driver_gpio.h"


static uint8_t led_mode = 0;
static uint16_t led_count = 0;

// PA1
void led_init(void)
{
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_1, PORTA1_FUNC_A1);
    gpio_set_dir(GPIO_PORT_A, GPIO_BIT_1, GPIO_DIR_OUT);
    gpio_set_pin_value(GPIO_PORT_A, GPIO_BIT_1, 0);
}

void led_set_mode(uint8_t mode)
{
    if (led_mode != mode)
    {
        led_mode = mode;
        led_count = 0;
    }
}

static void led_on(void)
{
    gpio_set_pin_value(GPIO_PORT_A, GPIO_BIT_1, 1);
}

static void led_off(void)
{
    gpio_set_pin_value(GPIO_PORT_A, GPIO_BIT_1, 0);
}

void led_tick(void)
{
    if (0 == led_mode)
    {
        // 熄灭
        led_off();
    }
    else if (1 == led_mode)
    {
        // 常亮
        led_on();
    }
    else if (2 == led_mode)
    {
        led_count++;
        led_count %= 100;

        // 慢闪
        if (led_count < 50)
        {
            led_on();
        }
        else
        {
            led_off();
        }
    }
    else if (3 == led_mode)
    {
        led_count++;
        led_count %= 10;

        // 快闪
        if (led_count < 5)
        {
            led_on();
        }
        else
        {
            led_off();
        }
    }
    else if (4 == led_mode)
    {
        led_count++;
        led_count %= 100;

        // 点闪
        if (led_count < 10)
        {
            led_on();
        }
        else
        {
            led_off();
        }
    }
}

key.h

#ifndef __MY_KEY_H__
#define __MY_KEY_H__

#include "sys_utils.h"


// PC5
void key_init(void);
uint8_t key_get_status(void);
void key_tick(void);

void key_demo(void);

#endif 



key.c

#include "key.h"
#include <stdio.h>

#include "os_timer.h"
#include "co_printf.h"
#include "driver_gpio.h"

#include "led.h"

// 按键检测定时器
os_timer_t key_timer;

// PC5
uint8_t key_status;

void key_init(void)
{
    system_set_port_mux(GPIO_PORT_C, GPIO_BIT_5, PORTC5_FUNC_C5);
    gpio_set_dir(GPIO_PORT_C, GPIO_BIT_5, GPIO_DIR_IN);
}

// 读取之后清零
uint8_t key_get_status(void)
{
    uint8_t tmp;

    if (key_status)
    {
        tmp = key_status;
        key_status = 0;

        return tmp;
    }

    return 0;
}

uint8_t key_get_pressed(void)
{
    // 按键按下
    if (gpio_get_pin_value(GPIO_PORT_C, GPIO_BIT_5) == 0)
    {
        return 1;
    }

    // 按键没有按下
    return 0;
}

void key_tick(void)
{
    static uint8_t count = 0;
    static uint8_t prev_state = 0, curr_state = 0;

    count++;

    // 20ms检测一次
    if (count >= 2)
    {
        count = 0;

        prev_state = curr_state;
        curr_state = key_get_pressed();

        // co_printf("prev_state: %d curr_state: %d\r\n", prev_state, curr_state);

        if (0 != prev_state && 0 == curr_state)
        {
            key_status = prev_state;
        }
    }
}

//--------------------------------------------------------------------------

// 定时器
void key_timer_func(void *parg)
{
    uint8_t key_status = 0;
    static uint8_t led_mode = 0;

    // co_printf("timer timeout.....\r\n");
    key_tick();
    led_tick();

    key_status = key_get_status();
    if (1 == key_status)
    {
        led_mode++;
        led_mode %= 5;

        co_printf("led_mode: %d\r\n", led_mode);

        led_set_mode(led_mode);
    }
}

void key_demo(void)
{
    uint8_t key_status = 0;
    uint8_t led_mode = 0;

    co_printf("key demo\r\n");

    // 创建定时器1
    os_timer_init(&key_timer, key_timer_func, NULL);
    // 10ms定时器
    os_timer_start(&key_timer, 10, 1);

    key_init();
    led_init();
}

程序运行结果

led_mode: 1
led_mode: 2
led_mode: 3
led_mode: 4
led_mode: 0
led_mode: 1
led_mode: 2
led_mode: 3
led_mode: 4
led_mode: 0
led_mode: 1
led_mode: 2
led_mode: 3
led_mode: 4

08. 附录

下载:按键控制LED闪烁模式示例.rar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沧海一笑-dj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值