DHT22适配GEC6818的设备驱动

 drv_dht22.c:

/*
 * @Author: SingleBiu
 * @Date: 2022-01-21 14:19:30
 * @LastEditors: SingleBiu
 * @LastEditTime: 2022-01-21 16:52:30
 * @Description: DHT22 driver
 */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/time.h>
#include "cfg_type.h"

//定义一个字符设备
static struct cdev dht22_cdev;
static unsigned int devno_major = 0; //主设备号
static unsigned int devno_minor = 0; //次设备号
static dev_t dht22_dev_num;          //设备号
static struct class *dht22_class;
static struct device *dht22_device;

// 板子引脚  CON2 TX1
#define DHT_DATA (PAD_GPIO_D + 19)
// 命令cmd
#define GEC6818_GET_DHTDATA _IOR('K', 0, unsigned int)

static int gec6818_dht22_open(struct inode *inode, struct file *filp)
{
    gpio_set_value(DHT_DATA, 1);
    printk("DHT22 driver is opened\n");
    return 0;
}

static int gec6818_dht22_realse(struct inode *inode, struct file *filp)
{
    gpio_set_value(DHT_DATA, 1);
    printk("DHT22 driver is closed\n");
    return 0;
}

static unsigned char get_byte(void)
{
    int i, j = 0;
    int ret = 0;

    for (j = 0; j < 8; j++)
    {
        i = 0;
        // 等待总线拉高跳出
        while (!gpio_get_value(DHT_DATA))
        {
            i++;
            udelay(1);
            if (j > 60)
            {
                printk("DHT22 high level get byte timeout error\n");
                break;
            }
        }

        udelay(22);

        //将数据移到最高位
        ret <<= 1;
        if (gpio_get_value(DHT_DATA))
        {
            // 接收最高位放在第一位
            ret |= 0x01;
        }

        i = 0;

        // 等待总线拉低跳出
        while (gpio_get_value(DHT_DATA))
        {
            i++;
            udelay(1);
            if (i > 200)
            {
                printk("DHT22 low level get byte timeout error\n");
                break;
            }
        }
    }
    return ret;
}

static long gec6818_dht22_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret, i = 0;

    unsigned long flags;                //中断
    unsigned char dht22_data[5] = {0}; //数据组
    unsigned char checksum = 0;

    int hum = 0;    //湿度
    int temp = 0;   //温度
    int temp_h = 0; //温度高位
    int temp_l = 0; //温度低位

    if (cmd == GEC6818_GET_DHTDATA)
    {
        local_irq_save(flags);                     //关中断
        ret = gpio_direction_output(DHT_DATA, 0); //设置输出
        if (ret != 0)
        {
            printk("gpio_direction_output DHT_DATA error\n");
            goto gpio_err;
        }

        udelay(800); //主机拉低800us

        ret = gpio_direction_output(DHT_DATA, 1); //设置输出
        if (ret != 0)
        {
            printk("gpio_direction_output DHT_DATA error\n");
            goto gpio_err;
        }

        udelay(30); //主机拉高 30us

        ret = gpio_direction_input(DHT_DATA); // 设置输入

        if (gpio_get_value(DHT_DATA)) //如果响应会拉低总线
        {
            printk("DHT22 low level timeout error\n");
            local_irq_restore(flags);
            return -EAGAIN;
        }

        i = 0;

        while (!gpio_get_value(DHT_DATA)) //等待总线拉高跳出
        {
            i++;
            udelay(1);
            if (i > 100)
            {
                printk("DHT22 high level timeout error\n");
                local_irq_restore(flags);
                return -EAGAIN;
            }
        }

        i = 0;

        while (gpio_get_value(DHT_DATA)) //等待总线拉低跳出
        {
            i++;
            udelay(1);
            if (i > 100)
            {
                printk("DHT22 low level timeout error\n");
                    local_irq_restore(flags);
                return -EAGAIN;
            }
        }

        for (i = 0; i < 5; i++)
        {
            dht22_data[i] = get_byte();
        }

        checksum = dht22_data[0] + dht22_data[1] + dht22_data[2] + dht22_data[3];
        if (checksum != dht22_data[4])
        {
            printk("DHT22 checksum error\n");
            return -EAGAIN;
        }

        local_irq_restore(flags); //恢复中断
    }
    else
        return -EINVAL; //无效命令

    hum = (dht22_data[0] * 256 + dht22_data[1]) / 10;
    temp = (dht22_data[2] * 256 + dht22_data[3]) / 10;
    temp_h = (dht22_data[2] * 256 + dht22_data[3]) / 10; //温度高位 小数点以前
    temp_l = (dht22_data[2] * 256 + dht22_data[3]) % 10; //温度地位 小数点之后

    printk("kdata: u8  th_data = %d %d  temp_data = %d %d\n", dht22_data[0], dht22_data[1], dht22_data[2], dht22_data[3]);
    printk("kdata:temp_h : %d temp_l : %d\n", temp_h, temp_l);
    printk("kdata:int th_data = %d  temp_data = %d\n", hum, temp);

    ret = copy_to_user(((int *)arg), &hum, sizeof(hum)); //拷贝湿度
    if (ret != 0)
        return -EFAULT;
    ret = copy_to_user(((int *)arg) + 1, &temp_h, (sizeof(temp_h))); //拷贝温度
    ret = copy_to_user(((int *)arg) + 2, &temp_l, (sizeof(temp_l))); //拷贝温度
    if (ret != 0)
        return -EFAULT;

    return 0;

gpio_err:
    //恢复中断
    local_irq_restore(flags);
    return ret;
}

static const struct file_operations gec6818_dht22_fops =
    {
        .owner = THIS_MODULE,
        .open = gec6818_dht22_open,
        .release = gec6818_dht22_realse,
        .unlocked_ioctl = gec6818_dht22_ioctl,
};

//驱动初始化
static int __init gec6818_dht22_init(void)
{
    int ret;
    //获取设备号
    if (devno_major == 0)
    {
        ret = alloc_chrdev_region(&dht22_dev_num, devno_minor, 1, "dht22_device");
    }
    else
    {
        dht22_dev_num = MKDEV(devno_major, devno_minor);
        ret = register_chrdev_region(dht22_dev_num, 1, "dht22_device");
    }
    if (ret < 0)
    {
        printk("Can not get dht22 device number\n");
        return ret;
    }

    //初始化cdev
    cdev_init(&dht22_cdev,&gec6818_dht22_fops);

    //将初始化好的cdev加入内核
    ret = cdev_add(&dht22_cdev, dht22_dev_num, 1);
    if (ret < 0)
    {
        printk("cdev add error\n");
        goto cdev_add_err;
    }

    //创建class
    dht22_class = class_create(THIS_MODULE, "DHT22_class");
    if (IS_ERR(dht22_class))
    {
        ret = PTR_ERR(dht22_class);
        printk("DHT22 driver class create error\n");
        goto class_create_err;
    }

    dht22_device = device_create(dht22_class, NULL, dht22_dev_num, NULL, "dht22_dev");
    if (IS_ERR(dht22_device))
    {
        ret = PTR_ERR(dht22_device);
        printk("dht22 driver device create error\n");
        goto device_create_err;
    }

    if (gpio_request(DHT_DATA, "DHT_DATA") != 0) //申请物理内存区
    {
        printk("gpio_request error\n");
    }

    ret = gpio_direction_output(DHT_DATA, 1); //设置输出
    if (ret != 0)
    {
        printk("gpio_direction_output DHT_DATA error\n");
        gpio_free(DHT_DATA);
        goto device_create_err;
    }

    printk("gec6818_dht22_init\n");
    return 0;

    //错误处理
device_create_err:
    class_destroy(dht22_class);
class_create_err:
    cdev_del(&dht22_cdev);
cdev_add_err:
    unregister_chrdev_region(dht22_dev_num, 1);
    return ret;
}

//驱动卸载
static void __exit gec6818_dht22_exit(void)
{
    gpio_free(DHT_DATA);
    device_destroy(dht22_class, dht22_dev_num);
	class_destroy(dht22_class);
	cdev_del(&dht22_cdev);
	unregister_chrdev_region(dht22_dev_num, 1);
	printk(KERN_INFO "gec6818_dht22_exit\n");
}

module_init(gec6818_dht22_init);
module_exit(gec6818_dht22_exit);

MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("DHT22 driver for GEC6818");
MODULE_LICENSE("GPL");
MODULE_VERSION("V1.0");

drv_dht22_app.c:

/*
 * @Author: SingleBiu
 * @Date: 2022-01-19 20:36:20
 * @LastEditors: SingleBiu
 * @LastEditTime: 2022-01-21 16:58:53
 * @Description: file content
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#define GEC6818_GET_DHTDATA _IOR('K', 0, unsigned int) //注册宏

int main(void)
{
	int ret, cnt_yes = 0, cnt_err = 0;
	// unsigned char data[2];
	int data[3];
	int ultrasonic_fd = open("/dev/dht22_dev", O_RDWR);
	if (ultrasonic_fd < 0)
	{
		perror("open dht22_dev driver");
		return -1;
	}
	while (1)
	{
		ret = ioctl(ultrasonic_fd, GEC6818_GET_DHTDATA, &data[0]);
		if (ret != 0)
		{
			cnt_err++;
			perror("GEC6818_GET_DHTDATA error");
		}
		else
		{
			cnt_yes++;
			printf("app:  Hum= %d  Temprature=%d.%d  err:%d  correct:%d\n", data[0], data[1], data[2], cnt_err, cnt_yes);
		}
		sleep(2);
	}
	close(ultrasonic_fd);

	return 0;
}

makefile:


#KERNELRELEASE这个变量,在内核源码的根目录下面的Makefile会初初始化的

ifeq ($(KERNELRELEASE),)

KERN_DIR := /home/china/6818GEC/kernel

#在Makefile中可以调用shell的命令,调用方法如下:
# $(shell  shell命令) -> 整个这个表达式,表示调用该shell命令的输出结果
PWD := $(shell pwd)

CROSS_COMPILE := /home/china/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-

modules:
	make -C $(KERN_DIR)  M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE)  modules
clean:
	rm -rf *.o
	rm -rf  modules.order  .tmp_versions *.ko  Module.symvers
	rm -f  *.cmd .*.cmd  *.mod.c

else
	
	obj-m += drv_dht22.o

endif

你可能感兴趣的:(linux,嵌入式硬件,c语言)