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. [Bzoj3131][Sdoi2013]淘金(数位dp)(优先队列)

    3131: [Sdoi2013]淘金 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 847  Solved: 423[Submit][Status][ ...

  2. HDU 2059 【DP】

    题意: 中文. 思路: 这题不是自己的思想. 当对第i个点的最优值进行求解的时候一定存在最后一个加油的点j.这里j直接枚举. 另外将0和n+1个加油站定义为起点和终点. dp需要加强训练. #incl ...

  3. EXTJS中整合tinymce的富文本编辑器,添加上传图片功能

    提供部分代码.Ext.create('Ext.window.Window', { id: 'wind', title: 'CRUD窗口', modal: true, height: 800, widt ...

  4. 【python】对象和面向对象

    类的定义 python支持多重继承,在类名后面的小括号中,可以列出多个类名,以逗号分割. __init__方法在类的实例创建后被立即调用,注意与c++中构造函数不一样,因为对象在调用__init__时 ...

  5. 【转】nginx 和 php-fpm 通信使用unix socket还是TCP,及其配置

    原文: http://blog.csdn.net/pcyph/article/details/46513521 -------------------------------------------- ...

  6. centos编辑界面和图形界面登陆切换设置

    输入命令 vi /etc/inittab 到最后一行.把5改成3 保存退出. 各数字的含义: #   0 - halt (Do NOT set initdefault to this)         ...

  7. (void __user *)arg 中__user的作用

    __user宏简单告诉编译器(通过 noderef)不应该解除这个指针的引用(因为在当前地址空间中它是没有意义的). (void __user *)arg 指的是arg值是一个用户空间的地址,不能直接 ...

  8. JavaSE入门学习23:Java面向对象之构造方法

    学了JavaSE面向对象这一部分,也该对构造方法做一个总结了. 一构造方法 在多数情况下,初始化一个对象的终于步骤是去调用这个对象的构造方法. 构造方法负责对象的初始化工作,为 实例变量赋予合适的初始 ...

  9. [读书笔记]《没人会告诉你的PPT真相》

    这本书分了三部分.第一部分偏重于基础技能,其中分为三部分,打印.放映.保存.第二部分是进阶,分为模板下载.模板修改.增加自定义页面等.第三部分是打造商业范的PPT,分为商业范的特征,具体技能体现(重复 ...

  10. mp3 pcm

    mp3  pcm javaMP3转pcm 百度语音识别 - 且学且珍惜 - SegmentFault 思否 https://segmentfault.com/a/1190000013383967