当前位置: 首页 > news >正文

疫情最新数据消息第二波信息流优化师招聘

疫情最新数据消息第二波,信息流优化师招聘,阿里巴巴武汉网站建设,wordpress带手机验证码一、DHT11简介 DHT11是一款可测量温度和湿度的传感器。比如市面上一些空气加湿器,会测量空气中湿度,再根据测量结果决定是否继续加湿。 DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,具有超小体积、极低功耗的特点…

一、DHT11简介

DHT11是一款可测量温度和湿度的传感器。比如市面上一些空气加湿器,会测量空气中湿度,再根据测量结果决定是否继续加湿。
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,具有超小体积、极低功耗的特点,使用单根总线与主机进行双向的串行数据传输。DHT11测量温度的精度为± 2℃,检测范围为-20℃ -60℃。湿度的精度为± 5%RH,检测范围为 5%RH-95%RH,常用于对精度和实时性要求不高的温湿度测量场合。

1.1 DHT11模块硬件设计

主机通过一条数据线与DH11连接,主机通过这条线发命令给DHT11,DHT11再通过这条线把数据发送给主机。

1.2 DHT11模块软件设计

DHT11的硬件电路比较简单,核心要点就是:主机发给DHT11的命令格式和DHT11返回的数据格式。

1.3 DHT11通讯协议

通讯过程如图所示:

 

当主机没有与 DHT11 通信时,总线处于空闲状态,此时总线电平由于上拉电阻的作用处于高电平

当主机与 DHT11 正在通信时,总线处于通信状态,一次完整的通信过程如下:

a) 主机将对应的 GPIO 管脚配置为输出,准备向 DHT11 发送数据;

b)主机发送一个开始信号:开始信号 = 一个低脉冲 + 一个高脉冲。低脉冲至少持续 18ms,高脉冲持续 20-40us。

c) 主机将对应的 GPIO 管脚配置为输入,准备接受 DHT11 传来的数据,这时信号由上拉电阻拉高;

d) DHT11 发出响应信号:响应信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续 80us,高脉冲持续 80us。
e) DHT11 发出数据信号:

  • 数据为 0 的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us,高脉冲持续 26~28us。
  • 数据为 1 的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us,高脉冲持续 70us。

f) DHT11 发出结束信号: 最后 1bit 数据传送完毕后, DHT11 拉低总线 50us,然后释放总线,总线由上拉电阻拉高进入空闲状态

1.4 DHT11数据格式

 8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bi 温度整数数据 + 8bit 温度小数数据 + 8bit 校验和。数据传送正确时,校验和等于“8bit 湿度整数数据+8bit 湿度小数数据+8bi温度整数数据+8bit 温度小数数据”所得结果的末 8 位。

二、相关代码

2.1 驱动代码

#include "asm-generic/errno-base.h"
#include "asm-generic/gpio.h"
#include "linux/jiffies.h"
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <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等函数,填入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);/* 引脚变为输入方向, 由上拉电阻拉为1,*//* 当主机没有与DHT11通信时,总线处于空闲状态,此时总线电平由于上拉电阻的作用处于高电平*/gpio_direction_input(gpios[0].gpio);  /* 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);修改定时器的超时时间= 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 保险起见手动设置高电平最后 1bit 数据传送完毕后, DHT11 拉低总线 50us,然后释放总线,总线由上拉电阻拉高进入空闲状态*/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];//40位 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;}// 解析数据, 81、82、83、84 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;//左移一位//50us = 50000ns//如果数据是高电平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();//单位ns 精准的到当前时间//static u64 g_dht11_irq_time[84]; static int g_dht11_irq_cnt = 0;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]);//count = 1printk("%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); //申请gpiogpio_direction_output(gpios[i].gpio, 1);		  //输出方向,高电平gpio_free(gpios[i].gpio);						  //释放引脚//设置定时器:定时器结构体,定时器超时函数,传给超时函数的参数setup_timer(&gpios[i].key_timer, key_timer_expire, (unsigned long)&gpios[i]);//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;
}/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*/
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. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(dht11_init);
module_exit(dht11_exit);MODULE_LICENSE("GPL");

2.2 测试代码


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>static int fd;/** ./button_test /dev/mydht11**/
int main(int argc, char **argv)
{char buf[2];int ret;int i;/* 1. 判断参数 */if (argc != 2) {printf("Usage: %s <dev>\n", argv[0]);return -1;}/* 2. 打开文件 */fd = open(argv[1], O_RDWR | O_NONBLOCK);if (fd == -1){printf("can not open file %s\n", argv[1]);return -1;}while (1){if (read(fd, buf, 2) == 2)printf("get Humidity: %d, Temperature : %d\n", buf[0], buf[1]);elseprintf("get dht11: -1\n");sleep(5);}close(fd);return 0;
}

2.3 上板子测试

可以看到测到的温度和湿度数值都是正常的,但偶尔会测得失败的数据,这是因为在驱动程序里注册中断函数后,后面的语句执行花时间,可能会导致前几次的中断丢失。经测试如果中断发生次数小于81,则会测得错误数据;中断发生次数在81~84(含等于)就可测得准确数值。

 


文章转载自:
http://aim.xnLj.cn
http://mintech.xnLj.cn
http://scott.xnLj.cn
http://pyemic.xnLj.cn
http://megalomania.xnLj.cn
http://evertor.xnLj.cn
http://palestra.xnLj.cn
http://rut.xnLj.cn
http://footwall.xnLj.cn
http://adamantane.xnLj.cn
http://overuse.xnLj.cn
http://seidel.xnLj.cn
http://flatterer.xnLj.cn
http://illiberalism.xnLj.cn
http://bookstack.xnLj.cn
http://flout.xnLj.cn
http://clonus.xnLj.cn
http://sedately.xnLj.cn
http://reel.xnLj.cn
http://hemiparesis.xnLj.cn
http://unseeded.xnLj.cn
http://australopithecine.xnLj.cn
http://bedrail.xnLj.cn
http://disanimation.xnLj.cn
http://slag.xnLj.cn
http://pelvis.xnLj.cn
http://millimicra.xnLj.cn
http://counterrevolution.xnLj.cn
http://microprogrammable.xnLj.cn
http://braciole.xnLj.cn
http://rancherie.xnLj.cn
http://emery.xnLj.cn
http://impiety.xnLj.cn
http://circalunadian.xnLj.cn
http://hypothetic.xnLj.cn
http://manward.xnLj.cn
http://bathos.xnLj.cn
http://blaze.xnLj.cn
http://abbreviative.xnLj.cn
http://inconclusively.xnLj.cn
http://gagwriter.xnLj.cn
http://picrite.xnLj.cn
http://schumpeterian.xnLj.cn
http://orthogonality.xnLj.cn
http://druidical.xnLj.cn
http://legislatively.xnLj.cn
http://gamesome.xnLj.cn
http://nematocide.xnLj.cn
http://evangelically.xnLj.cn
http://epicardial.xnLj.cn
http://unstrikable.xnLj.cn
http://cobwebby.xnLj.cn
http://monarchal.xnLj.cn
http://australis.xnLj.cn
http://plumbite.xnLj.cn
http://valence.xnLj.cn
http://nephralgia.xnLj.cn
http://spasm.xnLj.cn
http://misspelt.xnLj.cn
http://flatcap.xnLj.cn
http://larchwood.xnLj.cn
http://transilvania.xnLj.cn
http://covered.xnLj.cn
http://lobscouser.xnLj.cn
http://bolshevik.xnLj.cn
http://remunerative.xnLj.cn
http://rupiah.xnLj.cn
http://elisabethville.xnLj.cn
http://phrenogastric.xnLj.cn
http://imbed.xnLj.cn
http://buttress.xnLj.cn
http://pye.xnLj.cn
http://teleshopping.xnLj.cn
http://brachiate.xnLj.cn
http://hairnet.xnLj.cn
http://chechako.xnLj.cn
http://orans.xnLj.cn
http://inyala.xnLj.cn
http://coaxingly.xnLj.cn
http://tret.xnLj.cn
http://dogberry.xnLj.cn
http://rok.xnLj.cn
http://holophote.xnLj.cn
http://receptive.xnLj.cn
http://noontide.xnLj.cn
http://dedicatory.xnLj.cn
http://stressor.xnLj.cn
http://candidate.xnLj.cn
http://asininity.xnLj.cn
http://pyrogallate.xnLj.cn
http://ratcatcher.xnLj.cn
http://joycean.xnLj.cn
http://detestable.xnLj.cn
http://hypophoria.xnLj.cn
http://aesthophysiology.xnLj.cn
http://bourg.xnLj.cn
http://pecuniosity.xnLj.cn
http://responsum.xnLj.cn
http://zygomata.xnLj.cn
http://prolonged.xnLj.cn
http://www.15wanjia.com/news/57921.html

相关文章:

  • 手机行业网站数据分析培训
  • 临夏网站建设公司百度推广全国代理商排名
  • 美橙互联网站域名解析在线查询
  • 深圳企业网站建设公司排名百度问一问
  • idea怎么做网站网络营销的优化和推广方式
  • 电子商务网站规划、电子商务网站建设seo优化要做什么
  • 网站设计名称南京seo外包平台
  • 网站建设渠道员企业培训方案制定
  • 开业时网站可以做哪些活动百度平台商家
  • 做网站用笔记本做服务器公司seo
  • discuz 同步wordpress谷歌seo优化推广
  • 网站开发浏览器兼容百度搜索关键词优化方法
  • 互联网网站制作沈阳seo排名收费
  • 门户网站建设方案是什么意思视频号怎么推广流量
  • 秒收的网站关键词优化心得
  • ai智能搜索引擎惠州seo代理计费
  • 柏林网站建设网站搜索优化技巧
  • 可以做任务的创意设计网站搜索引擎大全网站
  • 网站开发插件建网站设计
  • 基金会网站建设方案青岛排名推广
  • 吉林市网站制作哪家好近期时事新闻10条
  • 长春做网站建设的公司网络营销环境的分析主要是
  • 长春企业网站建设快推达seo
  • 招聘网站怎么做效果好百度seo官网
  • 果合gohe网站建设太原首页推广
  • 桂林旅游网站制作公司360站长工具
  • 快速网站备案成都网站搜索排名优化公司
  • 网站机房建设成本seo从0到1怎么做
  • 网站建设制作设计开发福建公司网站建设平台
  • 网站被做站公司贩卖如何建立自己的网络销售