tiny 6410 ds18b20 温度传感器采集数据偶尔出错误
硬件 tiny 6410 ds18b20 传感器
系统:linux 2.3.68
问题:读取的数据有时候会产生错误,例如突然变成0度 或者1000度 然后在恢复。
驱动代码。
- C/C++ code
驱动代码/* * Temperature sensor driver for zc6410 * register list: * DQ:EINT8(GPN8) * GPNCON:0x7F008830 * GPNDAT:0x7F008834 * GPNPUD:0x7F008838 * * register contorl: * GPN8[17:16] 00=input 01=output 10=Ext.interrupt[8] 11=reserved * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/cdev.h>#include <linux/miscdevice.h>#include <linux/ioctl.h>#include <linux/io.h>#include <linux/ioport.h>#include <asm/uaccess.h>//#include <regs-gpio.h>//#include <mach/hardware.h>#define DEBUG_18B20 0#define DEVICE_NAME "ds18b20"#define DSDATA 0x7F008830#define DATAOUTP 1#define DATAINP 0#define DS18B20_MAGIC 'k'#define DS18B20_RESET _IO(DS18B20_MAGIC, 0)static void *pVmem = NULL;#define s3c6410_gpio_cfgpin(pin, state) \ (state?({unsigned int vmem; vmem = ioread32(pin); vmem &= ~(3<<16); vmem |= 1<<16; iowrite32(vmem, pin);}):({unsigned int vmem; vmem = ioread32(pin); vmem &= ~(3<<16); iowrite32(vmem, pin);}))#define s3c6410_gpio_setpin(pin, state) \ (state?({unsigned int vmem; vmem = ioread32(pin+4); vmem |= (1<<8); iowrite32(vmem, pin+4);}):({unsigned int vmem; vmem = ioread32(pin+4); vmem &= ~(1<<8); iowrite32(vmem, pin+4);}))#define s3c6410_gpio_getpin(pin) ((ioread32(pin+4)>>8) & 1)static ssize_t ds18b20_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ volatile int i, size=count; unsigned char ddat = 0; if (size > 2) size = 1; for (i=0; i<8; i++) { ddat >>= 1; s3c6410_gpio_cfgpin(pVmem, DATAOUTP); s3c6410_gpio_setpin(pVmem, 0); udelay(4); //4us s3c6410_gpio_setpin(pVmem, 1); s3c6410_gpio_cfgpin(pVmem, DATAINP); if ( s3c6410_gpio_getpin(pVmem) ) { ddat |= 0x80; } udelay(80); // >70us s3c6410_gpio_cfgpin(pVmem, DATAOUTP); s3c6410_gpio_setpin(pVmem, 1); udelay(3); // >1us } s3c6410_gpio_cfgpin(pVmem, DATAINP); if(copy_to_user(buff, &ddat, size)) { return -1; } return size;}static ssize_t ds18b20_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){ volatile int i, size=count; char ddat=0; if (size > 2) size = 1; if (copy_from_user(&ddat, buff, size)) { printk("write data error\n"); return -1; } s3c6410_gpio_cfgpin(pVmem, DATAOUTP); for (i=0; i<8; i++) { s3c6410_gpio_setpin(pVmem, 0); udelay(5); //5us if (ddat & 0x01) { s3c6410_gpio_setpin(pVmem, 1); } udelay(80); // >70us s3c6410_gpio_setpin(pVmem, 1); udelay(3); // >1us ddat >>= 1; } s3c6410_gpio_cfgpin(pVmem, DATAINP); return size;}static int ds18b20_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int ret = 0; switch(cmd) { //case DS18B20_RESET: // reset case 0: // reset s3c6410_gpio_cfgpin(pVmem, DATAOUTP); s3c6410_gpio_setpin(pVmem, 1); udelay(27); s3c6410_gpio_setpin(pVmem, 0); udelay(500); // 500us s3c6410_gpio_setpin(pVmem, 1); udelay(27); s3c6410_gpio_cfgpin(pVmem, DATAINP); udelay(60); ret = s3c6410_gpio_getpin(pVmem); msleep(3); default: return -EINVAL; } return ret;}static int ds18b20_open(struct inode *inode, struct file *file){ /* GPN8[17:16] = 00 */ s3c6410_gpio_cfgpin(pVmem, DATAINP); #if DEBUG_18B20 printk("context of 0x%x is 0x%x\n", DSDATA, ioread32(pVmem));#endif return 0;}static int ds18b20_release(struct inode *inode, struct file *file){ return 0;}static struct file_operations ds18b20_fops = { .owner = THIS_MODULE, .open = ds18b20_open, .release = ds18b20_release, .unlocked_ioctl = ds18b20_ioctl, .read = ds18b20_read, .write = ds18b20_write, //.compat_ioctl = ds18b20_ioctl,};static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &ds18b20_fops,};// register ds18b20static int __init dev_init(void){ int ret; ret = misc_register(&misc); if(!request_mem_region(DSDATA, 0x8, DEVICE_NAME)) goto error; pVmem = ioremap(DSDATA, 0x8); printk(DEVICE_NAME"\tinitialized\n"); return ret;error: misc_deregister(&misc); return -EFAULT; /* bad address */}// unregister ds18b20static void __exit dev_exit(void){ iounmap(pVmem); release_mem_region(DSDATA, 0x8); misc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("modified by __eabi");
测试代码!!
- C/C++ code
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#include <error.h>#include <time.h>#include <fcntl.h>#define DS18B20_MAGIC 'k'#define DS18B20_RESET _IO(DS18B20_MAGIC, 0)static int fd=0;static unsigned char a=0;static unsigned char b=0;/*****读取温度*****/static unsigned int ReadTemperature(void){ unsigned int t=0; ioctl(fd, DS18B20_RESET, 0); //初始化 a = 0xcc; write(fd, &a, 1); //跳过读序号列号的操作 a = 0x44; write(fd, &a, 1); //启动温度转换 sleep(1); ioctl(fd, DS18B20_RESET, 0); //初始化 a = 0xcc; write(fd, &a, 1); //跳过读序号列号的操作 a = 0xbe; write(fd, &a, 1); //读取温度寄存器 read(fd, &a, 1); //读低8位 read(fd, &b, 1); //读高8位 t = b; t <<= 8; t = t | a; usleep(5000); return t;}int main(int argc, char **argv){ int val; float fval; fd = open("/dev/ds18b20", O_RDWR); if (fd < 0) { perror("open device ds18b20!"); return -1; } while(1) { val = ReadTemperature(); val <<= 16; val >>= 16; // 扩展符号位 printf("Temperature is "); if (val < 0) { printf("-"); val = -val; } fval = val >> 4; // 整数 fval += (val & 0x000F) * 0.0625; // 小数 printf("%f \n",fval); sleep(1); } close(fd); return 0;}
[解决办法]
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
float change_to_temperature(char *temperature);
int main(int argc, char *argv[])
{
int fd;
int i = 10;
char temperature[2];
if((fd = open("/dev/18b20_driver", O_RDONLY)) < 0)
printf("open 18b20_driver file error!\n");
while(i--){
read(fd,temperature ,sizeof(temperature));
printf("temperature is: %f\n",change_to_temperature(temperature));
sleep(1);
}
return 0;
}
float change_to_temperature(char *temperature)
{
int tmp = 0;
tmp = (int)temperature[1] << 8;
tmp |= temperature[0];
return tmp * 0.0625;
}