DS18B20传感器的引脚及封装图如下:
内核代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#define DQ_IN_GPIO 40 // 操作DS18B20的GPIO
/*********************************************DS18B20************************************************/
/* 1.复位信号 */
void DS18B20_Rst(void)
{
int ret = gpio_request(DQ_IN_GPIO, "DQ_OUT");
if (ret != 0)
{
printk("Rst gpio_request fail !\n");
return;
}
gpio_direction_output(DQ_IN_GPIO, 0);
udelay(750); //拉低750us
gpio_direction_output(DQ_IN_GPIO, 1);
udelay(15); //拉高15us
gpio_free(DQ_IN_GPIO);
}
/* 2.应答信号 */
int DS18B20_CheckAck(void)
{
int retry = 0;
int ret = gpio_request(DQ_IN_GPIO, "DQ_OUT");
if (ret != 0)
{
printk("Check gpio_request fail !\n");
return;
}
gpio_direction_input(DQ_IN_GPIO);
while(gpio_get_value(DQ_IN_GPIO) & (retry < 200))
{
retry++;
udelay(1);
};
if(retry >= 200){
gpio_free(DQ_IN_GPIO);
return -1;
}
retry = 0;
while(!gpio_get_value(DQ_IN_GPIO) & (retry < 240))
{
retry++;
udelay(1);
}
if(retry >= 240){
gpio_free(DQ_IN_GPIO);
return -1;
}
gpio_free(DQ_IN_GPIO);
return 0;
}
/* 3.写时序,一个字节 */
void DS18B20_Write_Byte(int dat)
{
int j,testb;
gpio_request(DQ_IN_GPIO, "DQ_OUT");
for(j = 0; j < 8; j++){
testb = dat & 0x1;
dat >>= 1;
if(testb){ // 写1时序
gpio_direction_output(DQ_IN_GPIO, 0);
udelay(2);
gpio_direction_output(DQ_IN_GPIO, 1);
udelay(60);
} else { // 写0时序
gpio_direction_output(DQ_IN_GPIO, 0);
udelay(60);
gpio_direction_output(DQ_IN_GPIO, 1);
udelay(2);
}
}
gpio_free(DQ_IN_GPIO);
}
/* 4.读一bit数据 */
int DS18B20_Read_Bit(void)
{
int data;
gpio_request(DQ_IN_GPIO, "DQ_OUT");
gpio_direction_output(DQ_IN_GPIO, 0);
udelay(2);
gpio_direction_output(DQ_IN_GPIO, 1);
udelay(12);
// gpio_free(DQ_IN_GPIO);
// gpio_request(DQ_IN_GPIO, "DQ_IN");
gpio_direction_input(DQ_IN_GPIO);
if(gpio_get_value(DQ_IN_GPIO))
data = 1;
else
data = 0;
udelay(50);
gpio_free(DQ_IN_GPIO);
return data;
}
/* 5.读一个字节的数据 */
int DS18B20_Read_Byte(void)
{
int i, j, dat = 0;
for(i = 0; i < 8; i++)
{
j = DS18B20_Read_Bit();
//低位先行,j左移7位,把最低位赋给dat,同时dat左移1位,把低位右移,循环8次你懂的
dat = (j << 7) | (dat >> 1);
}
return dat;
}
/* 6.温度转换 */
void DS18B20_Start(void)
{
DS18B20_Rst();
DS18B20_CheckAck();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0x44);
}
/* 7.处理温度信息 */
int DS18B20_Get_temp(void)
{
int temp = 0,
TL = 0,
TH = 0;
DS18B20_Start();
DS18B20_Rst();
DS18B20_CheckAck();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0xbe);
TL = DS18B20_Read_Byte();
TH = DS18B20_Read_Byte();
if(TH > 7){
TH = ~TH;
TL = ~TL;
temp = 0;
}else{
temp = 1;
}
temp = TH;
temp <<= 8;
temp += TL;
/**
* 内核不支持浮点运算,如果在内核里做计算会丢失小数部分
* 所以计算留给用户程序来完成,这里直接传输原始数据即可
*/
if(temp){
return temp;
}else{
return ~temp + 1;
}
}
/*****************************************************************************************************/
int
ds18b20_open(struct inode *inode, struct file *filp)
{
// 硬件初始化
/*do nothing*/
return 0;
}
ssize_t
ds18b20_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
int temp_buf = 0;
temp_buf = DS18B20_Get_temp();
if (copy_to_user(buf, &temp_buf, sizeof(temp_buf))) {
printk(KERN_ERR "Failed to copy data to user space\n");
return -EFAULT;
}
return count;
}
const struct file_operations ds18b20_fops = {
.open = ds18b20_open,
.read = ds18b20_read,
};
struct miscdevice ds18_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ds18b20",
.fops = &ds18b20_fops,
};
static void __exit
ds18b20_drv_exit(void)
{
misc_deregister(&ds18_misc);
}
static int __init
ds18b20_drv_init(void)
{
// 注册杂项设备,因为比直接的普通字符设备少写好多代码
int ret = misc_register(&ds18_misc);
if(ret < 0){
printk("ds18b20_misc register failed !\n");
return -EINVAL;
}else {
printk("insmod ds18b20_misc! func:= %s\n", __func__);
}
return 0;
}
module_init(ds18b20_drv_init);
module_exit(ds18b20_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liufeng");
MODULE_DESCRIPTION("helpera133 ds18b20 Driver");
用户端代码
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define DS18B20 "/dev/ds18b20" // 你需要替换为实际的文件路径
int main() {
int fd = open(DS18B20, O_RDWR);
if (fd == -1) {
perror("open");
return 1; // 文件打开失败,程序退出
}
while (1) {
int temp = 0;
if (read(fd, &temp, sizeof(temp)) != sizeof(temp)) {
perror("read");
close(fd);
return 1; // 读取失败,程序退出
}
int a = (int)(temp * 0.65);
if (a > -551 && a < 1251) {
printf("<APP> temp: %d.%d C\n", a / 10, a % 10);
printf("----------------------------\n");
}
sleep(1); // 休眠一秒后再次读取温度
}
close(fd);
return 0;
}
读取温度结结果截图