【驱动篇】龙芯LS2K0300之单总线驱动

实验过程

实验目的: 在龙芯开发板上面使用单总线驱动DS18B20温度传感器

① 根据原理图连接DS18B20模块

② 将i2c0引脚的功能复用为GPIO

③ 注册字符设备,按照DS18B20的读写时序编写读写驱动接口

④ 编写测试用例解析传感器的数值

原理图

将板子上面的GPIO48连接传感器的DAT引脚,其余引脚连接如下

在这里插入图片描述

然后记得在设备树中把i2c0部分代码注释掉,将PIN16复用为GPIO48

驱动代码

定义相关传感器设备结构体

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/errno.h>#define DS18B20_DEV_NUM			1		  
#define DS18B20_DEV		        "ds18b20"	
#define DS18B20_GPIO            48
#define DS18B20_DQ_OUT(x)       gpio_direction_output(ds18b20.gpio, x)
#define DS18B20_DQ_IN           ds18b20_get_io()struct ds18b20_dev {dev_t dev_id;		struct cdev cdev;	struct class *class;	struct device *device;	int major;			int minor;	int gpio;				unsigned char data[2]; struct timer_list timer;	struct work_struct work;
};struct ds18b20_dev ds18b20;

传感器数据读写交互

static int ds18b20_get_io(void)
{gpio_direction_input(ds18b20.gpio);return gpio_get_value(ds18b20.gpio); 
}static void ds18b20_reset(void)
{DS18B20_DQ_OUT(0);  /* 拉低DQ,复位 */udelay(750);      /* 拉低750us */DS18B20_DQ_OUT(1);  /* DQ=1, 释放复位 */udelay(15);       /* 延迟15US */
}uint8_t ds18b20_check(void)
{uint8_t retry = 0;uint8_t rval = 0;while (DS18B20_DQ_IN && retry < 200)    /* 等待DQ变低, 等待200us */{retry++;udelay(1);}if (retry >= 200){rval = 1;}else{retry = 0;while (!DS18B20_DQ_IN && retry < 240)   /* 等待DQ变高, 等待240us */{retry++;udelay(1);}if (retry >= 240) rval = 1;}return rval;
}static uint8_t ds18b20_read_bit(void)
{uint8_t data = 0;DS18B20_DQ_OUT(0);udelay(2);DS18B20_DQ_OUT(1);udelay(12);if (DS18B20_DQ_IN){data = 1;}udelay(50);return data;
}static uint8_t ds18b20_read_byte(void)
{uint8_t i, b, data = 0;for (i = 0; i < 8; i++){b = ds18b20_read_bit(); /* DS18B20先输出低位数据 ,高位数据后输出 */data |= b << i;         /* 填充data的每一位 */}return data;
}static void ds18b20_write_byte(uint8_t data)
{uint8_t j;for (j = 1; j <= 8; j++){if (data & 0x01){DS18B20_DQ_OUT(0);  /*  Write 1 */udelay(2);DS18B20_DQ_OUT(1);udelay(60);}else{DS18B20_DQ_OUT(0);  /*  Write 0 */udelay(60);DS18B20_DQ_OUT(1);udelay(2);}data >>= 1;             /* 右移,获取高一位数据 */}
}static void ds18b20_start(void)
{ds18b20_reset();ds18b20_check();ds18b20_write_byte(0xcc);   /*  skip rom */ds18b20_write_byte(0x44);   /*  convert */
}static int ds18b20_init(void)
{gpio_direction_output(ds18b20.gpio, 0);ds18b20_reset();return ds18b20_check();	
}

注册字符设备,绑定相关回调函数

static int ds18b20_open(struct inode *inode, struct file *filp)
{return 0;
}static ssize_t ds18b20_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{int ret;ret = copy_to_user(buf, &ds18b20.data[0], 2);if(ret)return -ENOMEM;return ret;
}static struct file_operations ds18b20_fops = {.owner	= THIS_MODULE,.open = ds18b20_open,.read	= ds18b20_read,
};static void ds18b20_work_callback(struct work_struct *work)
{ds18b20_start();                            /*  ds1820 start convert */ds18b20_reset();ds18b20_check();ds18b20_write_byte(0xcc);                   /*  skip rom */ds18b20_write_byte(0xbe);                   /*  convert */ds18b20.data[0] = ds18b20_read_byte();      /*  LSB */ds18b20.data[1] = ds18b20_read_byte();      /*  MSB */
}static void ds18b20_timer_callback(struct timer_list *arg)
{schedule_work(&ds18b20.work);	mod_timer(&ds18b20.timer, jiffies + (1000 * HZ/1000));	
}static int ds18b20_module_init(void)
{int ret = 0;ds18b20.gpio = DS18B20_GPIO;if (!gpio_is_valid(ds18b20.gpio)) {return -EINVAL;}ret = gpio_request(ds18b20.gpio, "DS18B20-GPIO");if (ret) {printk(KERN_ERR "ds18b20 : Failed to request gpio\n");return ret;}ds18b20_init();if (ds18b20.major) {		ds18b20.dev_id = MKDEV(ds18b20.major, 0);ret = register_chrdev_region(ds18b20.dev_id, DS18B20_DEV_NUM, DS18B20_DEV);if(ret < 0) {pr_err("cannot register %s char driver [ret=%d]\n", DS18B20_DEV, DS18B20_DEV_NUM);goto free_gpio;}} else {					ret = alloc_chrdev_region(&ds18b20.dev_id, 0, DS18B20_DEV_NUM, DS18B20_DEV);if(ret < 0) {pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", DS18B20_DEV, ret);goto free_gpio;}ds18b20.major = MAJOR(ds18b20.dev_id);	ds18b20.minor = MINOR(ds18b20.dev_id);	}ds18b20.cdev.owner = THIS_MODULE;cdev_init(&ds18b20.cdev, &ds18b20_fops);cdev_add(&ds18b20.cdev, ds18b20.dev_id, DS18B20_DEV_NUM);if(ret < 0)goto del_unregister;ds18b20.class = class_create(THIS_MODULE, DS18B20_DEV);if (IS_ERR(ds18b20.class)) {goto del_cdev;}ds18b20.device = device_create(ds18b20.class, NULL, ds18b20.dev_id, NULL, DS18B20_DEV);if (IS_ERR(ds18b20.device)) {goto destroy_class;}timer_setup(&ds18b20.timer, ds18b20_timer_callback, 0);ds18b20.timer.expires=jiffies + msecs_to_jiffies(1000);add_timer(&ds18b20.timer);INIT_WORK(&ds18b20.work, ds18b20_work_callback);return 0;destroy_class:class_destroy(ds18b20.class);
del_cdev:cdev_del(&ds18b20.cdev);
del_unregister:unregister_chrdev_region(ds18b20.dev_id, DS18B20_DEV_NUM);
free_gpio:gpio_free(ds18b20.gpio);return -EIO;
}

整合代码

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/errno.h>#define DS18B20_DEV_NUM			1		  
#define DS18B20_DEV		        "ds18b20"	
#define DS18B20_GPIO            48	
#define DS18B20_DQ_OUT(x)       gpio_direction_output(ds18b20.gpio, x)
#define DS18B20_DQ_IN           ds18b20_get_io()struct ds18b20_dev {dev_t dev_id;		struct cdev cdev;	struct class *class;	struct device *device;	int major;			int minor;	int gpio;				unsigned char data[2]; struct timer_list timer;	struct work_struct work;
};struct ds18b20_dev ds18b20;static int ds18b20_get_io(void)
{gpio_direction_input(ds18b20.gpio);return gpio_get_value(ds18b20.gpio); 
}static void ds18b20_reset(void)
{DS18B20_DQ_OUT(0);  /* 拉低DQ,复位 */udelay(750);      /* 拉低750us */DS18B20_DQ_OUT(1);  /* DQ=1, 释放复位 */udelay(15);       /* 延迟15US */
}uint8_t ds18b20_check(void)
{uint8_t retry = 0;uint8_t rval = 0;while (DS18B20_DQ_IN && retry < 200)    /* 等待DQ变低, 等待200us */{retry++;udelay(1);}if (retry >= 200){rval = 1;}else{retry = 0;while (!DS18B20_DQ_IN && retry < 240)   /* 等待DQ变高, 等待240us */{retry++;udelay(1);}if (retry >= 240) rval = 1;}return rval;
}static uint8_t ds18b20_read_bit(void)
{uint8_t data = 0;DS18B20_DQ_OUT(0);udelay(2);DS18B20_DQ_OUT(1);udelay(12);if (DS18B20_DQ_IN){data = 1;}udelay(50);return data;
}static uint8_t ds18b20_read_byte(void)
{uint8_t i, b, data = 0;for (i = 0; i < 8; i++){b = ds18b20_read_bit(); /* DS18B20先输出低位数据 ,高位数据后输出 */data |= b << i;         /* 填充data的每一位 */}return data;
}static void ds18b20_write_byte(uint8_t data)
{uint8_t j;for (j = 1; j <= 8; j++){if (data & 0x01){DS18B20_DQ_OUT(0);  /*  Write 1 */udelay(2);DS18B20_DQ_OUT(1);udelay(60);}else{DS18B20_DQ_OUT(0);  /*  Write 0 */udelay(60);DS18B20_DQ_OUT(1);udelay(2);}data >>= 1;             /* 右移,获取高一位数据 */}
}static void ds18b20_start(void)
{ds18b20_reset();ds18b20_check();ds18b20_write_byte(0xcc);   /*  skip rom */ds18b20_write_byte(0x44);   /*  convert */
}static int ds18b20_init(void)
{gpio_direction_output(ds18b20.gpio, 0);ds18b20_reset();return ds18b20_check();	
}static int ds18b20_open(struct inode *inode, struct file *filp)
{return 0;
}static ssize_t ds18b20_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{int ret;ret = copy_to_user(buf, &ds18b20.data[0], 2);if(ret)return -ENOMEM;return ret;
}static struct file_operations ds18b20_fops = {.owner	= THIS_MODULE,.open = ds18b20_open,.read	= ds18b20_read,
};static void ds18b20_work_callback(struct work_struct *work)
{ds18b20_start();                            /*  ds1820 start convert */ds18b20_reset();ds18b20_check();ds18b20_write_byte(0xcc);                   /*  skip rom */ds18b20_write_byte(0xbe);                   /*  convert */ds18b20.data[0] = ds18b20_read_byte();      /*  LSB */ds18b20.data[1] = ds18b20_read_byte();      /*  MSB */
}static void ds18b20_timer_callback(struct timer_list *arg)
{schedule_work(&ds18b20.work);	mod_timer(&ds18b20.timer, jiffies + (1000 * HZ/1000));	
}static int ds18b20_module_init(void)
{int ret = 0;ds18b20.gpio = DS18B20_GPIO;if (!gpio_is_valid(ds18b20.gpio)) {return -EINVAL;}ret = gpio_request(ds18b20.gpio, "DS18B20-GPIO");if (ret) {printk(KERN_ERR "ds18b20 : Failed to request gpio\n");return ret;}ds18b20_init();if (ds18b20.major) {		ds18b20.dev_id = MKDEV(ds18b20.major, 0);ret = register_chrdev_region(ds18b20.dev_id, DS18B20_DEV_NUM, DS18B20_DEV);if(ret < 0) {pr_err("cannot register %s char driver [ret=%d]\n", DS18B20_DEV, DS18B20_DEV_NUM);goto free_gpio;}} else {					ret = alloc_chrdev_region(&ds18b20.dev_id, 0, DS18B20_DEV_NUM, DS18B20_DEV);if(ret < 0) {pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", DS18B20_DEV, ret);goto free_gpio;}ds18b20.major = MAJOR(ds18b20.dev_id);	ds18b20.minor = MINOR(ds18b20.dev_id);	}ds18b20.cdev.owner = THIS_MODULE;cdev_init(&ds18b20.cdev, &ds18b20_fops);cdev_add(&ds18b20.cdev, ds18b20.dev_id, DS18B20_DEV_NUM);if(ret < 0)goto del_unregister;ds18b20.class = class_create(THIS_MODULE, DS18B20_DEV);if (IS_ERR(ds18b20.class)) {goto del_cdev;}ds18b20.device = device_create(ds18b20.class, NULL, ds18b20.dev_id, NULL, DS18B20_DEV);if (IS_ERR(ds18b20.device)) {goto destroy_class;}timer_setup(&ds18b20.timer, ds18b20_timer_callback, 0);ds18b20.timer.expires=jiffies + msecs_to_jiffies(1000);add_timer(&ds18b20.timer);INIT_WORK(&ds18b20.work, ds18b20_work_callback);return 0;destroy_class:class_destroy(ds18b20.class);
del_cdev:cdev_del(&ds18b20.cdev);
del_unregister:unregister_chrdev_region(ds18b20.dev_id, DS18B20_DEV_NUM);
free_gpio:gpio_free(ds18b20.gpio);return -EIO;
}static void ds18b20_module_exit(void)
{cdev_del(&ds18b20.cdev);unregister_chrdev_region(ds18b20.dev_id, DS18B20_DEV_NUM); device_destroy(ds18b20.class, ds18b20.dev_id);class_destroy(ds18b20.class);del_timer(&ds18b20.timer);cancel_work_sync(&ds18b20.work);gpio_free(ds18b20.gpio); 
}module_init(ds18b20_module_init);
module_exit(ds18b20_module_exit);
MODULE_LICENSE("GPL");

Makefile文件

obj-m += ds18b20.o 
KDIR:=/home/asensing/loongson/linux-4.19
ARCH=loongarch 
CROSS_COMPILE=loongarch64-linux-gnu-
PWD?=$(shell pwd) 
all:make -C $(KDIR) M=$(PWD) modules 

构建脚本

export PATH=$PATH:/home/asensing/loongson/loongson-gnu-toolchain-8.3-x86_64-loongarch64-linux-gnu-rc1.3-1/bin
make -j8
loongarch64-linux-gnu-gcc test.c -o test
FILE=$PWD/$(basename $PWD).ko
scp $FILE test root@192.168.137.216:/home/root

测试用例

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"#define DEV_NAME "/dev/ds18b20"int main()
{int fd, ret;unsigned char result[2];unsigned char TH, TL;short tmp = 0;float temperature;int flag = 0;fd = open(DEV_NAME, 0);if(fd < 0){printf("open %s device failed\n", DEV_NAME);exit(1);}elseprintf("Open %s success!\n", DEV_NAME);while(1){ret = read(fd, &result, sizeof(result)); if(ret == 0) {	/* 读取到数据 */TL = result[0];TH = result[1];if(TH > 7) {	/* 负数处理 */TH = ~TH;TL = ~TL;flag = 1;	/* 标记为负数 */}tmp = TH;tmp <<= 8;tmp += TL;if(flag == 1) {temperature = (float)(tmp+1) * 0.0625; /* 计算负数的温度 */temperature = -temperature;}else {temperature = (float)tmp *0.0625;	/* 计算正数的温度 */}            if(temperature < 125 && temperature > -55) {	/* 温度范围 */printf("Environment Temperature Now : %0.2f℃\n", temperature);}}flag = 0;sleep(1);}close(fd);	/* 关闭文件 */
}

实验效果

插入驱动后,使用测试用例实时读取环境温度值

在这里插入图片描述

广东太热,我要回非洲!

在这里插入图片描述

参考

以上驱动参考自RT-Thread的工程:rtt-psoc62/one-wire/ds18b20.c at main · hywing/rtt-psoc62 (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/32935.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

马尔可夫聚类算法

马尔可夫聚类算法&#xff08;Markov Clustering Algorithm&#xff0c;MCL&#xff09;是一种用于图聚类的算法&#xff0c;广泛应用于生物信息学、社交网络分析、推荐系统等领域。 其核心思想是模拟随机游走过程&#xff0c;通过迭代地扩散和收缩图上的概率分布来识别图中的…

章十九、JavaVUE —— 框架、指令、声明周期、Vue-cli、组件路由、Element

目录 一、 框架 ● vue.js 框架 ● 特点 ● Vue 安装 二、 第一个vue程序 ● 创建项目 ​编辑 ● 导入 vue.js ● 创建vue对象&#xff0c;设置属性&#xff0c;使用模版渲染到页面 介绍 — Vue.js (vuejs.org) 三、 vue指令 ● v-text ● v-html ● v-…

LeetCode 671.二叉树第二小的结点

这个题我们可以用数组辅助完成&#xff0c;然后进行排序后&#xff0c;再用再进行取值&#xff0c;这是我的代码块: /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/void Preorde…

uniapp scroll-view 虚拟滚动【适合每条数据高度一致】

基本原理 有一万条数据&#xff0c;我们按10条一页来进行分组&#xff0c;会有1000页页面滚动到第10页的位置的时候&#xff0c;10页之后和10页之前是不用被显示的&#xff0c;可以直接隐藏掉如果是数据删除&#xff0c;页面会不流畅&#xff0c;会卡顿一下&#xff0c;且滚动位…

vue-cli搭建

一、vue-cli是什么&#xff1f; vue-cli 官方提供的一个脚手架&#xff0c;用于快速生成一个 vue 的项目模板&#xff1b;预先定义 好的目录结构及基础代码&#xff0c;就好比咱们在创建 Maven 项目时可以选择创建一个 骨架项目&#xff0c;这个骨架项目就是脚手架&#xff0c;…

QT事件处理系统之二:窗口部件的事件拦截,以及事件的传递顺序

1、案例说明 在父窗口中为selfLineEdit窗口安装事件过滤器,这样我们可以在父窗口中首先拦截来自于selfLineEdit本身产生的事件,并且决定该事件最终是否继续传递到selfLineEdit窗口本身。 2、关键代码 selfLineEdit.cpp #include "selfLineEdit.h" #include &l…

ECM和MEMS技术在心肺声学监测中的应用

心肺疾病是全球范围内导致死亡的主要原因。因此&#xff0c;对这些疾病迹象的准确和快速评估对于为患者提供适当的医疗保健至关重要。心血管疾病最重要的迹象之一是心脏周期的异常。大多数呼吸系统疾病则表现为呼吸周期的异常。有多种方法可以监测心脏和肺部的周期。听诊是监测…

pytest测试框架pytest-xdist插件并发执行测试用例

Pytest提供了丰富的插件来扩展其功能&#xff0c;本章介绍下插件pytest-xdist&#xff0c;主要是提供并行测试、分布式测试、循环测试等功能&#xff0c;可以加快测试速度。 pytest-xdist官方显示没有严格的python和pytest版本限制。 pytest-xdist安装 使用pip命令安装: pip…

java内置线程池

线程池常见方法 如何获取线程池对象 缓存线程池 自定义任务对象 public class MyRunnable implements Runnable{private int id;public MyRunnable(int id) {this.id id;}Overridepublic void run() {String name Thread.currentThread().getName();System.out.println(&quo…

DWG转PDF字体研究记录

1.前言 最近需要对PDF中的符合业务规则的文字进行提取&#xff0c;发现有些文字不是文字信息形式存储&#xff0c;而是polyline形式表达&#xff0c;意味着仅仅有形体上的表达&#xff0c;丢失了原本的文字信息。 经过沟通得知&#xff0c;这些PDF是AutoCAD软件导出的&#xf…

Linux 特殊变量 $?

一. 说明 在 Linux 和其他类 Unix 系统中&#xff0c;$? 是一个特殊的变量&#xff0c;用于获取上一个命令的退出状态码。 退出状态码是一个整数值&#xff0c;通常用来表示命令的执行结果。 ⏹退出状态码的含义 0&#xff1a;命令成功执行。0以外的数字&#xff1a;命令执…

STM32 串口通讯

使用STM32的串口通讯&#xff0c;接收串口助手的数据&#xff0c;并且将接收到的数据返回串口&#xff0c;重定义printf功能。 配置引脚信息 由于每次新建工程都需要配置信息&#xff0c;比较麻烦&#xff0c;好在STM32CubeIDE提供了导入.ioc文件的功能&#xff0c;可以帮我们…

华为Mate 70系列,将首发搭载纯血鸿蒙正式版,第四季度登场

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 6月22日消息&#xff0c;华为在HDC 2024上已经宣布&#xff0c;HarmonyOS NEXT开启开发者先锋用户Beta测试。 首批覆盖Mate 60系列、Mate X5系列、MatePad Pro 13.2英寸。 根据官方公布的时间表&…

Sublime Text for Mac v4.0 【注册汉化版】代码编辑器(保姆级教程,简单易懂,轻松上手)

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、Sublime Text 安装出现“软件已损坏&#xff0c;无法打开。要移到废纸篓”问题&#xff0c;解决办法&#xff1a; 2、汉化补丁安装3、输入注册码4、查询使用期限 安装完成&#xff01;&#xff01;&#xff01; 效果 一、下…

【牛客深信服总结】

1.反转链表 2.协议 交换机路由器 3.手写代码&#xff0c;一个二叉树&#xff0c;从根节点到叶子结点算一条路径&#xff0c;打印出所有路径。 4.一些数据结构相关的问题&#xff0c;包括栈和队列的应用&#xff0c;链表和数组的区别&#xff0c;最大堆和最小堆&#xff0c;动态…

OpenCV机器学习-人脸识别

一 基本概念 1 计算机视觉与机器学习的关系 计算机视觉是机器学习的一种应用&#xff0c;而且是最有价的应用。 2 人脸识别 哈尔(haar)级联方法 Harr是专门为解决人脸识别而推出的&#xff1b; 在深度学习还不流行时&#xff0c;Harr已可以商用&#xff1b; 深度学习方法&am…

示例:WPF中如何绑定ContextMenu和Menu

一、目的&#xff1a;开发过程中&#xff0c;有些模块的右键ContextMenu菜单是需要动态显示的&#xff0c;既是根据不同条件显示不同的菜单&#xff0c;很多是通过代码去生成ContextMenu的MenuItem&#xff0c;本文介绍通过绑定的方式去加载ContextMenu&#xff0c;Menu菜单栏的…

【操作系统】期末复习,一篇就够了!【全面】

并发是指多个事件在同一时间间隔内发生 并行是指多个事件在同一时刻发生 设计实时操作系统时&#xff0c;首先应该考虑的是&#xff08; &#xff09; B、实时性和可靠性 .单道批处理系统的主要缺点是&#xff08; &#xff09; A、CPU利用率不高 批处理系统的主要缺点是&…

家政预约小程序14权限配置

目录 1 创建用户2 创建角色3 启用登录4 实现退出总结 我们现在小程序端的功能基本开发好了&#xff0c;小程序开发好之后需要给运营人员提供管理后台&#xff0c;要分配账号、配置权限&#xff0c;我们本篇就介绍一下权限如何分配。 1 创建用户 在微搭中&#xff0c;用户分为内…

简单了解ESD模型与TLP曲线

上文讲了ESD和EOS的区别&#xff0c;说实话远不止那些。今日再稍加深入的介绍ESD。 一 ESD原理 ESD-Electro Static Discharge静电放电&#xff0c;具有不同静电电位的物体互相靠近或者直接接触引起的电荷转移。正常情况下&#xff0c;物体内部的正负电荷是相等的&#xff0c…