当前位置: 代码迷 >> 驱动开发 >> 在S3C2440内核为2.6.24下写18B20驱动温度总是随机的
  详细解决方案

在S3C2440内核为2.6.24下写18B20驱动温度总是随机的

热度:29   发布时间:2016-04-28 10:45:03.0
在S3C2440内核为2.6.24上写18B20驱动温度总是随机的
最近在用18B20想测温度,但是纠结了好多天,温度总是0,8,16,2000多这样乱跳,大多还是0,时序我也是按照18B20手册的,但是还是不对。还有一个不懂的是释放总线这个概念,有些地方说是直接给总线置1,有些是把IO改为输入模式,我试了下用置1的方法不成功。 下面是我的代码:::
C/C++ code
#include <linux/miscdevice.h>#include <linux/delay.h>#include <asm/irq.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/errno.h>#include<linux/init.h>#include<linux/kernel.h>#include<linux/module.h>#include<linux/fs.h>#include<asm/uaccess.h>#include<asm/io.h>#include<linux/device.h>#include<asm/gpio.h>#include<linux/poll.h>#include<linux/interrupt.h>#include<linux/irq.h>#include<linux/time.h>#include<linux/delay.h>#include<asm/hardware.h>#include <asm-arm/arch-s3c2410/regs-gpio.h>MODULE_LICENSE("GPL");#define DEVICE_NAME "18B20-drv"#define GPJCON (unsigned long)(0x560000D0)#define GPJDAT (unsigned long)(0x560000D4)#define GPJUP  (unsigned long) (0x560000D8)typedef  char BYTE;static volatile unsigned long* _io_gpjcon;static volatile unsigned long* _io_gpjdat;static volatile unsigned long* _io_gpjup;static BYTE data[2];//store 18B20rature 1 and 0static int major=0;static int minor=0;static int temp_open(struct inode *, struct file *);static int temp_release(struct inode *, struct file *);static ssize_t temp_read(struct file *, char *, size_t, loff_t *);//static ssize_t temp_write(struct file *, const char *, size_t, loff_t *);//static int temp_ioctl(struct inode *, struct file *, unsigned int cmd, unsigned long arg);void DQ_OUTP(void);void DQ_INTP(void);void set_DQ(unsigned int);unsigned long get_DQ(void);int DQ_reset(void);unsigned char DQ_RBYTE(void);int DQ_PRO(void);static struct file_operations fops = {    .owner = THIS_MODULE,    .open = temp_open,    .release = temp_release,    .read = temp_read,//    .write = temp_write,    //.ioctl = temp_ioctl,};static struct class *dev_class;//use this to create device nodestatic int temp_init(void){    major = register_chrdev(0,DEVICE_NAME,&fops);    if(major < 0)    {        printk("register %s error\n",DEVICE_NAME);        return 1;    }        printk("DEV Number:%d,%d\n",major,minor);    dev_class = class_create(THIS_MODULE,DEVICE_NAME);    if(dev_class == NULL)    {        printk("18B20 node create error\n");        printk("TODO:mknod /dev/%s c %d %d\n",DEVICE_NAME,major,minor);    }    else    {        device_create(dev_class,NULL,MKDEV(major,minor),"%s%d",DEVICE_NAME,minor);        printk("/dev/%s%d register sucess\n",DEVICE_NAME,minor);    }        return 0;}static void temp_exit(void){    if(dev_class)    {        device_destroy(dev_class,MKDEV(major,minor));        class_destroy(dev_class);    }    unregister_chrdev(major,DEVICE_NAME);}static int temp_open(struct inode * pnode, struct file * pfile){    _io_gpjcon = (unsigned long*)ioremap(GPJCON,4);    _io_gpjdat = (unsigned long*)ioremap(GPJDAT,4);    _io_gpjup  = (unsigned long*)ioremap(GPJUP,4);    printk("18b20 open\n");        return 0;}static int temp_release(struct inode *pnode, struct file *pfile){    printk("18b20 release\n");    return 0;}module_init(temp_init);module_exit(temp_exit);////////////////////////////registerover/////////////////////////////////void DQ_OUTP()//GPJCON为输出模式{    unsigned long temp;    temp = *(unsigned long*)_io_gpjcon;    temp &=(~0x3);    temp |= 0x1;    *(unsigned long*)_io_gpjcon = temp;}void DQ_INTP()//GPJCON为输入状态{    unsigned long temp;    temp = *(unsigned long*)_io_gpjcon;    temp &=(~0x3);    *(unsigned long*)_io_gpjcon = temp;}void set_DQ(unsigned int flag)//设置GPJ0的高低电平{    unsigned long temp;    temp = *(unsigned long*)_io_gpjdat;    temp &= ~0x1;    if(flag&0x1)    temp |= 0x1;        *(unsigned long*)_io_gpjdat = temp;}unsigned long get_DQ()//获得当前18B20的DQ状态{    unsigned long temp;    temp = *(unsigned long*)_io_gpjdat;    temp &=0x01;    return temp;}/*         复位流程:                1.总线先置为高电平                2.拉低至少480us                3再拉高15-60us                4检测是否18B20产生复位电平,复位点评存在 60-240us*/int DQ_reset(void){        //unsigned long temp;    DQ_OUTP();        set_DQ(1);        udelay(1);        set_DQ(0);        udelay(600);        //set_DQ(1);//这里释放总线如果用置1,则复位不成功,但是改为输入口,则可以    DQ_INTP();    udelay(65);        if(get_DQ()==0)    {        printk("reset sucessfully\n");        DQ_OUTP();        set_DQ(1);        return 0;    }    else    {        DQ_OUTP();        set_DQ(1);         return 1;     }}/*    18b20写ROM指令:                    1.GPJ0为输出状态,并拉低电平                    2.向总线写入相应的位,并延时1us                    3.在接下来的15~60us内,18B20对总线采样。                    若是高电平,则写入1,并将电平拉高                    若是低电平,则继续保持低电平。  直到60us结束                    4,拉高电平,并延时至少1us    */void DQ_WBYTE(unsigned long flag){    int i;    int d;     DQ_OUTP();    printk("%x\n",flag);    for(i=0;i<8;i++)    {        set_DQ(0);        udelay(2);        if(flag & 1)        {            set_DQ(1);            udelay(60);/////        }        else        {            udelay(60);            set_DQ(1);/////        }                flag>>=1;        udelay(1);    }}/*    读一个bit的程序:                    1.GPJ0为输入模式                    2.拉低总线1us,然后释放总线                    3.在接下去的14us内读数据,若为1,则拉高总线                    若为低电平则保持低电平到周期结束                    4.延时60~120us,拉高总线*/unsigned char DQ_RBYTE(){    int i;    unsigned char data=0;    for(i = 0;i<8;i++)    {        data>>=1;        DQ_OUTP();        set_DQ(0);        udelay(2);                DQ_INTP();        if(get_DQ())        data|=0x80;        udelay(60);                 set_DQ(1);///change by zjc         udelay(2);    }    return data;}/*    温度转换进程:                1.复位                2.写ROM指令                3.写RAM指令                4.读温度*/int DQ_PRO(){    if(DQ_reset())    return 1;        DQ_WBYTE(0xcc);    DQ_WBYTE(0x44);        mdelay(500);        if(DQ_reset())    return 1;    DQ_WBYTE(0xcc);    DQ_WBYTE(0xbe);        data[0] = DQ_RBYTE();    data[1] = DQ_RBYTE();    DQ_reset();        return 0;}static ssize_t temp_read(struct file *pfile, char *buff, size_t len, loff_t *ploff){        if(DQ_PRO())    printk("reset failed\n");    buff[0] = data[0];//这里我想把温度直接通过buff穿回去,可以吗,还是必须要用copy_to_user();    buff[1] = data[1];//    printk("%x %x\n",buff[0],buff[1]);    return 0;}
  相关解决方案