RK3568笔记四十一:DHT11驱动开发测试

news2024/9/21 22:36:28

若该文为原创文章,转载请注明原文出处。

记录开发单总线,读取DHT11温湿度

一、DHT11介绍

DHT11是串行接口(单线双向)DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分。

1、协议及数据格式

DHT11 采用单总线协议与单片机通信,单片机发送一次复位信号后,DHT11 从低功耗模式转换到高速模式,等待主机复位结束后,DHT11 发送响应信号,并拉高总线准备传输数据。一次完整的数据为 40bit,按照高位在前,低位在后的顺序传输。

数据格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和,一共 5 字节(40bit)数据。由于 DHT11 分辨率只能精确到个位,所以小数部分是数据全为 0。校验和为前 4 个字节数据相加,校验的目的是为了保证数据传输的准确性。
 

2、时序

根据时序读取DHT11流程为:

1、主机发送复位信号

2、等待DHT11 发送响应信号

3、读取数据(40bit,5个字节)

前面4字节为数据位,第5字节为校验和位

二、原理图

使用的是前面的IO口,GPIO3_PC4。IO口可以跟换,设备的节点需要对应修改。

三、创建节点

1、在设备树中创建设备节点

修改/home/alientek/rk3568_linux_sdk/kernel/arch/arm64/boot/dts/rockchip/目录下的rk3568-atk-evb1-ddr4-v10.dtsi文件,添加gpiodht11节点

gpiodht11 {
  compatible = "alientek,dht11";
  pinctrl-names = "alientek,dht11";
  pinctrl-0 = <&dht11_gpio>;
  dht11-gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>;
  status = "okay";
};

2、创建设备的 pinctrl 节点

dht11-gpios{
  /omit-if-no-ref/
  dht11_gpio: dht11-pin {
  rockchip,pins =
    <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
  };
};

修改后,重新编译内核,生成boot.img文件,重新烧写即可。

重启后会在/proc/device-tree下找到gpiodht11节点.

四、驱动编写

1、drv_dht11.c

/* 
dht11-gpios{
  /omit-if-no-ref/
  dht11_gpio: dht11-pin {
  rockchip,pins =
    <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
  };
};

gpiodht11 {
  compatible = "alientek,dht11";
  pinctrl-names = "alientek,dht11";
  pinctrl-0 = <&dht11_gpio>;
  dht11-gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>;
  status = "okay";
};
*/


#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
//#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


#define DHT11DEV_CNT           1              /* 设备号长度 */
#define DHT11DEV_NAME          "dtsplatdht11"   /* 设备名字 */


/* dht11dev 设备结构体 */
struct dht11dev_dev{
  dev_t devid;                  /* 设备号 */
  struct cdev cdev;             /* cdev */
  struct class *class;          /* 类 */
  struct device *device;        /* 设备 */ 
  struct device_node *node;     /* dht11dev 设备节点 */
  int gpio_dht11;                 /* dht11dev 灯 GPIO 标号 */
};

struct dht11dev_dev dht11dev; /* dht11d ev 设备 */

unsigned char getdata[4] = {0xff, 0xff, 0xff, 0xff};

static void dht11_release( void )
{
    gpio_direction_output(dht11dev.gpio_dht11, 1);
}

static void dht11_start(void)
{
    gpio_direction_output(dht11dev.gpio_dht11, 1);
    mdelay(30);
    
    gpio_set_value( dht11dev.gpio_dht11, 0);
    mdelay(20);
    
    gpio_set_value(dht11dev.gpio_dht11, 1);
    udelay(40);
    
    gpio_direction_input(dht11dev.gpio_dht11);
}


static int dht11_wait_ack(void)
{
    long timeout_us = 50000;
 
    /* 等待低电平 */
    while (gpio_get_value(dht11dev.gpio_dht11) && --timeout_us)
    {
        udelay(1);
    }
    if (!timeout_us)
    {
        return -1;
    }
 
    /* 现在是低电平 */
    /* 等待高电平 */
    timeout_us = 50000;
    
    while (!gpio_get_value(dht11dev.gpio_dht11) && --timeout_us)
    {
        udelay(1);
    }
    
    if (!timeout_us)
    {
        return -1;
    }
 
    /* 现在是高电平 */
    /* 等待低电平 */
    timeout_us = 20000;
    while (gpio_get_value(dht11dev.gpio_dht11) && --timeout_us)
    {
        udelay(1);
    }
    
    if (!timeout_us)
    {
        return -1;
    }

    
    return 0;
}
 
 
static int dht11_read_byte( unsigned char datalist )
{
    int i;
    unsigned char data = 0;
    int timeout_us = 20000;
    u64 pre = 0, last = 0;
    
    for (i = 0; i < 8; i++)
    {
        /* 现在是低电平 */
        /* 等待高电平 */
        timeout_us = 20000;
        while (!gpio_get_value(dht11dev.gpio_dht11) && --timeout_us)
        {
            udelay(1);
        }
        
        if (!timeout_us)
        {
            return -1;
        }
 
        /* 现在是高电平 */
        /* 等待低电平,累加高电平的时间 */
        timeout_us = 20000000;
 
        /* set another gpio low  */
        pre = ktime_get_boot_ns();
        while (1) 
        {
            last = ktime_get_boot_ns();
            if (last - pre >= 40000)
                break;
        }
 
        if (gpio_get_value(dht11dev.gpio_dht11))
        {
            /* get bit 1 */
            data = (data << 1) | 1;
            /* 当前位的高电平未结束, 等待 */
            timeout_us = 20000;
            while (gpio_get_value(dht11dev.gpio_dht11) && --timeout_us)
            {
                udelay(1);
            }
            if (!timeout_us)
            {
                return -1;
            }
        }
        else
        {
            /* get bit 0 */
            data = (data << 1) | 0;
        }
    }
 
    getdata[datalist] = data;
    
    return 0;
}
 
 
static int dht11_get_value(void)
{
	unsigned long flags;
	int i;
	
	
	local_irq_save(flags);  // 关中断
	
	/* 1. 发送高脉冲启动DHT11 */
    dht11_start();
	
	/* 2. 等待DHT11就绪 */
    if (dht11_wait_ack())
    {
        local_irq_restore(flags); // 恢复中断
        return -EAGAIN;
    }
	
	/* 3. 读5字节数据 */
    for (i = 0; i < 5; i++)
    {
		dht11_read_byte(i); 
    }
	
    /* 4. 释放总线 */
    dht11_release();
	
	local_irq_restore(flags); // 恢复中断
	
	/* 5. 根据校验码验证数据 */
    if (getdata[4] != (getdata[0] + getdata[1] + getdata[2] + getdata[3]))
    {
		getdata[0] = 0xff;
		getdata[1] = 0xff;
		getdata[2] = 0xff;
		getdata[3] = 0xff;
		
        return -1;
    }	
    
    return 0;
}


static int dht11_gpio_init(struct device_node *nd)
{
  int ret;
  
  /* 从设备树中获取 GPIO */
  dht11dev.gpio_dht11 = of_get_named_gpio(nd, "dht11-gpio", 0);
  if(!gpio_is_valid(dht11dev.gpio_dht11)) {
    printk(KERN_ERR "dht11dev: Failed to get dht11-gpio\n");
    return -EINVAL;
  }
  
  /* 申请使用 GPIO */
  ret = gpio_request(dht11dev.gpio_dht11, "DHT11");
  if (ret) {
    printk(KERN_ERR "dht11: Failed to request dht11-gpio\n");
    return ret;
  }
  
  /* 将 GPIO 设置为输出模式并设置 GPIO 初始电平状态 */
  gpio_direction_output(dht11dev.gpio_dht11,0);

  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  
  return 0;
}

/*
* @description : 打开设备
* @param – inode : 传递给驱动的 inode
* @param - filp : 设备文件,file 结构体有个叫做 private_data 的成员变量
* 一般在 open 的时候将 private_data 指向设备结构体。
* @return : 0 成功;其他 失败
*/
static int dht11_open(struct inode *inode, struct file *filp)
{
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  
  return 0;
}


/*
    linux driver 驱动接口: 
    实现对应的open/read/write等函数,填入file_operations结构体
*/
static ssize_t dht11_drv_read ( struct file *file, char __user *buf, 
                                size_t size, loff_t *offset)
{
    int ret =0;

    
    if( !dht11_get_value() )
	{
		//printk("data[0] = %d, data[1] = %d, data[2] = %d, data[3] = %d\n", getdata[0], getdata[1], getdata[2], getdata[3]);
		
        ret = copy_to_user(buf, getdata, sizeof(getdata));
		
        return ret;
    }
	
	return ret;

}
 


/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t dht11_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  
  return 0;
}

static int dht11_drv_close(struct inode *node, struct file *file)
{
    printk(" %s line %d \r\n",  __FUNCTION__, __LINE__);
	
	dht11_get_value();
 
    return 0;
}


/* 设备操作函数 */
static struct file_operations dht11_fops = {
  .owner   = THIS_MODULE,
  .open    = dht11_open,
  .read    = dht11_drv_read,
  .write   = dht11_write,
  .release = dht11_drv_close,
};

/*
* @description : flatform 驱动的 probe 函数,当驱动与
* 设备匹配以后此函数就会执行
* @param - dev : platform 设备
* @return : 0,成功;其他负值,失败
*/
static int dht11_probe(struct platform_device *pdev)
{ 
  int ret;
  
  printk("dht11 driver and device was matched!\r\n");
  
  /* 初始化 DHT11 */
  ret = dht11_gpio_init(pdev->dev.of_node);
  if(ret < 0)
    return ret;
  
  /* 1、设置设备号 */
  ret = alloc_chrdev_region(&dht11dev.devid, 0, DHT11DEV_CNT, DHT11DEV_NAME);
  if(ret < 0) {
    pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", DHT11DEV_NAME, ret);
    goto free_gpio;
  }
  
  /* 2、初始化 cdev */
  dht11dev.cdev.owner = THIS_MODULE;
  cdev_init(&dht11dev.cdev, &dht11_fops);
  
  /* 3、添加一个 cdev */
  ret = cdev_add(&dht11dev.cdev, dht11dev.devid, DHT11DEV_CNT);
  if(ret < 0)
    goto del_unregister;
  
  /* 4、创建类 */
  dht11dev.class = class_create(THIS_MODULE, DHT11DEV_NAME);
  if (IS_ERR(dht11dev.class)) {
    goto del_cdev;
  }
  
  /* 5、创建设备 */
  dht11dev.device = device_create(dht11dev.class, NULL, dht11dev.devid, NULL, DHT11DEV_NAME);
  if (IS_ERR(dht11dev.device)) {
    goto destroy_class;
  }

  return 0;

destroy_class:
  class_destroy(dht11dev.class);
del_cdev:
  cdev_del(&dht11dev.cdev);
del_unregister:
  unregister_chrdev_region(dht11dev.devid, DHT11DEV_CNT);
free_gpio:
  gpio_free(dht11dev.gpio_dht11);
  
  return -EIO;
}

/*
* @description : platform 驱动的 remove 函数
* @param - dev : platform 设备
* @return : 0,成功;其他负值,失败
*/
static int dht11_remove(struct platform_device *dev)
{
  gpio_set_value(dht11dev.gpio_dht11, 0);/* 卸载驱动的时候 GPIO置0 */
  gpio_free(dht11dev.gpio_dht11); /* 注销 GPIO */
  cdev_del(&dht11dev.cdev); /* 删除 cdev */
  unregister_chrdev_region(dht11dev.devid, DHT11DEV_CNT);
  device_destroy(dht11dev.class, dht11dev.devid); /* 注销设备 */
  class_destroy(dht11dev.class); /* 注销类 */
  
  return 0;
}

/* 匹配列表 */
static const struct of_device_id dht11_of_match[] = {
{
  .compatible = "alientek,dht11" },
  { /* Sentinel */ }
};

MODULE_DEVICE_TABLE(of, dht11_of_match);

/* platform 驱动结构体 */
static struct platform_driver dht11_driver = {
    .driver = {
    .name = "rk3568-dht11", /* 驱动名字,用于和设备匹配 */
    .of_match_table = dht11_of_match, /* 设备树匹配表 */
  },
  
  .probe = dht11_probe,
  .remove = dht11_remove,
};

/*
* @description : 驱动模块加载函数
* @param : 无
* @return : 无
*/
static int __init dht11driver_init(void)
{
  return platform_driver_register(&dht11_driver);
}

/*
* @description : 驱动模块卸载函数
* @param : 无
* @return : 无
*/
static void __exit dht11driver_exit(void)
{
  platform_driver_unregister(&dht11_driver);
}

module_init(dht11driver_init);
module_exit(dht11driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("yifeng");
MODULE_INFO(intree, "Y");



程序是根据正点原子的注册platform平台驱动点亮LED修改,增加读功能. 这里有点需要注意,内存的使用,使用指针,不清楚为什么,会出错。

2、makefile

KERNELDIR := /home/alientek/rk3568_linux_sdk/kernel
ARCH=arm64
CROSS_COMPILE=/opt/atk-dlrk356x-toolchain/usr/bin/aarch64-buildroot-linux-gnu-

export  ARCH  CROSS_COMPILE

CURRENT_PATH := $(shell pwd)
obj-m := drv_dht11.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

直接make编译,生成ko文件,拷贝到开发板。

五、应用程序编写

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     : dht11App.c
作者       : yifeng
版本       : V1.0
描述       : 测试dth11驱动程序
其他       : 无
日志       : 初版V1.0 2024/07/18
***************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <time.h>
 
#define DEV_FILE    "/dev/dtsplatdht11"
 
 
int main(void)
{
    int fd;
    int count_run = 0;
	int ret = 0;
    unsigned char data[4];
 
    fd = open(DEV_FILE, 0);
    if (fd == -1){
        printf("can not open file: %s \n", DEV_FILE);
        return -1;
    }
 
    while( count_run < 50000)
    {
        count_run++;

        if (read(fd, &data[0], 4) == 0) 
		{
            printf("get humidity  : %d.%d\n", data[0], data[1]);
            printf("get temprature: %d.%d\n", data[2], data[3]);
        } 
        else 
		{
            printf("read dht11 device fail!\n");
        }
		
        sleep(1);  // 1毫秒
    }
 
    close(fd);
 
    return 0;
}

程序比较简单,5秒读一次数据,并打印。

编译:

/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-gcc dht11App.c -o dht11App

六、测试

测试使用的是正点原子的ATK-DLRK3568板子

加载驱动

insmod drv_dht11.ko

测试

./dht11App

测试虽然有读取到温湿度,也有变化,但驱动不是很完美,只限测试使用。

如有侵权,或需要完整代码,请及时联系博主。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1940173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无刷电机控制之——帕克变换

前言 克拉克逆变换请参考如下链接 等幅值变换与克拉克逆变换 一、FOC算法流程图 二、帕克变换概念 1、我们需要知道二维坐标系中的I α \alpha α和I β \beta β&#xff0c;这两个变量的变化规律&#xff0c;通俗来讲就是要知道这两个变量是谁输入的、谁控制的&#xff0c…

pytorch学习(十六)conda和pytorch的安装

1.安装anaconda 1.1 首先下载安装包 1&#xff09;进入anaconda官网 Anaconda | The Operating System for AI 2&#xff09;注册一下 3&#xff09;下载 4&#xff09;一直点直到安装完 5&#xff09;配置环境变量 在path路径中加入 Anaconda安装路径 Anaconda安装路径\S…

Redis高级篇—分布式缓存

目录 Redis持久化 RDB持久化 AOF持久化 RDB与AOF对比 Redis主从 全量同步 增量同步 Redis哨兵 RedisTemplate集成哨兵实现 Redis分片集群 散列插槽 集群伸缩 故障转移 自动故障转移 手动故障转移 RedisTemplate访问分片集群 Redis持久化 RDB持久化 RDB全称Re…

zabbix监控Windows机器进程数量

zabbix监控Windows机器进程数量 文章目录 zabbix监控Windows机器进程数量背景前提条件目的实施 背景 一个windows上的进程总是崩溃&#xff0c;总会出现进程不存在的情况&#xff0c;不能实时去服务器上检查&#xff0c;自己不勤快就要动脑子&#xff0c;让自己变的更懒&#…

Java语言程序设计基础篇_编程练习题*15.9 (使用箭头键画线)

*15.9 (使用箭头键画线) 请编写一个程序&#xff0c;使用箭头键绘制线段。所画的线从面板的中心开始&#xff0c;当敲 击向右、向上、向左或向下的箭头键时&#xff0c;相应地向东、向北、向西或向南方向画线&#xff0c;如图 15-26b所示 代码展示&#xff1a;编程练习题15_9D…

汽车电动空调系统

1.电动空调系统概述 电动汽车制冷空调系统与传统汽车制冷空调系统基本原理一样&#xff0c;区别在于电动汽车空调系统采用电动空调压缩机。电动空调压缩机由驱动电机&#xff0c;压缩机&#xff0c;控制器集成。 电动空调压缩机的驱动电机采用体积小&#xff0c;质量轻&#x…

【线性表】:顺序表里一些主要功能的实现

框架 线性表 是 n 个具有相同特征的数据元素的有限序列 常见的线性表&#xff1a;顺序表、链表、栈、队列… 线性表在逻辑上是线性结构&#xff0c;也就是连续的一条直线 但在物理结构上不一定是连续的&#xff0c;线性表在物理上存储时&#xff0c;通常以数组和链式结构的形式…

数据结构(栈及其实现)

栈 概念与结构 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只允许在固定的⼀端进⾏插⼊和删除元素操作。 进⾏数据插⼊和删除操作的⼀端称为栈顶&#xff0c;另⼀端称为栈底。栈中的数据元素遵守后进先出 LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&…

Windows版MySQL5.7解压直用(如何卸载更换位置重新安装)

文章目录 停止mysql进程及服务迁移整个mysql文件夹删除data重启计算机重新安装 停止mysql进程及服务 net stop mysql mysqld -remove mysql迁移整个mysql文件夹 删除data 重启计算机 shutdown -r -t 0重新安装 https://blog.csdn.net/xzzteach/article/details/137723185

【Socket 编程 】基于UDP协议实现通信并添加简单业务

文章目录 前言实现echo server对于服务器端对于客户端UdpServer.hpp文件nococpy.hpp文件InetAddr.hpp头文件Log.hpp头文件UdpServerMain.cpp源文件UdpClientMain.cpp源文件运行结果 实现翻译业务Dict.hpp头文件UdpServerMain.cppUdpserver.hpp运行结果 前言 在了解了Socket编程…

最优化理论与方法-第十一讲-线性规划-极点的刻画

文章目录 1. 概述2. 线性规划定义3. 多面体的基本性质3.1 定义3.2 证明13.3 证明2 B站老师学习视频 1. 概述 线性规划的标准形式&#xff1b;多面体的几何分解&#xff1b;单纯形法&#xff1b;对偶单纯形法 2. 线性规划定义 线性规划Linear Programming&#xff1a;目标函数…

Ubuntu16.04环境下Baxter机器人开发环境搭建要点说明

Ubuntu16.04环境下Baxter机器人开发环境搭建要点说明 前面写过一篇文章&#xff0c;描述了在ubuntu20.04环境下baxter机器人开发环境的搭建&#xff0c;本人在后来的使用中&#xff0c;出于一些原因又在ubuntu16环境下搭建了开发环境&#xff0c;二者总体流程基本类似&#xf…

【数据分享】2013-2022年我国省市县三级的逐年SO2数据(excel\shp格式\免费获取)

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2000——2022年的省市县三级的逐年PM2.5数据和2013-2022年的省市县三级的逐年CO数据&#xff08;均可查看之前的文章获悉详情&#xff09;&#xff01; 本次我们分享的是我国2013——2022年的省…

【Spark官方文档部分翻译】RDD编程指南(RDD Programming Guide)

写在前面 内容如何选择 本翻译只翻译本人认为精华的部分&#xff0c;本人认为的Spark的一些核心理念&#xff0c;编程思想。一些特别基础的操作包括但不限于搭建环境就不在此赘述了。 配套版本 本系列基于Spark 3.3.1&#xff0c;Scala 2.12.10&#xff0c;进行翻译总结 原…

pycharm报错:No module named pip/No module named pytest

1、问题概述? 今天在执行一个python脚本的时候,控制台提示:No module named pytest,就是没有pytest模块,于是我使用pip命令进行安装,命令如下; pip install pytest 结果又提示No module named pip,说我没有pip模块,没办法,再安装pip 2、安装pip-方式1 在pycharm的T…

路由表与IP数据报转发:基础小白指南

目录 1. 路由表的基本概念 2. 路由表中的默认路由 3. IP数据报的转发流程 4. 路由聚合 5. 最长前缀匹配 总结 在网络世界中&#xff0c;IP数据报的转发是如何进行的&#xff1f; 这篇文章将带你深入了解路由表的基本概念和IP数据报的转发流程。我们会用简洁明了的语言和实…

华为mate20 激活设备

升级失败 需要 准备2个usb线 一根usb1.0工程线 一根正常线 。工程线怎么做&#xff0c;找一个10k电阻 把红线和绿线连起来。我用的是贴片电阻103 大概是2512 1W&#xff0c;也可以用金属膜电阻 步骤① 热风枪吹开后盖

vscode下运行django项目(命令与可视化操作两种方式python .\demo\manage.py runserver)

文章目录 实验前提1. 命令方式操作2. code图形方式操作 实验前提 vscode配置django环境并创建django项目&#xff08;全图文操作&#xff09; https://blog.csdn.net/xzzteach/article/details/140591167 1. 命令方式操作 python .\demo\manage.py runserver关闭运行 2. c…

App Instance 架构示例

前言 在Unity程序设计过程中&#xff0c;我们处理的第一个对象是Application Instance。 它的主要职责是启动流程管理、卸载流程管理&#xff0c;次要职责是管理在内部的子系统生命周期。其他职责&#xff0c;提供或桥接应用程序的配置信息、及其他第三方接口。 它通常以单例的…

buu做题(7)

[BJDCTF2020]Mark loves cat 开始的界面没啥东西, 看了下源码好像也没啥东西 用dirsearch扫描一下 有git 泄露 用工具githack下载源码 <?phpinclude flag.php;$yds "dog"; $is "cat"; $handsome yds;foreach($_POST as $x > $y){$$x $y; }f…