K210开发板学习笔记-点亮LED灯
1. 介绍
和 51 单片机非常像,实验的2个LED灯都是一头接了 +3.3v 电源,控制 LED灯亮的话需要 K210芯片 对应的管脚提供一个低电平。
管脚:
- 低电平-LED亮
- 高电平-LED灭
GPIO 连接为:
- K210-io0 -> LED0 ->+3.3v
- K210-io17 -> LED1 ->+3.3v
2. 代码
- pin_config.h
/**
* @par Copyright (C): 2016-2022, Shenzhen Yahboom Tech
* @file pin_config.c
* @author Gengyue
* @version V1.0
* @date 2020.05.27
* @brief 硬件引脚与软件GPIO的宏定义
* @details
* @par History 见如下说明
*
* version: 由于K210使用fpioa现场可编程IO阵列,允许用户将255个内部功能映射到芯片外围的48个自由IO上
* 所以把硬件IO和软件GPIO功能抽出来单独设置,这样更容易理解。
*/
#ifndef _PIN_CONFIG_H_
#define _PIN_CONFIG_H_
/*****************************HEAR-FILE************************************/
#include "fpioa.h"
/*****************************HARDWARE-PIN*********************************/
// 硬件IO口,与原理图对应
#define PIN_LED_0 (0)
#define PIN_LED_1 (17)
/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define LED0_GPIONUM (0)
#define LED1_GPIONUM (1)
/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
//通用gpio共8个,使用同一个中断源,可配置输入输出信号,可配置触发IO口总中断,边沿触发和电平触发。每隔IO可以分配到FPIOA上48个管脚之一
//也就是说,可用的通用 gpio 一共有 8 个, 从 FUNC_GPIO0 可知, 对应功能编号为 FUNC_GPIO0(56) ~ FUNC_GPIO7(63)
//在此处采用了 在 基准 FUNC_GPIO0 基础上 +0、+1 来确定对应的 通用 gpio 编号
#define FUNC_LED0 (FUNC_GPIO0 + LED0_GPIONUM)
#define FUNC_LED1 (FUNC_GPIO0 + LED1_GPIONUM)
#endif /* _PIN_CONFIG_H_ */
- main.c
/**
* @par Copyright (C): 2016-2022, Shenzhen Yahboom Tech
* @file main.c
* @author Gengyue
* @version V1.0
* @date 2020.05.27
* @brief FPIOA映射和GPIO驱动LED灯
* @details
* @par History 见如下说明
*
* version: V1.0: LED0与LED1交替点亮,时间间隔为1秒。
*/
#include <stdio.h>
#include <unistd.h>
#include "gpio.h"
#include "pin_config.h"
/**
* Function hardware_init
* @author Gengyue
* @date 2020.05.27
* @brief 硬件初始化,绑定GPIO口
* @param[in] void
* @param[out] void
* @retval void
* @par History 无
*/
void hardware_init(void)
{
//绑定 K210芯片实际管脚与其对应的fpioa函数编号
fpioa_set_function(PIN_LED_0, FUNC_LED0);
fpioa_set_function(PIN_LED_1, FUNC_LED1);
}
/**
* Function main
* @author Gengyue
* @date 2020.05.27
* @brief 主函数,程序的入口
* @param[in] void
* @param[out] void
* @retval 0
* @par History 无
*/
int main(void)
{
hardware_init();// 硬件引脚初始化
gpio_init(); // 使能GPIO的时钟
// 设置LED0和LED1的GPIO模式为输出
gpio_set_drive_mode(LED0_GPIONUM, GPIO_DM_OUTPUT);
gpio_set_drive_mode(LED1_GPIONUM, GPIO_DM_OUTPUT);
// 先关闭LED0和LED1
gpio_pin_value_t value = GPIO_PV_HIGH;
gpio_set_pin(LED0_GPIONUM, value);
gpio_set_pin(LED1_GPIONUM, value);
while (1)
{
sleep(1);
gpio_set_pin(LED0_GPIONUM, value);
gpio_set_pin(LED1_GPIONUM, value = !value);
}
return 0;
}
通过 main.c 可以看到,总共有如下步骤:
- 硬件引脚初始化;
- 使能 GPIO 时钟;
- 设置LED0和LED1的GPIO模式为输出
- 循环控制 LED0 和 LED1 亮灭交替
1. 硬件引脚初始化
void hardware_init(void)
{
//绑定 K210芯片实际管脚与其对应的fpioa函数编号
fpioa_set_function(PIN_LED_0, FUNC_LED0);
fpioa_set_function(PIN_LED_1, FUNC_LED1);
}
PIN_LED_0 是 K210 实际引脚编号,FUNC_LED0 (FUNC_GPIO0 + LED0_GPIONUM)是映射的 fpioa 函数编号
在fpioa_set_function(int number, fpioa_function_t function)中
int fpioa_set_function(int number, fpioa_function_t function)
{
uint8_t index = 0;
/* Check parameters */
// 检查参数
//1. 0<引脚编号number<FPIOA_NUM_IO(48)
//2. 0<函数编号<FUNC_MAX(256)
if(number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX)
return -1;
//如果引脚绑定的函数为 保留功能FUNC_RESV0(120),直接设置并返回
if(function == FUNC_RESV0)
{
fpioa_set_function_raw(number, FUNC_RESV0);
return 0;
}
/* Compare all IO */
//在48个IO FPIOA_NUM_IO 查询
//如果待绑定的函数 function 已被其他 管脚io占用,设置占用的管脚io绑定保留功能
for(index = 0; index < FPIOA_NUM_IO; index++)
{
if((fpioa->io[index].ch_sel == function) && (index != number))
fpioa_set_function_raw(index, FUNC_RESV0);
}
//绑定 K210 实际管脚 number 与 内置函数编号 function
//注意,在点亮LED例程,传入的 function:
// (FUNC_GPIO0 + LED0_GPIONUM) 和 (FUNC_GPIO0 + LED0_GPIONUM) (56+0, 56+1)
fpioa_set_function_raw(number, function);
return 0;
}
2. 设置LED0和LED1的GPIO模式为输出
使能 GPIO 时钟 就是字面意思,不再加以分析
// 设置LED0和LED1的GPIO模式为输出
// 传参分别为:
// LED0_GPIONUM(0), GPIO_DM_OUTPUT(3)
// LED1_GPIONUM(1), GPIO_DM_OUTPUT(3)
gpio_set_drive_mode(LED0_GPIONUM, GPIO_DM_OUTPUT);
gpio_set_drive_mode(LED1_GPIONUM, GPIO_DM_OUTPUT);
void gpio_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode)
{
// 确保 GPIO pin < GPIO_MAX_PINNO(8,最大通用gpio)
configASSERT(pin < GPIO_MAX_PINNO);
//根据功能号获取 IO 管脚号
//大于等于 0 IO 管脚号
//小于 0 失败
int io_number = fpioa_get_io_by_function(FUNC_GPIO0 + pin);
//确保获取通用管脚号成功
configASSERT(io_number >= 0);
fpioa_pull_t pull;
uint32_t dir;
switch(mode)
{
case GPIO_DM_INPUT:
pull = FPIOA_PULL_NONE;
dir = 0;
break;
case GPIO_DM_INPUT_PULL_DOWN:
pull = FPIOA_PULL_DOWN;
dir = 0;
break;
case GPIO_DM_INPUT_PULL_UP:
pull = FPIOA_PULL_UP;
dir = 0;
break;
case GPIO_DM_OUTPUT:
pull = FPIOA_PULL_DOWN;
dir = 1;
break;
default:
configASSERT(!"GPIO drive mode is not supported.") break;
}
//设置 IO 的上拉下拉
fpioa_set_io_pull(io_number, pull);
set_gpio_bit(gpio->direction.u32, pin, dir);
}
在这个函数中,就可以看出之前明明绑定 k210实际管脚时用的是:
//FUNC_LED0 (FUNC_GPIO0 + LED0_GPIONUM)
fpioa_set_function(PIN_LED_0, FUNC_LED0);
但是设置 GPIO模式为输出 时用的是:
gpio_set_drive_mode(LED0_GPIONUM, GPIO_DM_OUTPUT);
原理就在于 在传入到 gpio_set_drive_mode 函数后,找 函数对应的管脚号用的是:
int io_number = fpioa_get_io_by_function(FUNC_GPIO0 + pin);
其中 pin=LED0_GPIONUM
可能考虑到函数的简洁,函数fpioa_get_io_by_function(uint8_t pin, gpio_drive_mode_t mode)
把 软件GPIO口 LED0_GPIONUM
和 GPIO口的功能 FUNC_LED0
的对应关系封装起来了;
结果就导致虽然在 pin_config.h 中定义了
/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define LED0_GPIONUM (0)
#define LED1_GPIONUM (1)
/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
//通用gpio共8个,使用同一个中断源,可配置输入输出信号,可配置触发IO口总中断,边沿触发和电平触发。每隔IO可以分配到FPIOA上48个管脚之一
//也就是说,可用的通用 gpio 一共有 8 个, 从 FUNC_GPIO0 可知, 对应功能编号为 FUNC_GPIO0(56) ~ FUNC_GPIO7(63)
//在此处采用了 在 基准 FUNC_GPIO0 基础上 +0、+1 来确定对应的 通用 gpio 编号
#define FUNC_LED0 (FUNC_GPIO0 + LED0_GPIONUM)
#define FUNC_LED1 (FUNC_GPIO0 + LED1_GPIONUM)
但在 main.c 中不知道为什么可以通过 LED0_GPIONUM
设置 FUNC_LED0
绑定的 K210 实际管脚的工作方式