硬件介绍:荔枝派nano(f1c100s)
软件介绍:嵌入式Linux开发
一、基本情况介绍
1、电池
电池用的是锂电池,满电4.2v,放电截止电压2.75v;
2、F1C100s KEYADC
下图是官方手册对于KEYADC的介绍,可以看到:
F1C100s KEYADC的检测电压范围在0-2V之间(全志其他芯片可能不一样);
6bit分辨率,也就是2V电压对应模拟量值为63,0V电压对应模拟量值为0;
3、分压电阻选择
关于检测电路我参考了这篇文章;
对于R22,这里选择了330K,因为最好可以通过控制分压电阻来决定分压后的电压范围刚好与KEYADC的检测范围一致,这样有利于后面程序的编写;
可以计算一下:
当电池满电4.2V时,LRADC电压 = (4.2V * R21) / (R21 + R22) = 1260 / 630 = 2V
当电池达到放电限压2.75V时,LRADC电压 = (2.75V * R21) / (R21 + R22) = 1110 / 630 = 1.3V
二、驱动程序编写
下图是KEYADC相关寄存器;
程序大体思路:
1、设置KEYADC_CTRL_REG寄存器;
2、读取KEYADC_DATA_REG寄存器;
因为使用的轮询读取,程序并不复杂,简单粗暴!
部分关键程序如下:
#include <linux/err.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/of.h>
/* 相关寄存器宏 */
#define LRADC_BASE 0x01C23400
#define LRADC_CTRL 0x00
#define LRADC_INTC 0x04
#define LRADC_INTS 0x08
#define LRADC_DATA0 0x0c
/* LRADC_CTRL bits */
#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */
#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */
#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */
#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */
#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */
#define HOLD_EN(x) ((x) << 6)
#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */
#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */
#define ENABLE(x) ((x) << 0)
static volatile unsigned int *KEYADC_CTRL_REG;
static volatile unsigned int *KEYADC_DATA_REG;
//在驱动程序的read函数里读取KEYADC_DATA_REG寄存器
static ssize_t adc_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
int err;
unsigned int tmpValue, voltage;
//3、读取KEYADC_DATA_REG寄存器
tmpValue = (*KEYADC_DATA_REG) & 0x3f;
voltage = tmpValue * 2000000 / 63; //把读到寄存器的值换算成mV,2000000/63是分辨率
err = copy_to_user(buf, &voltage, 4); //把换算后的值返回到应用程序
return 0;
}
//在驱动程序的open函数里内存映射、设置寄存器
static int adc_drv_open (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
//1、内存映射
KEYADC_CTRL_REG = ioremap(LRADC_BASE + LRADC_CTRL, 4);
KEYADC_DATA_REG = ioremap(LRADC_BASE + LRADC_DATA0, 4);
if(KEYADC_CTRL_REG == NULL)
printk("KEYADC_CTRL_REG is NULL\n");
if(KEYADC_DATA_REG == NULL)
printk("KEYADC_DATA_REG is NULL\n");
//2、设置KEYADC_CTRL_REG寄存器,这些设置是参考的官方的KEYADC驱动
writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(2) | HOLD_EN(1) |
SAMPLE_RATE(0) | ENABLE(1), KEYADC_CTRL_REG);
return 0;
}
三、测试
我是在Qt里写的测试程序,关键部分如下:
注意:这里电量显示为86%,和上面应用程序中举的例子没有关系。
四、总结
1、程序写完后,要使用正确的方法来测试,因为KEYADC检测的电压范围就是0-2V,只要超过2V,读出来的值都是63;
2、欢迎纠错点评!