adc与触摸屏调试记录
原理看了下面这张图就知道了
图中虚线表示屏被按压时x方向和y方向的电阻线会在按压的位置短接。
6410相比2440的触摸屏硬件接口没有变化,但中断系统有变化。
NOTE
When Touch Screen device is used, XM or YM is only connected to ground for Touch Screen I/F.
When Touch Screen device is not used, XM or YM is connecting Analog Input Signal for Normal ADC conversion
refer to
http://blog.chinaunix.net/uid-18921523-id-107097.html
************************************************
ok6410 linux2.6.36.2
adc 配置
Device Drivers --->Character devices ---><M> ADC driver for 6410
/drivers/char/adc.c
触摸屏配置
Device Drivers --->Input device support ---> [*] Touchscreens ---><*> S3C touchscreen driver
drivers/input/touchscreen/s3c-ts.c
飞凌提供的内核,ad和触摸屏不能共同使用,甚至将adc.c编译成模块,在insmod时都会出现
[root@FORLINX6410]# insmod /mnt/adc.ko
insmod: cannot insert '/mnt/adc.ko': Device or resource busy
经过排查发现是adc.c在注册中断时报的错
ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
原来在s3c-ts.c已经独自的注册了这个中断,
ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM, "s3c_action", ts);
加上中断号共享标志,如下,重新编译下载即可
ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM|IRQF_SHARED, "s3c_action", ts);
还有问题是ok6410的rmmod不管用,解决方法是建立目录/lib/modules/2.6.36.2
[root@FORLINX6410]# rmmod adc
rmmod: chdir(/lib/modules): No such file or directory
此时建立modules目录
[root@FORLINX6410]# cd /lib
[root@FORLINX6410]# mkdir modules
[root@FORLINX6410]# rmmod adc
rmmod: chdir(2.6.36.2): No such file or directory
此时建立2.6.36.2,即可卸载成功。使用modprobe -r adc卸载也可以。
[root@FORLINX6410]# cd modules/
[root@FORLINX6410]# mkdir 2.6.36.2
[root@FORLINX6410]# rmmod adc
rmmod: module 'adc' not found
使用ok6410的8个ai通道
首先把触摸屏驱动取消掉--在feiling给的2.6.36内核,需要在板子文件mach-smdk6410.c中注释掉两处触摸屏的部分,否则如果不把触摸屏搞进内核,编译不通过。
改动adc.c文件,init中注释掉ADCTSC = 0否则ai5和ai7不正常,加入ioctl函数。其他不必变。但是我把read函数也改了一下,去掉了sscanf和20自字节的str数组,直接将value拷给用户,为调用进程省了20字节的栈空间。
//adc8_driver.c #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/serio.h> #include <linux/delay.h> #include <linux/clk.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> #include <mach/map.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <plat/regs-timer.h> #include <plat/regs-adc.h> #define DEBUG #ifdef DEBUG #define DBG(...) printk(" DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); printk(__VA_ARGS__) #else #define DBG(...) #endif #define DEVICE_NAME "adc" static void __iomem *base_addr; typedef struct { wait_queue_head_t wait; int channel; int prescale; } ADC_DEV; #ifdef CONFIG_TOUCHSCREEN_X6410 extern int X6410_adc_acquire_io(void); extern void X6410_adc_release_io(void); #else static inline int X6410_adc_acquire_io(void) { return 0; } static inline void X6410_adc_release_io(void) { /* Nothing */ } #endif static int __ADC_locked = 0; static ADC_DEV adcdev; static volatile int ev_adc = 0; static int adc_data; static struct clk *adc_clock; #define __ADCREG(name) (*(volatile unsigned long *)(base_addr + name)) #define ADCCON __ADCREG(S3C_ADCCON) // ADC control #define ADCTSC __ADCREG(S3C_ADCTSC) // ADC touch screen control #define ADCDLY __ADCREG(S3C_ADCDLY) // ADC start or Interval Delay #define ADCDAT0 __ADCREG(S3C_ADCDAT0) // ADC conversion data 0 #define ADCDAT1 __ADCREG(S3C_ADCDAT1) // ADC conversion data 1 #define ADCUPDN __ADCREG(S3C_ADCUPDN) // Stylus Up/Down interrupt status #define PRESCALE_DIS (0 << 14) #define PRESCALE_EN (1 << 14) #define PRSCVL(x) ((x) << 6) #define ADC_INPUT(x) ((x) << 3) #define ADC_START (1 << 0) #define ADC_ENDCVT (1 << 15) #define START_ADC_AIN(ch, prescale) \ do { \ ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \ ADCCON |= ADC_START; \ } while (0) static irqreturn_t adcdone_int_handler(int irq, void *dev_id) { if (__ADC_locked) { adc_data = ADCDAT0 & 0x3ff; ev_adc = 1; wake_up_interruptible(&adcdev.wait); /* clear interrupt */ __raw_writel(0x0, base_addr + S3C_ADCCLRINT); } return IRQ_HANDLED; } static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) { int value; size_t len=sizeof(value); if (X6410_adc_acquire_io() == 0) { __ADC_locked = 1; START_ADC_AIN(adcdev.channel, adcdev.prescale); wait_event_interruptible(adcdev.wait, ev_adc); ev_adc = 0; DBG("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0); value = adc_data; __ADC_locked = 0; X6410_adc_release_io(); } else { value = -1; } if (count != len) { count=len; }; int r = copy_to_user(buffer, &value, len); DBG("len=%d,count=%d,r=%d\n",len,count,r); return r ? r : len;//if r=0,then return len } static int s3c2410_adc_open(struct inode *inode, struct file *filp) { init_waitqueue_head(&(adcdev.wait)); adcdev.channel=0; adcdev.prescale=0xff; DBG("adc opened\n"); return 0; } //static int s3c2410_adc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static long s3c2410_adc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { DBG("\n"); DBG("cmd=%d,arg=%lx\n", cmd, arg); switch (cmd) { case 0: adcdev.channel=arg; DBG("adcdev.channel= %x\n",adcdev.channel); break; defalut: DBG("case defalut\n"); return -EINVAL; break; } return 0; } static int s3c2410_adc_release(struct inode *inode, struct file *filp) { DBG("adc closed\n"); return 0; } static struct file_operations dev_fops = { owner: THIS_MODULE, open: s3c2410_adc_open, read: s3c2410_adc_read, unlocked_ioctl: s3c2410_adc_ioctl, release: s3c2410_adc_release, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; base_addr = ioremap(SAMSUNG_PA_ADC, 0x20); if (base_addr == NULL) { printk(KERN_ERR "Failed to remap register block\n"); return -ENOMEM; } adc_clock = clk_get(NULL, "adc"); if (!adc_clock) { printk(KERN_ERR "failed to get adc clock source\n"); return -ENOENT; } clk_enable(adc_clock); /* normal ADC */ //ADCTSC = 0; ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev); if (ret) { iounmap(base_addr); return ret; } printk (DEVICE_NAME"\therr\n"); ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit dev_exit(void) { free_irq(IRQ_ADC, &adcdev); iounmap(base_addr); if (adc_clock) { clk_disable(adc_clock); clk_put(adc_clock); adc_clock = NULL; } misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Forlinx Inc.");
//adc_app.c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <linux/fs.h> #include <errno.h> #define DEBUG #ifdef DEBUG #define DBG(...) fprintf(stderr, " DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); fprintf(stderr, __VA_ARGS__) #else #define DBG(...) #endif int main() { int fd,ret,i; int value[8]={0}; int len=sizeof(value[0]); fd = open("/dev/adc", 0); if (fd < 0) { exit(1); } //while(1){ //printf("\n"); for(i=0;i<8;i++) { ret = ioctl(fd,0,i);//cmd,arg(channel) if(ret < 0) { perror("ioctl ADC error"); exit(1); } int ret = read(fd, &value[i],len); if(ret==len) { printf("ADC %d Value: %d,len=%d\n", i,value[i],len); } } //} return 0; }专业一点的话,就使用_IOW()构造设置通道的命令。类型使用0xfe,貌似在documentation/ioctl-number.c中还没被占用。驱动重写为
//adc8_driver.c #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/serio.h> #include <linux/delay.h> #include <linux/clk.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> #include <mach/map.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <plat/regs-timer.h> #include <plat/regs-adc.h> #define DEBUG #ifdef DEBUG #define DBG(...) printk(" DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); printk(__VA_ARGS__) #else #define DBG(...) #endif #define DEVICE_NAME "adc" #define ADC8_IOC_MAGIC 0xfe //类型,0xfe代表adc8设备 #define ADC8_IOC_SELECT_CHANNEL _IOW(ADC8_IOC_MAGIC,0,int) //第0个命令是选择通道 static void __iomem *base_addr; typedef struct { wait_queue_head_t wait; int channel; int prescale; } ADC_DEV; #ifdef CONFIG_TOUCHSCREEN_X6410 extern int X6410_adc_acquire_io(void); extern void X6410_adc_release_io(void); #else static inline int X6410_adc_acquire_io(void) { return 0; } static inline void X6410_adc_release_io(void) { /* Nothing */ } #endif static int __ADC_locked = 0; static ADC_DEV adcdev; static volatile int ev_adc = 0; static int adc_data; static struct clk *adc_clock; #define __ADCREG(name) (*(volatile unsigned long *)(base_addr + name)) #define ADCCON __ADCREG(S3C_ADCCON) // ADC control #define ADCTSC __ADCREG(S3C_ADCTSC) // ADC touch screen control #define ADCDLY __ADCREG(S3C_ADCDLY) // ADC start or Interval Delay #define ADCDAT0 __ADCREG(S3C_ADCDAT0) // ADC conversion data 0 #define ADCDAT1 __ADCREG(S3C_ADCDAT1) // ADC conversion data 1 #define ADCUPDN __ADCREG(S3C_ADCUPDN) // Stylus Up/Down interrupt status #define PRESCALE_DIS (0 << 14) #define PRESCALE_EN (1 << 14) #define PRSCVL(x) ((x) << 6) #define ADC_INPUT(x) ((x) << 3) #define ADC_START (1 << 0) #define ADC_ENDCVT (1 << 15) #define START_ADC_AIN(ch, prescale) \ do { \ ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \ ADCCON |= ADC_START; \ } while (0) static irqreturn_t adcdone_int_handler(int irq, void *dev_id) { if (__ADC_locked) { adc_data = ADCDAT0 & 0x3ff; ev_adc = 1; wake_up_interruptible(&adcdev.wait); /* clear interrupt */ __raw_writel(0x0, base_addr + S3C_ADCCLRINT); } return IRQ_HANDLED; } static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) { int value; size_t len=sizeof(value); if (X6410_adc_acquire_io() == 0) { __ADC_locked = 1; START_ADC_AIN(adcdev.channel, adcdev.prescale); wait_event_interruptible(adcdev.wait, ev_adc); ev_adc = 0; DBG("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0); value = adc_data; __ADC_locked = 0; X6410_adc_release_io(); } else { value = -1; } if (count != len) { count=len; }; int r = copy_to_user(buffer, &value, len); DBG("len=%d,count=%d,r=%d\n",len,count,r); return r ? r : len;//if r=0,then return len } static int s3c2410_adc_open(struct inode *inode, struct file *filp) { init_waitqueue_head(&(adcdev.wait)); adcdev.channel=0; adcdev.prescale=0xff; DBG("adc opened\n"); return 0; } //static int s3c2410_adc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static long s3c2410_adc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { DBG("\n"); DBG("cmd=%d,arg=%lx\n", cmd, arg); DBG("ADC8_IOC_SELECT_CHANNEL=%d\n",ADC8_IOC_SELECT_CHANNEL); switch (cmd) { case ADC8_IOC_SELECT_CHANNEL: adcdev.channel=arg; DBG("adcdev.channel= %x\n",adcdev.channel); break; defalut: DBG("case defalut\n"); return -EINVAL; break; } return 0; } static int s3c2410_adc_release(struct inode *inode, struct file *filp) { DBG("adc closed\n"); return 0; } static struct file_operations dev_fops = { owner: THIS_MODULE, open: s3c2410_adc_open, read: s3c2410_adc_read, unlocked_ioctl: s3c2410_adc_ioctl, release: s3c2410_adc_release, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; base_addr = ioremap(SAMSUNG_PA_ADC, 0x20); if (base_addr == NULL) { printk(KERN_ERR "Failed to remap register block\n"); return -ENOMEM; } adc_clock = clk_get(NULL, "adc"); if (!adc_clock) { printk(KERN_ERR "failed to get adc clock source\n"); return -ENOENT; } clk_enable(adc_clock); /* normal ADC */ //ADCTSC = 0; ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev); if (ret) { iounmap(base_addr); return ret; } printk (DEVICE_NAME"\therr\n"); ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit dev_exit(void) { free_irq(IRQ_ADC, &adcdev); iounmap(base_addr); if (adc_clock) { clk_disable(adc_clock); clk_put(adc_clock); adc_clock = NULL; } misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Forlinx Inc.");用户中也使用_IOW()构造命令
//adc_app.c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <linux/fs.h> #include <errno.h> #define DEBUG #ifdef DEBUG #define DBG(...) fprintf(stderr, " DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); fprintf(stderr, __VA_ARGS__) #else #define DBG(...) #endif #define ADC8_IOC_MAGIC 0xfe #define ADC8_IOC_SELECT_CHANNEL _IOW(ADC8_IOC_MAGIC,0,int) int main() { int fd,ret,i; int value[8]={0}; int len=sizeof(value[0]); fd = open("/dev/adc", 0); if (fd < 0) { exit(1); } //while(1){ //printf("\n"); for(i=0;i<8;i++) { ret = ioctl(fd,ADC8_IOC_SELECT_CHANNEL,i);//cmd,arg DBG("ADC8_IOC_SELECT_CHANNEL=%d\n",ADC8_IOC_SELECT_CHANNEL); if(ret < 0) { perror("ioctl ADC error"); exit(1); } int ret = read(fd, &value[i],len); if(ret==len) { printf("ADC %d Value: %d,len=%d\n", i,value[i],len); } } //} return 0; }执行
[root@FORLINX6410]# /mnt/adc_app DBG(drivers/char/adc.c, s3c2410_adc_open(), 140): adc opened DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 0 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[0] = 0x030d, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=1 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[1] = 0x0129, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=2 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 2 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[2] = 0x00b9, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=3 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 3 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[3] = 0x00a9, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=4 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 4 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[4] = 0x0081, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=5 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 5 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[5] = 0x0131, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=6 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 6 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[6] = 0x0090, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=7 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 7 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[7] = 0x0121, 1 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0 DBG(drivers/char/adc.c, s3c2410_adc_release(), 164): adc closed DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 0 Value: 781,len=4 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 1 Value: 297,len=4 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 2 Value: 185,len=4 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 3 Value: 169,len=4 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 4 Value: 129,len=4 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 5 Value: 305,len=4 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 6 Value: 144,len=4 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992 ADC 7 Value: 289,len=4
多说一点,6410的adc分辨率是10位或者12位的,可以通过ADCCON.16来配置
RESSEL [16]
A/D converter resolution selection
0 = 10-bit A/D conversion
1 = 12-bit A/D conversion
不同分辨率时,结果数据在ADCDAT0占用的位数不一样。10位分辨率时用到10位,12位分辨率时用到12位。上面程序用的是10位分辨率。
XPDATA_12[11:10] When A/D resolution is 12bit, this is X-position conversion data [11:0] value.
XPDATA(Normal ADC)[9:0] X-Position Conversion data value (Includes Normal ADC Conversion data value) Data value : 0x0 ~ 0x3FF
电压和测量数据对应关系:
10位分辨率时:0-3.3------>0-1023
12位分辨率时:0-3.3------>0-4095
关于分辨率和精度的区别:
http://bbs.ednchina.com/BLOG_ARTICLE_2058763.HTM
简单点说,“精度”是用来描述物理量的准确程度的,而“分辨率”是用来描述刻度划分的。从定义上看,这两个量应该是风马牛不相及的。(是不是有朋友感到愕然^_^)。很多卖传感器的JS就是利用这一点来糊弄人的了。简单做个比喻:有这么一把常见的塑料尺(中学生用的那种),它的量程是10厘米,上面有100个刻度,最小能读出1毫米的有效值。那么我们就说这把尺子的分辨率是1毫米,或者量程的1%;而它的实际精度就不得而知了(算是0.1毫米吧)。当我们用火来烤一下它,并且把它拉长一段,然后再考察一下它。我们不难发现,它还有有100个刻度,它的“分辨率”还是1毫米,跟原来一样!然而,您还会认为它的精度还是原来的0.1毫米么?(这个例子是引用网上的,个人觉得比喻的很形象!)
回到电子技术上,我们考察一个常用的数字温度传感器:AD7416。供应商只是大肆宣扬它有10位的AD,分辨率是1/1024。那么,很多人就会这么欣喜:哇塞,如果测量温度0-100摄氏度,100/1024……约等于0.098摄氏度!这么高的精度,足够用了。但是我们去浏览一下AD7416的数据手册,居然发现里面赫然写着:测量精度0.25摄氏度!所以说分辨率跟精度完全是两回事,在这个温度传感器里,只要你愿意,你甚至可以用一个14位的AD,获得1/16384的分辨率,但是测量值的精度还是0.25摄氏度^_^
所以很多朋友一谈到精度,马上就和分辨率联系起来了,包括有些项目负责人,只会在那里说:这个系统精度要求很高啊,你们AD的位数至少要多少多少啊……
其实,仔细浏览一下AD的数据手册,会发现跟精度有关的有两个很重要的指标:DNL和INL。似乎知道这两个指标的朋友并不多,所以在这里很有必要解释一下。
DNL:Differencial NonLiner——微分非线性度
INL:Interger NonLiner——积分非线性度(精度主要用这个值来表示)
他表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。也就是,输出数值偏离线性最大的距离。单位是LSB(即最低位所表示的量)。
当然,像有的AD如△—∑系列的AD,也用Linearity error 来表示精度。
为什么有的AD很贵,就是因为INL很低。分辨率同为12bit的两个ADC,一个INL=±3LSB,而一个做到了±1.5LSB,那么他们的价格可能相差一倍。
所以在这里帮大家把这两个概念理一下,以后大家就可以理直气壮的说精度和分辨率了,而不是将精度理解为分辨率。呵呵,希望对大家有用!
分辨率计算:测量电压范围/(2^AD位数-1);
************************************************
sprintf函数,int-->str
//test.c #include <stdio.h> int main() { char str[2]; int value=0x5678; int i; char *cc; sprintf(str, "%x", value); cc=(char*)&value; printf("value[0]=%x\n",*cc); cc++; printf("value[1]=%x\n",*cc); cc++; printf("value[2]=%x\n",*cc); cc++; printf("value[3]=%x\n",*cc); printf("str=%s\n",str); for( i=0 ;i<7;i++) { printf("str[%d]=%c\n",i,str[i]); } return 0; }
root@song-virtual-machine:test# ./test value[0]=78 value[1]=56 value[2]=0 value[3]=0 str=5678 str[0]=5 str[1]=6 str[2]=7 str[3]=8 str[4]= str[5]= str[6]=如果line9 是 sprintf(str, "%d", value);
即将value按照10进制数,每位数字依次塞进str。
root@song-virtual-machine:test# ./test value[0]=78 value[1]=56 value[2]=0 value[3]=0 str=22136 str[0]=2 str[1]=2 str[2]=1 str[3]=3 str[4]=6 str[5]= str[6]=************************************************
sscanf函数,str-->int
#include <stdio.h> int main() { char str[20]="56"; int value; sscanf(str, "%d", &value); printf("value: %d\n",value); sscanf(str, "%x", &value); printf("value: %d\n",value); return 0; }
root@song-virtual-machine:test# ./test value: 56 value: 86