OS版本:RT-Thread 4.0.0

芯片:STM32F407

下面时官方ADC提供的参考访问接口

访问 ADC 设备

应用程序通过 RT-Thread 提供的 ADC 设备管理接口来访问 ADC 硬件,相关接口如下所示:

函数 描述
rt_device_find() 根据 ADC 设备名称查找设备获取设备句柄
rt_adc_enable() 使能 ADC 设备
rt_adc_read() 读取 ADC 设备数据
rt_adc_disable() 关闭 ADC 设备

下面对驱动源码主要实现方式做简要分析:

在drv_adc.c中,缺少对 RT_USING_DEVICE_OPS 项的支持,增加如下代码

#ifdef RT_USING_DEVICE_OPS  //增加对RT_USING_DEVICE_OPS的支持
const static struct rt_device_ops adc_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
_adc_read,
RT_NULL,
_adc_control
};
#endif rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data)
{
rt_err_t result = RT_EOK;
RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL); device->parent.type = RT_Device_Class_Miscellaneous; #ifdef RT_USING_DEVICE_OPS
device->parent.ops = &adc_ops;
#else
device->parent.init = RT_NULL;
device->parent.open = RT_NULL;
device->parent.close = RT_NULL;
device->parent.read = _adc_read;
device->parent.write = RT_NULL;
device->parent.control = _adc_control;
#endif device->ops = ops;
device->parent.user_data = (void *)user_data; result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR); return result;
}

其中设备ops接口要实现 adc_ops

const static struct rt_device_ops adc_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
_adc_read,
RT_NULL,
_adc_control
};

设备的子类 rt_adc_device 需要实现的ops 为 rt_adc_ops

static const struct rt_adc_ops stm_adc_ops =
{
.enabled = stm32_adc_enabled,
.convert = stm32_get_adc_value,
};

其中 _adc_control 调用 stm32_adc_enabled, _adc_read 调用 stm32_get_adc_value;

官方示例为了简化ADC驱动操作,直接export相关adc操作函数供用户使用,使用方式如下:

    rt_adc_device_t adc_dev;
rt_uint32_t value, vol;
rt_err_t ret = RT_EOK; /* 查找设备 */
adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
if (adc_dev == RT_NULL)
{
rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
return RT_ERROR;
} /* 使能设备 */
ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL); /* 读取采样值 */
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d \n", value); /* 转换为对应电压值 */
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d \n", vol / , vol % ); /* 关闭通道 */
ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);

既然有I/O设备模型,再使用这种方式现得驱动接口太分散了,下面以 I/O device接口实现adc采集示例:

使用 rt_device_read 时,注意 pos 和 size 的含义

    rt_device_t adc_dev = rt_device_find(ADC_DEV_NAME);
rt_device_open(adc_dev, RT_DEVICE_FLAG_RDWR); //记住一定要有打开设备操作,否则后面的rt_device_read无法使用 ret = rt_device_control(adc_dev, RT_ADC_CMD_ENABLE, (void*)ADC_DEV_CHANNEL); //使能ADC ret = rt_device_read(adc_dev, ADC_DEV_CHANNEL, &value, ); //程序不做修改时,_adc_read函数的pos项表示adc通道,size为4的倍数,大于4则依序读取后面的通道
// value = rt_adc_read((rt_adc_device_t)adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d %d %d\n", value, ret, *_rt_errno());
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d \n", vol / , vol % ); ret = rt_device_control(adc_dev, RT_ADC_CMD_DISABLE, (void*)ADC_DEV_CHANNEL); //禁止ADC

改进建议:

读取adc使用 rt_device_read 很不方便,建议取消 rt_device_read 项,读取采用 rt_device_control 来实现;

const static struct rt_device_ops adc_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
_adc_control
};

在adc.h中添加对 RT_ADC_CMD_READ 的支持,并添加对于读取数据参数结构体

struct rt_device_adc_value
{
rt_uint32_t channel;
rt_uint32_t value;
}; typedef enum
{
RT_ADC_CMD_ENABLE,
RT_ADC_CMD_DISABLE,
RT_ADC_CMD_READ,
} rt_adc_cmd_t;

在adc.c中的_adc_control 函数添加对 RT_ADC_CMD_READ 的支持

static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args)
{
rt_err_t result = RT_EOK;
rt_adc_device_t adc = (struct rt_adc_device *)dev; if (adc->ops->enabled == RT_NULL)
{
return -RT_ENOSYS;
}
if (cmd == RT_ADC_CMD_ENABLE)
{
result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_TRUE);
}
else if (cmd == RT_ADC_CMD_DISABLE)
{
result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_FALSE);
}
else if (cmd == RT_ADC_CMD_READ)  //通过control读取adc指定通道
{
struct rt_device_adc_value *adc_value;
adc_value = (struct rt_device_adc_value *) args;
if (adc_value == RT_NULL) return -RT_ERROR; result = adc->ops->convert(adc, adc_value->channel, &(adc_value->value));
} return result;
}

使用方式如下:

    rt_device_t adc_dev = rt_device_find(ADC_DEV_NAME);
rt_device_open(adc_dev, RT_DEVICE_FLAG_RDWR); //记住一定要有打开设备操作,否则后面的rt_device_read无法使用 ret = rt_device_control(adc_dev, RT_ADC_CMD_ENABLE, (void*)ADC_DEV_CHANNEL); //使能ADC struct rt_device_adc_value adc_value;
adc_value.channel = ADC_DEV_CHANNEL;
ret = rt_device_control(adc_dev, RT_ADC_CMD_READ, &adc_value);
value = adc_value.value; rt_kprintf("the value is :%d %d %d\n", value, ret, *_rt_errno());
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d \n", vol / , vol % ); ret = rt_device_control(adc_dev, RT_ADC_CMD_DISABLE, (void*)ADC_DEV_CHANNEL); //禁止ADC

RT-Thread 设备驱动ADC浅析与改进的更多相关文章

  1. RT thread 设备驱动组件之USART设备

    本文以stm32f4xx平台介绍串口驱动,主要目的是:1.RTT中如何编写中断处理程序:2.如何编写RTT设备驱动接口代码:3.了解串行设备的常见处理机制.所涉及的主要源码文件有:驱动框架文件(usa ...

  2. linux设备驱动模型-浅析-转

    1.  typeof typeof并非ISO C的关键字,而是gcc对C的一个扩展.typeof是一个关键字(类似sizeof),用于获取一个表达式的类型. 举个简单的例子: char tt; typ ...

  3. RT-Thread 设备驱动I2C浅析及使用

    由于 I2C 可以控制多从机的属性,设备驱动模型分为  I2C总线设备(类似与Linux里面的I2C适配器) + I2C从设备: 系统I2C设备驱动主要实现 I2C 总线设备驱动,而具体的I2C 从设 ...

  4. RT-Thread 设备驱动SPI浅析及使用

    OS版本:RT-Thread 4.0.0 测试BSP:STM32F407 SPI简介 SPI总线框架其实和I2C差不多,可以说都是总线设备+从设备,但SPI设备的通信时序配置并不固定,也就是说控制特定 ...

  5. RT-Thread 设备驱动UART浅析

    OS版本:RT-Thread 4.0.0 芯片:STM32F407 RT-Thread的串口驱动框架与Linux相识,分成 I/O设备框架 + 设备底层驱动: 1. serial设备初始化及使用 将配 ...

  6. RT Thread的SPI设备驱动框架的使用以及内部机制分析

    注释:这是19年初的博客,写得很一般,理解不到位也不全面.19年末得空时又重新看了RTThread的SPI和GPIO,这次理解得比较深刻.有时间时再整理上传. -------------------- ...

  7. linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-119723.html linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟 xxxxxxxxxx ...

  8. linux 混杂设备驱动之adc驱动

    linux2.6.30.4中,系统已经自带有了ADC通用驱动文件---arch/arm/plat-s3c24xx/adc.c,它是以平台驱动设备模型的架构来编写的,里面是一些比较通用稳定的代码,但是l ...

  9. 【Linux开发】linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟

    linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

随机推荐

  1. Codeforces Round Edu 36

    A.B.C 略 D(dfs+强连通分量) 题意: 给出一个n(n<=500)点m(m<=100000)边的有向图,问能否通过删去一条边使得该图无环. 分析: 最简单的想法就是枚举一条边删去 ...

  2. [Angular] Modify User Provided UI with Angular Content Directives

    If we’re going to make our toggle accessible, we’ll need to apply certain aria attributes to the con ...

  3. Atomic Builtins - Using the GNU Compiler Collection (GCC) GCC 提供的原子操作

    http://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Atomic-Builtins.html gcc从4.1.2提供了__sync_*系列的built-in函数,用 ...

  4. eclipse maven 插件的安装和配置

    maven3 安装: 安装 Maven 之前要求先确定你的 JDK 已经安装配置完毕.Maven是 Apache 下的一个项目.眼下最新版本号是 3.0.4.我用的也是这个. 首先去官网下载 Mave ...

  5. (八)Java 修饰符

    Java 修饰符 Java语言提供了很多修饰符,主要分为以下两类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class ...

  6. HDU 5056 Boring count(不超过k个字符的子串个数)

    Boring count Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tot ...

  7. ABAP 检查全角半角

    check全角or半角的方法 第一种方法SJIS_DBC_TO_SBC 全角转半角 SJIS_SBC_TO_DBC 半角转换为全角 设定 import all =xtext = 文本全角-〉半角,返回 ...

  8. Oracle常用SQL与练习

    基本 数学函数 rownum相关 分页查询 (假设每页显示10条) 不包含排序: 包含排序: 时间处理 1. to_char和to_date基本使用 eg1: eg2: 2)months_betwee ...

  9. HDU1087 Super Jumping! Jumping! Jumping! —— DP

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1087 Super Jumping! Jumping! Jumping! Time Limi ...

  10. 二.OC基础--1,对象的存储细节,2,#pragma mark指令,3,函数和对象方法的区别,4,对象和方法之间的关系 ,5.课堂习题

    1,对象的存储细节, 1. 当创建一个对象的时候:Person *p1 = [Person new],做了三件事情: 1,申请堆内存空间: 2,给实例变量初始化: 3,返回所申请空间的首地址; 2. ...