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. eclipse导入maven工程步骤

    转自:http://jingyan.baidu.com/article/cbf0e500a6e3252eaa2893c1.html 感谢作者 步骤一 : 选择 “Import”操作 有两个途径可以选择 ...

  2. python读取大文件的方法

    python计算文件的行数和读取某一行内容的实现方法 :最简单的办法是把文件读入一个大的列表中,然后统计列表的长度.如果文件的路径是以参数的形式filepath传递的,那么只用一行代码就可以完成我们的 ...

  3. c++多线程编程:常见面试题

    题目:子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码 子线程与主线程必有一个满足条件(flag == ...

  4. C#:excel导入导出

    资源:excelService 服务 http://download.csdn.net/detail/istend/8060501 排列问题 导出时,数字和字符的排列格式默认不一样,数字靠右,字符靠左 ...

  5. XMLHttpRequest对象解读

    <!DOCTYPE html> <html> <body> <script> function reqListener () { console.log ...

  6. CentOS 7下安装Logstash ELK Stack 日志管理系统(上)

    介绍 The Elastic Stack - 它不是一个软件,而是Elasticsearch,Logstash,Kibana 开源软件的集合,对外是作为一个日志管理系统的开源方案.它可以从任何来源,任 ...

  7. Linux内核project导论——网络:Filter(LSF、BPF、eBPF)

    概览 LSF(Linux socket filter)起源于BPF(Berkeley Packet Filter).基础从架构一致.但使用更简单.LSF内部的BPF最早是cBPF(classic).后 ...

  8. HDU 1272: 小希的迷宫(并查集)

    小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  9. 百万级PHP网站Poppen.de的架构分享心得

    在了解过世界最大的PHP站点,Facebook的后台技术后, 今天我们来了解一个百万级PHP站点的网站架构:Poppen.de.Poppen.de是德国的一个社交网站,相对Facebook.Flick ...

  10. ABP框架 - 介绍 VS2017调试器无法附加到IIS进程(w3wp.exe) c# 动态实例化一个泛型类

    ABP框架 - 介绍   在14,15年间带领几个不同的团队,交付了几个项目,在这个过程中,虽然几个项目的业务不一样,但是很多应用程序架构基础性的功能却是大同小异,例如认证.授权.请求验证.异常处理. ...