原理看了下面这张图就知道了
图中虚线表示屏被按压时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