
LED驱动程序#include linux/module.h #include linux/poll.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[1] { { 131, 0, led_0, }}; int major; static struct class *gpio_class; // 提供结构体中的read write函数 static ssize_t gpio_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { // 访问的引脚放在buf[0] int cnt sizeof(gpios) / sizeof(gpios[0]); if (size ! 2) return -EINVAL; char temp_buf[2]; int err copy_from_user(temp_buf, buf, 1); if (temp_buf[0] cnt) return -EINVAL; temp_buf[1] gpio_get_value(gpios[temp_buf[0]].gpio); err copy_to_user(buf, temp_buf, 2); return 2; } static ssize_t gpio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { unsigned char key_buf[2]; if (size ! 2) return -EINVAL; int err copy_from_user(key_buf, buf, size); if (key_buf[0] sizeof(gpios) / sizeof(gpios[0])) return -EINVAL; gpio_set_value(gpios[key_buf[0]].gpio, key_buf[1]); return 2; } // 定义自己的file_operations结构体 static struct file_operations gpio_key_drv { .owner THIS_MODULE, .read gpio_drv_read, .write gpio_drv_write} // 入口函数 static int __init gpio_drv_init(void) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); int count sizeof(gpios) / sizeof(gpios[0]); for (int i 0; i count; i) { int err gpio_request(gpios[i].gpio, gpios[i].name); if (err) { printk(can not request gpio %s %d\n, gpios[i].name, gpios[i].gpio); return -ENODEV; } gpio_direction_output(gpios[i].gpio, 1); // set output } major register_chrdev(0, 100ask_led, gpio_key_drv); gpio_class class_create(THIS_MODULE, 100ask_led_class); if (IS_ERR(gpio_class)) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, 100ask_led); return PTR_ERR(gpio_class); } device_create(gpio_class, NULL, MKDEV(major, 0), NULL, 100ask_led); /* /dev/100ask_led */ } static void __exit gpio_drv_exit(void) { 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_gpio_key); for (int i 0; i count; i) { // free_irq(gpios[i].irq, gpios[i]); // del_timer(gpios[i].key_timer); gpio_free(gpios[i].gpio); } } /* 7. 其他完善提供设备信息自动创建设备节点 */ module_init(gpio_drv_init); module_exit(gpio_drv_exit); MODULE_LICENSE(GPL);sr04驱动程序如果想要进行测距的话我们需要先通过trigger来发送一个10us的高电平然后再echo端口获得对应的一个时间为T的高电平我们可以根据高电平的持续时间T来计算对应的距离。但trigger的两次高电平之间至少要间隔50uscopy_to_user函数前两个参数都是地址因此对于读取到的高电平维持时间T传入时需要按照下面的格式copy_to_user(buf, T, 4) 这里的T为int所以为4unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);#include asm-generic/gpio.h #include asm/delay.h #include linux/module.h #include linux/poll.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 #define CMD_TRIG 100 struct gpio_desc { int gpio; int irq; char *name; int key; struct timer_list key_timer; }; /* 主设备号 */ static int major 0; static struct class *gpio_class; static struct gpio_desc gpios[2] { { 115, 0, trig, }, { 116, 0, echo, }, }; /* 环形缓冲区 */ #define BUF_LEN 128 static int g_keys[BUF_LEN]; static int r, w; struct fasync_struct *button_fasync; #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(int key) { if (!is_key_buf_full()) { g_keys[w] key; w NEXT_POS(w); } } static int get_key(void) { int 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 ssize_t sr04_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { if (is_key_buf_empty() (file-flag O_NONBLOCK)) return -EAGAIN; wait_event_interruptible(gpio_wait, !is_key_buf_empty()); val get_key(); if (val -1) return -ENODATA; int err copy_to_user(buf, val, 4); return 4; } static long sr04_ioctl(struct file *filp, unsigned int command, unsigned long arg) { switch (command) { case CMD_TRIG: { gpio_set_value(gpios[0].gpio, 1); udelay(20); gpio_set_value(gpios[0].gpio, 0); // start timer mod_timer(gpios[1].key_timer, jiffies msecs_to_jiffies(50)); } } return 0; } static unsigned int sr04_poll(struct file *fp, poll_table *wait) { // printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); poll_wait(fp, gpio_wait, wait); return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM; } static int sr04_fasync(int fd, struct file *file, int on) { if (fasync_helper(fd, file, on, button_fasync) 0) return 0; else return -EIO; } static struct file_operations sr04_drv { .owner THIS_MODULE, .read sr04_read, .poll sr04_poll, .fasync sr04_fasync, .unlocked_ioctl sr04_ioctl, } static irqreturn_t sr04_isr(int irq, void *dev_id) { struct gpio_desc *gpio_desc dev_id; int val gpio_get_value(gpio_desc-gpio); static u64 rising_time 0; u64 time 0; if (val) { rising_time ktime_get_ns(); } else { if (rising_time 0) { return IRQ_HANDLED; } // stop timer del_timer(gpios[1].key_timer); time ktime_get_ns() - rising_time; rising_time 0; put_key(time); wake_up_interruptible(gpio_wait); kill_fasync(button_fasync, SIGIO, POLL_IN); } return IRQ_HANDLED; } static void sr04_timer_func(unsigned long data) { put_key(-1); wake_up_interruptible(gpio_wait); kill_fasync(button_fasync, SIGIO, POLL_IN); } static int __init sr04_init(void) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); int err; // trigger pin err gpio_request(gpios[0].gpio, gpios[0].name); gpio_direction_output(gpios[0].gpio, 0); // echo pin gpios[1].irq gpio_to_irq(gpios[1].gpio); err request_irq(gpios[1].irq, sr04_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[1].name, gpios[1]); /* 注册file_operations */ major register_chrdev(0, 100ask_sr04, sr04_drv); /* /dev/gpio_desc */ gpio_class class_create(THIS_MODULE, 100ask_sr04_class); if (IS_ERR(gpio_class)) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, 100ask_sr04); return PTR_ERR(gpio_class); } device_create(gpio_class, NULL, MKDEV(major, 0), NULL, sr04); /* /dev/sr04 */ setup_timer(gpios[1].key_timer, sr04_timer_func, (unsigned long)gpios[1]); return err; } static void __exit sr04_exit(void) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); device_detroy(gpio_class, MKDEV(major, 0)); class_detroy(gpio_class); unregister_chrdev(major, 100ask_sr04); gpio_free(gpios[0].gpio); free_irq(gpios[1].irq, gpios[1]); } module_init(sr04_init); module_exit(sr04_exit); MODULE_LICENSE(GPL);步进电机对于步进电机其内部的转子有6个齿外圈的定子则有6个齿当我们导通B时3号会对准B。而此时2号和A会有一个夹角因此当我们截断B并导通A时2号会对准A此时转子发生旋转旋转角度为 15°转子6个齿所以相邻的两个之间夹角为60°定子有8个齿所以夹角为45°。因此我们可以轮流 导通BADC这样转子就完成了八分之一圈。依此类推8 个四节拍以后转子将转过完整的一圈而其中单个节拍使转子转过的角度就很容易计算出来了即 360度/(8*4)11.25度这个值就叫做步进角度。逻辑真值表如下#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, motor_gpio0, }, { 116, 0, motor_gpio1, }, { 117, 0, motor_gpio2, }, { 118, 0, motor_gpio3, }, }; /* 主设备号 */ static int major 0; static struct class *gpio_class; /* 马达引脚设置数字 */ static int g_motor_pin_ctrl[8] {0x2, 0x3, 0x1, 0x9, 0x8, 0xc, 0x4, 0x6}; static int g_motor_index 0; void set_pins_for_motor(int index) { for (int i 0; i 4; i) gpio_set_value(gpios[i].gpio, g_motor_pin_ctrl[index] (1 i) ? 1 : 0); } void disable_motor() { for (int i 0; i 4; i) gpio_set_value(gpios[i].gpio, 0); } /* int buf[2]; * buf[0] 步进的次数, 0 : 逆时针步进; 0 : 顺时针步进 * buf[1] mdelay的时间 */ static ssize_t motor_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { if (size ! 8) return -EINVAL; int ker_buf[2]; int err copy_from_user(ker_buf, buf, 8); if (ker_buf[0] 0) { // 逆时针旋转 for (int step 0; step ker_buf[0]; step) { set_pins_for_motor(g_motor_index); mdelay(ker_buf[1]); g_motor_index--; if (g_motor_index 0) g_motor_index 7; } } else { // 顺时针旋转 ker_buf[1] 0 - ker_buf[1] for (int step 0; step ker_buf[0]; step) { set_pins_for_motor(g_motor_index); mdelay(ker_buf[1]); g_motor_index; if (g_motor_index 7) g_motor_index 0; } } /* 改进旋转到位后让马达不再消耗电源 */ disable_motor(); return 8; } /* 定义自己的file_operations结构体 */ static struct file_operations gpio_motor { .owner THIS_MODULE, .write motor_write, }; /* 在入口函数 */ static int __init motor_init(void) { int err; for (int i 0; i sizeof(gpios) / sizeof(gpios[0]); i) { err gpio_request(gpios[i].gpio, gpios[i].name); gpio_direction_output(gpios[i].gpio, 0); } major register_chrdev(0, 100ask_motor, gpio_key_drv); gpio_class class_create(THIS_MODULE, 100ask_motor_class); if (IS_ERR(gpio_class)) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, 100ask_gpio_key); return PTR_ERR(gpio_class); } device_create(gpio_class, NULL, MKDEV(major, 0), NULL, motor); /* /dev/motor */ return err; } /* 有入口函数就应该有出口函数卸载驱动程序时就会去调用这个出口函数 */ static void __exit motor_exit(void) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); device_destroy(gpio_class, MKDEV(major, 0)); class_destroy(gpio_class); unregister_chrdev(major, 100ask_motor_class); for (int i 0; i sizeof(gpios) / sizeof(gpio[0]); i) { gpio_free(gpios[i].gpio); } } /* 7. 其他完善提供设备信息自动创建设备节点 */ module_init(motor_init); module_exit(motor_exit); MODULE_LICENSE(GPL);DHT11DHT11的通信协议非常简单主机只需要拉低发送一个开始信号然后再拉高即可后续等待dht11发来数据。dht11发来的数据数据为0的一位信号一个低脉冲一个高脉冲。低脉冲持续50us高脉冲持续26~28us。数据为1的一位信号一个低脉冲一个高脉冲。低脉冲持续50us高脉冲持续70us。而其发来的数据格式则是8bit的湿度整数部分8bit的湿度小数部分8bit的温度整数部分8bit的温度小数部分8bit校验和。注arm-linux-gcc规定char为unsigned char因此范围变为0~255。#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) ((x1) % 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, 唤醒APP parse_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); 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); // 唤醒APP wake_up_interruptible(gpio_wait); g_dht11_irq_cnt 0; return; } // 解析数据 for (i g_dht11_irq_cnt - 80; i g_dht11_irq_cnt; i2) { 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; } } // 放入环形buffer crc 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; // 唤醒APP wake_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; } /* 有入口函数就应该有出口函数卸载驱动程序时就会去调用这个出口函数 */ 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);DS18B20DS18B20温度传感器具有线路简单、体积小的特点用来测量温度非常简单在一根通信线上可以挂载多个DS18B20温度传感器。用户可以通过编程实现9~12位的温度读数每个DS18B20有唯一的64位序列号保存在rom中因此一条总线上可以挂载多个DS18B20。DS18B20内部有个64位只读存储器(ROM)和64位配置存储器(SCRATCHP64位配置存储器(SCRATCHP)由9个Byte组成包含温度数据、配置信息等具体格式如下图:其通信时序如下图所示#include asm-generic/errno-base.h #include asm-generic/gpio.h #include asm/gpio.h #include asm/uaccess.h #include linux/module.h #include linux/poll.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, ds18b20, }, }; /* 主设备号 */ static int major 0; static struct class *gpio_class; static spinlock_t ds18b20_spinlock; static void ds18b20_udelay(int us) { u64 time ktime_get_ns(); while (ktime_get_ns() - time us * 1000) ; } static int ds18b20_reset_and_wait_ack(void) { int time_out 100; gpio_set_value(gpios[0].gpio, 0); ds18b20_udelay(480); gpio_direction_input(gpios[0].gpio); while (gpio_get_value(gpios[0].gpio) time--) { ds18b20_udelay(1); } if (time 0) return -EIO; // 等待ACK结束 time_out 300; while (!gpio_get_value(gpios[0].gpio) time--) ds18b20_udelay(1); if (time 0) return -EIO; return 0; } static void ds18b20_send_cmd(unsigned char cmd) { gpio_direction_output(gpios[0].gpio, 1); for (int i 0; i 8; i) { if (cmd (1 i)) { // 发送1 gpio_direction_output(gpios[0].gpio, 0); ds18b20_udelay(2); gpio_direction_output(gpios[0].gpio, 1); ds18b20_udelay(60); } else { // 发送0 gpio_direction_output(gpios[0].gpio, 0); ds18b20_udelay(60); gpio_direction_output(gpios[0].gpio, 1); } } } static void ds18b20_read_data(unsigned char *buf) { gpio_direction_output(gpios[0].gpio, 1); unsigned char data; for (int i 0; i 8; i) { gpio_direction_output(gpios[0].gpio, 0); ds18b20_udelay(2); gpio_direction_input(gpios[0].gpio); // 立即释放总线转为输入 ds18b20_udelay(13); // 等待 13µs使总采样点约在 15µs if (gpio_get_value(gpios[0].gpio)) { data | (1 i); } ds18b20_udelay(50); } buf[0] data; } /********************************************************/ /*DS18B20的CRC8校验程序*/ /********************************************************/ /* 参考: https://www.cnblogs.com/yuanguanghui/p/12737740.html */ static unsigned char calcrc_1byte(unsigned char abyte) { unsigned char i, crc_1byte; crc_1byte 0; // 设定crc_1byte初值为0 for (i 0; i 8; i) { if (((crc_1byte ^ abyte) 0x01)) { crc_1byte ^ 0x18; crc_1byte 1; crc_1byte | 0x80; } else crc_1byte 1; abyte 1; } return crc_1byte; } /* 参考: https://www.cnblogs.com/yuanguanghui/p/12737740.html */ static unsigned char calcrc_bytes(unsigned char *p, unsigned char len) { unsigned char crc 0; while (len--) // len为总共要校验的字节数 { crc calcrc_1byte(crc ^ *p); } return crc; // 若最终返回的crc为0则数据传输正确 } static int ds18b20_verify_crc(unsigned char *buf) { unsigned char crc; crc calcrc_bytes(buf, 8); if (crc buf[8]) return 0; else return -1; } static void ds18b20_calc_val(unsigned char ds18b20_buf[], int result[]) { unsigned char tempL 0, tempH 0; unsigned int integer; unsigned char decimal1, decimal2, decimal; tempL ds18b20_buf[0]; // 读温度低8位 tempH ds18b20_buf[1]; // 读温度高8位 if (tempH 0x7f) // 最高位为1时温度是负 { tempL ~tempL; // 补码转换取反加一 tempH ~tempH 1; integer tempL / 16 tempH * 16; // 整数部分 decimal1 (tempL 0x0f) * 10 / 16; // 小数第一位 decimal2 (tempL 0x0f) * 100 / 16 % 10; // 小数第二位 decimal decimal1 * 10 decimal2; // 小数两位 } else { integer tempL / 16 tempH * 16; // 整数部分 decimal1 (tempL 0x0f) * 10 / 16; // 小数第一位 decimal2 (tempL 0x0f) * 100 / 16 % 10; // 小数第二位 decimal decimal1 * 10 decimal2; // 小数两位 } result[0] integer; result[1] decimal; } static ssize_t ds18b20_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { unsigned long flags; int err; unsigned char kern_buf[9]; int result_buf[2]; if (size ! 8) return -EINVAL; // 关中断 spin_lock_irqsave(ds18b20_spinlock, flags); // 发送reset信号并等待回应 err ds18b20_reset_and_wait_ack(); if (err) { spin_unlock_irqrestore(ds18b20_spinlock, flags); printk(ds18b20_reset_and_wait_ack err\n); return err; } // 发命令 0xcc ds18b20_send_cmd(0xcc); // 发命令启动温度转换 0x44 ds18b20_send_cmd(0x44); // 恢复中断 spin_unlock_irqrestore(ds18b20_spinlock, flags); // 等待 set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(1000)); // 关中断 spin_lock_irqsave(ds18b20_spinlock, flags); // 发送rest err ds18b20_reset_and_wait_ack(); if (err) { spin_unlock_irqrestore(ds18b20_spinlock, flags); printk(ds18b20_reset_and_wait_ack err\n); return err; } // 发命令 0xcc ds18b20_send_cmd(0xcc); // 发命令 0xbe ds18b20_send_cmd(0xbe); // 读9字节数据 for (int i 0; i 9; i) { ds18b20_read_data(kern_buf[i]); } // 恢复中断 spin_unlock_irqrestore(ds18b20_spinlock, flags); // 计算CRC if (ds18b20_verify_crc(kern_buf)) { printk(ds18b20_verify_crc err\n); return err; } // copy_to_user ds18b20_calc_val(kern_buf, result_buf); err copy_to_user(buf, result_buf, 8); return 8; } static struct file_opetations ds18b20_drv{ .owner THIS_MODULE, .read ds18b20_read}; static int __init ds18b20_init(void) { int cnt sizeof(gpios) / sizeof(gpios[0]); int err; printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); spin_lock_init(ds18b20_spinlock); for (int i 0; i cnt; i) { err gpio_request(gpios[i].gpio, gpios[i].name); gpio_direction_output(gpios[i].gpio, 1); } major register_chrdev(0, 100ask_ds18b20, gpio_key_drv); gpio_class class_create(THIS_MODULE, 100ask_ds18b20_class); if (IS_ERR(gpio_class)) { printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, 100ask_ds18b20); return PTR_ERR(gpio_class); } device_create(gpio_class, NULL, MKDEV(major, 0), NULL, myds18b20); return err; } /* 有入口函数就应该有出口函数卸载驱动程序时就会去调用这个出口函数 */ static void __exit ds18b20_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_ds18b20); for (i 0; i count; i) { gpio_free(gpios[i].gpio); } } /* 7. 其他完善提供设备信息自动创建设备节点 */ module_init(ds18b20_init); module_exit(ds18b20_exit); MODULE_LICENSE(GPL);