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

搭建钓鱼网站教程网络推广的调整和优化

搭建钓鱼网站教程,网络推广的调整和优化,做兼职做网站的是什么,pc端自定义页设计与制作一、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://www.ritt.cn/news/9847.html

相关文章:

  • 门户网站建设公司案例新闻营销发稿平台
  • h5网站模板开发app推广策略
  • 类似淘宝网站建设费用seo推广有哪些
  • 建设公司网站的会计分录广告网
  • 织梦装修网站模板2345网址导航官方网站
  • 263企业邮箱登陆入囗广东网站seo营销
  • 北京 公司网站制作一份完整的营销策划方案
  • 长治一般建一个网站需要多少钱学生班级优化大师
  • 平台网站怎么做的网站建设对企业品牌价值提升的影响
  • 四川省建设招标网站首页查域名备案信息查询
  • 树莓派网站建设google代理
  • 在门户网站做产品单页多少钱一天seo排名优化软件免费
  • 做云购网站网络营销有哪些例子
  • 网站域名解析怎么做最近新闻事件
  • 常州专业房产网站建设学技术包分配的培训机构
  • 如何做网站防劫持自己建个网站要多少钱
  • 拉了专线可以直接做网站吗sem竞价推广代运营收费
  • 手机app开发网站如何设计推广方案
  • 织梦网站图片不显示图片深圳seo推广培训
  • asp网站开发的开发环境广告优化师适合女生吗
  • 做网购网站谷歌推广代理
  • 网页制作布局模板seo工具不包括
  • 徐州网站建设方案竞价排名机制
  • wordpress5.0文章模块模式广州网站建设方案优化
  • 湖南省建设厅建筑业信息网蜗牛精灵seo
  • 上海网站建设shzanen外链代发免费
  • 如何用c语言做网站营销型网站和普通网站
  • 济南网站制作公司报价推广软文发稿
  • 做动画视频的网站有哪些免费个人网站制作
  • 甘肃做网站哪家好深圳网络推广优化