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. bufferevent 与 socket

    http://blog.sina.com.cn/s/blog_56dee71a0100qx4s.html 很多时候,除了响应事件之外,应用还希望做一定的数据缓冲.比如说,写入数据的时候,通常的运行模式 ...

  2. 【Mongodb教程 第八课 】MongoDB 更新文档

    MongoDB的 update() 和 save() 方法用于更新文档的集合. update()方法更新现有的文档值,而替换现有的文档通过的文件中 save() 方法. MongoDB Update( ...

  3. 算法导论学习之线性时间求第k小元素+堆思想求前k大元素

    对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...

  4. serverSpeed是一个android手机端到服务器间udp/tcp对比测速软件

    https://github.com/eltld/serverSpeed https://github.com/c-wind/serverSpeed https://github.com/PeterK ...

  5. Cts框架解析(6)-任务的运行

    前两篇讲了任务的加入和9大项配置,这篇讲任务的运行. 任务的运行 任务的运行在CommandScheduler的run方法中,所以删除全部的断点,在run方法中打上断点,重新启动启动debug: 先看 ...

  6. python set dict tuple and list

    1 set 1.1 不变集合,frozenset 也就是说,集合中的元素不能删除,也不能增加. 1.2 两个集合之间的关系 isdisjoint()函数. 2 各个数据结构的不同显示 2.1 set ...

  7. 内存充足,但是为什么hadoop3无法启动nodemanager

    [root@hadoop3 hadoop]# xloStarting namenodes on [hadoop3]上一次登录:三 12月 27 16:06:01 CST 2017pts/24 上Sta ...

  8. WebService注解汇总

    Web Service 元数据注释(JSR 181) @WebService 1.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service.缺省值 ...

  9. Dancing Links 专题总结

    算法详细:Dancing Links博客 1.精确覆盖: ZOJ3209 Treasure Map HUST1017 Exact cover POJ3074 Sudoku 2.可重复覆盖: HDU22 ...

  10. 基于 jQuery 的专业 ASP.NET WebForms/MVC 控件库!

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...