Linux platform tree下的单总线驱动程序设计(DHT11)
目录
概述
1 认识DHT11
1.1 DHT11特性
1.2 DHT11数据格式
1.3 DHT11与MCU通信
1.4 DHT11信号解析
1.4.1 起始信号
1.4.2 解析信号0
1.4.3 解析信号1
2 驱动开发
2.1 硬件接口
2.2 更新设备树
2.2.1 添加驱动节点
2.2.2 编译.dts
2.2.3 更新板卡中的.dtb
2.3 驱动程序实现
2.3.1 编写驱动程序
2.3.2 编写Makefile
3 测试程序
3.1 编写测试程序
3.2 编写Makefile
4 编译和运行
4.1 编译和安装驱动程序
4.2 编译和运行测试程序
5 波形分析
5.1 起始信号波形
5.2 信息bit = 0波形
5.3 信息bit = 1波形
概述
本文介绍platform tree下,如何设计一个单总线设备的驱动,根据datasheeet提供的波形图,使用代码来实现该驱动程序。然后用逻辑分析仪捕捉信号波形,分析其是否和datasheet中的波形一致。
1 认识DHT11
1.1 DHT11特性
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。 它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。

由上表可得:
温度范围: 0~ 50℃, 低于或者高于这个范围的温度不能测量
湿度范围:20~90%RH
1.2 DHT11数据格式
DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,读一次数据总共包括8bytes( 40 bit )具体格式如下:
Byte-0: 8bit 湿度 整数 数据
Byte-1: 8bit 湿度 小数 数据
Byte-2: 8bit 温度 整数 数据
Byte-3: 8bit 温度 小数 数据
byte-4: 8bit校验和( Byte-0 + Byte-1 + Byte-2 + Byte-3)
1.3 DHT11与MCU通信
Step-1: Master 发送起始信号------->dth11, 信号变化规律为 1 - > 0 -> 1
Step-2: dht11发出响应信号,信号特征为 0 ->1
Step-3:dht11发送数据bit位,总共40个bit

1.4 DHT11信号解析
1.4.1 起始信号
Step-1: Master 发出触发信号:1 -> 0, 该信号至少持续18ms
step-2: Master电平0 ->1,该电平持续20~40us
Step-3: dht11发送响应信号0->1,该电平持续80us
step-4: dht11发送信号1,准备发送数据信息,该电平持续时间80us

1.4.2 解析信号0
信号0特征:
1)0 ->1持续 50us
2)1->0持续26~28us

1.4.3 解析信号1
信号1特征:
1)0 ->1持续 50us
2)1->0持续70us

2 驱动开发
2.1 硬件接口
DHT-11与MCU之间的连接图:

在板卡ATK-DL6Y2C上DTH-11的对应接口:
GPIO4_19: DHT11-IO

硬件实物图:

DHT11引脚说明:

2.2 更新设备树
2.2.1 添加驱动节点
DHT11引脚和IMX.6ULL引脚对应关系:
GPIO4_19: DHT11-IO
.dts文件路径:
/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c/arch/arm/boot/dts/imx6ull-14x14-evk.dts
在.dts文件中添加如下代码:
//mftang: user's dht11, 2024-2-14// IO: GPIO-4-PIN19mftangdht11 {compatible = "atk-dl6y2c,dht11";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_mftang_1_wire>;gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>;status = "okay";};
其在imx6ull-14x14-evk.dts中位置:

2.2.2 编译.dts
编译.dts文件,并把编译生成的.dtb文件发送到NFS共享目录下,便于在板卡中操作该文件。
1)在内核根目录下使用如下命令编译.dts文件
make dtbs

2) 复制 .dtb 文件至NFS共享目录
cp arch/arm/boot/dts/imx6ull-14x14-emmc-4.3-480x272-c.dtb /home/mftang/nfs/atk_dl6y2c/

2.2.3 更新板卡中的.dtb
复制.dtb文件到相应的运行目录,然后重新板卡
cp /mnt/atk_dl6y2c/imx6ull-14x14-emmc-4.3-480x272-c.dtb /run/media/mmcblk1p1

reboot板卡后,内核会重新读取.dtb文件。然后在/proc/device-tree目录下查看板卡device tree,使用如下命令:
cd /proc/device-tree
ls -l
运行该命令后,在该目录下可以看见sensor信息,说明device已经加载到内核:

2.3 驱动程序实现
2.3.1 编写驱动程序
创建drv_dht11.c,并在该文件中编写驱动程序,驱动程序代码地址
/***************************************************************
Copyright 2024-2029. All rights reserved.
文件名 : drv_14_dht11.c
作者 : tangmingfei2013@126.com
版本 : V1.0
描述 : dht11 驱动程序, GPIO4_PIN19-----DHT11 IO port
其他 : 无
日志 : 初版V1.0 2024/1/30 使用方法:
1) 在.dts文件中定义节点信息//mftang: user's dht11, 2024-2-14// IO: GPIO-4-PIN19mftangdht11 {compatible = "atk-dl6y2c,dht11";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_mftang_1_wire>;gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>;status = "okay";};2) 在驱动匹配列表
static const struct of_device_id dht11_of_match[] = {{ .compatible = "atk-dl6y2c,dht11" },{ } // Sentinel
};
***************************************************************/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ktime.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 DEVICE_NAME "treedht11" // dev/treedht11/* dht11dev设备结构体 */
struct dht11stru_dev{dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct class *class; /* 类 */struct device *device; /* 设备 */int major; /* 主设备号 */struct device_node *node; /* dht11设备节点 */int userdht11; /* dht11 GPIO标号*/struct gpio_desc *pin;
};struct dht11stru_dev dht11dev; /* dht11设备 */ int us_low_array[40];
int us_low_index;
int us_array[40];
int time_array[40];
int us_index;/*dht11 driver
*/
static void dht11_release( void )
{gpiod_direction_output(dht11dev.pin, 1);
}static void dht11_start(void)
{gpiod_direction_output(dht11dev.pin, 1);mdelay(30);gpiod_set_value( dht11dev.pin, 0);mdelay(20);gpiod_set_value(dht11dev.pin, 1);udelay(40);gpiod_direction_input(dht11dev.pin);
}static int dht11_wait_ack(void)
{int timeout_us = 20000;/* 等待低电平 */while (gpiod_get_value(dht11dev.pin) && --timeout_us){udelay(1);}if (!timeout_us){printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -1;}/* 现在是低电平 *//* 等待高电平 */timeout_us = 200;while (!gpiod_get_value(dht11dev.pin) && --timeout_us){udelay(1);}if (!timeout_us){printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -1;}/* 现在是高电平 *//* 等待低电平 */timeout_us = 200;while (gpiod_get_value(dht11dev.pin) && --timeout_us){udelay(1);}if (!timeout_us){printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -1;}return 0;
}static int dht11_read_byte( unsigned char *datalist )
{int i;int us = 0;unsigned char data = 0;int timeout_us = 200;u64 pre, last;for (i = 0; i < 8; i++){/* 现在是低电平 *//* 等待高电平 */timeout_us = 400;us = 0;while (!gpiod_get_value(dht11dev.pin) && --timeout_us){udelay(1);us++;}if (!timeout_us){printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -1;}us_low_array[us_low_index++] = us;/* 现在是高电平 *//* 等待低电平,累加高电平的时间 */timeout_us = 20000000;us = 0;/* set another gpio low */pre = ktime_get_boot_ns();while (1) {last = ktime_get_boot_ns();if (last - pre >= 40000)break;}if (gpiod_get_value(dht11dev.pin)){/* get bit 1 */data = (data << 1) | 1;/* 当前位的高电平未结束, 等待 */timeout_us = 400;us = 0;while (gpiod_get_value(dht11dev.pin) && --timeout_us){udelay(1);us++;}if (!timeout_us){printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -1;}}else{/* get bit 0 */data = (data << 1) | 0;}}*datalist = data;return 0;
}static int dht11_get_value( unsigned char *data )
{unsigned long flags;int i;local_irq_save(flags); // 关中断us_index = 0;us_low_index = 0;/* 1. 发送高脉冲启动DHT11 */dht11_start();/* 2. 等待DHT11就绪 */if (dht11_wait_ack()){local_irq_restore(flags); // 恢复中断printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -EAGAIN;}/* 3. 读5字节数据 */for (i = 0; i < 5; i++){if (dht11_read_byte(&data[i])){local_irq_restore(flags); // 恢复中断printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -EAGAIN;}}/* 4. 释放总线 */dht11_release();local_irq_restore(flags); // 恢复中断/* 5. 根据校验码验证数据 */if (data[4] != (data[0] + data[1] + data[2] + data[3])){printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -1;}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)
{unsigned char data[4];int err;if( !dht11_get_value( data ) ){printk(" %s line %d \r\n", __FUNCTION__, __LINE__);err = copy_to_user(buf, data, 4);return 4;}return -1;
}static int dht11_drv_close(struct inode *node, struct file *file)
{printk(" %s line %d \r\n", __FUNCTION__, __LINE__);return 0;
}static int dht11_drv_open(struct inode *inode, struct file *filp)
{filp->private_data = &dht11dev; /* 设置私有数据 */return 0;
}/* 定义driver的file_operations结构体
*/
static struct file_operations dht11_fops = {.owner = THIS_MODULE,.read = dht11_drv_read,.open = dht11_drv_open,.release = dht11_drv_close,
};/* 1. 从platform_device获得GPIO* 2. gpio=>irq* 3. request_irq*/
static int dht11_probe(struct platform_device *pdev)
{printk("dht11 driver and device was matched!\r\n");/* 1. 获得硬件信息 */dht11dev.pin = gpiod_get(&pdev->dev, NULL, 0);if (IS_ERR(dht11dev.pin)){printk("%s line %d get pin parameter error! \n", __FUNCTION__, __LINE__);}/* 2. device_create */device_create( dht11dev.class, NULL, MKDEV( dht11dev.major, 0 ), NULL, DEVICE_NAME); // device name return 0;
}static int dht11_remove(struct platform_device *pdev)
{printk("%s line %d\n", __FUNCTION__, __LINE__);device_destroy( dht11dev.class, MKDEV( dht11dev.major, 0));gpiod_put(dht11dev.pin);return 0;
}static const struct of_device_id atk_dl6y2c_dht11[] = {{ .compatible = "atk-dl6y2c,dht11" },{ },
};/* 1. 定义platform_driver */
static struct platform_driver dht11_driver = {.probe = dht11_probe,.remove = dht11_remove,.driver = {.name = "atk_dht11",.of_match_table = atk_dl6y2c_dht11,},
};/* 2. 在入口函数注册platform_driver
*/
static int __init dht11_init(void)
{int err;printk("%s line %d\n",__FUNCTION__, __LINE__);/* register file_operations */dht11dev.major = register_chrdev( 0, DEVICE_NAME, /* device name */&dht11_fops); /* create the device class */dht11dev.class = class_create(THIS_MODULE, "dht11_class");if (IS_ERR(dht11dev.class)) {printk("%s line %d\n", __FUNCTION__, __LINE__);unregister_chrdev( dht11dev.major, DEVICE_NAME);return PTR_ERR( dht11dev.class );}err = platform_driver_register(&dht11_driver); return err;
}/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数* 卸载platform_driver*/
static void __exit dht11_exit(void)
{printk("%s line %d\n", __FUNCTION__, __LINE__);platform_driver_unregister(&dht11_driver);class_destroy(dht11dev.class);unregister_chrdev(dht11dev.major, DEVICE_NAME);
}/*4. 驱动入口和出口函数
*/
module_init(dht11_init);
module_exit(dht11_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("tangmingfei2013@126.com");
2.3.2 编写Makefile
在驱动程序同级目录中创建Makefile,然后编写如下代码
PWD := $(shell pwd)KERNEL_DIR=/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c
ARCH=arm
CROSS_COMPILE=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-export ARCH CROSS_COMPILEobj-m:= drv_14_dht11.oall:$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modulesclean:rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *.symvers
3 测试程序
3.1 编写测试程序
编写一个测试程序,目的是验证驱动程序是否能正常工作
/***************************************************************
Copyright 2024-2029. All rights reserved.
文件名 : test_14_dht11.c
作者 : tangmingfei2013@126.com
版本 : V1.0
描述 : 测试dth11驱动程序
其他 : 无
日志 : 初版V1.0 2024/02/15***************************************************************/
#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/treedht11"int main(void)
{int fd;int count_run = 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 < 10000){count_run++;if (read(fd, data, 4) == 4) {printf("get humidity : %d.%d\n", data[0], data[1]);printf("get temprature: %d.%d\n", data[2], data[3]);} else {perror("read dht11 device fail!\n");}sleep(1);}close(fd);return 0;
}
3.2 编写Makefile
CFLAGS= -Wall -O2
CC=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
STRIP=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-striptest_14_dht11: test_14_dht11.o$(CC) $(CFLAGS) -o test_14_dht11 test_14_dht11.o$(STRIP) -s test_14_dht11clean:rm -f test_14_dht11 test_14_dht11.o
4 编译和运行
4.1 编译和安装驱动程序
1) 编译驱动程序,并将其copy到NFS的共享目录中,方便在板卡中安装该程序

2) 在板卡中安装该驱动程序 , 使用命令
insmod dev_14_dth11.ko

安装成功后,使用命令查看驱动
ls /dev -l

4.2 编译和运行测试程序
1) 编译测试程序,并将其copy到NFS的共享目录中,方便在板卡中运行该程序

2)在板卡中运行测试程序

5 波形分析
在板卡上运行测试程序,然后使用逻辑分析仪捕捉DHT11-IO上的波形,分析其信号特征,以更好的理解驱动程序。

5.1 起始信号波形
datasheet 上提供的波形

逻辑分析仪上捕捉的波形:

查看电平持续时间:

5.2 信息bit = 0波形
datasheet 上提供的波形

逻辑分析仪上捕捉的波形:

5.3 信息bit = 1波形
datasheet 上提供的波形

逻辑分析仪上捕捉的波形:

相关文章:
Linux platform tree下的单总线驱动程序设计(DHT11)
目录 概述 1 认识DHT11 1.1 DHT11特性 1.2 DHT11数据格式 1.3 DHT11与MCU通信 1.4 DHT11信号解析 1.4.1 起始信号 1.4.2 解析信号0 1.4.3 解析信号1 2 驱动开发 2.1 硬件接口 2.2 更新设备树 2.2.1 添加驱动节点 2.2.2 编译.dts 2.2.3 更新板卡中的.dtb 2.3 驱…...
自研爬虫框架的经验总结(理论及方法)
背景: 由于业务需要,承接一部分的数据采集工作。目前市场内的一些通用框架不太适合。故而进行了自研。 对比自研和目前成熟的框架,自研更灵活适配,可以自己组装核心方法;后者对于新场景的适配需要对框架本身有较高的理…...
配置基于 AWS CRT 的 HTTP 客户端
基于 AWS CRT 的 HTTP 客户端包括同步 AwsCrtHttpClient 和异步 AwsCrtAsyncHttpClient。基于 AWS CRT 的 HTTP 客户端具有以下 HTTP 客户端优势: 更快的 SDK 启动时间 更小的内存占用空间 降低的延迟时间 连接运行状况管理 DNS 负载均衡 SDK 中基于 AWS CRT …...
挑战杯 基于LSTM的天气预测 - 时间序列预测
0 前言 🔥 优质竞赛项目系列,今天要分享的是 机器学习大数据分析项目 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/po…...
我为什么不喜欢关电脑?
程序员为什么不喜欢关电脑? 你是否注意到,程序员们似乎从不关电脑?别以为他们是电脑上瘾,实则是有他们自己的原因!让我们一起揭秘背后的原因,看看程序员们真正的“英雄”本色! 一、上大学时。 …...
Unity【角色/摄像机移动控制】【1.角色移动】
本文主要总结实现角色移动的解决方案。 1. 创建脚本:PlayerController 2. 创建游戏角色Player,在Player下挂载PlayerController脚本 3. 把Camera挂载到Player的子物体中,调整视角,以实现相机跟随效果 3. PlayerController脚本代码…...
Oracle12cR2之Job定时作业调度器详解
Oracle12cR2之Job定时作业调度器详解 文章目录 Oracle12cR2之Job定时作业调度器详解1.Oracle Job1. 关于Job2. 使用方法 2. Job详细说明1. 查看Job的相关视图2.SYS.DBA_JOBS视图字段详细说明 3. 创建及查看Job1. 创建Job2. 查看运行中的Job 1.Oracle Job 1. 关于Job 在 Oracle…...
python自学...
一、稍微高级一点的。。。 1. 闭包(跟js差不多) 2. 装饰器 就是spring的aop 3. 多线程...
Message Pack 协议详解及应用
文章目录 一、Message Pack是什么二、Message Pack的语法规则三、Message Pack相关链接四、Message Pack应用场景五、MessagePack 兼容性与特点 一、Message Pack是什么 Message Pack是一种高效的二进制序列化格式,用于在不同的应用程序之间进行数据交换。它类似于J…...
智慧社区管理系统:构建未来的生活模式
在这个信息化、智能化的时代,我们期待的不再是简单的居住空间,而是一个集安全、便捷、舒适、环保于一体的智能化社区。为此,我们推出了全新的智慧社区管理系统,旨在将先进的科技力量引入社区管理,为居民提供更优质的生…...
Rocky 8.9 Kubespray v2.24.0 在线部署 kubernetes v1.28.6 集群
文章目录 1. 简介2. 预备条件3. 基础配置3.1 配置hostname3.2 配置互信 4. 配置部署环境4.1 在线安装docker4.2 启动容器 kubespray4.3 编写 inventory.ini4.4 关闭防火墙、swap、selinux4.5 配置内核模块 5. 部署6. 集群检查 1. 简介 kubespray 是一个用于部署和管理 Kuber…...
新版AI系统ChatGPT源码支持GPT-4/支持AI绘画去授权
源码获取方式 搜一搜:万能工具箱合集 点击资源库直接进去获取源码即可 如果没看到就是待更新,会陆续更新上 新版AI系统ChatGPT网站源码支持GPT-4/支持AI绘画/Prompt应用/MJ绘画源码/PCH5端/免授权,支持关联上下文,意间绘画模型…...
学习鸿蒙基础(5)
一、honmonyos的page路由界面的路径 新建了一个page,然后删除了。运行模拟器的时候报错了。提示找不到这个界面。原来是在路由界面没有删除这个page。新手刚接触找了半天才找到这个路由。在resources/base/profile/main_pages.json 这个和微信小程序好类似呀。 吐槽…...
Tuxera NTFS2024最新中文版支持M1/M2/M3苹果全系机型
Tuxera NTFS的传输速度会受到多种因素的影响,包括硬件配置、文件大小、存储设备的性能等。因此,无法给出具体的传输速度数值。 不过,根据一些用户的使用经验和测试数据,Tuxera NTFS的传输速度通常都非常快,能够满足大…...
【Python】OpenCV-图片添加水印处理
图片添加水印处理 1. 引言 图像处理中的水印添加是一种常见的操作,用于在图片上叠加一些信息或标识。本文将介绍如何使用OpenCV库在图片上添加水印,并通过详细的代码注释来解释每一步的操作。 2. 代码示例 以下是一个使用OpenCV库的简单代码示例&…...
Milvus数据库介绍
参考:https://www.xjx100.cn/news/1726910.html?actiononClick Milvus 基于FAISS、Annoy、HNSW 等向量搜索库构建,核心是解决稠密向量相似度检索的问题。在向量检索库的基础上,Milvus 支持数据分区分片、数据持久化、增量数据摄取、标量向量…...
notepad++的下载与使用
1.进入官网下载 https://notepad-plus-plus.org/ 点击下载即可 2.选择中文简体 3.建议安装在D盘 其余步骤按照指示就行 4.安装后这几个是必选的 设置完成后就可以写中文了 以此为例 结果为...
论UI的糟糕设计:以百度网盘为例
上面这一排鼠标一经过就会弹出来(不是点才弹出来),然后挡住你的各种操作, 弹出来时你就必须等它消失,卡一下才能操作。 在用户顺畅地操作内容时,经常就卡一下、卡一下、卡一下…… 1、比如鼠标从下到上&am…...
【Spring】三级缓存
目录标题 触发所有未加载的实例a - 开始getBean( doGetBean) - 获取单例beangetSingleton() - 获取单例beancreateBean(doCreateBean) - 创建beancreateBeanInstance - 创建并返回beanaddSingletonFactory -放三级缓存populateBea…...
CVE-2016-3088(ActiveMQ任意文件写入漏洞)
漏洞描述 1、漏洞编号:CVE-2016-3088 2、影响版本:Apache ActiveMQ 5.x~5.13.0 在 Apache ActiveMQ 5.12.x~5.13.x 版本中,默认关闭了 fileserver 这个应用(不过,可以在conf/jetty.xml 中开启);…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
