首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 驱动开发 >

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

2013-03-26 
在S3C2440内核为2.6.24上写18B20驱动温度总是随机的最近在用18B20想测温度,但是纠结了好多天,温度总是0,8,

在S3C2440内核为2.6.24上写18B20驱动温度总是随机的
    最近在用18B20想测温度,但是纠结了好多天,温度总是0,8,16,2000多这样乱跳,大多还是0,时序我也是按照18B20手册的,但是还是不对。还有一个不懂的是释放总线这个概念,有些地方说是直接给总线置1,有些是把IO改为输入模式,我试了下用置1的方法不成功。    下面是我的代码:::


#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 0

static 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 node

static 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;
}



[解决办法]
没用过18B20,释放总线就是把IO口设为不要上下拉,然后设为输入,这样就可以了。看看你硬件有没有问题。

热点排行