031——从GUI->Client->Server->driver实现dht11数据的采集

ops/2024/9/20 1:23:49/ 标签: 嵌入式, linux, python, git, c
cle class="baidu_pl">
cle_content" class="article_content clearfix">
content_views" class="htmledit_views">

c">目录

c" style="margin-left:40px;">0、设置ip

c" style="margin-left:40px;">1、修改显示界面

c" style="margin-left:40px;">2、 修改客户端

c" style="margin-left:40px;">3、 修改服务器程序通信部分

c" style="margin-left:40px;">4、 修改驱动处理程序

c" style="margin-left:40px;">5、 重写驱动程序

c" style="margin-left:40px;">6、 展示


c" />

ckground-color:transparent;">0、设置ip

因为ifconfig命令要被淘汰了࿰c;所以我们改成使用ip命令设置ubuntu的ip

<code class="language-bash">ip addr add 192.168.5.10/24 dev ens36code>
<code class="language-bash">ip addr showcode>

c="https://img-blog.csdnimg.cn/direct/80b936b1844040b4a82c5b2c91bc631f.png" width="1200" />

1、修改显示界面

c="https://img-blog.csdnimg.cn/direct/47b7e37ce9ce47dbaa5aa5661605153f.png" width="1200" />

之前共用一个get value现在给每个人一个单独的显示框

c="https://img-blog.csdnimg.cn/direct/bac0af7c7330407582f2680479db0fe0.png" width="865" />

2、 修改客户端

<code class="language-class="tags" href="/PYTHON.html" title=python>python">            #dht11elif cmd[2] == '0' and cmd[3] == '5':if cmd[4] == 'g':global_var.TEM=cmd[4]+cmd[5]global_var.HUM=cmd[6]+cmd[7]message = f"{global_var.TEM}°C   {global_var.HUM}%"window['DHT11_O'].update(message)else:print("DHT11: message ERROR")  code>
<code class="language-class="tags" href="/PYTHON.html" title=python>python">            elif event == 'dht11':set_tx_buf('dht11', 'g')send_cmd(client_socket)code>

        DHT11 测量温度的精度为± 2℃࿰c;检测范围为-20℃ -60℃。湿度的精度为± 5%RH࿰c;检测范围为 5%RH-95%RH࿰c;常用于对精度和实时性要求不高的温湿度测量场合。

所以温度要用三位数表示把低温也加上࿰c;湿度的话两位就够了

<code class="language-class="tags" href="/PYTHON.html" title=python>python">            #dht11elif cmd[2] == '0' and cmd[3] == '5':if cmd[4] == 'g':global_var.TEM=cmd[5]+cmd[6]+cmd[7]global_var.HUM=cmd[8]+cmd[9]message = f"{global_var.TEM}°C   {global_var.HUM}%"window['DHT11_O'].update(message)else:print("DHT11: message ERROR")  code>

ckground-color:transparent;">3、 修改服务器程序通信部分

<code class="language-cpp">                printf("dht11!!!\n");if ('g' == cmd[4]){opt = dht11_handle(buf);tx_buffer = buf;}printf(">>>>>>%s\n",tx_buffer);         if (send(acceptfd, tx_buffer, strlen(tx_buffer), 0) < 0){perror("send failed");  }break;code>

局部变量太多了东西展示都给driver_handele做

ckground-color:transparent;">4、 修改驱动处理程序

<code class="language-cpp">/*
*author   : xintianyu
*function : Handle dht11 Settings
*date     : 2024-4-20
-----------------------
author date  modify*/
int dht11_handle(char *data)
{/*传入参数后面要做通用处理使用空指针*/char *device = "/dev/cebss_dht11";unsigned char buf[2];int ret = NOERROR;static int fd;/* 打开文件 */fd = open(device, O_RDWR);if (fd == -1){printf("can not open file %s\n", device);return ERROR;}
read:if (read(fd, buf, 2) == 2){printf("get Humidity: %d, Temperature : %d\n", buf[0], buf[1]);sprintf(data,"@005g%d%d", buf[0], buf[1]);}else{sleep(5);printf("get dht11: -1\n");goto read;}close(fd);return ret;
}code>

ckground-color:transparent;">5、 重写驱动程序

<code class="language-cpp">#include "asm-generic/errno-base.h"
#include "asm-generic/gpio.h"
#include "class="tags" href="/LINUX.html" title=linux>linux/jiffies.h"
#include <class="tags" href="/LINUX.html" title=linux>linux/module.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/poll.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/delay.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/fs.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/errno.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/miscdevice.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/kernel.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/major.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/mutex.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/proc_fs.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/seq_file.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/stat.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/init.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/device.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/tty.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/kmod.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/gfp.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/gpio/consumer.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/platform_device.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/of_gpio.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/of_irq.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/interrupt.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/irq.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/slab.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/fcntl.h>
#include <class="tags" href="/LINUX.html" title=linux>linux/timer.h>struct gpio_desc{int gpio;int irq;char *name;int key;struct timer_list key_timer;
} ;static struct gpio_desc gpios[] = {{115, 0, "dht11", },
};/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_class;static u64 g_dht11_irq_time[84];
static int g_dht11_irq_cnt = 0;/* 环形缓冲区 */
#define BUF_LEN 128
static char g_keys[BUF_LEN];
static int r, w;struct fasync_struct *button_fasync;static irqreturn_t dht11_isr(int irq, void *dev_id);
static void parse_dht11_datas(void);#define NEXT_POS(x) ((x+1) % BUF_LEN)static int is_key_buf_empty(void)
{return (r == w);
}static int is_key_buf_full(void)
{return (r == NEXT_POS(w));
}static void put_key(char key)
{if (!is_key_buf_full()){g_keys[w] = key;w = NEXT_POS(w);}
}static char get_key(void)
{char key = 0;if (!is_key_buf_empty()){key = g_keys[r];r = NEXT_POS(r);}return key;
}static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);// static void key_timer_expire(struct timer_list *t)
static void key_timer_expire(unsigned long data)
{// 解析数据, 放入环形buffer, 唤醒APPparse_dht11_datas();
}/* 实现对应的open/read/write等函数࿰c;填入file_operations结构体                   */
static ssize_t dht11_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{int err;char kern_buf[2];if (size != 2)return -EINVAL;g_dht11_irq_cnt = 0;/* 1. 发送18ms的低脉冲 */err = gpio_request(gpios[0].gpio, gpios[0].name);gpio_direction_output(gpios[0].gpio, 0);gpio_free(gpios[0].gpio);mdelay(18);gpio_direction_input(gpios[0].gpio);  /* 引脚变为输入方向, 由上拉电阻拉为1 *//* 2. 注册中断 */err = request_irq(gpios[0].irq, dht11_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[0].name, &gpios[0]);mod_timer(&gpios[0].key_timer, jiffies + 10);	/* 3. 休眠等待数据 */wait_event_interruptible(gpio_wait, !is_key_buf_empty());free_irq(gpios[0].irq, &gpios[0]);//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);/* 设置DHT11 GPIO引脚的初始状态: output 1 */err = gpio_request(gpios[0].gpio, gpios[0].name);if (err){printk("%s %s %d, gpio_request err\n", __FILE__, __FUNCTION__, __LINE__);}gpio_direction_output(gpios[0].gpio, 1);gpio_free(gpios[0].gpio);/* 4. copy_to_user */kern_buf[0] = get_key();kern_buf[1] = get_key();printk("get val : 0x%x, 0x%x\n", kern_buf[0], kern_buf[1]);if ((kern_buf[0] == (char)-1) && (kern_buf[1] == (char)-1)){printk("get err val\n");return -EIO;}err = copy_to_user(buf, kern_buf, 2);return 2;
}static int dht11_release (struct inode *inode, struct file *filp)
{return 0;
}/* 定义自己的file_operations结构体                                              */
static struct file_operations dht11_drv = {.owner	 = THIS_MODULE,.read    = dht11_read,.release = dht11_release,
};static void parse_dht11_datas(void)
{int i;u64 high_time;unsigned char data = 0;int bits = 0;unsigned char datas[5];int byte = 0;unsigned char crc;/* 数据个数: 可能是81、82、83、84 */if (g_dht11_irq_cnt < 81){/* 出错 */put_key(-1);put_key(-1);// 唤醒APPwake_up_interruptible(&gpio_wait);g_dht11_irq_cnt = 0;return;}// 解析数据for (i = g_dht11_irq_cnt - 80; i < g_dht11_irq_cnt; i+=2){high_time = g_dht11_irq_time[i] - g_dht11_irq_time[i-1];data <<= 1;if (high_time > 50000) /* data 1 */{data |= 1;}bits++;if (bits == 8){datas[byte] = data;data = 0;bits = 0;byte++;}}// 放入环形buffercrc = datas[0] + datas[1] + datas[2] + datas[3];if (crc == datas[4]){put_key(datas[0]);put_key(datas[2]);}else{put_key(-1);put_key(-1);}g_dht11_irq_cnt = 0;// 唤醒APPwake_up_interruptible(&gpio_wait);
}static irqreturn_t dht11_isr(int irq, void *dev_id)
{struct gpio_desc *gpio_desc = dev_id;u64 time;/* 1. 记录中断发生的时间 */time = ktime_get_ns();g_dht11_irq_time[g_dht11_irq_cnt] = time;/* 2. 累计次数 */g_dht11_irq_cnt++;/* 3. 次数足够: 解析数据, 放入环形buffer, 唤醒APP */if (g_dht11_irq_cnt == 84){del_timer(&gpio_desc->key_timer);parse_dht11_datas();}return IRQ_HANDLED;
}/* 在入口函数 */
static int __init dht11_init(void)
{int err;int i;int count = sizeof(gpios)/sizeof(gpios[0]);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);for (i = 0; i < count; i++){		gpios[i].irq  = gpio_to_irq(gpios[i].gpio);/* 设置DHT11 GPIO引脚的初始状态: output 1 */err = gpio_request(gpios[i].gpio, gpios[i].name);gpio_direction_output(gpios[i].gpio, 1);gpio_free(gpios[i].gpio);setup_timer(&gpios[i].key_timer, key_timer_expire, (unsigned long)&gpios[i]);//timer_setup(&gpios[i].key_timer, key_timer_expire, 0);//gpios[i].key_timer.expires = ~0;//add_timer(&gpios[i].key_timer);//err = request_irq(gpios[i].irq, dht11_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpios[i]);}/* 注册file_operations 	*/major = register_chrdev(0, "100ask_dht11", &dht11_drv);  /* /dev/gpio_desc */gpio_class = class_create(THIS_MODULE, "100ask_dht11_class");if (IS_ERR(gpio_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "100ask_dht11");return PTR_ERR(gpio_class);}device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "mydht11"); /* /dev/mydht11 */return err;
}/* 有入口函数就应该有出口函数:卸载驱动程序时࿰c;就会去调用这个出口函数*/
static void __exit dht11_exit(void)
{int i;int count = sizeof(gpios)/sizeof(gpios[0]);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);unregister_chrdev(major, "100ask_dht11");for (i = 0; i < count; i++){//free_irq(gpios[i].irq, &gpios[i]);//del_timer(&gpios[i].key_timer);}
}/* 7. 其他完善:提供设备信息࿰c;自动创建设备节点                                     */module_init(dht11_init);
module_exit(dht11_exit);MODULE_LICENSE("GPL");code>

韦东山老师基于中断的驱动程序准确度太低了࿰c;所以我们写个不基于中断的试试

<code class="language-cpp">#include <class="tags" href="/LINUX.html" title=linux>linux/module.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/kernel.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/fs.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/gpio.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/delay.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/uaccess.h>  #define DHT11_GPIO 115  // 假设DHT11连接到GPIO 115  
#define DHT11_DATA_LEN 8  // DHT11数据长度(包括温湿度值、校验和)  static int dht11_gpio;
static u8 dht11_data[DHT11_DATA_LEN];static void dht11_set_gpio_output(void)  
{  gpio_direction_output(dht11_gpio, 0);  
}  static void dht11_set_gpio_input(void)  
{  gpio_direction_input(dht11_gpio);  
}  static int dht11_read_data(void)  
{  int i, j;  u8 last_state = 0;  // 发送开始信号  dht11_set_gpio_output();  gpio_set_value(dht11_gpio, 0);  udelay(18000);  gpio_set_value(dht11_gpio, 1);  udelay(20);  dht11_set_gpio_input();  // 等待DHT11响应  while (gpio_get_value(dht11_gpio)) {  udelay(1);  if (j++ > 100) {  return -1;  // 超时  }  }  // 读取数据  for (i = 0; i < DHT11_DATA_LEN; i++) {  dht11_data[i] = 0;  for (j = 0; j < 8; j++) {  while (!gpio_get_value(dht11_gpio)) {  udelay(1);  if (j++ > 100) {  return -1;  // 超时  }  }  udelay(40);  if (!gpio_get_value(dht11_gpio)) {  dht11_data[i] |= (1 << (7 - j));  }  }  }  // 检查校验和  u8 sum = 0;  for (i = 0; i < DHT11_DATA_LEN - 1; i++) {  sum += dht11_data[i];  }  if (sum != dht11_data[DHT11_DATA_LEN - 1]) {  return -1;  // 校验和错误  }  return 0;  
}
static int dht11_open(struct inode *inode, struct file *file)  
{  return 0;  
}  static ssize_t dht11_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  
{  int ret;  char data_str[32];  int temp_integral, temp_decimal;  int humi_integral, humi_decimal;  ret = dht11_read_data();  if (ret < 0) {  return ret;  }  // 解析温度和湿度值  temp_integral = dht11_data[2];  temp_decimal = dht11_data[3];  humi_integral = dht11_data[0];  humi_decimal = dht11_data[1];  // 将数据转换为字符串格式  snprintf(data_str, sizeof(data_str), "Temp: %d.%d C, Humidity: %d.%d %%\n",  temp_integral, temp_decimal, humi_integral, humi_decimal);  // 将数据复制到用户空间  if (copy_to_user(buf, data_str, strlen(data_str))) {  return -EFAULT;  }  return strlen(data_str);  
}static int dht11_release(struct inode *inode, struct file *file)  
{  return 0;  
}  static loff_t dht11_lseek(struct file *file, loff_t offset, int whence)  
{  return -EINVAL; // 不支持lseek操作  
}static const struct file_operations dht11_fops = {  .owner = THIS_MODULE,  .read = dht11_read,  .open = dht11_open,  .release = dht11_release,  .llseek = dht11_lseek,  
};  static int __init dht11_init(void)  
{  int ret;  // 请求GPIO资源  dht11_gpio = gpio_request(DHT11_GPIO, "DHT11");  if (dht11_gpio < 0) {  printk(KERN_ERR "Failed to request GPIO %d\n", DHT11_GPIO);  return -ENODEV;  }  // 导出GPIO到用户空间(可选)  // gpio_export(DHT11_GPIO, false);  // 注册字符设备  ret = register_chrdev(0, "dht11", &dht11_fops);  if (ret < 0) {  printk(KERN_ERR "Failed to register character device\n");  gpio_free(dht11_gpio);  return ret;  }  // 创建设备节点  ret = device_create(class_create(THIS_MODULE, "dht11"), NULL, MKDEV(ret, 0), NULL, "cebss_dht11");  if (ret < 0) {  printk(KERN_ERR "Failed to create device\n");  unregister_chrdev(ret, "dht11");  gpio_free(dht11_gpio);  return ret;  }  printk(KERN_INFO "DHT11 driver loaded\n");  return 0;  
}  static void __exit dht11_exit(void)  
{  device_destroy(class_destroy(dht11_class), MKDEV(major, 0));  unregister_chrdev(major, "dht11");  gpio_free(dht11_gpio);  printk(KERN_INFO "DHT11 driver unloaded\n");  
}  module_init(dht11_init);
module_exit(dht11_exit);
MODULE_LICENSE("GPL");code>

c="https://img-blog.csdnimg.cn/direct/c19c4f90809d4a36a8dcc7db72f742c6.png" width="1200" />

不认识࿰c;因为注册的时候没用变量直接给返回值拿来用了

c="https://img-blog.csdnimg.cn/direct/e5cdf9ed67d243ccba88b789252ea062.png" width="1200" />

c="https://img-blog.csdnimg.cn/direct/39277113931e4508a2ae96ca60441836.png" width="1200" />

主设备号也没对上

<code class="language-cpp">static int __init dht11_init(void)  
{  int ret;  // 请求GPIO资源  dht11_gpio = gpio_request(DHT11_GPIO, "DHT11");  if (dht11_gpio < 0) {  printk(KERN_ERR "Failed to request GPIO %d\n", DHT11_GPIO);  return -ENODEV;  }  // 导出GPIO到用户空间(可选)  // gpio_export(DHT11_GPIO, false);  // 注册字符设备  major = register_chrdev(0, "dht11", &dht11_fops);  if (major < 0) {  printk(KERN_ERR "Failed to register character device\n");  gpio_free(dht11_gpio);  return ret;  }  gpio_class = class_create(THIS_MODULE, "dht11");// 创建设备节点  ret = device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "cebss_dht11");  if (ret < 0) {  printk(KERN_ERR "Failed to create device\n");  unregister_chrdev(major, "dht11");  gpio_free(dht11_gpio);  return ret;  }  printk(KERN_INFO "DHT11 driver loaded\n");  return 0;  
}  static void __exit dht11_exit(void)  
{  device_destroy(gpio_class, MKDEV(major, 0));  unregister_chrdev(major, "dht11");  gpio_free(dht11_gpio);  printk(KERN_INFO "DHT11 driver unloaded\n");  
}  code>

color:#fe2c24;">/home/book/program/cebss/driver/01_driver/06_dht11/dht11_drv.c: In function ‘dht11_read_data’:
/home/book/program/cebss/driver/01_driver/06_dht11/dht11_drv.c:65:5: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
     u8 sum = 0;

这个是经典问题࿰c;变量要在最开始定义

color:#fe2c24;">/home/book/program/cebss/driver/01_driver/06_dht11/dht11_drv.c: In function ‘dht11_init’:
/home/book/program/cebss/driver/01_driver/06_dht11/dht11_drv.c:151:9: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
     ret = device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "cebss_dht11");

这个函数的返回值是device结构体

color:#fe2c24;">WARNING: "__bad_udelay" [/home/book/program/cebss/driver/01_driver/06_dht11/dht11_drv.ko] undefined!

这个警告是可能是因为gcc或内核不支持这个级别演延时导致的࿰c;不过问题不大

c="https://img-blog.csdnimg.cn/direct/fc785c04227d4be78e02ca9aed584e2e.png" width="1081" />

c="https://img-blog.csdnimg.cn/direct/3c15e97c57b94d4d95b241590aedc9fb.png" width="1200" />

查了内核源码发现好多人都用了࿰c;证明是支持的࿰c;所以可能是头文件包含的问题。

算了自己写一个假的好了正常要考虑架构频率进程切换等很多问题所以就简单延时一下好了

<code class="language-cpp">void my_udelay(unsigned long usecs)  
{  unsigned long loops = usecs * LOOP_PER_USEC;  while(loops--);
}code>

color:#fe2c24;">[root@100ask:/mnt]# insmod dht11_drv.ko 
[ 2587.699869] ------------[ cut here ]------------
[ 2587.711912] WARNING: CPU: 0 PID: 362 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x64/0x74
[ 2587.722923] sysfs: cannot create duplicate filename '/class/dht11'
[ 2587.731625] ---[ end trace b08c58d5eeb9152c ]---
[ 2587.739230] ------------[ cut here ]------------
[ 2587.744038] WARNING: CPU: 0 PID: 362 at lib/kobject.c:240 kobject_add_internal+0x2a8/0x344
[ 2587.753533] ---[ end trace b08c58d5eeb9152d ]---
[ 2587.761908] Failed to create device
insmod: ERROR: could not insert module dht11_drv.ko: File exists

和单板自带的驱动撞class名了

[root@100ask:/mnt]# insmod dht11_drv.ko 
[ 2757.481544] Failed to request GPIO 115
insmod: ERROR: could not insert module dht11_drv.ko: No such device

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊࿰c;改了一晚上啦࿰c;都不好不知道咋回事算了还是用老师的代码吧

下面是我改过的最新版

<code class="language-cpp">#include <class="tags" href="/LINUX.html" title=linux>linux/module.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/kernel.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/fs.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/gpio.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/delay.h>  
#include <class="tags" href="/LINUX.html" title=linux>linux/uaccess.h>
#include <asm/io.h>  // 假设DHT11连接到GPIO 115
#define DHT11_GPIO 115
// DHT11数据长度(包括温湿度值、校验和)
#define DHT11_DATA_LEN 8
// 假设每个循环迭代需要1微秒
#define LOOP_PER_USEC 1000static int dht11_gpio;
static u8 dht11_data[DHT11_DATA_LEN];
static struct class *gpio_class;
static int major = 0;void my_udelay(unsigned long usecs)  
{  unsigned long loops = usecs * LOOP_PER_USEC;  while(loops--);
}static void dht11_set_gpio_output(void)  
{  gpio_direction_output(dht11_gpio, 0);  
}  static void dht11_set_gpio_input(void)  
{  gpio_direction_input(dht11_gpio);  
}  static int dht11_read_data(void)  
{  int i = 0, j = 0;u8 sum = 0;  // 发送开始信号  dht11_set_gpio_output();  gpio_set_value(dht11_gpio, 0);  mdelay(18);  gpio_set_value(dht11_gpio, 1);  my_udelay(20);  dht11_set_gpio_input();  // 等待DHT11响应  while (gpio_get_value(dht11_gpio)) {  my_udelay(1);  if (j++ > 100) {printk("等待响应失败\n");  return -1;  // 超时  }  }  // 读取数据  for (i = 0; i < DHT11_DATA_LEN; i++) {  dht11_data[i] = 0;  for (j = 0; j < 8; j++){my_udelay(40);  if (!gpio_get_value(dht11_gpio)) {  dht11_data[i] |= (1 << (7 - j));  }  }  }  // // 检查校验和// for (i = 0; i < DHT11_DATA_LEN - 1; i++) {  //     sum += dht11_data[i];  // }  // if (sum != dht11_data[DHT11_DATA_LEN - 1]) {// 	printk("和校验错误区\n");//     return -1;  // 校验和错误  // }  return 0;  
}
static int dht11_open(struct inode *inode, struct file *file)  
{  return 0;  
}  static ssize_t dht11_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  
{  int ret;  char data_str[32];  int temp_integral, temp_decimal;  int humi_integral, humi_decimal;  ret = dht11_read_data();  if (ret < 0) {  return ret;  }  // 解析温度和湿度值  temp_integral = dht11_data[2];  temp_decimal = dht11_data[3];  humi_integral = dht11_data[0];  humi_decimal = dht11_data[1];  // 将数据转换为字符串格式  snprintf(data_str, sizeof(data_str), "%3d %2d\n", temp_integral, humi_integral);  printk("%s\n", data_str);// 将数据复制到用户空间  if (copy_to_user(buf, data_str, 6)) {  return -EFAULT;  }  return strlen(data_str);  
}static int dht11_release(struct inode *inode, struct file *file)  
{  return 0;  
}  static loff_t dht11_lseek(struct file *file, loff_t offset, int whence)  
{  return -EINVAL; // 不支持lseek操作  
}static const struct file_operations dht11_fops = {  .owner = THIS_MODULE,  .read = dht11_read,  .open = dht11_open,  .release = dht11_release,  .llseek = dht11_lseek,  
};  static int __init dht11_init(void)  
{// 请求GPIO资源  // dht11_gpio = gpio_request(DHT11_GPIO, "DHT11");  // if (dht11_gpio < 0) {  //     printk(KERN_ERR "Failed to request GPIO %d\n", DHT11_GPIO);  //     return -ENODEV;  // }  // 导出GPIO到用户空间(可选)  // gpio_export(DHT11_GPIO, false);  // 注册字符设备  major = register_chrdev(0, "dht11", &dht11_fops);  if (major < 0) {  printk(KERN_ERR "Failed to register character device\n");  gpio_free(dht11_gpio);return major;  }  gpio_class = class_create(THIS_MODULE, "dht11");// 创建设备节点  device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "cebss_dht11");  if (IS_ERR(gpio_class)) {  printk(KERN_ERR "Failed to create device\n");  unregister_chrdev(major, "dht11");  gpio_free(dht11_gpio);  return PTR_ERR(gpio_class);  }  printk(KERN_INFO "DHT11 driver loaded\n");  return 0;  
}  static void __exit dht11_exit(void)  
{  device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);  unregister_chrdev(major, "dht11");  gpio_free(dht11_gpio);printk(KERN_INFO "DHT11 driver unloaded\n");
}  module_init(dht11_init);
module_exit(dht11_exit);
MODULE_LICENSE("GPL");code>

最后挣扎一下

试试内核中的dht11程序

c="https://img-blog.csdnimg.cn/direct/1238e707796342e9ad7fcd43495af69e.png" width="1200" />

也是不行啊࿰c;没办法单核cpu这中持续采集就是没法很准确就这样吧。哎

ckground-color:transparent;">6、 展示

c="https://img-blog.csdnimg.cn/direct/b9eda9b8d4b348dc9fda8a1a31f809bd.png" width="882" />

c="https://img-blog.csdnimg.cn/direct/17bb15a496f547c1a72790d754dc8842.png" width="1033" />


http://www.ppmy.cn/ops/7758.html

相关文章

每日一题:痛苦数

编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&#xff0c…

Redis中的慢查询日志(一)

慢查询日志 概述 Redis的慢查询日志功能用于记录执行时间超过给定时长的命令请求&#xff0c;用户可以通过这个功能产生的日志来 监视和优化查询速度。服务器配置有两个和慢查询日志相关的选项: 1.slowlog-log-slower-than选项指定执行时间超过多少微妙(1秒1000 000微妙)的命…

The C programming language (second edition,KR) exercise(CHAPTER 4)

E x c e r c i s e 4 − 1 Excercise\quad 4-1 Excercise4−1&#xff1a; #include <stdlib.h> #include <stdio.h> #include <string.h> int strindex(char s[],char t[]); int strrindex(char s[],char t[]);int main(void) {char s[100]"qwoulddf…

spring注解驱动系列-- BeanPostProcessor与BeanFactoryPostProcessor

一、BeanPostProcessor与BeanFactoryPostProcessor的定义 一、BeanPostProcessor bean后置处理器&#xff0c;bean创建对象初始化前后进行拦截工作的 二、BeanFactoryPostProcessor beanFactory的后置处理器&#xff0c;在BeanFactory标准初始化之后调用&#xff0c;来定制和…

计算机网络(王道考研)笔记个人整理——第二章

第二章 物理层主要任务&#xff1a;确定与传输媒体有关的一些特性 机械特性&#xff1a;物理连接的特性 规定物理连接时所采用的规格、接口形状、引线数目、引脚数量和排列情况 电气特性 规定传输二进制位时&#xff0c;线路上信号的电压范围、阻抗匹配、传输速率和距离限制等…

【KingSCADA】通过地址引用和弹窗模板实现设备控制

当相同的设备过多时&#xff0c;要做很多相同的弹窗&#xff0c;这种情况下可以通过地址引用和弹窗模板实现设备控制。 1.变量创建 2.画面开发 以阀门控制为例&#xff0c;只需要做一个阀门控制界面模板 3.地址引用 # 4.实现效果

【网络运维知识】—路由器与交换机区别

【网络运维知识】—路由器与交换机区别 一、路由器&#xff08;Router&#xff09;和交换机&#xff08;Switch&#xff09;对比1.1 功能1.2 转发方式1.3 范围1.4 处理方式 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 路由器&#xff08…

面试高频:HTTPS 通信流程

更多大厂面试内容可见 -> http://11come.cn 面试高频&#xff1a;HTTPS 通信流程 HTTPS 的加密流程 接下来说一下 HTTPS 协议是如何进行通信的&#xff1a; HTTPS 通信使用的 对称加密 非对称加密 两者结合的算法 HTTPS 通信时&#xff0c;会先使用 非对称加密 让通信双…

深入理解计算机网络:从基本原理到实践应用

前言&#xff1a; 计算机网络是现代信息技术的基石&#xff0c;它连接了全球数以亿计的设备&#xff0c;使得信息传输和资源共享成为可能。本文将从计算机网络的基本原理出发&#xff0c;深入探讨其关键技术&#xff0c;并分享一些实践应用的经验。 一、计算机网络的基本原理 1…

【Qt】Qt界面构建与对象管理:从 “Hello World“ 到内存释放

文章目录 1. 通过图形化界面创建控件2. 通过纯代码方式创建控件3. 对象树管理与内存管理小结&#xff1a; 在软件开发中&#xff0c;构建用户界面是至关重要的一步。Qt作为一个跨平台的C框架&#xff0c;提供了强大的界面构建工具和对象树管理机制&#xff0c;使得界面开发变得…

李宏毅2022机器学习/深度学习 个人笔记(1)

本系列用于推导、记录该系列视频中本人不熟悉、或认为有价值的知识点 本篇记录第一讲&#xff08;选修&#xff09;&#xff1a;神奇宝贝分类 如图&#xff0c;为了估算某个样本属于某类的概率&#xff0c;在二分类问题中&#xff0c;我们需要计算红框所示的4个参数&#xff0…

Linux Centos 9保姆级系统安装教程

文章目录 下载Centos 9镜像文件安装Centos 下载Centos 9镜像文件 清华大学源网址https://mirrors.tuna.tsinghua.edu.cn/ 安装Centos 所需软件&#xff1a;VMware Workstation 16 Pro 版本里面没有Centos 9&#xff1b; 这里我们选择Centos 7同样可以使用 用户设置

Elasticsearch:使用向量化和 FFI/madvise 加速 Lucene

作者&#xff1a;来自 Elastic Chris Hegarty 在 Lucene 领域&#xff0c;我们一直热切地采用新版本 Java 的功能。这些功能使 Lucene 更接近 JVM 和底层硬件&#xff0c;从而提高了性能和稳定性。这使得 Lucene 保持现代化和具有竞争力。 Lucene 的下一个主要版本&#xff0…

RIME-SVM,基于RIME寒冰优化算法优化SVM支持向量机回归预测 (多输入单输出)-附代码

支持向量机&#xff08;SVM&#xff09; 支持向量机&#xff08;SVM&#xff09;是一种广泛用于分类和回归的强大监督学习算法。在回归任务中&#xff0c;特别是在SVM被用作支持向量回归&#xff08;SVR&#xff09;时&#xff0c;目标是找到一个函数&#xff0c;这个函数在给…

Apache Hadoop 输入格式示例

目录 TextInputFormat 示例 SequenceFileInputFormat 示例 总结 TextInputFormat 示例 描述: TextInputFormat 是 Hadoop 中使用最广泛的输入格式之一&#xff0c;适用于纯文本文件。它将文件按行划分&#xff0c;把每一行的起始偏移量作为键&#xff08;key&#xff09;&am…

JDBC学习

DriverManager&#xff08;驱动管理类&#xff09; Drivermanager的作用有&#xff1a; 1.注册驱动&#xff1b; 2.获取数据库连接 Class.forName("com.mysql.cj.jdbc.Driver"); 这一行的作用就是注册Mysql驱动&#xff08;把我们下载的jar包加载到内存里去&…

实现 Android 设备屏幕录制的批处理脚本

在本文中&#xff0c;我们将介绍如何使用批处理脚本来实现在 Android 设备上进行屏幕录制&#xff0c;并将录制的视频文件传输到计算机上。这个脚本利用了 Windows 的批处理脚本和 Android 的 adb 工具。 背景 在进行 Android 应用开发、教学演示或问题排查时&#xff0c;我们…

毕业设计——基于ESP32的智能家居系统(语音识别、APP控制)

ESP32嵌入式单片机实战项目 一、功能演示二、项目介绍1、功能演示2、外设介绍 三、资料获取 一、功能演示 多种控制方式 ① 语音控制 ②APP控制 ③本地按键控制 ESP32嵌入式单片机实战项目演示 二、项目介绍 1、功能演示 这一个基于esp32c3的智能家居控制系统&#xff0c;能实…

使用51单片机控制T0和T1分别间隔1秒2秒亮灭逻辑

#include <reg51.h>sbit LED1 P1^0; // 设置LED1灯的接口 sbit LED2 P1^1; // 设置LED2灯的接口unsigned int cnt1 0; // 设置LED1灯的定时器溢出次数 unsigned int cnt2 0; // 设置LED2灯的定时器溢出次数// 定时器T0 void Init_Timer0() {TMOD | 0x01;; // 定时器…

三、Flask模型基础

ORM 创建模型 # exts.py&#xff1a;插件管理 # 扩展的第三方插件 # 1.导入第三方插件 from flask_sqlalchemy import SQLAlchemy # ORM插件 from flask_migrate import Migrate # 2. 初始化 db SQLAlchemy() # ORM migrate Migrate() # 数据迁移 # 3. 和app对象绑定 def…