打印
[其他ST产品]

【正点原子K210连载】第六章 跑马灯实验-《DNK210使用指南-SDK版》

[复制链接]
32|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
第六章 跑马灯实验
本章实验将介绍如何使用SDK编程让Kendryte K210控制板载的双色LED闪烁,以实现跑马灯的效果。通过本章的学习,读者将学习到用SDK编程技术控制Kendryte K210GPIO输出高低电平。
本章分为如下几个小节:
6.1 FPIOA介绍
6.2 GPIO介绍
6.3 硬件设计
6.4 程序设计
6.5 运行验证
6.1 FPIOA介绍
FPIOAField Programmable Input and Output Array,现场可编程IO阵列)是Kendryte K210芯片内部的模块,FPIOA最主要的功能是允许用户将Kendryte K210芯片内部的255个功能映射到芯片外围的48个自由IO上,因为Kendryte K210芯片内部外设的功能与Kendryte K210引出的外部引脚是彼此独立的,这样的好处是IO引脚可以再不同时刻扮演不同的角色,极大地方便了软硬件的开发,同时它还具有以下功能:
1. 支持IO的可编程功能选择;
2. 支持IO输出的8种驱动能选择;
3. 支持IO的内部上拉电阻选择;
4. 支持IO的内部下拉电阻选择;
5. 支持IO输入的内部施密特触发器设置;
6. 支持IO输出的斜率控制;
7. 支持内部输入逻辑的电平设置。
裸机SDK内置了FPIOA 驱动文件fpioa.c和对应的头文件,共有数十个API函数,能够帮助开发者将引脚与具体的硬件功能进行绑定或解绑,以及方便各个管脚的使用和功能配置。
Kendryte K210一共有48个自由IO,对应的引脚编号为0~47,本章实验只使用到几个普通GPIO口,更详细的硬件功能列表请见表6.1.1。
硬件功能
描述
硬件功能
描述
JTAG_TCLK
JTAG Test Clock
I2S1_IN_D1
I2S1 Serial Data Input 1
JTAG_TDI
JTAG Test Data In
I2S1_IN_D2
I2S1 Serial Data Input 2
JTAG_TMS
JTAG Test Mode Select
I2S1_IN_D3
I2S1 Serial Data Input 3
JTAG_TDO
JTAG Test Data Out
I2S1_OUT_D0
I2S1 Serial Data Output 0
SPI0_D0
SPI0 Data 0
I2S1_OUT_D1
I2S1 Serial Data Output 1
SPI0_D1
SPI0 Data 1
I2S1_OUT_D2
I2S1 Serial Data Output 2
SPI0_D2
SPI0 Data 2
I2S1_OUT_D3
I2S1 Serial Data Output 3
SPI0_D3
SPI0 Data 3
I2S2_MCLK
I2S2 Master Clock
SPI0_D4
SPI0 Data 4
I2S2_SCLK
I2S2 Serial Clock(BCLK)
SPI0_D5
SPI0 Data 5
I2S2_WS
I2S2 Word Select(LRCLK)
SPI0_D6
SPI0 Data 6
I2S2_IN_D0
I2S2 Serial Data Input 0
SPI0_D7
SPI0 Data 7
I2S2_IN_D1
I2S2 Serial Data Input 1
SPI0_SS0
SPI0 Chip Select 0
I2S2_IN_D2
I2S2 Serial Data Input 2
SPI0_SS1
SPI0 Chip Select 1
I2S2_IN_D3
I2S2 Serial Data Input 3
SPI0_SS2
SPI0 Chip Select 2
I2S2_OUT_D0
I2S2 Serial Data Output 0
SPI0_SS3
SPI0 Chip Select 3
I2S2_OUT_D1
I2S2 Serial Data Output 1
SPI0_ARB
SPI0 Arbitration
I2S2_OUT_D2
I2S2 Serial Data Output 2
SPI0_SCLK
SPI0 Serial Clock
I2S2_OUT_D3
I2S2 Serial Data Output 3
UARTHS_RX
UART High speed Receiver
RESV0
Reserved function
UARTHS_TX
UART High speed Transmitter
RESV1
Reserved function
RESV6
Reserved function
RESV2
Reserved function
RESV7
Reserved function
RESV3
Reserved function
CLK_SPI1
Clock SPI1
RESV4
Reserved function
CLK_I2C1
Clock I2C1
RESV5
Reserved function
GPIOHS0
GPIO High speed 0
I2C0_SCLK
I2C0 Serial Clock
GPIOHS1
GPIO High speed 1
I2C0_SDA
I2C0 Serial Data
GPIOHS2
GPIO High speed 2
I2C1_SCLK
I2C1 Serial Clock
GPIOHS3
GPIO High speed 3
I2C1_SDA
I2C1 Serial Data
GPIOHS4
GPIO High speed 4
I2C2_SCLK
I2C2 Serial Clock
GPIOHS5
GPIO High speed 5
I2C2_SDA
I2C2 Serial Data
GPIOHS6
GPIO High speed 6
CMOS_XCLK
DVP System Clock
GPIOHS7
GPIO High speed 7
CMOS_RST
DVP System Reset
GPIOHS8
GPIO High speed 8
CMOS_PWDN
DVP Power Down Mode
GPIOHS9
GPIO High speed 9
CMOS_VSYNC
DVP Vertical Sync
GPIOHS10
GPIO High speed 10
CMOS_HREF
DVP Horizontal Reference output
GPIOHS11
GPIO High speed 11
CMOS_PCLK
Pixel Clock
GPIOHS12
GPIO High speed 12
CMOS_D0
Data Bit 0
GPIOHS13
GPIO High speed 13
CMOS_D1
Data Bit 1
GPIOHS14
GPIO High speed 14
CMOS_D2
Data Bit 2
GPIOHS15
GPIO High speed 15
CMOS_D3
Data Bit 3
GPIOHS16
GPIO High speed 16
CMOS_D4
Data Bit 4
GPIOHS17
GPIO High speed 17
CMOS_D5
Data Bit 5
GPIOHS18
GPIO High speed 18
CMOS_D6
Data Bit 6
GPIOHS19
GPIO High speed 19
CMOS_D7
Data Bit 7
GPIOHS20
GPIO High speed 20
SCCB_SCLK
SCCB Serial Clock
GPIOHS21
GPIO High speed 21
SCCB_SDA
SCCB Serial Data
GPIOHS22
GPIO High speed 22
UART1_CTS
UART1 Clear To Send
GPIOHS23
GPIO High speed 23
UART1_DSR
UART1 Data Set Ready
GPIOHS24
GPIO High speed 24
UART1_DCD
UART1 Data Carrier Detect
GPIOHS25
GPIO High speed 25
UART1_RI
UART1 Ring Indicator
GPIOHS26
GPIO High speed 26
UART1_SIR_IN
UART1 Serial Infrared Input
GPIOHS27
GPIO High speed 27
UART1_DTR
UART1 Data Terminal Ready
GPIOHS28
GPIO High speed 28
UART1_RTS
UART1 Request To Send
GPIOHS29
GPIO High speed 29
UART1_OUT2
UART1 User-designated Output 2
GPIOHS30
GPIO High speed 30
UART1_OUT1
UART1 User-designated Output 1
GPIOHS31
GPIO High speed 31
UART1_SIR_OUT
UART1 Serial Infrared Output
GPIO0
GPIO pin 0
UART1_BAUD
UART1 Transmit Clock Output
GPIO1
GPIO pin 1
UART1_RE
UART1 Receiver Output Enable
GPIO2
GPIO pin 2
UART1_DE
UART1 Driver Output Enable
GPIO3
GPIO pin 3
UART1_RS485_EN
UART1 RS485 Enable
GPIO4
GPIO pin 4
UART2_CTS
UART2 Clear To Send
GPIO5
GPIO pin 5
UART2_DSR
UART2 Data Set Ready
GPIO6
GPIO pin 6
UART2_DCD
UART2 Data Carrier Detect
GPIO7
GPIO pin 7
UART2_RI
UART2 Ring Indicator
UART1_RX
UART1 Receiver
UART2_SIR_IN
UART2 Serial Infrared Input
UART1_TX
UART1 Transmitter
UART2_DTR
UART2 Data Terminal Ready
UART2_RX
UART2 Receiver
UART2_RTS
UART2 Request To Send
UART2_TX
UART2 Transmitter
UART2_OUT2
UART2 User-designated Output 2
UART3_RX
UART3 Receiver
UART2_OUT1
UART2 User-designated Output 1
UART3_TX
UART3 Transmitter
UART2_SIR_OUT
UART2 Serial Infrared Output
SPI1_D0
SPI1 Data 0
UART2_BAUD
UART2 Transmit Clock Output
SPI1_D1
SPI1 Data 1
UART2_RE
UART2 Receiver Output Enable
SPI1_D2
SPI1 Data 2
UART2_DE
UART2 Driver Output Enable
SPI1_D3
SPI1 Data 3
UART2_RS485_EN
UART2 RS485 Enable
SPI1_D4
SPI1 Data 4
UART3_CTS
UART3 Clear To Send
SPI1_D5
SPI1 Data 5
UART3_DSR
UART3 Data Set Ready
SPI1_D6
SPI1 Data 6
UART3_DCD
UART3 Data Carrier Detect
SPI1_D7
SPI1 Data 7
UART3_RI
UART3 Ring Indicator
SPI1_SS0
SPI1 Chip Select 0
UART3_SIR_IN
UART3 Serial Infrared Input
SPI1_SS1
SPI1 Chip Select 1
UART3_DTR
UART3 Data Terminal Ready
SPI1_SS2
SPI1 Chip Select 2
UART3_RTS
UART3 Request To Send
SPI1_SS3
SPI1 Chip Select 3
UART3_OUT2
UART3 User-designated Output 2
SPI1_ARB
SPI1 Arbitration
UART3_OUT1
UART3 User-designated Output 1
SPI1_SCLK
SPI1 Serial Clock
UART3_SIR_OUT
UART3 Serial Infrared Output
SPI_SLAVE_D0
SPI Slave Data 0
UART3_BAUD
UART3 Transmit Clock Output
SPI_SLAVE_SS
SPI Slave Select
UART3_RE
UART3 Receiver Output Enable
SPI_SLAVE_SCLK
SPI Slave Serial Clock
UART3_DE
UART3 Driver Output Enable
I2S0_MCLK
I2S0 Master Clock
UART3_RS485_EN
UART3 RS485 Enable
I2S0_SCLK
I2S0 Serial Clock(BCLK)
TIMER0_TOGGLE1
TIMER0 Toggle Output 1
I2S0_WS
I2S0 Word Select(LRCLK)
TIMER0_TOGGLE2
TIMER0 Toggle Output 2
I2S0_IN_D0
I2S0 Serial Data Input 0
TIMER0_TOGGLE3
TIMER0 Toggle Output 3
I2S0_IN_D1
I2S0 Serial Data Input 1
TIMER0_TOGGLE4
TIMER0 Toggle Output 4
I2S0_IN_D2
I2S0 Serial Data Input 2
TIMER1_TOGGLE1
TIMER1 Toggle Output 1
I2S0_IN_D3
I2S0 Serial Data Input 3
TIMER1_TOGGLE2
TIMER1 Toggle Output 2
I2S0_OUT_D0
I2S0 Serial Data Output 0
TIMER1_TOGGLE3
TIMER1 Toggle Output 3
I2S0_OUT_D1
I2S0 Serial Data Output 1
TIMER1_TOGGLE4
TIMER1 Toggle Output 4
I2S0_OUT_D2
I2S0 Serial Data Output 2
TIMER2_TOGGLE1
TIMER2 Toggle Output 1
I2S0_OUT_D3
I2S0 Serial Data Output 3
TIMER2_TOGGLE2
TIMER2 Toggle Output 2
I2S1_MCLK
I2S1 Master Clock
TIMER2_TOGGLE3
TIMER2 Toggle Output 3
I2S1_SCLK
I2S1 Serial Clock(BCLK)
TIMER2_TOGGLE4
TIMER2 Toggle Output 4
I2S1_WS
I2S1 Word Select(LRCLK)
CLK_SPI2
Clock SPI2
I2S1_IN_D0
I2S1 Serial Data Input 0
CLK_I2C2
Clock I2C2
表6.1.1 Kendryte K210 FPIOA硬件功能表
我们简单介绍下即将使用的API函数fpioa_set_function(),该函数的功能是将硬件的管脚号与FPIOA的功能号绑定,从而设置引脚的功能,这个和STM32的引脚复用功能有点相似,使用需要传入两个参数,分别是硬件引脚和功能号,方法如下所示:
int fpioa_set_function(int number, fpioa_function_t function)
{
    uint8_t index = 0;
    /* Check parameters */
    if(number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX)
        return -1;
    if(function == FUNC_RESV0)
    {
        fpioa_set_function_raw(number, FUNC_RESV0);
        return 0;
    }
    /* Compare all 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);
    }
    fpioa_set_function_raw(number, function);
    return 0;
}
其他未用到的API函数这里暂时不再介绍,大家如果想对其他API函数进一步了解可以查阅《裸机SDK编程指南》这份文档,第一章节的时候我们也介绍过这份文档的作用,所以大家一定要先保存好这份文档方便我们查阅,在A盘存放路径是:AàKendryte K210参考资料àKendryte K210裸机SDK编程指南,接下来讲解GPIO功能。

6.2 GPIO介绍
Kendryte K210上有两种GPIOGeneral-purpose input/output,通用输入/输出),分别为GPIOHS(高速GPIO)和GPIO(通用GPIO)。
GPIOHS一共有32个,其特点如下所示:
1. 可配置输入输出信号
2. 每个IO具有独立的中断源
3. 中断支持边缘触发和电平触发
4. 每个IO可以分配到FPIOA48个管脚之一
5. 可配置上下拉,或者高阻
GPIO一共有8个,其特点如下所示:
1. 可配置输入输出信号
2. 8IO使用一个中断源
3. 可配置触发IO总中断,边沿触发和电平触发
4. 每个IO可以分配到FPIOA48个管脚之一
5. 可配置上下拉,或者高阻态

6.2.1 Kendryte K210GPIO简介
上面提到,Kendryte K210的自由IO48个,可作为GPIO的管脚情况如下图红框部分所示。
图6.2.1.1 Kendryte K210可做GPIO功能管脚图
GPIO口输出来的信号是数字信号。数字信号是以0,1表示的不连续信号,也就是以二进制形式表示的信号。在SDK中数字信号用高低电平来表示,高电平为数字信号1,低电平为数字信号0。如下图所示:
图6.2.1.2数字信号
图中Kendryte K210输出的低电平为0V,输出的高电平为当前Kendryte K210的工作电压,我们K210开发板芯片的供电电压为3.3V,则其高电平为3.3V。

6.2.2 GPIO函数介绍
Kendryte K210提供非常多操作GPIO的函数,这里我们只讲述本实验用到的函数,这些函数介绍如下,高速GPIO口这里就不再介绍了,用法都差不多。

1, gpio_init函数
该函数是通用GPIO才有的,主要用于时钟使能,如下代码所示:
int gpio_init(void)
{
    return sysctl_clock_enable(SYSCTL_CLOCK_GPIO);
}

2gpio_set_drive_mode函数
该函数来配置指定管脚的工作模式,包括输入输出模式、上下拉等,如下代码所示:
/* 函数原型 */
void gpio_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode)
/**
* gpio_set_drive_mode功能的mode配置参数
*/
typedef enum _gpio_drive_mode
{
    GPIO_DM_INPUT,
    GPIO_DM_INPUT_PULL_DOWN,
    GPIO_DM_INPUT_PULL_UP,
    GPIO_DM_OUTPUT,
} gpio_drive_mode_t;
下面我们来讲解一下这几个变量的作用。
①:参数pin为引脚软件编号,最大值要小于8
②:参数mode为指定的配置模式,如下表所示:
模式名称
说明
GPIO_DM_INPUT
输入模式(不带上下拉)
GPIO_DM_INPUT_PULL_DOWN
输入下拉模式
GPIO_DM_INPUT_PULL_UP
输入上拉模式
GPIO_DM_OUTPUT
输出模式
表6.2.2.1 引脚配置的模式
该函数无返回值。

3gpio_set_pin函数
该函数用来设置GPIO的电平状态,该函数原型及参数描述如下所示:
void gpio_set_pin(uint8_t pin, gpio_pin_value_t value)
typedef enum _gpio_pin_value
{
    GPIO_PV_LOW,
    GPIO_PV_HIGH
} gpio_pin_value_t;
下面我们讲解下这个函数的两个参数,第一个是引脚的软件编号,同上,第二个参数用于设置IO管脚的高低电平状态,GPIO_PV_LOW为指向IO输出低电平, GPIO_PV_HIGH为输出的高电平。该函数无返回值。

4gpio_get_pin函数
该函数用来获取IO的电平状态,该函数原型如下所示:
gpio_pin_value_t gpio_get_pin(uint8_t pin)
pin用来指向获取那个IO的电平,该函数的返回值就是指定IO的电平状态01

6.3 硬件设计
6.3.1 例程功能
1. 控制板载双色LED轮流闪烁,实现跑马灯的效果

6.3.2 硬件资源
1. 双色LED
        LEDR - IO24
        LEDB - IO25

6.3.3 原理图
本章实验内容,需要控制板载双色LED轮流闪烁,以实现跑马灯的效果,正点原子DNK210开发板上双色LED的连接原理图,如下图所示:
6.3.3.1 双色LED连接原理图
通过以上原理图可以看出,双色LED中红色和蓝色LED对应的IO编号分别为IO24IO25,且都是当IO输出低电平时LED亮起,当IO输出高电平时LED熄灭。

6.3 程序设计
6.3.1 led驱动代码
这里我们只讲核心部分,LED驱动源码包括两个文件:led.cled.h(正点原子团队编写的外设驱动基本都是包含一个.c 文件和一个.h 文件,下同),下面我们先介绍led.h文件。
/*****************************HARDWARE-PIN*********************************/
/* 硬件IO口,与原理图对应 */
#define PIN_LED_G             (25)
#define PIN_LED_B             (24)
/*****************************SOFTWARE-GPIO********************************/
/* 软件GPIO口,与程序对应 */
#define LEDR_GPIONUM          (0)
#define LEDB_GPIONUM          (1)
/*****************************FUNC-GPIO************************************/
/* GPIO口的功能,绑定到硬件IO*/
#define FUNC_LEDR             (FUNC_GPIO0 + LEDR_GPIONUM)
#define FUNC_LEDB             (FUNC_GPIO0 + LEDB_GPIONUM)
这部分宏定义了两个led引脚的硬件引脚号、软件编号和功能号,通过这里,我们便可通过函数将引脚功能绑定起来,同时也方便我们修改功能和硬件管脚。
/* IO操作 */
#define LEDR(x)                 do { (x) ?                                     \
                                    gpio_set_pin(LEDR_GPIONUM, GPIO_PV_HIGH):  \
                                    gpio_set_pin(LEDR_GPIONUM, GPIO_PV_LOW);   \
                                } while (0)
#define LEDB(x)                 do { (x) ?                                     \
                                    gpio_set_pin(LEDB_GPIONUM, GPIO_PV_HIGH):  \
                                    gpio_set_pin(LEDB_GPIONUM, GPIO_PV_LOW);   \
                                } while (0)
LEDRLEDB的这两个宏定义,分别控制红灯和蓝灯连接的IO引脚的高低电平,进而控制灯的亮灭,通过硬件连接图我们可以,当连接LED灯的引脚为低电平时,LED亮,为高电平时,LED灭。
x=1时,对应引脚输出高电平,当x=0时,对应引脚输出低电平,这样我们就非常方便的控制led的亮灭。
接下来我们看led.c文件。
void led_init(void)
{
    gpio_init();     /* 使能GPIO时钟 */
   
    fpioa_set_function(PIN_LED_R, FUNC_LEDR);
    fpioa_set_function(PIN_LED_B, FUNC_LEDB);
   
    /* 设置LEDRLEDBGPIO模式为输出 */
    gpio_set_drive_mode(LEDR_GPIONUM, GPIO_DM_OUTPUT);
    gpio_set_drive_mode(LEDB_GPIONUM, GPIO_DM_OUTPUT);
   
    /* 先关闭LEDRLEDB */
    gpio_set_pin(LEDR_GPIONUM, GPIO_PV_HIGH);
    gpio_set_pin(LEDB_GPIONUM, GPIO_PV_HIGH);
}
这个文件只有led_init()这个函数,我们首先是进行GPIO使能,然后通过fpioa的函数将硬件管脚和功能绑定,然后设置GPIO的功能,最后将管脚电平拉高,使两个LED灯处于关闭状态,这部分内容还是比较容易理解。
6.3.2 main.c代码
main.c中的代码如下所示:
#include <stdio.h>
#include <unistd.h>
#include "./BSP/LED/led.h"
#include "gpio.h"
#include "fpioa.h"
int main(void)
{
    led_init();    /* LED初始化 */
    while (1)
    {
        LEDR(1);   /* 红灯灭 */
        LEDB(0);   /* 蓝灯亮 */
        sleep(1);  /* 延时1*/
        LEDR(0);   /* 红灯亮 */
        LEDB(1);   /* 蓝灯灭 */
        sleep(1);  /* 延时1*/
    }
}
可以看到,首先通过led_init()为控制双色LED的两个IO分别分配了GPIO0GPIO1的功能,并配置为输出模式,最后在一个循环中轮流设置LEDR和LEDB输出不同的高低电平并延时一秒时间,从而应该能看到板载的双色LED轮流亮起、熄灭,实现跑马灯的效果。

6.4 运行验证
将DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中(方法参考上一章内容,下同),可以看到板载的双色LED轮流亮起、熄灭,实现跑马灯的效果,这与理论推断的结果一致。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

69

主题

70

帖子

1

粉丝