RT-Thread Studio学习(十四)ADC

RT-Thread Studio学习(十四)ADC

  • 一、简介
  • 二、新建RT-Thread项目并使用外部时钟
  • 三、启用ADC
  • 四、测试

一、简介

本文将基于STM32F407VET芯片介绍如何在RT-Thread Studio开发环境下使用ADC设备。硬件及开发环境如下:

  • OS WIN10
  • STM32F407VET6
  • STM32CubeMX v6.10.0
  • STM32Cube MCU Package for STM32F4 Series v1.28.0
  • RT-Thread Studio v2.2.7
  • RT-Thread Source Code v5.0.2
  • STM32F4 chip support packages v0.2.3

二、新建RT-Thread项目并使用外部时钟

打开RT-Thread Studio软件新建基于芯片的项目,并使用外部时钟系统,具体参见《RT-Thread Studio学习(一)使用外部时钟系统》。

三、启用ADC

  1. 打开ADC驱动框架
    RT-Thread Setting 中借助图形化配置工具打开软件ADC的驱动框架,如下图所示:
    在这里插入图片描述
  2. 定义ADC相关的宏
    board.h文件中使能宏定义:
#define BSP_USING_ADC1
#define BSP_USING_ADC2
#define BSP_USING_ADC3
  1. 复制ADC初始化函数
    双击RT-Thread Studio工程中的cubemx.ioc文件,使能ADC1、ADC2和ADC3,具体如下图:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    3个ADC分别对应引脚PC0、PC1和PC2。

使能ADC后再重新生成STM32CubeMX代码,将.\cubemx\Src\adc.c中的函数HAL_DAC_MspInit(DAC_HandleTypeDef* dacHandle)复制到board.c的末尾。

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */

  /* USER CODE END ADC1_MspInit 0 */
    /* ADC1 clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**ADC1 GPIO Configuration
    PC0     ------> ADC1_IN10
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /* USER CODE BEGIN ADC1_MspInit 1 */

  /* USER CODE END ADC1_MspInit 1 */
  }
  else if(adcHandle->Instance==ADC2)
  {
  /* USER CODE BEGIN ADC2_MspInit 0 */

  /* USER CODE END ADC2_MspInit 0 */
    /* ADC2 clock enable */
    __HAL_RCC_ADC2_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**ADC2 GPIO Configuration
    PC1     ------> ADC2_IN11
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /* USER CODE BEGIN ADC2_MspInit 1 */

  /* USER CODE END ADC2_MspInit 1 */
  }
  else if(adcHandle->Instance==ADC3)
  {
  /* USER CODE BEGIN ADC3_MspInit 0 */

  /* USER CODE END ADC3_MspInit 0 */
    /* ADC3 clock enable */
    __HAL_RCC_ADC3_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**ADC3 GPIO Configuration
    PC2     ------> ADC3_IN12
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /* USER CODE BEGIN ADC3_MspInit 1 */

  /* USER CODE END ADC3_MspInit 1 */
  }
}
  1. 定义.\cubemx\Inc\stm32f4xx_hal_conf.h中的相关宏
#define HAL_ADC_MODULE_ENABLED

四、测试

修改main.c的代码为:

/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-01-15     RT-Thread    first version
 */

#include <rtthread.h>
#include "stm32f4xx.h"
#include <rtdevice.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

// PC0     ------> ADC1_IN10
// PC1     ------> ADC2_IN11
// PC2     ------> ADC3_IN12
// PA4     ------> DAC_OUT1
// PA5     ------> DAC_OUT2

#define ADC_DEV_NAME        "adc1"      /* ADC 设备名称 */
#define REFER_VOLTAGE       330         /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
#define CONVERT_BITS        (1 << 12)   /* 转换位数为12位 */

#define DAC_DEV_NAME        "dac1"  /* DAC 设备名称 */
#define DAC_DEV_CHANNEL     1       /* DAC 通道 */
#define REFER_VOLTAGE       330         /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
#define CONVERT_BITS        (1 << 12)   /* 转换位数为12位 */


// 读取adc的使用命令get_adc adc1 1
// 第一个参数为命令,第二个参数为 adc 设备名称,第 3 个参数为 adc 通道,
// 返回值为 adc 电压值
static int adc_get(int argc, char *argv[])
{
    if(argc!=3)
    {
        rt_kprintf("Usage:    adc_get <device name> <channel>\n");
        rt_kprintf("Example:  adc_get adc1 1\n");
        return RT_ERROR;
    }
    rt_adc_device_t adc_dev;
    rt_uint32_t value, vol, channel;
    rt_err_t ret = RT_EOK;
    char adcdevname[RT_NAME_MAX];

    rt_strncpy(adcdevname, argv[1], RT_NAME_MAX);
    channel = atoi(argv[2]);  // ADC channel

    /* 查找设备 */
    adc_dev = (rt_adc_device_t)rt_device_find(adcdevname);
    if (adc_dev == RT_NULL)
    {
        rt_kprintf("adc sample run failed! can't find %s device!\n", adcdevname);
        return RT_ERROR;
    }

    /* 使能设备 */
    ret = rt_adc_enable(adc_dev, channel);

    /* 读取采样值 */
    value = rt_adc_read(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 / 100, vol % 100);

    /* 关闭通道 */
    ret = rt_adc_disable(adc_dev, channel);
    rt_kprintf("adc_get %s channel:%d\n", adcdevname, channel);

    return ret;
}

// 设置dac的使用命令 dac_set dac1 1 200
// 第一个参数为命令,第二个参数为 dac 设备名称,第 3 个参数为 dac 通道,
// 第 4 个参数为 dac 输出数值
static int dac_set(int argc, char *argv[])
{
    if(argc!=4)
    {
        rt_kprintf("Usage:    dac_set <device name> <channel> <value>\n");
        rt_kprintf("Example:  dac_set dac1 1 1000\n");
        return RT_ERROR;
    }
    rt_dac_device_t dac_dev;
    rt_uint32_t value, vol, channel;
    rt_err_t ret = RT_EOK;

    char dacdevname[RT_NAME_MAX];

    rt_strncpy(dacdevname, argv[1], RT_NAME_MAX);
    channel = atoi(argv[2]);  // DAC channel
    value = atoi(argv[3]);

    /* 查找设备 */
    dac_dev = (rt_dac_device_t)rt_device_find(dacdevname);
    if (dac_dev == RT_NULL)
    {
        rt_kprintf("dac sample run failed! can't find %s device!\n", dacdevname);
        return RT_ERROR;
    }

    /* 打开通道 */
    ret = rt_dac_enable(dac_dev, channel);

    /* 设置输出值 */
    rt_dac_write(dac_dev, channel, value);
    rt_kprintf("the value is :%d \n", value);

    /* 转换为对应电压值 */
    vol = value * REFER_VOLTAGE / CONVERT_BITS;
    rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);

    /* 延时查看效果,关闭通道后无输出 */
//    rt_thread_mdelay(500);

    /* 关闭通道 */
//    ret = rt_dac_disable(dac_dev, channel);

    return ret;
}

static int dac1_vol_sample()
{
    rt_dac_device_t dac_dev;
    rt_uint32_t value, vol;
    rt_err_t ret = RT_EOK;

    /* 查找设备 */
    dac_dev = (rt_dac_device_t)rt_device_find(DAC_DEV_NAME);
    if (dac_dev == RT_NULL)
    {
        rt_kprintf("dac sample run failed! can't find %s device!\n", DAC_DEV_NAME);
        return RT_ERROR;
    }

    /* 打开通道 */
    ret = rt_dac_enable(dac_dev, DAC_DEV_CHANNEL);

    /* 设置输出值 */
    value=1000;
    rt_dac_write(dac_dev, DAC_DEV_CHANNEL, value);
    rt_kprintf("the value is :%d \n", value);

    /* 转换为对应电压值 */
    vol = value * REFER_VOLTAGE / CONVERT_BITS;
    rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);

    /* 延时查看效果,关闭通道后无输出 */
   // rt_thread_mdelay(500);

    /* 关闭通道 */
   // ret = rt_dac_disable(dac_dev, DAC_DEV_CHANNEL);

    return ret;
}

int main(void)
{
    int count = 1;
    LOG_D("Hello RT-Thread! 2024.1.17");
    LOG_D("System CLock information");
    LOG_D("SYSCLK_Frequency = %d", HAL_RCC_GetSysClockFreq());
    LOG_D("HCLK_Frequency   = %d", HAL_RCC_GetHCLKFreq());
    LOG_D("PCLK1_Frequency  = %d", HAL_RCC_GetPCLK1Freq());
    LOG_D("PCLK2_Frequency  = %d", HAL_RCC_GetPCLK2Freq());
    LOG_D("SysTick->LOAD    = %d", SysTick->LOAD);
    LOG_D("Current tick     = %d", rt_tick_get());
    dac1_vol_sample();
    while (count++)
    {
        LOG_D("Hello RT-Thread! %d", rt_tick_get());
        rt_thread_mdelay(60000);
    }

    return RT_EOK;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(adc_get, get adc voltage);
MSH_CMD_EXPORT(dac_set, set dac voltage. Useage: dac_set adc2 11 200);

将引脚PA4和PC1短接,运行结果如下:
在这里插入图片描述

在PA4脚用万用表测得输出电压为0.8080V

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/330402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2.常见的点云数据滤波的方法总结(C++)

常见的点云数据处理有体素网格滤波、半径滤波、直通滤波、双边滤波器&#xff0c;统计滤波器&#xff0c;卷积滤波&#xff0c;条件滤波&#xff0c;高斯滤波等等。每种方法的原理和代码如下&#xff1a; 1.体素网格滤波 体素网格滤波是对密度大的三维的点在保持原来形状的条件…

Go后端开发 -- 反射reflect

Go后端开发 – 反射reflect && 结构体标签 文章目录 Go后端开发 -- 反射reflect && 结构体标签一、反射reflect1.编程语言中反射的概念2.interface 和反射3.变量内置的pair结构4.reflect的基本功能TypeOf和ValueOf5.从relfect.Value中获取接口interface的信息6…

SSL证书自动化管理有什么好处?如何实现SSL证书自动化?

SSL证书是用于加密网站与用户之间传输数据的关键元素&#xff0c;在维护网络安全方面&#xff0c;管理SSL证书与部署SSL证书一样重要。定期更新、监测和更换SSL证书&#xff0c;可以确保网站的安全性和合规性。而自动化管理可以为此节省时间&#xff0c;并避免人为错误和不必要…

React 基于Ant Degisn 实现table表格列表拖拽排序

效果图&#xff1a; 代码&#xff1a; myRow.js import { MenuOutlined } from ant-design/icons; import { DndContext } from dnd-kit/core; import { restrictToVerticalAxis } from dnd-kit/modifiers; import {arrayMove,SortableContext,useSortable,verticalListSorti…

【Java实战项目】基于ssm的数据结构课程网络学习平台

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Datawhale 强化学习笔记(二)马尔可夫过程,DQN 算法

文章目录 参考马尔可夫过程DQN 算法&#xff08;Deep Q-Network&#xff09;如何用神经网络来近似 Q 函数如何用梯度下降的方式更新网络参数强化学习 vs 深度学习 提高训练稳定性的技巧经验回放目标网络 代码实战 DQN 算法进阶Double DQNDueling DQN 算法代码实战 参考 在线阅…

计算机网络-计算机网络的概念 功能 发展阶段 组成 分类

文章目录 计算机网络的概念 功能 发展阶段总览计算机网络的概念计算机网络的功能计算机网络的发展计算机网络的发展-第一阶段计算机网络的发展-第二阶段-第三阶段计算机网络的发展-第三阶段-多层次ISP结构 小结 计算机网络的组成与分类计算机网络的组成计算机网络的分类小结 计…

RDMA原理浅析

1. DMA和RDMA概念 1.1 DMA DMA(直接内存访问)是一种能力&#xff0c;允许在计算机主板上的设备直接把数据发送到内存中去&#xff0c;数据搬运不需要CPU的参与。 传统内存访问需要通过CPU进行数据copy来移动数据&#xff0c;通过CPU将内存中的Buffer1移动到Buffer2中。DMA模式…

【Axure高保真原型】文字翻页效果

今天和大家分享选择文字翻页效果的原型模板&#xff0c;我们通过这个模板实现类似翻书的效果。鼠标点击右箭头&#xff0c;可以翻开下一页&#xff0c;点击左箭头翻开上一页&#xff1b;当然我们也可以通过鼠标拖动的操作进行翻页&#xff0c;鼠标想左拖动时&#xff0c;翻开下…

algotithm -- 排序算法

排序算法总结表&#xff1a; 1. In-place 和 Out-place 含义 参考链接 in-place 占用常数内存&#xff0c;不占用额外内存 假如问题规模是n&#xff0c;在解决问题过程中&#xff0c;只开辟了常数量的空间&#xff0c;与n无关&#xff0c;这是原址操作&#xff0c;就是In-…

Kotlin 移动端多平台

支持多平台编程是 Kotlin 的主要优势之一。它减少了为不同平台编写和维护相同代码所花费的时间&#xff0c;同时保留了本机编程的灵活性和优势。 1. 基本概念 KMM&#xff1a;Kotlin Multiplatform for mobile&#xff08;移动设备的 Kotlin 多平台&#xff09; KMM 多平台的主…

vue3有了解过吗?能说说跟vue2的区别吗?

一、Vue3介绍 关于vue3的重构背景&#xff0c;尤大是这样说的&#xff1a; 「Vue 新版本的理念成型于 2018 年末&#xff0c;当时 Vue 2 的代码库已经有两岁半了。比起通用软件的生命周期来这好像也没那么久&#xff0c;但在这段时期&#xff0c;前端世界已经今昔非比了 在我…

Redis 笔记一

概览 1.Redis核心数据存储结构 2.Redis底层String编码int&embstr&raw 3.Redis底层压缩列表&跳表&哈希表 4.Redis底层Zset实现压缩列表和跳表如何选择 5.基于Redis实现微博&抢红包&12306核心业务 辅助学习&#xff1a;Redis 教程 | 菜鸟教程 1.Redis为什…

web3.0基本概念简析

web3.0概念简析 web3.0的发展史 web1.0 仅用于展示&#xff0c;无法进行点赞评论等交互 web2.0 不仅可以展示&#xff0c;还可以上传视频、图片等&#xff0c;用户可以参与创作内容并获取收益。但还是中心化的模型 缺点 1 机械化的人机验证 2 账户安全无法保证 多年未登陆…

dp--64. 最小路径和/medium 理解度A

64. 最小路径和 1、题目2、题目分析3、复杂度最优解代码示例4、抽象与扩展 1、题目 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 示例 …

Dockerfile镜像实战

目录 一 构建SSH镜像 1.开启ip转发功能 2. 准备工作目录 3.修改配置文件 5.启动容器并修改root密码 二 构建Systemctl镜像 1. 准备工作目录 ​编辑2.修改配置文件 3.生成镜像 4.启动容器&#xff0c;并挂载宿主机目录挂载到容器中&#xff0c;进行初始化 5.进入容器 三…

C++三剑客之std::variant(二):深入剖析

目录 1.概述 2.辅助类介绍 2.1.std::negation 2.2.std::conjunction 2.3.std::is_destructible 2.4.std::is_object 2.5.is_default_constructible 2.6.std::is_trivially_destructible 2.7.std::in_place_type和std::in_place_index 3.原理分析 3.1.存储分析 3.2.…

【昕宝爸爸小模块】深入浅出之针对大Excel做文件读取问题

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…

VUE 中的 v-for 和 v-if 是否可以共存

VUE 中的 v-for 和 v-if 是否可以共存 前言1、面试经2、正确回答3、总结总结&#xff1a; 前言 要成功&#xff0c;先发疯&#xff0c;头脑简单往前冲&#xff01; 三金四银&#xff0c;金九银十&#xff0c;多学知识&#xff0c;也不能埋头苦干&#xff0c;要成功&#xff0c…

uniapp中uview组件库的NoticeBar 滚动通知 使用方法

目录 #平台差异说明 #基本使用 #配置主题 #配置图标 #配置滚动速度 #控制滚动的开始和暂停 #事件回调 #API #Props #Events 该组件用于滚动通告场景&#xff0c;有多种模式可供选择 #平台差异说明 AppH5微信小程序支付宝小程序百度小程序头条小程序QQ小程序√√√√…