文章目录

  • 系列文章目录
  • 前言
  • 正文
    • Device Tree Overlays:"插件"设备树
      • 传统设备树
      • "插件"设备树
      • 使用前提
      • 案例说明
        • 设备树:foo.dts
        • “插件”设备树:bar.dts
        • 设备树+"插件设备树":foo.dts + bar.dts
      • 编译方式
      • APT下载dtc工具
      • 使用方式
        • 内核运行状态加载(通用)
        • uboot加载(野火linux开发板)
    • "插件"设备树实现RGB灯驱动
      • 设备树添加节点信息
      • reg属性内存映射
        • of_iomap()函数
    • 代码示例
  • 总结

系列文章目录

Linux字符设备驱动详解
Linux字符设备驱动详解二(使用设备驱动模型)
Linux字符设备驱动详解三(使用class)
Linux字符设备驱动详解四(使用自属的xbus驱动总线)
Linux字符设备驱动详解五(使用platform虚拟平台总线)
Linux字符设备驱动详解六(设备树实现RGB灯驱动)
Linux字符设备驱动详解七(“插件“设备树实现RGB灯驱动)

前言

本文主要来自正点原子、野火Linux教程及本人理解,若有侵权请及时联系本人删除。

正文

Device Tree Overlays:"插件"设备树

传统设备树

批量管理硬件资源,机制僵化

"插件"设备树

模块化管理硬件资源,灵活定制

使用前提

  • 内核配置

    • CONFIG_OF_OVERLAY = y
    • CONFIG_OF_CONFIGFS = y
  • 挂载ConfigFS
mount x /sys/kernel/config -t configfs

案例说明

设备树:foo.dts

 / {compatible = "corp,foo";/* On chip peripherals */ocp: ocp {/* peripherals that are always instantiated */peripheral1 { ... };}};

“插件”设备树:bar.dts

/dts-v1/;
/plugin/;
/ {.... fragment@0 {target = <&ocp>;__overlay__ {/* bar peripheral */bar {compatible = "corp,bar";... /* various properties and child nodes */}};};
};
  • /dts-v1/ :指定dts版本号
  • /plugin/:允许设备树中引用未定义的节点
  • target = <&xxx>:指定"插件"设备树的父节点
  • target-path = “xxx”:指定"插件"设备树的父节点路径

设备树+“插件设备树”:foo.dts + bar.dts

/ {compatible = "corp,foo";/* shared resources */res: res {};/* On chip peripherals */ocp: ocp {/* peripherals that are always instantiated */peripheral1 { ... };/* bar peripheral */bar {compatible = "corp,bar";... /* various properties and child nodes */}}};

编译方式

./scripts/dtc/dtc -I dts -O dtb -o xxx.dtbo arch/arm/boot/dts/xxx.dts // 编译 dts 为 dtbo
./scripts/dtc/dtc -I dtb -O dts -o xxx.dts arch/arm/boot/dts/xxx.dtbo // 反编译 dtbo 为 dts

APT下载dtc工具

sudo apt install device-tree-compiler

使用方式

内核运行状态加载(通用)

1、在/sys/kernel/config/device-tree/overlays/下创建一个新目录:

mkdir /sys/kernel/config/device-tree/overlays/xxx

2、将dtbo固件echo到path属性文件中(第一种方法)

echo xxx.dtbo >/sys/kernel/config/device-tree/overlays/xxx/path

或者将dtbo的内容cat到dtbo属性文件(第二种方法)

cat xxx.dtbo >/sys/kernel/config/device-tree/overlays/xxx/dtbo

3、节点将被创建,查看内核设备树

ls /proc/device-tree

4、删除"插件"设备树

rmdir /sys/kernel/config/device-tree/overlays/xxx

uboot加载(野火linux开发板)

修改/boot/uEnv.txt

"插件"设备树实现RGB灯驱动

设备树添加节点信息

RGB灯的相关寄存器

/*
*CCM_CCGR1                         0x020C406C
*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04  0x020E006C
*IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04  0x020E02F8
*GPIO1_GD                          0x0209C000
*GPIO1_GDIR                        0x0209C004
*//*
*CCM_CCGR3                         0x020C4074
*IOMUXC_SW_MUX_CTL_PAD_CSI_HSYNC   0x020E01E0
*IOMUXC_SW_PAD_CTL_PAD_CSI_HSYNC   0x020E046C
*GPIO4_GD                          0x020A8000
*GPIO4_GDIR                        0x020A8004
*//*
*CCM_CCGR3                         0x020C4074
*IOMUXC_SW_MUX_CTL_PAD_CSI_VSYNC   0x020E01DC
*IOMUXC_SW_PAD_CTL_PAD_CSI_VSYNC   0x020E0468
*GPIO4_GD                          0x020A8000
*GPIO4_GDIR                        0x020A8004
*//*添加led节点*/rgb_led{#address-cells = <1>;#size-cells = <1>;compatible = "fire,rgb_led";/*红灯节点*/ranges;rgb_led_red@0x020C406C{reg = <0x020C406C 0x000000040x020E006C 0x000000040x020E02F8 0x000000040x0209C000 0x000000040x0209C004 0x00000004>;status = "okay";};/*绿灯节点*/rgb_led_green@0x020C4074{reg = <0x020C4074 0x000000040x020E01E0 0x000000040x020E046C 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};/*蓝灯节点*/rgb_led_blue@0x020C4074{reg = <0x020C4074 0x000000040x020E01DC 0x000000040x020E0468 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};};

reg属性内存映射

of_iomap()函数

将reg属性值的物理地址转化为虚拟地址

void __iomem *of_iomap(struct device_node *np,
int index)

参数:

  • np:device_node表示的节点
  • index:通常情况下reg属性包含多段,index 用于指定映射那一段,标号从0开始。

代码示例

以野火代码为例
led.dts

/dts-v1/;
/plugin/;
/ {fragment@0 {target-path = "/";__overlay__ {/* bar peripheral */rgb_led{#address-cells = <1>;#size-cells = <1>;compatible = "fire,rgb_led";/*红灯节点*/ranges;rgb_led_red@0x020C406C{reg = <0x020C406C 0x000000040x020E006C 0x000000040x020E02F8 0x000000040x0209C000 0x000000040x0209C004 0x00000004>;status = "okay";};/*绿灯节点*/rgb_led_green@0x020C4074{reg = <0x020C4074 0x000000040x020E01E0 0x000000040x020E046C 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};/*蓝灯节点*/rgb_led_blue@0x020C4074{reg = <0x020C4074 0x000000040x020E01DC 0x000000040x020E0468 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};};};};
};

dts_led.c,该代码与上一篇一样

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/device.h>#include <linux/platform_device.h>/*------------------字符设备内容----------------------*/
#define DEV_NAME "rgb_led"
#define DEV_CNT (1)/*定义 led 资源结构体,保存获取得到的节点信息以及转换后的虚拟寄存器地址*/
struct led_resource
{struct device_node *device_node; //rgb_led_red的设备树节点void __iomem *virtual_CCM_CCGR;void __iomem *virtual_IOMUXC_SW_MUX_CTL_PAD;void __iomem *virtual_IOMUXC_SW_PAD_CTL_PAD;void __iomem *virtual_DR;void __iomem *virtual_GDIR;
};static dev_t led_devno;                    //定义字符设备的设备号
static struct cdev led_chr_dev;          //定义字符设备结构体chr_dev
struct class *class_led;                 //保存创建的类
struct device *device;                   // 保存创建的设备
struct device_node *rgb_led_device_node; //rgb_led的设备树节点结构体/*定义 R G B 三个灯的led_resource 结构体,保存获取得到的节点信息*/
struct led_resource led_red;
struct led_resource led_green;
struct led_resource led_blue;/*字符设备操作函数集,open函数*/
static int led_chr_dev_open(struct inode *inode, struct file *filp)
{printk("\n open form driver \n");return 0;
}/*字符设备操作函数集,write函数*/
static ssize_t led_chr_dev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int ret,error;unsigned int register_data = 0; //暂存读取得到的寄存器数据unsigned char receive_data[10]; //用于保存接收到的数据unsigned int write_data; //用于保存接收到的数据if(cnt>10)cnt =10;error = copy_from_user(receive_data, buf, cnt);if (error < 0){return -1;}ret = kstrtoint(receive_data, 16, &write_data);if (ret) {return -1;}/*设置 GPIO1_04 输出电平*/if (write_data & 0x04){register_data = ioread32(led_red.virtual_DR);register_data &= ~(0x01 << 4);iowrite32(register_data, led_red.virtual_DR); // GPIO1_04引脚输出低电平,红灯亮}else{register_data = ioread32(led_red.virtual_DR);register_data |= (0x01 << 4);iowrite32(register_data, led_red.virtual_DR); // GPIO1_04引脚输出高电平,红灯灭}/*设置 GPIO4_20 输出电平*/if (write_data & 0x02){register_data = ioread32(led_green.virtual_DR);register_data &= ~(0x01 << 20);iowrite32(register_data, led_green.virtual_DR); // GPIO4_20引脚输出低电平,绿灯亮}else{register_data = ioread32(led_green.virtual_DR);register_data |= (0x01 << 20);iowrite32(register_data, led_green.virtual_DR); // GPIO4_20引脚输出高电平,绿灯灭}/*设置 GPIO4_19 输出电平*/if (write_data & 0x01){register_data = ioread32(led_blue.virtual_DR);register_data &= ~(0x01 << 19);iowrite32(register_data, led_blue.virtual_DR); //GPIO4_19引脚输出低电平,蓝灯亮}else{register_data = ioread32(led_blue.virtual_DR);register_data |= (0x01 << 19);iowrite32(register_data, led_blue.virtual_DR); //GPIO4_19引脚输出高电平,蓝灯灭}return cnt;
}/*字符设备操作函数集*/
static struct file_operations led_chr_dev_fops ={.owner = THIS_MODULE,.open = led_chr_dev_open,.write = led_chr_dev_write,
};/*----------------平台驱动函数集-----------------*/
static int led_probe(struct platform_device *pdv)
{int ret = -1; //保存错误状态码unsigned int register_data = 0;printk(KERN_ALERT "\t  match successed  \n");/*获取rgb_led的设备树节点*/rgb_led_device_node = of_find_node_by_path("/rgb_led");if (rgb_led_device_node == NULL){printk(KERN_ERR "\t  get rgb_led failed!  \n");return -1;}/*获取rgb_led节点的红灯子节点*/led_red.device_node = of_find_node_by_name(rgb_led_device_node,"rgb_led_red");if (led_red.device_node == NULL){printk(KERN_ERR "\n get rgb_led_red_device_node failed ! \n");return -1;}/*获取 reg 属性并转化为虚拟地址*/led_red.virtual_CCM_CCGR = of_iomap(led_red.device_node, 0);led_red.virtual_IOMUXC_SW_MUX_CTL_PAD = of_iomap(led_red.device_node, 1);led_red.virtual_IOMUXC_SW_PAD_CTL_PAD = of_iomap(led_red.device_node, 2);led_red.virtual_DR = of_iomap(led_red.device_node, 3);led_red.virtual_GDIR = of_iomap(led_red.device_node, 4);/*初始化红灯*/register_data = ioread32(led_red.virtual_CCM_CCGR);register_data |= (0x03 << 26);iowrite32(register_data, led_red.virtual_CCM_CCGR); //开启时钟register_data = ioread32(led_red.virtual_IOMUXC_SW_MUX_CTL_PAD);register_data &= ~(0xf << 0);register_data |= (0x05 << 0);iowrite32(register_data, led_red.virtual_IOMUXC_SW_MUX_CTL_PAD); //设置复用功能register_data = ioread32(led_red.virtual_IOMUXC_SW_PAD_CTL_PAD);register_data = (0x10B0);iowrite32(register_data, led_red.virtual_IOMUXC_SW_PAD_CTL_PAD); //设置PAD 属性register_data = ioread32(led_red.virtual_GDIR);register_data |= (0x01 << 4);iowrite32(register_data, led_red.virtual_GDIR); //设置GPIO1_04 为输出模式register_data = ioread32(led_red.virtual_DR);register_data |= (0x01 << 4);iowrite32(register_data, led_red.virtual_DR); //设置 GPIO1_04 默认输出高电平/*获取rgb_led节点的绿灯子节点*/led_green.device_node = of_find_node_by_name(rgb_led_device_node,"rgb_led_green");if (led_green.device_node == NULL){printk(KERN_ERR "\n get rgb_led_green_device_node failed ! \n");return -1;}/*获取 reg 属性并转化为虚拟地址*/led_green.virtual_CCM_CCGR = of_iomap(led_green.device_node, 0);led_green.virtual_IOMUXC_SW_MUX_CTL_PAD = of_iomap(led_green.device_node, 1);led_green.virtual_IOMUXC_SW_PAD_CTL_PAD = of_iomap(led_green.device_node, 2);led_green.virtual_DR = of_iomap(led_green.device_node, 3);led_green.virtual_GDIR = of_iomap(led_green.device_node, 4);/*初始化绿灯*/register_data = ioread32(led_green.virtual_CCM_CCGR);register_data |= (0x03 << 12);iowrite32(register_data, led_green.virtual_CCM_CCGR); //开启时钟register_data = ioread32(led_green.virtual_IOMUXC_SW_MUX_CTL_PAD);register_data &= ~(0xf << 0);register_data |= (0x05 << 0);iowrite32(register_data, led_green.virtual_IOMUXC_SW_MUX_CTL_PAD); //设置复用功能register_data = ioread32(led_green.virtual_IOMUXC_SW_PAD_CTL_PAD);register_data = (0x10B0);iowrite32(register_data, led_green.virtual_IOMUXC_SW_PAD_CTL_PAD); //设置PAD 属性register_data = ioread32(led_green.virtual_GDIR);register_data |= (0x01 << 20);iowrite32(register_data, led_green.virtual_GDIR); //设置GPIO4_IO20 为输出模式register_data = ioread32(led_green.virtual_DR);register_data |= (0x01 << 20);iowrite32(register_data, led_green.virtual_DR); //设置 GPIO4_IO20 默认输出高电平/*获取rgb_led节点的蓝灯子节点*/led_blue.device_node = of_find_node_by_name(rgb_led_device_node,"rgb_led_blue");if (led_blue.device_node == NULL){printk(KERN_ERR "\n get rgb_led_blue_device_node failed ! \n");return -1;}/*获取 reg 属性并转化为虚拟地址*/led_blue.virtual_CCM_CCGR = of_iomap(led_blue.device_node, 0);led_blue.virtual_IOMUXC_SW_MUX_CTL_PAD = of_iomap(led_blue.device_node, 1);led_blue.virtual_IOMUXC_SW_PAD_CTL_PAD = of_iomap(led_blue.device_node, 2);led_blue.virtual_DR = of_iomap(led_blue.device_node, 3);led_blue.virtual_GDIR = of_iomap(led_blue.device_node, 4);/*初始化蓝灯*/register_data = ioread32(led_blue.virtual_CCM_CCGR);register_data |= (0x03 << 12);iowrite32(register_data, led_blue.virtual_CCM_CCGR); //开启时钟register_data = ioread32(led_blue.virtual_IOMUXC_SW_MUX_CTL_PAD);register_data &= ~(0xf << 0);register_data |= (0x05 << 0);iowrite32(register_data, led_blue.virtual_IOMUXC_SW_MUX_CTL_PAD); //设置复用功能register_data = ioread32(led_blue.virtual_IOMUXC_SW_PAD_CTL_PAD);register_data = (0x10B0);iowrite32(register_data, led_blue.virtual_IOMUXC_SW_PAD_CTL_PAD); //设置PAD 属性register_data = ioread32(led_blue.virtual_GDIR);register_data |= (0x01 << 19);iowrite32(register_data, led_blue.virtual_GDIR); //设置GPIO4_IO19 为输出模式register_data = ioread32(led_blue.virtual_DR);register_data |= (0x01 << 19);iowrite32(register_data, led_blue.virtual_DR); //设置 GPIO4_IO19 默认输出高电平/*---------------------注册 字符设备部分-----------------*///第一步//采用动态分配的方式,获取设备编号,次设备号为0,//设备名称为rgb-leds,可通过命令cat  /proc/devices查看//DEV_CNT为1,当前只申请一个设备编号ret = alloc_chrdev_region(&led_devno, 0, DEV_CNT, DEV_NAME);if (ret < 0){printk("fail to alloc led_devno\n");goto alloc_err;}//第二步//关联字符设备结构体cdev与文件操作结构体file_operationsled_chr_dev.owner = THIS_MODULE;cdev_init(&led_chr_dev, &led_chr_dev_fops);//第三步//添加设备至cdev_map散列表中ret = cdev_add(&led_chr_dev, led_devno, DEV_CNT);if (ret < 0){printk("fail to add cdev\n");goto add_err;}//第四步/*创建类 */class_led = class_create(THIS_MODULE, DEV_NAME);/*创建设备*/device = device_create(class_led, NULL, led_devno, NULL, DEV_NAME);return 0;add_err://添加设备失败时,需要注销设备号unregister_chrdev_region(led_devno, DEV_CNT);printk("\n error! \n");
alloc_err:return -1;
}static const struct of_device_id rgb_led[] = {{.compatible = "fire,rgb_led"},{/* sentinel */}};/*定义平台设备结构体*/
struct platform_driver led_platform_driver = {.probe = led_probe,.driver = {.name = "rgb-leds-platform",.owner = THIS_MODULE,.of_match_table = rgb_led,}};/*
*驱动初始化函数
*/
static int __init led_platform_driver_init(void)
{int DriverState;DriverState = platform_driver_register(&led_platform_driver);printk(KERN_ALERT "\tDriverState is %d\n", DriverState);return 0;
}/*
*驱动注销函数
*/
static void __exit led_platform_driver_exit(void)
{/*取消物理地址映射到虚拟地址*/iounmap(led_green.virtual_CCM_CCGR);iounmap(led_green.virtual_IOMUXC_SW_MUX_CTL_PAD);iounmap(led_green.virtual_IOMUXC_SW_PAD_CTL_PAD);iounmap(led_green.virtual_DR);iounmap(led_green.virtual_GDIR);iounmap(led_red.virtual_CCM_CCGR);iounmap(led_red.virtual_IOMUXC_SW_MUX_CTL_PAD);iounmap(led_red.virtual_IOMUXC_SW_PAD_CTL_PAD);iounmap(led_red.virtual_DR);iounmap(led_red.virtual_GDIR);iounmap(led_blue.virtual_CCM_CCGR);iounmap(led_blue.virtual_IOMUXC_SW_MUX_CTL_PAD);iounmap(led_blue.virtual_IOMUXC_SW_PAD_CTL_PAD);iounmap(led_blue.virtual_DR);iounmap(led_blue.virtual_GDIR);/*删除设备*/device_destroy(class_led, led_devno);          //清除设备class_destroy(class_led);                     //清除类cdev_del(&led_chr_dev);                        //清除设备号unregister_chrdev_region(led_devno, DEV_CNT); //取消注册字符设备/*注销字符设备*/platform_driver_unregister(&led_platform_driver);printk(KERN_ALERT "led_platform_driver exit!\n");
}module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);MODULE_LICENSE("GPL");/**/

总结

将led.dts编译为rgb.dtbo插件设备树,将传统设备树和插件设备树都加载到内核中,加载完成后就使用以下命令查看设备树,此时可以在设备数中看到新增了rgb_led节点。

ls /sys/firmware/devicetree/base
或者
ls /proc/device-tree

再编译dts_led.c源文件为dto.led.ko内核模块并加载进内核。这时就有了/dev/rgb_led节点,最后向/dev/rgb_led节点写入数据就能控制rgb灯了。

sudo sh -c "ecoh '1' >/dev/rgb_led"
亮蓝灯
sudo sh -c "ecoh '2' >/dev/rgb_led"
亮绿灯
sudo sh -c "ecoh '4' >/dev/rgb_led"
亮红灯
sudo sh -c "ecoh '7' >/dev/rgb_led"
全亮

Linux字符设备驱动详解七(“插件“设备树实现RGB灯驱动)相关推荐

  1. Linux字符设备驱动详解四(使用自属的xbus驱动总线)

    文章目录 系列文章目录 前言 驱动目录 正文 驱动总线 总线管理 总线注册 设备注册 驱动注册 代码示例 总结 系列文章目录 Linux字符设备驱动详解 Linux字符设备驱动详解二(使用设备驱动模型 ...

  2. 第九节 使用设备树实现RGB 灯驱动

    通过上一小节的学习,我们已经能够编写简单的设备树节点,并且使用常用的of 函数从设备树中获取我们想要的节点资源.这一小节我们带领大家使用设备树编写一个简单的RGB 灯驱动程序,加深对设备树的理解. 实 ...

  3. 深入学习Linux摄像头(四)三星平台fimc驱动详解

    深入学习Linux摄像头系列 深入学习Linux摄像头(一)v4l2应用编程 深入学习Linux摄像头(二)v4l2驱动框架 深入学习Linux摄像头(三)虚拟摄像头驱动分析 深入学习Linux摄像头 ...

  4. Linux驱动开发_设备文件系统详解

    目录 何为设备管理器? Linux下dev的作用 Devfs sysfs kobject udev proc 何为设备管理器? 设备管理器就是负责管理这台电脑上的外设,当我们通过电脑提供的USB口插入 ...

  5. Linux的tty架构及UART驱动详解

    Linux的tty架构及UART驱动详解 一.模块硬件学习 1.1. Uart介绍 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称 ...

  6. 【genius_platform软件平台开发】第五十二讲:Linux系统之V4L2视频驱动详解

    V4L2视频驱动详解 刚建的微信群欢迎加入一起学习.讨论: 1. 简介 1.1 视频输入输出设备(video capture device,video output device) 1.2 VBI设备 ...

  7. php调用linux摄像头,Linux_Linux中开发USB摄像头驱动详解,USB摄像头以其良好的性能和低 - phpStudy...

    Linux中开发USB摄像头驱动详解 USB摄像头以其良好的性能和低廉的价格得到广泛应用.同时因其灵活.方便的特性,易于集成到嵌入式系统中.但是如果使用现有的符合Video for Linux标准的驱 ...

  8. linux usb gadget驱动详解(一)

    由于PC的推广,USB(通用串行总线)是我们最熟知的通信总线规范之一,其他的还有诸如以太网.PCIE总线和RS232串口等.这里我们主要讨论USB. USB是一个主从通信架构,但只能一主多从.其中us ...

  9. 【正点原子Linux连载】第三十五章 Linux内核顶层Makefile详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

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

最新文章

  1. windows1064安装oracle,在Windows 10系统下安装Oracle 11g数据库
  2. tf.keras.losses.CategoricalCrossentropy 多分类 交叉熵 损失函数示例
  3. CentOS-创建yum本地源
  4. lua读取linux文件内容,使用lua模拟tail -n命令读取最后n行
  5. AtomicInteger相关类
  6. html文字向上移动10px,HTML文字移动特效代码
  7. oracle undo数据文件坏,oracle undo数据文件损坏故障处理案例
  8. Django 之 Session的简单使用
  9. 神经网络模型压缩优化方法
  10. Go基础:数组、切片与指针
  11. 计算机没有本地网络,网络连接里没有本地连接
  12. Activity启动模式之SingleTask
  13. 软件测试项目案例.pdf,【精选】最经典软件测试案例.pdf
  14. 【金蝶K3】新/老单据转换流程相关表说明(单据转换流程下推老单,钩稽关系可为严格控制)
  15. 钉钉的微应用如何测试;
  16. LaTeX:斜线表头的表格制作
  17. Mean Rank 和Mean reciprocal rank
  18. 视频编码中的I帧、P帧、B帧的概念和特点
  19. Exchange邮箱服务器后利用
  20. python django(1170, BLOB/TEXT column 'name' used in key specification without a key length)

热门文章

  1. 电脑网络看不到其它计算机,电脑看不到局域网其他计算机怎么办_电脑看不到局域网其他计算机的处理方法-系统城...
  2. 中国企业做大也要做强做优
  3. 阿里云域名DNS解析到网站服务器空间IP地址教程
  4. 我的世界服务器修改后变回来,我的世界:经营8年的服务器主人去世后,城市中心变成了纪念馆...
  5. ios开发之View属性hidden, opaque, alpha, opacity的区别
  6. 按照下列给定步骤完成求累加和程序: 程序: MOV BX,1000 MOV CX,10 MOV AL,0 LOP: ADD AL,[BX] INC BX J: LOOP LOP INT
  7. Android系统系统升级过程分析之------update.zip包的制作
  8. java回合制游戏女主牺牲自己_java – 回合制游戏设计:事件驱动与游戏循环
  9. 穷人冲冲冲:做什么副业? 更容易成为有钱人?
  10. 晓莲说-何不原创:java 实现二维数组冒泡排序