DS18B20的驱动代码无法读取数据

问题遇到的现象和发生背景

开发板是s5p6818的,编写arm-liunx的驱动代码,但是运行以后无法读取数据

问题相关代码,请勿粘贴截图
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>   /*杂项字符设备头文件*/
#include <linux/fs.h>           /*文件操作集合*/
#include  <linux/delay.h>       /*延时函数*/

#include <linux/uaccess.h>
#include <asm/io.h>

#include <asm/irq.h>
#include <linux/mm.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include<linux/timer.h>
#include<linux/jiffies.h>
#include <linux/ioport.h>

/*DS18B20 GPIO接口:GPIOA30*/

/*定义指针,用于接收虚拟地址*/
/*volatile unsigned int *DS18B20_GPIOAOUTENB;//*DS18B20_GPACON;//设置ds18b20为1输出/0输入模式
volatile unsigned int *DS18B20_GPIOAOUT;//*DS18B20_GPADAT;//寄存器对应的地址0xC001_A000,输出高低电平
volatile unsigned int *DS18B20_GPIOAPAD;//--------------------------------------------------------------
#define DS18B20_INPUT() {*DS18B20_GPIOAOUTENB &= ~(1<<30);}
#define DS18B20_OUTPUT() {*DS18B20_GPIOAOUTENB |= (1 << 30);}*/

volatile unsigned int *DS18B20_GPIODOUTENB;//*DS18B20_GPACON;//设置ds18b20为1输出/0输入模式
volatile unsigned int *DS18B20_GPIODOUT;//*DS18B20_GPADAT;//寄存器对应的地址0xC001_A000,输出高低电平
volatile unsigned int *DS18B20_GPIODPAD;//--------------------------------------------------------------
#define DS18B20_INPUT() {*DS18B20_GPIODOUTENB &= ~(1<<0);}
#define DS18B20_OUTPUT() {*DS18B20_GPIODOUTENB |= (1 << 0);}

/*
函数功能:等待DS18B20的回应
返回1:未检测到DS18B20的存在
返回0:存在
*/
unsigned char DS18B20_Check(void)
{
    unsigned char retry=0;//u8
    DS18B20_INPUT();
    while((*DS18B20_GPIODPAD & (1<<0))&& retry<200)//----------------------------------------
    {
        retry++;
        udelay(1);
    };
    if(retry>=200) return 1;
    else retry=0;
    while(!(*DS18B20_GPIODPAD &(1 << 0))&&retry<240)//----------------------------------------
    {
        retry ++;
        udelay(1);
    };
    if(retry>=240) 
        return 1;
    return 0;
    //else
        //return 1;
}

/*写一个复位函数*/
unsigned char DS18B20_reset(void)
{

    DS18B20_OUTPUT();

    *DS18B20_GPIODOUT |= (1 << 0);
    udelay(1);
    *DS18B20_GPIODOUT &= ~(1 << 0);
    udelay(750);
    
    *DS18B20_GPIODOUT |= (1 << 0);
    udelay(30);
    
    
    DS18B20_INPUT();
    
    while((*DS18B20_GPIODPAD & (1<<0)));
    udelay(480);
    
    *DS18B20_GPIODOUT |= (1 << 0);
}



/*
从DS18B20读取一个位
返回值:1/0
*/
unsigned char DS18B20_Read_Bit(void)
{
    unsigned char data;
    DS18B20_OUTPUT();
    *DS18B20_GPIODOUT |= (1 << 0);//
    udelay(2);
    *DS18B20_GPIODOUT &= ~(1 << 0);//out 0;//--------------------------
    udelay(3);
    *DS18B20_GPIODOUT |= (1 << 0);//out 1;//-----------------------
    udelay(5);
    DS18B20_INPUT();
    
    
    if((*DS18B20_GPIODPAD & (1 << 0))) data=1;
    else data=0;
    udelay(50);
    *DS18B20_GPIODOUT |= (1 << 0);
    printk(KERN_INFO "我读到啦%d\r\n",data);
    udelay(1);
    return data;
}

/*
从DS18B20读取一个字节
返回值:读到的数据
*/
unsigned char DS18B20_Read_Byte(void)
{
    //local_irq_disable();
    unsigned char i,j,dat;
    dat=0;
    for(i=1;i<=8;i++)
    {
        j=DS18B20_Read_Bit();
        dat=dat>>1;
        if(j)    //主机对总线采样的数 判断-------读数据-1就是1,否则就是0
            dat |= 0x80;    //先收低位数据--一步一步向低位移动>>
    }
    //local_irq_enable();
    return dat;
}

/*
写一个字节到DS18B20
dat:要写入的字节
*/
void DS18B20_Write_Byte(unsigned char dat)
{
    unsigned char j;
    unsigned char testb;
    DS18B20_OUTPUT();
    //DS18B20_INPUT();
    for(j=1;j<=8;j++)
    {
        
        udelay(1);//
        testb= dat&0x01;
        dat=dat>>1;
    
        if(testb)
          { 
            DS18B20_OUTPUT();
            *DS18B20_GPIODOUT &= ~(0x1<<0);//----------------------------拉低
              udelay(2);
   
            *DS18B20_GPIODOUT |= (0x1 << 0);//out 1//------------------------拉高 
            udelay(60);
  
            DS18B20_INPUT();
            if((*DS18B20_GPIODPAD & (1 << 0)))
                printk(KERN_INFO "yi我write 1啦\r\n");
   
        }
        else
        {
            DS18B20_OUTPUT();
            *DS18B20_GPIODOUT &= ~(1<<0);//---------------------------拉低
            udelay(60);

            DS18B20_INPUT();
            if(!(*DS18B20_GPIODPAD & (1 << 0)))
                    printk(KERN_INFO "ling我write 0啦\r\n");

            DS18B20_OUTPUT();
            *DS18B20_GPIODOUT |= (1 << 0);//out 1---------------------拉高
            udelay(2);
        }
    }
}

/*
从ds18b20得到温度值
精度:0.1C
返回值:温度值 (-550~1250) 
*/
short DS18B20_Get_Temp(void)
{
    unsigned short aaa;
    //unsigned char temp=1;
    unsigned char LT,HT;
    unsigned char result[2]={};
    local_irq_disable();

    unsigned int temp=1;
    temp=DS18B20_reset();
    if(!temp)
    {
        printk(KERN_INFO "我复位啦\r\n");
    }


    DS18B20_Write_Byte(0xcc);//进入接收模式

    DS18B20_Write_Byte(0x44);//执行温度测量和AD转换
    
    
    DS18B20_reset();


    DS18B20_Write_Byte(0xcc);//skip rom
    DS18B20_Write_Byte(0xbe);//convert

    LT=DS18B20_Read_Byte();//LSB
    HT=DS18B20_Read_Byte();//MSB
    
    local_irq_enable();
    aaa=(((unsigned short)HT<<8)|LT);    

//----------------------------------------
    printk(KERN_INFO "读取温度值%d%d\n",HT,LT);
    return aaa;
}

/*
杂项字符设备注册示例----->DS18B20
*/
static int s5p6818_open(struct inode *my_inode,struct file *my_file)
{
    /*映射物理地址*/
    /*DS18B20_GPIOAOUTENB=ioremap(0xC001A004,4);
    DS18B20_GPIOAOUT=ioremap(0xC001A000,4);
    DS18B20_GPIOAPAD=ioremap(0xC001A018,4);*///-------------------------------------------------

    DS18B20_GPIODOUTENB=ioremap(0xC001D004,4);
    DS18B20_GPIODOUT=ioremap(0xC001D000,4);
    DS18B20_GPIODPAD=ioremap(0xC001D018,4);

    printk(KERN_INFO "DS18B20初始化成功!\r\n");
    
    /*设置ds18b20为输出模式*/
    //*DS18B20_GPIOAOUTENB &= ~(1 << 30);
    //*DS18B20_GPIOAOUTENB |= (1 << 30);
    *DS18B20_GPIODOUTENB |= (1 << 0);
    return 0;
}

static int s5p6818_release(struct inode *mynode,struct file *my_file)
{
    /*释放虚拟地址*/
    /*iounmap(DS18B20_GPIOAOUTENB);
    iounmap(DS18B20_GPIOAOUT);
    iounmap(DS18B20_GPIOAPAD);*///---------------------------------------------------------------
    
    iounmap(DS18B20_GPIODOUTENB);
    iounmap(DS18B20_GPIODOUT);
    iounmap(DS18B20_GPIODPAD);
    printk(KERN_INFO "DS18B20释放成功\r\n");
    return 0;
}

static ssize_t s5p6818_read(struct file *my_file,char __user *buf, size_t len, loff_t *loff)
{
    /*读取温度信息*/
    short temp = DS18B20_Get_Temp();
    copy_to_user(buf,&temp,2);//拷贝温度至应用层
    return 0;
}

static ssize_t s5p6818_write(struct file *my_file,const char __user *buf, size_t len, loff_t *loff)
{
    return 0;
}

/*文件操作集合*/
static struct file_operations s5p6818_fops=
{
    .open=s5p6818_open,
    .read=s5p6818_read,
    .write=s5p6818_write,
    .release=s5p6818_release
};

/*
核心结构体
*/
static struct miscdevice s5p6818_misc=
{
    .minor=8,  /*自动分配次设备号*/
    .name="DS18B20",              /*设备文件,指定/dev/生成的文件名称*/
    .fops=&s5p6818_fops
};

static int __init DS18B20_dev_init(void)
{
    printk(KERN_INFO "--> ds18b20 register\n");
    int ret; 
    /*杂项设备注册*/
    ret = misc_register(&s5p6818_misc);
    if(ret)
        printk(KERN_INFO "misc register failed\n");
    else
        printk(KERN_INFO "misc register success\n");

    return 0;
}

static void __exit DS18B20_dev_exit(void)
{
    /*杂项设备注销*/
    misc_deregister(&s5p6818_misc);
}

module_init(DS18B20_dev_init);
module_exit(DS18B20_dev_exit);
MODULE_LICENSE("GPL");
运行结果及报错内容

img

我的解答思路和尝试过的方法

快两个星期试了各种办法都不行,如果是时序错误,我也按照数据手册写了,怎么会不行呢。好奇怪啊

我想要达到的结果

能够正确读取温度

无法读取数据的报错是社么啊

可能是 udelay 函数用的不对。这个函数等待延时的参数是微秒,ds18b20需要的延时应该是毫秒。
你可以用示波器测试一下看看波形

你好请问你解决了嘛 我也需要用到sp56818接ds18b20 弄了好几天没进展