IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> RT-Thread Nano如何适配ADC设备API -> 正文阅读

[嵌入式]RT-Thread Nano如何适配ADC设备API

本文介绍了如何在 RT-Thread Studio 上使用 RT-Thread Nano,并基于 BearPI-IOT STM32L431RCT6 的基础工程进行讲解如何使用 ADC 设备接口。

BearPI-IOT board

为什么需要设备接口

  1. RT-Thread 分为标准版本和 Nano 版本,其特点如下:

  • RT-Thread 标准版:拥有驱动框架,软件包等组件,软件包都是基于设备驱动接口来实现。

  • RT-Thread Nano :仅仅只是一个 RTOS 内核。没有任何组件。

  • Nano 是无法直接使用 RT-Thread 丰富软件包功能。

  • Nano 是一个面向低资源的 MCU 等芯片,不可能增加如同标准版的设备驱动框架。

  • Nano 需要一套统一设备驱动 API,屏蔽不同芯片的 HAL 层的区别。方便移植工程到不同的平台。

  • Nano 需要一套设备驱动 API,可以方便使用丰富软件包组件。

  • 准备工作

    1. 使用 RT-Thread Studio 建立一个 STM32L431RCT6 的 RT-Thread Nano 基础工程。

    2. 基础工程创建可参考:在 RT-Thread Studio 上使用 RT-Thread Nano

    ADC 设备接口

    1. 在 RT-Thread 标准版中,ADC设备驱动提供了一套设备管理接口来访问 ADC,用户程序可以直接使用该 API 操作 ADC 的功能,设备管理接口如下:

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

    1. 由于 RT-Thread Nano 不使用设备驱动框架,所以没有对应的 rt_device_find() 这个API获取设备对象。为了能够与 RT-Thread 标准版的接口相近,我们需要做了简单的修改,设备管理接口如下:

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

    1. 对于 RT-Thread Nano,只需要适配如上这套 API,便可简单修改后使用 RT-Thread 丰富软件包功能。

    适配 ADC 设备驱动接口

    1. 复制 RT-Thread 完整版工程中的 adc.h 文件(路径:rt-thread\components\drivers\include\drivers\adc.h)到我们准备好的 STM32L431RCT6 的 RT-Thread Nano 基础工程中。

    2. 由于 RT-Thread Nano 没有驱动框架,所以我们要把 adc.h 中有关完整版的内容去掉。整理完之后的 adc.h 文件如下:

    /*
    ?*?Copyright?(c)?2006-2021,?RT-Thread?Development?Team
    ?*
    ?*?SPDX-License-Identifier:?Apache-2.0
    ?*
    ?*?Change?Logs:
    ?*?Date???????????Author???????Notes
    ?*?2021-08-22?????RiceChen??????first?version
    ?*/
    
    #ifndef?__ADC_H__
    #define?__ADC_H__
    #include?<rtthread.h>
    
    struct?rt_adc_device
    {
    ????uint8_t?*user_data;
    };
    typedef?struct?rt_adc_device?*rt_adc_device_t;
    
    typedef?enum
    {
    ????RT_ADC_CMD_ENABLE,
    ????RT_ADC_CMD_DISABLE,
    }?rt_adc_cmd_t;
    
    struct?rt_adc_device?*rt_adc_device_find(const?char?*name);
    rt_uint32_t?rt_adc_read(rt_adc_device_t?dev,?rt_uint32_t?channel);
    rt_err_t?rt_adc_enable(rt_adc_device_t?dev,?rt_uint32_t?channel);
    rt_err_t?rt_adc_disable(rt_adc_device_t?dev,?rt_uint32_t?channel);
    
    #endif?/*?__ADC_H__?*/
    
    1. 我们需要适配如上4个 ADC 设备 API,参考实例:drv_adc.c 和 drv_adc.h。

    • drv_adc.c实例:

    /*
    ?*?Copyright?(c)?2006-2021,?RT-Thread?Development?Team
    ?*
    ?*?SPDX-License-Identifier:?Apache-2.0
    ?*
    ?*?Change?Logs:
    ?*?Date???????????Author????????????Notes
    ?*?2021-08-21?????RiceChen?????the?first?version
    ?*/
    
    #include?<board.h>
    #include?"drv_adc.h"
    
    #ifdef?RT_USING_ADC
    
    struct?rt_i2c_config
    {
    ????char?*name;
    ????ADC_HandleTypeDef?ADC_Handler;
    };
    
    struct?rt_i2c_config?adc_config[]?=
    {
    #ifdef?RT_USING_ADC1
    ????ADC1_CONFIG,
    #endif
    };
    
    struct?stm32_adc
    {
    ????struct?rt_i2c_config?*config;
    ????struct?rt_adc_device?stm32_adc_device;
    };
    
    static?struct?stm32_adc?stm32_adc_obj[sizeof(adc_config)?/?sizeof(adc_config[0])];
    
    static?rt_err_t?stm32_adc_enabled(struct?rt_adc_device?*device,?rt_uint32_t?channel,?rt_bool_t?enabled)
    {
    ????ADC_HandleTypeDef?*stm32_adc_handler;
    ????RT_ASSERT(device?!=?RT_NULL);
    ????stm32_adc_handler?=?(ADC_HandleTypeDef?*)device->user_data;
    
    ????rt_kprintf("%d:?0x%08x\r\n",?__LINE__,?stm32_adc_handler);
    
    ????if?(enabled)
    ????{
    ????????ADC_Enable(stm32_adc_handler);
    ????}
    ????else
    ????{
    ????????ADC_Disable(stm32_adc_handler);
    ????}
    
    ????return?RT_EOK;
    }
    
    static?rt_uint32_t?stm32_adc_get_channel(rt_uint32_t?channel)
    {
    ????rt_uint32_t?stm32_channel?=?0;
    
    ????switch?(channel)
    ????{
    ????case??0:
    ????????stm32_channel?=?ADC_CHANNEL_0;
    ????????break;
    ????case??1:
    ????????stm32_channel?=?ADC_CHANNEL_1;
    ????????break;
    ????case??2:
    ????????stm32_channel?=?ADC_CHANNEL_2;
    ????????break;
    ????case??3:
    ????????stm32_channel?=?ADC_CHANNEL_3;
    ????????break;
    ????case??4:
    ????????stm32_channel?=?ADC_CHANNEL_4;
    ????????break;
    ????case??5:
    ????????stm32_channel?=?ADC_CHANNEL_5;
    ????????break;
    ????case??6:
    ????????stm32_channel?=?ADC_CHANNEL_6;
    ????????break;
    ????case??7:
    ????????stm32_channel?=?ADC_CHANNEL_7;
    ????????break;
    ????case??8:
    ????????stm32_channel?=?ADC_CHANNEL_8;
    ????????break;
    ????case??9:
    ????????stm32_channel?=?ADC_CHANNEL_9;
    ????????break;
    ????case?10:
    ????????stm32_channel?=?ADC_CHANNEL_10;
    ????????break;
    ????case?11:
    ????????stm32_channel?=?ADC_CHANNEL_11;
    ????????break;
    ????case?12:
    ????????stm32_channel?=?ADC_CHANNEL_12;
    ????????break;
    ????case?13:
    ????????stm32_channel?=?ADC_CHANNEL_13;
    ????????break;
    ????case?14:
    ????????stm32_channel?=?ADC_CHANNEL_14;
    ????????break;
    ????case?15:
    ????????stm32_channel?=?ADC_CHANNEL_15;
    ????????break;
    ????}
    
    ????return?stm32_channel;
    }
    
    static?rt_err_t?stm32_get_adc_value(struct?rt_adc_device?*device,?rt_uint32_t?channel,?rt_uint32_t?*value)
    {
    ????ADC_ChannelConfTypeDef?ADC_ChanConf;
    ????ADC_HandleTypeDef?*stm32_adc_handler;
    
    ????RT_ASSERT(device?!=?RT_NULL);
    ????RT_ASSERT(value?!=?RT_NULL);
    
    ????stm32_adc_handler?=?(ADC_HandleTypeDef?*)device->user_data;
    
    ????rt_memset(&ADC_ChanConf,?0,?sizeof(ADC_ChanConf));
    
    ????if?(channel?<=?18)
    ????{
    ????????/*?set?stm32?ADC?channel?*/
    ????????ADC_ChanConf.Channel?=??stm32_adc_get_channel(channel);
    ????}
    ????else
    ????{
    ????????rt_kprintf("ADC?channel?must?be?between?0?and?18.");
    ????????return?-RT_ERROR;
    ????}
    
    ????ADC_ChanConf.Rank?=?1;
    ????ADC_ChanConf.SamplingTime?=?ADC_SAMPLETIME_247CYCLES_5;
    ????ADC_ChanConf.Offset?=?0;
    ????ADC_ChanConf.OffsetNumber?=?ADC_OFFSET_NONE;
    ????ADC_ChanConf.SingleDiff?=?LL_ADC_SINGLE_ENDED;
    ????HAL_ADC_ConfigChannel(stm32_adc_handler,?&ADC_ChanConf);
    
    ????if?(HAL_ADCEx_Calibration_Start(stm32_adc_handler,?ADC_ChanConf.SingleDiff)?!=?HAL_OK)
    ????{
    ????????rt_kprintf("ADC?calibration?error!\n");
    ????????return?-RT_ERROR;
    ????}
    ????/*?start?ADC?*/
    ????HAL_ADC_Start(stm32_adc_handler);
    
    ????/*?Wait?for?the?ADC?to?convert?*/
    ????HAL_ADC_PollForConversion(stm32_adc_handler,?100);
    
    ????/*?get?ADC?value?*/
    ????*value?=?(rt_uint32_t)HAL_ADC_GetValue(stm32_adc_handler);
    
    ????return?RT_EOK;
    }
    
    rt_uint32_t?rt_adc_read(rt_adc_device_t?dev,?rt_uint32_t?channel)
    {
    ????rt_uint32_t?value;
    
    ????RT_ASSERT(dev);
    
    ????stm32_get_adc_value(dev,?channel,?&value);
    
    ????return?value;
    }
    
    rt_err_t?rt_adc_enable(rt_adc_device_t?dev,?rt_uint32_t?channel)
    {
    ????rt_err_t?result?=?RT_EOK;
    
    ????RT_ASSERT(dev);
    
    ????result?=?stm32_adc_enabled(dev,?channel,?RT_TRUE);
    
    ????return?result;
    }
    
    rt_err_t?rt_adc_disable(rt_adc_device_t?dev,?rt_uint32_t?channel)
    {
    ????rt_err_t?result?=?RT_EOK;
    
    ????RT_ASSERT(dev);
    
    ????result?=?stm32_adc_enabled(dev,?channel,?RT_FALSE);
    
    ????return?result;
    }
    
    struct?rt_adc_device?*rt_adc_device_find(const?char?*name)
    {
    ????int?i?=?0;
    ????for?(i?=?0;?i?<?sizeof(adc_config)?/?sizeof(adc_config[0]);?i++)
    ????{
    ????????if(rt_strncmp(stm32_adc_obj[i].config->name,?name,?RT_NAME_MAX)?==?0)
    ????????{
    ????????????return?&stm32_adc_obj[i].stm32_adc_device;
    ????????}
    ????}
    ????return?RT_NULL;
    }
    
    static?int?rt_hw_adc_init(void)
    {
    ????int?i?=?0;
    ????for?(i?=?0;?i?<?sizeof(adc_config)?/?sizeof(adc_config[0]);?i++)
    ????{
    ????????stm32_adc_obj[i].config?=?&adc_config[i];
    ????????stm32_adc_obj[i].stm32_adc_device.user_data?=?(uint8_t?*)&stm32_adc_obj[i].config->ADC_Handler;
    ????????rt_kprintf("%d:?0x%08x\r\n",?__LINE__,?&stm32_adc_obj[i].config->ADC_Handler);
    
    ????????rt_kprintf("%d:?0x%08x\r\n",?__LINE__,?ADC1);
    ????????rt_kprintf("%d:?0x%08x\r\n",?__LINE__,?stm32_adc_obj[i].config->ADC_Handler.Instance);
    
    ????????if?(HAL_ADC_Init(&stm32_adc_obj[i].config->ADC_Handler)?!=?HAL_OK)
    ????????{
    ????????????rt_kprintf("%s?init?failed",?stm32_adc_obj[i].config->name);
    ????????????return?-RT_ERROR;
    ????????}
    ????}
    
    ????return?RT_EOK;
    }
    INIT_APP_EXPORT(rt_hw_adc_init);
    
    void?adc_get_obj(void)
    {
    ????int32_t?value?=?0;
    ????struct?rt_adc_device?*dev?=?RT_NULL;
    ????dev?=?rt_adc_device_find("adc1");
    ????if(dev?==?RT_NULL)
    ????{
    ????????rt_kprintf("%s?not?found\r\n",?"adc1");
    ????????return;
    ????}
    ????else
    ????{
    ????????rt_adc_enable(dev,?3);
    ????????value?=?rt_adc_read(dev,?3);
    ????????rt_kprintf("adc?value:?%d\r\n",?value);
    ????}
    }
    MSH_CMD_EXPORT(adc_get_obj,?adc_get_obj);
    
    #endif?/*?RT_USING_ADC?*/
    
    
    • drv_adc.h实例:

    /*
    ?*?Copyright?(c)?2006-2021,?RT-Thread?Development?Team
    ?*
    ?*?SPDX-License-Identifier:?Apache-2.0
    ?*
    ?*?Change?Logs:
    ?*?Date???????????Author????????????Notes
    ?*?2021-04-20?????RiceChen??????first?version
    ?*/
    
    #ifndef?__DRV_ADC_H__
    #define?__DRV_ADC_H__
    
    #include?<drv_common.h>
    #include?<board.h>
    #include?"adc.h"
    
    #ifdef?__cplusplus
    extern?"C"?{
    #endif
    
    #ifdef?RT_USING_ADC1
    #ifndef?ADC1_CONFIG
    #define?ADC1_CONFIG????????????????????????????????????????????????????????\
    ????{??????????????????????????????????????????????????????????????????????\
    ???????.name???????????????????????????????????=?"adc1",????????????????????????\
    ???????.ADC_Handler.Instance???????????????????=?ADC1,??????????????????????????\
    ???????.ADC_Handler.Init.ClockPrescaler????????=?ADC_CLOCK_SYNC_PCLK_DIV4,??????\
    ???????.ADC_Handler.Init.Resolution????????????=?ADC_RESOLUTION_12B,????????????\
    ???????.ADC_Handler.Init.DataAlign?????????????=?ADC_DATAALIGN_RIGHT,???????????\
    ???????.ADC_Handler.Init.ScanConvMode??????????=?DISABLE,???????????????????????\
    ???????.ADC_Handler.Init.EOCSelection??????????=?DISABLE,???????????????????????\
    ???????.ADC_Handler.Init.ContinuousConvMode????=?DISABLE,???????????????????????\
    ???????.ADC_Handler.Init.NbrOfConversion???????=?1,?????????????????????????????\
    ???????.ADC_Handler.Init.DiscontinuousConvMode?=?DISABLE,???????????????????????\
    ???????.ADC_Handler.Init.NbrOfDiscConversion???=?0,?????????????????????????????\
    ???????.ADC_Handler.Init.ExternalTrigConv??????=?ADC_SOFTWARE_START,????????????\
    ???????.ADC_Handler.Init.ExternalTrigConvEdge??=?ADC_EXTERNALTRIGCONVEDGE_NONE,?\
    ???????.ADC_Handler.Init.DMAContinuousRequests?=?DISABLE,???????????????????????\
    ????}
    #endif?/*?ADC1_CONFIG?*/
    #endif?/*?RT_USING_ADC1?*/
    
    #ifdef?__cplusplus
    }
    #endif
    
    #endif?/*?__DRV_ADC_H__?*/
    
    
    

    编写 ADC 设备使用示例

    void?adc_test(void)
    {
    ????int32_t?value?=?0;
    ????struct?rt_adc_device?*dev?=?RT_NULL;
    ????dev?=?rt_adc_device_find("adc1");
    ????if(dev?==?RT_NULL)
    ????{
    ????????rt_kprintf("%s?not?found\r\n",?"adc1");
    ????????return;
    ????}
    ????else
    ????{
    ????????rt_adc_enable(dev,?3);
    ????????value?=?rt_adc_read(dev,?3);
    ????????rt_kprintf("adc?value:?%d\r\n",?value);
    ????}
    }
    MSH_CMD_EXPORT(adc_test,?adc?test);
    
    1. 实例代码运行现象:

    msh?>adc_test
    adc?value:?565
    msh?>
    

    总结

    • 通过适配PIN设备接口,我们可以无缝对接到软件包的使用。

    • 对于低资源的芯片使用 Nano 并且能够使用 RT-THREAD 丰富的软件,无疑是一个非常完美的做法。也没有庞大的驱动框架。

    • 通过这样的方式,学习完 RT-THREAD Nano 在转移到 RT-THREAD 标准版的学习,更加简单方便。


    关注微信公众号『Rice嵌入式开发技术分享』,后台回复“微信”添加作者微信,备注”入群“,便可邀请进入技术交流群。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-04 17:42:22  更:2021-09-04 17:44:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:33:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码