【龙芯1c库】封装gpio接口和使用示例

来源:互联网 发布:9988bi新域名 编辑:程序博客网 时间:2024/06/16 13:29

龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库。git地址:http://git.oschina.net/caogos/OpenLoongsonLib1c

本文首先以一个例子介绍“龙芯1c库”中gpio接口是怎样使用的,然后再详细讲解是怎样封装这些接口的。

龙芯1c库中gpio接口使用示例

gpio接口简介

龙芯1c库提供3个接口,分别是gpio_init(),gpio_set()和gpio_get()。

使用步骤为,先使用gpio_init()初始化对应的gpio,然后使用gpio_set()在gpio上输出高低电平,或者使用gpio_get()读取gpio上的电平值。

测试思路

使用led测试gpio输出,选择了GPIO6,GPIO32,GPIO74三个引脚来测试。

用按键测试gpio输入,采用不断读取gpio的方式,一旦发现按键按下,则指示灯点亮,否则指示灯熄灭。按键所在引脚为GPIO85(智龙v2.0和v2.1上的按键S3),指示灯为GPIO32。

在智龙首发版、v2.0和v2.1上gpio32都接有led,并且都可控。

代码清单

app\main.c

#include "../lib/gpio.h"#include "../lib/clock.h"#include "led.h"/* * 测试库中gpio作为输出时的相关接口 * led闪烁10次 */void gpio_test_output(void){    int i;    unsigned int gpio = 32;     // 智龙首发版、v2.0和v2.1都有这个led//    unsigned int gpio = 6;//    unsigned int gpio = 74;    // 初始化    gpio_init(gpio, gpio_mode_output);    // 输出10个矩形波,如果gpio50上有led,则可以看见led闪烁10次    for (i=0; i<10; i++)    {        gpio_set(gpio, gpio_level_low);        delay();        gpio_set(gpio, gpio_level_high);        delay();    }    return ;}/* * 测试库中gpio作为输入时的相关接口 * 按键按下时,指示灯点亮,否则,熄灭 */void gpio_test_input(void){    unsigned int key_gpio = 85;     // GPIO85/I2C_SDA0,智龙v2.1上的按键S3    unsigned int led_gpio = 32;     // 用于当按键被按下时,此led点亮,否则熄灭    // 初始化    gpio_init(key_gpio, gpio_mode_input);    led_init(led_gpio);    while (1)    {        if (gpio_level_low != gpio_get(key_gpio))            continue;       // 按键没有按下        // 延时(软件消抖)后再次确认按键是否按下        delay();        if (gpio_level_low != gpio_get(key_gpio))            continue;       // 按键没有按下        // 点亮指示灯        led_on(led_gpio);        // 等待释放按键        while (gpio_level_high != gpio_get(key_gpio))            ;        delay();        // 熄灭指示灯        led_off(led_gpio);    }}int main(void){    /*     * 测试库中gpio作为输出时的相关接口     * led闪烁10次     */    gpio_test_output();            /*     * 测试库中gpio作为输入时的相关接口     * 按键按下时,指示灯点亮,否则,熄灭     */    gpio_test_input();return(0);}

更完整的代码清单,请查看http://git.oschina.net/caogos/OpenLoongsonLib1c的提交记录


龙芯1c的GPIO简介

gpio命名规则

龙芯1c的gpio命名与其它单片机有点不一样。龙芯1c的gpio有gpio0、gpio1、gpio2………gpio103、gpio104,目前QFP176封装的编号最大达到了gpio104。其它单片机都是把gpio分为多个端口,每个端口有n个io,这点上龙芯1c是不是和其它单片机有点不一样啊。更多的具体信息请参考《龙芯1c300处理器数据手册 v1.3》如下

gpio相关寄存器

再来看看《龙芯1c300处理器用户手册v1.4》中关于gpio寄存器相关的描述

截图最下面的文字说了,假设要在gpio16上输出1,需要配置 GPIO_CFG[16]=1,  GPIO_EN[16]=0,  GPIO_OUT[16]=1。

同理可得把gpio16作为输入,并读取io上的值,那么需要配置GPIO_CFG[16]=1,   GPIO_EN[16]=1,然后读取GPIO_IN[16]的值就知道了io上是高电平,还是低电平。

寄存器GPIO_CFG0的作用是配置某个io用作普通GPIO,还是其它功能。

寄存器GPIO_EN0的作用是配置某个gpio作为输入,还是输出。(个人认为)这个寄存器名字取得不好,en通常用于表示使能(enable)

寄存器GPIO_IN0的作用是,当gpio作为输入时,读取寄存器GPIO_IN0中的值就得到了对应GPIO引脚上的高低电平值。

寄存器GPIO_OUT0的作用是,当gpio作为输出时,向寄存器GPIO_OUT0中写入值,那么对应的GPIO上就呈现出相应的高低电平。

注意上面截图中标题5.2.8提示GPIO_CFG0, GPIO_EN0, GPIO_IN0, GPIO_OUT0为一组寄存器,控制GPIO0到GPIO31共32个io引脚。后面还有几组类似的寄存器如下

这组寄存器对应GPIO32到GPIO63

这组寄存器对应GPIO64到GPIO95


这组寄存器对应GPIO96到GPIO127


封装代码库

代码要点

经过上面分析,其实还是蛮有规律的。封装代码库时我就把一组寄存器当作“一个端口的寄存器”,寄存器中每一位当作“一个端口中的一个io”。

“端口号”为0,1,2,3。端口号 = 龙芯1c的GPIO编号 / 32。

"一个端口中引脚的序号"从0到31,序号 = 龙芯1c的gpio编号 % 32。

转换为代码就是

#define GPIO_GET_PORT(gpio)                 ((gpio) / 32)#define GPIO_GET_PIN(gpio)                  ((gpio) % 32)
再来回顾一下前面介绍的gpio配置过程

假设要在gpio16上输出1,需要配置 GPIO_CFG[16]=1,  GPIO_EN[16]=0,  GPIO_OUT[16]=1。

同理可得把gpio16作为输入,并读取io上的值,那么需要配置GPIO_CFG[16]=1,   GPIO_EN[16]=1,然后读取GPIO_IN[16]的值就知道了io上是高电平,还是低电平。

将以上步骤用伪代码来表示就是

gpio_init(GPIOn, 输入或输出){    通过设置寄存器GPIO_CFGx,将引脚GPIOn配置为普通gpio    通过设置寄存器GPIO_ENx,将引脚GPIOn配置为输入或输出}gpio_set(GPIOn, 0或1){    通过设置寄存器GPIO_OUTx,在引脚GPIOn上输出0或1}gpio_get(GPIOn){    通过读取寄存器GPIO_INx,获取引脚GPIOn上的电平值}

具体代码见下面的代码清单

完整的代码清单

lib\gpio.h

#ifndef __OPENLOONGSON_GPIO_H#define __OPENLOONGSON_GPIO_H// gpio的工作模式--输入、输出typedef enum{    gpio_mode_output = 0,       // 输出    gpio_mode_input = 1         // 输入}gpio_mode_t;//  gpio高低电平值typedef enum{    gpio_level_low = 0,         // 低电平    gpio_level_high = 1         // 高电平}gpio_level_t;/* * gpio初始化 * @gpio gpio引脚,取值范围[0, 127] * @mode gpio的工作模式(输入、输出) * * 例: 将gpio50初始化为输出 * gpio_init(50, gpio_mode_output); */void gpio_init(unsigned int gpio, gpio_mode_t mode);/* * 在指定gpio输出高电平或低电平 * @gpio gpio引脚,取值范围[0, 127] * @level 电平值 * * 例: 在gpio50上输出低电平 * gpio_set(50, gpio_level_low); */void gpio_set(unsigned int gpio, gpio_level_t level);/* * 读取指定gpio引脚的值 * @gpio gpio引脚,取值范围[0,127] * * 例: 读取gpio50引脚上的值 * gpio_level_t level; * level = gpio_get(50); */gpio_level_t gpio_get(unsigned int gpio);#endif



lib\gpio.c

// 封装gpio接口#include "gpio.h"// 寄存器地址#define LS1C_GPIO_CFG0                      (0xbfd010c0)#define LS1C_GPIO_EN0                       (0xbfd010d0)#define LS1C_GPIO_IN0                       (0xbfd010e0)#define LS1C_GPIO_OUT0                      (0xbfd010f0)#define LS1C_GPIO_CFG1                      (0xbfd010c4)#define LS1C_GPIO_EN1                       (0xbfd010d4)#define LS1C_GPIO_IN1                       (0xbfd010e4)#define LS1C_GPIO_OUT1                      (0xbfd010f4)#define LS1C_GPIO_CFG2                      (0xbfd010c8)#define LS1C_GPIO_EN2                       (0xbfd010d8)#define LS1C_GPIO_IN2                       (0xbfd010e8)#define LS1C_GPIO_OUT2                      (0xbfd010f8)#define LS1C_GPIO_CFG3                      (0xbfd010cc)#define LS1C_GPIO_EN3                       (0xbfd010dc)#define LS1C_GPIO_IN3                       (0xbfd010ec)#define LS1C_GPIO_OUT3                      (0xbfd010fc)// 龙芯1c的gpio是按照0,1,2,3,4...这样的顺序编号的,// 但在操作寄存器的时候,又是按照每32个一组来分的// 这里利用这个特性,将每组的32个gpio叫做一个"port",每个gpio在每组中的索引叫"pin"// port = gpio / 32// pin  = gpio % 32// 例如GPIO50,port=1,pin=18#define GPIO_GET_PORT(gpio)                 ((gpio) / 32)#define GPIO_GET_PIN(gpio)                  ((gpio) % 32)/* * gpio初始化 * @gpio gpio引脚,取值范围[0, 127] * @mode gpio的工作模式(输入、输出) * * 例: 将gpio50初始化为输出 * gpio_init(50, gpio_mode_output); */void gpio_init(unsigned int gpio, gpio_mode_t mode){    volatile unsigned int *gpio_cfgx;       // GPIO_CFGx寄存器    volatile unsigned int *gpio_enx;        // GPIO_ENx寄存器    unsigned int port = GPIO_GET_PORT(gpio);    unsigned int pin = GPIO_GET_PIN(gpio);    unsigned int temp;    unsigned int mask;    switch (port)    {        case 0:            gpio_cfgx   = (volatile unsigned int *)LS1C_GPIO_CFG0;            gpio_enx    = (volatile unsigned int *)LS1C_GPIO_EN0;            break;        case 1:            gpio_cfgx   = (volatile unsigned int *)LS1C_GPIO_CFG1;            gpio_enx    = (volatile unsigned int *)LS1C_GPIO_EN1;            break;        case 2:            gpio_cfgx   = (volatile unsigned int *)LS1C_GPIO_CFG2;            gpio_enx    = (volatile unsigned int *)LS1C_GPIO_EN2;            break;        case 3:            gpio_cfgx   = (volatile unsigned int *)LS1C_GPIO_CFG3;            gpio_enx    = (volatile unsigned int *)LS1C_GPIO_EN3;            break;        default:        // 正确的程序不应该走到这里,直接返回            return ;    }    // 将pin设为普通GPIO    mask = 1 << pin;    temp = *gpio_cfgx;    temp |= mask;           // 将指定位置1    *gpio_cfgx = temp;    // 设置gpio工作模式(输入、输出)    temp = *gpio_enx;    if (gpio_mode_output == mode)       // 输出    {        temp &= ~mask;      // 将指定位清零    }    else                                // 输入    {        temp |= mask;       // 将指定位置1    }    *gpio_enx = temp;    return ;}/* * 在指定gpio输出高电平或低电平 * @gpio gpio引脚,取值范围[0, 127] * @level 电平值 * * 例: 在gpio50上输出低电平 * gpio_set(50, gpio_level_low); */void gpio_set(unsigned int gpio, gpio_level_t level){    volatile unsigned int *gpio_outx;       // GPIO_OUTx寄存器    unsigned int port   = GPIO_GET_PORT(gpio);    unsigned int pin    = GPIO_GET_PIN(gpio);    unsigned int temp;    unsigned int mask;    switch (port)    {        case 0:            gpio_outx = (volatile unsigned int *)LS1C_GPIO_OUT0;            break;        case 1:            gpio_outx = (volatile unsigned int *)LS1C_GPIO_OUT1;            break;        case 2:            gpio_outx = (volatile unsigned int *)LS1C_GPIO_OUT2;            break;        case 3:            gpio_outx = (volatile unsigned int *)LS1C_GPIO_OUT3;            break;        default:        // 正确的程序不应该走到这里,直接返回            return ;    }    mask = 1 << pin;    temp = *gpio_outx;    if (gpio_level_low == level)    {        temp &= ~mask;          // 输出低电平    }    else    {        temp |= mask;           // 输出高电平    }    *gpio_outx = temp;    return ;}/* * 读取指定gpio引脚的值 * @gpio gpio引脚,取值范围[0,127] * * 例: 读取gpio50引脚上的值 * gpio_level_t level; * level = gpio_get(50); */gpio_level_t gpio_get(unsigned int gpio){    volatile unsigned int *gpio_inx;        // GPIO_INx寄存器        unsigned int port   = GPIO_GET_PORT(gpio);    unsigned int pin    = GPIO_GET_PIN(gpio);    unsigned int temp;    gpio_level_t level;    switch (port)    {        case 0:            gpio_inx = (volatile unsigned int *)LS1C_GPIO_IN0;            break;        case 1:            gpio_inx = (volatile unsigned int *)LS1C_GPIO_IN1;            break;        case 2:            gpio_inx = (volatile unsigned int *)LS1C_GPIO_IN2;            break;        case 3:            gpio_inx = (volatile unsigned int *)LS1C_GPIO_IN3;            break;        default:        // 正常的流程不应该走到这里,直接返回            return ;    }    temp = *gpio_inx;    temp = (temp >> pin) & 1;    if (temp)    {        level = gpio_level_high;    }    else    {        level = gpio_level_low;    }    return level;}    






0 0
原创粉丝点击