文章目录

  • 一、6ull 的 gpio 使用步骤
  • 二、pinctrl子系统
  • 三、gpio 子系统
  • 四、驱动编写
  • 五、总结
  • 六、相关函数

一、6ull 的 gpio 使用步骤

  • 1、设置 pin 的 复用 和 电气属性(通过 pinctrl 子系统
  • 2、配置 gpio 的输入输出,高低电平(通过 GPIO子系统

二、pinctrl子系统

pinctrl 和 gpio 子系统详解

  • 借助 pinctrl子系统 来设置一个 pin 的 复用电气属性
    打开文件 imx6ull.dtsi
// 详见 imx6ull.dtsi 参考手册 176,1542
iomuxc: iomuxc@020e0000 {    // 这个结点表示 IO控制器 外设// compatible属性用来匹配pinctrl驱动compatible = "fsl,imx6ul-iomuxc";// 此为寄存器地址范围,此地址范围的寄存器控制每个 pin 的复用和电气属性// 基地址,大小reg = <0x020e0000 0x4000>;
};
// gpr 控制器,详见 imx6ull.dtsi 参考手册 1475
gpr: iomuxc-gpr@020e4000 {compatible =    "fsl,imx6ul-iomuxc-gpr","fsl,imx6q-iomuxc-gpr", "syscon";reg = <0x020e4000 0x4000>;
};......
// iomuxc_snvs 控制器,详见 imx6ull.dtsi 参考手册 1495
iomuxc_snvs: iomuxc-snvs@02290000 {compatible = "fsl,imx6ull-iomuxc-snvs";reg = <0x02290000 0x10000>;
};
  • 打开 imx6ull-alientek-emmc.dts 文件:
// 对节点 iomuxc 进行追加
// 追加方式:&标签名
&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog_1>;imx6ul-evk {  // evk 是官方开发板pinctrl_hog_1: hoggrp-1 {fsl,pins = <MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT    0x17059 /* SD1 VSELECT */MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 /* SD1 RESET */>;};...pinctrl_i2c2: i2c2grp {fsl,pins = <MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0>;};pinctrl_lcdif_dat: lcdifdatgrp {fsl,pins = <MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79...>;};...};
};
  • pinctrl 子系统就是:创建一个 设备子节点 ,然后 将此设备所用 pin 的配置信息 都放到 这个子节点 里面
    注意格式:存放 pin 配置信息的 属性名 一定要是 fsl,pins

  • 如何添加 一个 pin 的配置信息
    MX6UL_PAD_UART1_RTS_B__GPIO1_IO19

fsl,pins = <MX6UL_PAD_UART1_RTS_B__GPIO1_IO19    0x17059 /* SD1 CD */MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT    0x17059 /* SD1 VSELECT */MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 /* SD1 RESET */>;

imx6ul-pinfunc.h 中找到

/** The pin function ID is a tuple of* <mux_reg conf_reg input_reg mux_mode input_val>*/

#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0

mux_reg conf_reg input_reg mux_mode input_val
0x0090 0x031C 0x0000 0x5 0x0

iomuxc 节点 首地址0x020e00000x0090 是偏移地址,UART1_RTS_B 绝对地址为 0x020e0090(imx6ull参考手册 1581)
muxmode:5 表示复用为 GPIO1_IO19

conf_reg:0x031C,相对于基地址的偏移,0x020e0000 + 0x031c = 0x020e031c ,这个地址寄存器是 UART1_RTS_B电气属性配置寄存器0x17059 是写给此寄存器来配置电气属性
input_reg :0,偏移为 0,表示 UART1_RTS_B 这个 pin 没有 input 功能
input_val:0,写给 input_reg 寄存器的值,但是这个 pin 没有

  • pinctrl 驱动工作原理简介
    如何找到 imx6ull 对应的 pinctrl 子系统驱动(半导体厂商写好的)
    使用 节点的 compatible 属性
    驱动文件里面有一个描述 驱动兼容性 的内容,当设备树节点的 compatible 属性驱动里面的兼容性(也是字符串)匹配时,就表示设备和驱动匹配了,表示设备可以使用该驱动文件
    所以只需要全局搜索设备节点里面的 compatible 属性的值 即可找到那个文件,为 /driver/pinctrl/freescale/pinctrl-imx6ul.c,注意其中的 of_device_id 结构体
static struct of_device_id imx6ul_pinctrl_of_match[] = {{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },{ /* sentinel */ }
};

因此设备树中的对应节点使用的驱动是此文件
当驱动和设备节点匹配以后,会执行 probe类 函数 :imx6ul_pinctrl_probe

三、gpio 子系统

  • 使用 gpio 子系统 来操作 gpio
&usdhc1 {pinctrl-names = "default", "state_100mhz", "state_200mhz";pinctrl-0 = <&pinctrl_usdhc1>;  // 此设备相关的io有这3个pinctrl-1 = <&pinctrl_usdhc1_100mhz>;pinctrl-2 = <&pinctrl_usdhc1_200mhz>;cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;keep-power-in-suspend;enable-sdio-wakeup;vmmc-supply = <&reg_sd1_vmmc>;status = "okay";
};
  • 定义了一个 cd-gpios 属性,属性名自取。属性值描述 io 信息
    参考设备绑定文档:devicetree/binfings/gpio/fsl-gpio.txt
    此处使用 gpio1_io19
    打开参考手册 1357
    cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; :&gpio 表示 使用 gpio1 这一组,19 表示第19个 pin,GPIO_ACTIVE_LOW 是个宏,值为1,表示低电平有效

  • imx6ull.dtsi 中 的 gpio1 节点

gpio1: gpio@0209c000 {compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";reg = <0x0209c000 0x4000>;interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;};
  • 1、获取gpio所处的设备节点 of_find_node_by_path
    2、获取 gpio 编号,of_get_named_gpio ,(int型)
    3、申请一个 GPIO 管脚,gpio_request
    4、设置 gpio,输入或输出,
    gpio_direction_inputgpio_direction_output
    若设置成输入,gpio_get_value 读取某个值
    若设置成输出,gpio_set_value 设置输出值

  • gpiolib
    两部分,一部分是给原厂编写 gpio底层驱动的,一部分给驱动开发人员使用 gpio 操作函数的
    使用 gpiochip_add 向系统添加 gpio_chip,这些都是半导体原厂做的,这部分就是最底层的 gpio 驱动

  • gpio驱动
    drivers/gpio 目录下,gpio-xxx.c 文件 为具体的芯片的驱动文件(最底层):gpio_mxc.c
    gpiolib位于 应用层api 和 底层驱动之间,gpiochip_add add的是一个 gpio_chip 结构体,这个结构体里面包含了底层gpio的操作方法,操作gpio时最终都是调用这个结构体里面的成员函数

  • 全局搜索某节点的 compatible属性值,就能找到它的驱动文件

// gpio-muxc.c gpio 的 各个控制寄存器偏移地址
static struct mxc_gpio_hwdata imx35_gpio_hwdata = {.dr_reg     = 0x00,.gdir_reg   = 0x04,.psr_reg    = 0x08,.icr1_reg   = 0x0c,.icr2_reg   = 0x10,.imr_reg    = 0x14,.isr_reg    = 0x18,.edge_sel_reg   = 0x1c,.low_level  = 0x00,.high_level = 0x01,.rise_edge  = 0x02,.fall_edge  = 0x03,
};
  • 函数调用流程
    mxc_gpio_probe
    -> mxc_gpio_get_hw 获取 6ull 的 gpio控制寄存器组的地址
    -> bgpio_init (重点)初始化 gpio_chip 结构体
    -> gpio_add 想内核添加 gpio_chip

四、驱动编写

  • 1、修改设备树
    参考 imx6ul-pinfunc.h
    访问 iomuxc 节点, 在其下添加节点
pinctrl_gpiobeep: beepgrp {fsl,pins = </*MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10b0*/MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10b0>;};
  • 根结点下添加节点
gpiobeep {compatible = "alientek,gpiobeep" ; // 其实用不到这个compatible 属性pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpiobeep>; // pin 的 配置信息// 此项属性用来获取 gpio 编号beep-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;status = "okay";};
  • 2、驱动
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include <linux/fs.h>
#include<linux/slab.h>
#include<linux/io.h>
#include<linux/uaccess.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/of.h>
#include<linux/of_address.h>
#include<linux/of_irq.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>#define GPIOBEEP_DEVID_CNT 1
#define GPIOBEEP_NAME    "gpiobeep"
#define BEEP_OFF 0
#define BEEP_ON 1extern struct gpiobeep_dev gpiobeep;// 自定义 beep设备类型,描述一个 beep 的信息
struct gpiobeep_dev
{dev_t devid; // 设备号u32 major;u32 minor;struct cdev cdev; // 用于注册字符设备struct class *class; // 用于自动创建设备节点,注意成员变量类型是结构体指针struct device *device; // 用于自动创建设备节点,注意成员变量类型是结构体指针struct device_node *nd; // 用来表示设备树中的一个节点,用于获取设备树信息int beep_gpio; // gpio 标号
};  // 数据类型定义一定要放在最前面static ssize_t beep_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{int ret;u8 databuf;struct gpiobeep_dev *dev = filp->private_data;ret = copy_from_user(&databuf, buf, count); // 从 用户空间 到 内核空间if(ret < 0){printk("%d:--------------\r\n", __LINE__);return -1;}if(databuf == BEEP_OFF) // 蜂鸣器不响{gpio_set_value(dev->beep_gpio, 1);}else if(databuf == BEEP_ON) // // 蜂鸣器响{gpio_set_value(dev->beep_gpio, 0);}return 0;
}static int beep_open(struct inode *inode, struct file *filp)
{// 其它操作集成员函数都可以通过 filp->private_data 来访问 beep类型结构体filp->private_data = &gpiobeep;return 0;
}static int beep_release(struct inode *inode, struct file *filp)
{return 0;
}// 操作集函数
static const struct file_operations gpiobeep_fops =
{.owner = THIS_MODULE,.write = beep_write,.open = beep_open,.release = beep_release,
};struct gpiobeep_dev gpiobeep;// 驱动入口函数
static int __init beep_init(void)
{int val;int ret = 0;// 注册字符设备//1 获取设备号gpiobeep.major = 0;if(gpiobeep.major){gpiobeep.devid = MKDEV(gpiobeep.major, 0); // 次设备号设为0// 注册自己指定的设备号ret = register_chrdev_region(gpiobeep.devid, GPIOBEEP_DEVID_CNT, GPIOBEEP_NAME);}else{// 系统分配设备号,就不要再向系统注册了ret = alloc_chrdev_region(&gpiobeep.devid, 0, GPIOBEEP_DEVID_CNT, GPIOBEEP_NAME);gpiobeep.major = MAJOR(gpiobeep.devid);gpiobeep.minor = MINOR(gpiobeep.devid);}if(ret < 0){printk("%d:-------fail--------\r\n", __LINE__);goto fail_devid;}printk("%d: gpiobeep.devid = %u\r\n", __LINE__, gpiobeep.devid);printk("%d: gpiobeep.major = %u\r\n", __LINE__, gpiobeep.major);printk("%d: gpiobeep.minor = %u\r\n", __LINE__, gpiobeep.minor);// 2 初始化 cdev结构体,注册字符设备gpiobeep.cdev.owner = THIS_MODULE;cdev_init(&gpiobeep.cdev, &gpiobeep_fops); // 注意两个参数都是结构体指针ret = cdev_add(&gpiobeep.cdev, gpiobeep.devid, GPIOBEEP_DEVID_CNT);if(ret){printk("%d:-------fail--------\r\n", __LINE__);goto fail_cdevadd;}// 3 自动创建设备节点// 一个 class结构体, 一个 device结构体 ,注意这两个结构体是以指针的形式存在于 自定义beep结构体 中的// 3.1 创建 class结构体gpiobeep.class = class_create(THIS_MODULE, GPIOBEEP_NAME);if(IS_ERR(gpiobeep.class)){ret = PTR_ERR(gpiobeep.class);goto fail_class;}// 3.2 创建 device结构体 // 第一个 NULL 表示副设备,  第二个 NULL 表示 drvdatagpiobeep.device = device_create(gpiobeep.class, NULL, gpiobeep.devid, NULL, GPIOBEEP_NAME);// IS_ERR include/linux/err.hif(IS_ERR(gpiobeep.device)){ret = PTR_ERR(gpiobeep.device);goto fail_device;}// 4. 获取 设备树节点 gpiobeep.nd = of_find_node_by_path("/gpiobeep");if(gpiobeep.nd == NULL){ret = -1;goto fail_findnd;}// 5 获取 beep 对应的 gpio 标号,第二个参数属性名要和设备树文件中的一致gpiobeep.beep_gpio = of_get_named_gpio(gpiobeep.nd, "beep-gpios", 0);if(gpiobeep.beep_gpio < 0){ret = -1;printk("%d:-------fail--------\r\n", __LINE__);goto fail_findnd;}printk("%d:beep_gpio num = %u\r\n", __LINE__, gpiobeep.beep_gpio);// 6 申请 gpio 标号ret = gpio_request(gpiobeep.beep_gpio, "beep-gpio");if(ret){printk("%d:---------fail-----------\r\n", __LINE__);ret = -1;goto fail_findnd;}// 7 申请 gpio 标号 ret = gpio_direction_output(gpiobeep.beep_gpio, 1);if(ret){printk("%d:---------fail------------\r\n", __LINE__);ret = -1;goto fail_findsetdir;}//8 设置 GPIO 输出低电平gpio_set_value(gpiobeep.beep_gpio, 0);return 0;fail_findsetdir: // 释放 gpio标号gpio_free(gpiobeep.beep_gpio);
fail_findnd: // 删除设备device_destroy(gpiobeep.class, gpiobeep.devid);
fail_device: // 删除类class_destroy(gpiobeep.class);
fail_class: // 删除字符设备cdev_del(&gpiobeep.cdev);
fail_cdevadd: // 释放设备号unregister_chrdev_region(gpiobeep.devid, GPIOBEEP_DEVID_CNT);
fail_devid:printk("%d:---------------\r\n", __LINE__);return ret;
}// 驱动出口函数
static void __exit beep_exit(void)
{// 退出驱动时关闭蜂鸣器gpio_set_value(gpiobeep.beep_gpio, 1);// 删除字符设备cdev_del(&gpiobeep.cdev);// 释放设备号unregister_chrdev_region(gpiobeep.devid, GPIOBEEP_DEVID_CNT);// 删除设备device_destroy(gpiobeep.class, gpiobeep.devid);// 删除类class_destroy(gpiobeep.class);// 释放 gpio 标号gpio_free(gpiobeep.beep_gpio);
}module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");

五、总结

  • 1、添加 pinctrl 信息
    iomuxc 结点下的 imx6ul-evk 子节点下,创建一个新的节点
    这个新的节点表示某一外设所用到的所有 pin 的配置信息(复用和电气属性)
pinctrl_gpiobeep: beepgrp {   // 节点标签一定要是 “pinctrl_xxx”fsl,pins = <    // 属性名一定要是 “fsl,pins”MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10b0/*MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10b0*/>;};
  • 2、检查当前设备树中要使用的 IO 是否被其他设备使用,若有则要进行处理(屏蔽或者禁用)
  • 3、添加设备节点
    在设备节点中创建一个属性,此属性所使用的 GPIO
gpiobeep {compatible = "alientek,gpiobeep" ;pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpiobeep>;      <----- 蜂鸣器 pin 的配置信息led-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;   <----- 由此属性知道使用哪个 GPIOstatus = "okay";};
  • 4、编写驱动,获取对应的 GPIO 编号,申请 IO,成功以后使用 GPIO子系统 提供的 API函数 来操作 GPIO

六、相关函数

  • 1、int of_get_named_gpio (struct device_node *np, const char *propname, int index)
    描述:用于获取 gpio编号
    np :设备节点结构体指针
    propname :包含要获取 GPIO 信息的属性名(要和设备书中的属性名一致)
    index :gpio索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO 的编号,若只有一个 GPIO信息 的话,此参数为 0
    返回值:正值,获取到的 gpio编号。负值,失败
  • 2、int gpio_request (unsigned gpio, const char *label)
    描述:用于申请一个 GPIO 管脚,在使用一个 GPIO 之前一定要使用 gpio_request 进行申请
    gpio :要申请的 gpio标号
    label :给 gpio 设置一个名字
    返回值 :0,申请成功。其他值,申请失败
    若申请失败,一般都是因为这个 pin 被占用了
    例如:开发板上的 led 使用的 gpio 是 gpio1 io03,检查设备树文件 dts
&tsc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_tsc>;xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;          <----- 此行要注释掉measure-delay-time = <0xffff>;pre-charge-time = <0xfff>;status = "okay";
};...pinctrl_tsc: tscgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO01__GPIO1_IO01  0xb0MX6UL_PAD_GPIO1_IO02__GPIO1_IO02    0xb0MX6UL_PAD_GPIO1_IO03__GPIO1_IO03    0xb0    <----- 此行要注释掉MX6UL_PAD_GPIO1_IO04__GPIO1_IO04    0xb0>;
};
  • 3、void gpio_free (unsigned gpio)
    描述:若不使用某个 GPIO 了,那么就要调用此函数进行释放
    gpio :要释放的 gpio 标号

  • 4、int gpio_direction_input (unsigned gpio)
    描述:此函数用于设置某个 gpio 为输入
    gpio :要设置为输入的 GPIO 标号
    返回值:0,设置成功;负值,设置失败

  • 5、int gpio_direction_output (unsigned gpio, int value)
    描述:此函数用于设置某个 gpio 为输入,并且设置默认值
    gpio :要设置为输出的 GPIO 标号
    value :gpio 默认输出值
    返回值:0,设置成功;负值,设置失败

  • 6、#define gpio_get_value __gpio_get_value
    int __gpio_get_value (unsigned gpio)
    描述:此函数用于获取某个 GPIO 的值(0 或 1),此函数是个宏
    gpio :要获取的 GPIO 标号
    返回值:非负值,得到的 GPIO 值;负值,获取失败

  • 7、#define gpio_set_value __gpio_set_value
    void __gpio_set_value(unsigned gpio, int value)
    描述:此函数用于设置某个 GPIO 的值,此函数是个宏
    gpio :要设置的 GPIO 标号
    value :要设置的值

  • 8、int of_gpio_named_count(struct device_node *np, const char *propname)
    描述:用于获取设备树某个属性里面定义了几个 GPIO 信息,要注意的是空的 GPIO 信息也会被统计到

    np :设备节点
    propname :要统计的 gpio 属性
    返回值:正值,统计到的 GPIO 数量。负值,失败

  • 9、int of_gpio_count(struct device_node *np)
    描述:和 of_gpio_named_count 函数一样,但是不同的地方在于,此函数统计的是“gpios”这个属性的 GPIO 数量,而 of_gpio_named_count 函数可以统计任意属性的 GPIO 信息
    np :设备节点
    返回值:正值,统计到的 GPIO 数量;负值,失败

45 pinctrl子系统 和 gpio子系统相关推荐

  1. pinctrl 和 gpio 子系统

    内容来自<[正点原子]I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf> 目录 pinctrl 子系统 pinctrl 子系统简介 I.MX6ULL 的 pinctrl 子系统 ...

  2. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之Pinctrl子系统和GPIO子系统的使用

    文章目录 前言 1.Pinctrl子系统 1.1.为什么有Pinctrl子系统 1.2.重要的概念 1.3.代码中怎么引用pinctrl 2.GPIO子系统 2.1.为什么有GPIO子系统 2.2.在 ...

  3. linux系统中pinctrl 和gpio子系统使用方法(教你点灯)

    如何使用pinctrl和gpio子系统点亮led pinctrl 子系统作用 设备树PIN配置 gpio子系统介绍 配置gpio相关 编写驱动程序 编写应用程序 pinctrl 子系统作用 pinct ...

  4. 【正点原子Linux连载】第四十五章 pinctrl和gpio子系统实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  5. 【正点原子MP157连载】第二十五章 pinctrl和gpio子系统实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  6. 使用pinctrl 和 gpio 子系统的字符设备驱动

    pinctrl 和 gpio 子系统的字符设备驱动 一. 修改设备树文件 二. LED 灯驱动程序编写 三.makefile 四.应用层代码 运行测试 一. 修改设备树文件 打开 imx6ull-al ...

  7. pinctrl子系统和gpio子系统

    pinctrl子系统gpio子系统与硬件之间的联系 GPIO与IOMUXC寄存器共同配置IO口 GPIO寄存器与gpio子系统相关联:控制IO口输入输出. led {compatible = &quo ...

  8. pinctrl和gpio子系统

    目录 1.pinctrl子系统 1)pinctrl子系统简介 2)I.MX6ULL的的pinctrl子系统驱动 3)设备树中添加pinctrl节点模板 2.gpio子系统 1)gpio子系统简介 2) ...

  9. Linux设备模型、平台设备驱动、设备树(device tree)、GPIO子系统以及pinctrl子系统介绍

    文章目录 一.Linux设备模型介绍 (1)设备驱动模型总体介绍 (2)设备驱动模型文件表现 (3)设备驱动模型工作原理 [1]总线 [2]设备 [3]驱动 [4]注册流程 二.平台设备驱动介绍 (1 ...

  10. pinctrl 和 gpio 子系统 终极总结

    1.内核提供了 pinctrl  和  gpio 子系统用于 gpio驱动.linux是一个庞大而又完善的系统  不可能 让你用裸板开发的方式 去 操作 gpio. 该系统是按照面向对象的设计思想设计 ...

最新文章

  1. 预示敏捷方法走偏的15个标志——第1部分
  2. 【MySQL】(万字解析)MySQL表的增删改查(进阶-上)
  3. android按钮随机数,Android随机数
  4. 我是如何用机器学习技术帮助 HR 省时间的
  5. linux tar.gz指定目录,tar.gz包内提取某个文件在指定目录下。
  6. Junit4 简单教程
  7. 在Java中,如何使一个字符串的首字母变为大写
  8. HTML+CSS+JS实现echarts图表炫光分布地图动画
  9. java的joptionpane空白_java – JOptionPane无法正确显示?
  10. linux ps画图,PhotoGIMP:让Linux下的GIMP交互体验就像Photoshop
  11. Android开发笔记(十九)底部标签栏TabBar
  12. 不卡顿成用户购机第一要素,Mate 9深得人心
  13. 【深度学习】使用opencv在视频上添加文字和标记框
  14. java dns 解析域名解析_JavaWeb(3)DNS域名解析
  15. 云通讯 发送短信模板代码
  16. 用c语言编写天数计算器,C/C++实现日期计算器的示例代码
  17. 阿里腾讯暑期实习面试被刷的经历
  18. 首尾相连数组的最大子数组和
  19. python描述性统计命令_描述性统计_Python数据分析实战应用_数据挖掘与分析视频-51CTO学院...
  20. 3款Android版epub阅读器推荐

热门文章

  1. Spring: J2EE框架
  2. 《微观经济学》第四章供给与需求的市场力量
  3. 2003-2007回顾贴:yeguiren个人随笔
  4. 3dmaxvray的使用方法有哪些?
  5. 计算机d盘无法格式化,d盘无法格式化,小编教你解决D盘无法格式化的方法
  6. YOLOV5目标检测-后处理NMS(非极大值抑制)
  7. 凸优化学习笔记:内点法
  8. ISSCC上的微型计算机:体积更小、功耗更少、算力更强
  9. 如何做好BI项目的规划与实施方案?
  10. 一个500人天的BI项目实施记录