龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库。git地址:https://gitee.com/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上的按键S3unsigned 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设为普通GPIOmask = 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;
}

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

  1. 【龙芯1c库】封装硬件pwm接口和使用示例

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.Git地址:https://gitee.com/caogos/OpenLoongsonLib1c 本文通过"龙芯1 ...

  2. 【龙芯1c库】封装模拟I2C接口和使用示例

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.Git地址:https://gitee.com/caogos/OpenLoongsonLib1c I2C接口是常用的接口之一 ...

  3. 【龙芯1c库】封装硬件定时器接口和使用示例

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1c库中硬件定时器 ...

  4. 用龙芯1c库实现无源蜂鸣器唱歌《送别》

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,可用于裸机编程和实时系统,类似于STM32库.Git地址:http://git.oschina.NET/caogos/OpenLoongsonL ...

  5. 【龙芯1c库】移植硬浮点FPU

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1C上有硬浮点协处 ...

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

    can使用还是比较广泛的,之前有网友在龙芯1b和龙芯1c上已经测试过了在裸机编程中使用CAN接口,这里把他们分享的程序贴上来,供大家参考. 龙芯1b上的测试程序在https://gitee.com/c ...

  7. 在龙芯1C单片机上使用ESP8266 wifi透传模块

    龙芯1C既可以运行linux,也可以当作单片机用.当用作linux时,可以通过USB wifi模块RTL8192C,RTL8188ETV等,当作单片机用时,可以像STM32那样使用串口透传wifi模块 ...

  8. 【龙印】用龙芯1c的硬件pwm产生单个脉冲来驱动步进电机

    本文为在用龙芯1c做3D打印机过程中的笔记.龙芯1c做的3d打印机简称"龙印",Git地址"http://git.oschina.NET/caogos/marlin_ls ...

  9. Buildroot 龙芯1C支持指南

    本文转载自:https://github.com/pengphei/smartloong-sphinx/blob/master/source/cn/loongson1c_buildroot_guide ...

  10. 龙芯处理器可以适配鸿蒙os吗,SylixOS龙芯1C适配总结

    1.龙芯1C简介 1.1龙芯1C简介 龙芯 1C300(以下简称 1C)芯片是基于 LS232 处理器核的高性价比单芯片系统,可应用于指纹生物识别.物联传感等领域.1C 包含浮点处理单元,可以有效增强 ...

最新文章

  1. Rust语言开发基础(六)基础语法
  2. Facebook收购GrokStyle:布局AI零售
  3. 每一个人都是平凡的英雄
  4. python 保留两位小数 占位_第17p,Python中格式化输出的3种方式
  5. windows href 可以设置header吗_windows电脑端有什么桌面办公便签可以设置农历时间提醒?...
  6. XGBoost使用教程(与sklearn一起使用)二
  7. 关于HibernateDaoSupport中的getHibernateTemplate().execute及executeFind方法
  8. python 爬虫 博客园_Python爬虫爬取博客园作业
  9. 系统架构工作笔记-数据展示进程与读取数据进程分离,实现低耦合(展示软件可适用任意厂家数据库)
  10. 智慧讲台:office 文件 pdf 文件 转成 png图片
  11. FlutterFragment 踩坑记
  12. python入门指南by-Python 入门指南
  13. 拿到参考资料的预训练模型,太可怕了!
  14. 优盘(U 盘) 采用TLC, MLC, SLC芯片 的区别 与使用寿命
  15. 范围变更管控案例_项目变更管理案例.doc
  16. LeetCode打家劫舍系列
  17. 零点和极点到底影响了什么?什么是最小相位系统?
  18. win10 蓝牙耳机 连接后输出 没有耳机选择 的 解决办法
  19. python中按钮位置设定_tkinter Python中的按钮位置(网格)
  20. 【工大SCIR】首次探索中文词信息增强中文口语语言理解!

热门文章

  1. 卓有成效的管理者(笔记)——要事优先
  2. 联想怎么启动windows无线服务器,Windows7系统下开启无线的多种方法
  3. Centos7.6上安装水族馆遇到报错BEGIN failed--compilation aborted at /usr/local/bin/asciiquarium line 42.
  4. SSH基础----【超级干货】Spring常用注解用法汇总(附DEMO)
  5. RAM 与 ROM, CPU 与 GPU ,显卡与显存 区别以及关系等
  6. 大学英语综合教程四 Unit 1 课文内容英译中 中英翻译
  7. 蓝牙芯片解决方案市场规模
  8. OpenCV—播放AVI视频
  9. 微信支付 django
  10. Java 知识点总结笔记(篇1)