GD32450i-EVAL学习笔记 6 - ADC

2023-11-19

目录

1. 初始化ADC

1.1 使能RCU

1.2 设置频率

1.3 设置分辨率

1.4 设置数据对齐方式

1.5 使能扫描模式

1.6 设置触发模式

1.6 使能ADC

2. 初始化通道规则

3.  通道使能

4. 软件触发使能

5.  获取ADC的值

5.1 等待转换结束

5.2 读入数值

6. 实例

6.1 GPIO初始化

6.2 初始化ADC

6.3 软件触发

6.4 打印ADC结果


GD32F450的ADC最多有3个,每个ADC有19个通道(16个外部通道),ADC0的通道16,通道17和通道18分别连接到温度传感器,内部参考电压和VBAT/4模拟输入。 ADC1的通道16,通道17和通道18内部都连接到VSSA。 ADC2的通道16,通道17和通道18内部都连接到VSSA。

注意:Datasheet中似乎通道数与用户手册的不一样,但是应该是19个通道。

最高12位分辨率,可配置为12、10、8、6位分辨率。

采用率最高2.6MSPs(12位分辨率)、3.0MSPs(10位分辨率)。

通道可以按照特定的序列组织为2种方式的序列:规则通道和注入通道

规则通道:最多16 个转换的序列,这种方式类似顺序执行的代码,ADC硬件按照定义好的顺序(由寄存器RSQ0、RSQ1、RSQ2决定个数和顺序)转换ADC。规则通道得到的ADC值都是更新到寄存器ADC_SYNCDATA中,因此多规则通道如果需要每个通道正确的读到ADC值,必须采用DMA的方式。

注入通道:最多4 个转换的序列,这种方式类似中断程序,它会中断规则通道(由寄存器ISQ决定个数和顺序)。注入通道得到的ADC值每个通道有对应的寄存器(ADC_IDATA0 - ADC_IDATA3)。

ADC的功能组合特别多,为了方便使用和理解,先选择最简单的一种方式:只用注入通道、软件启动,无DMA,数据格式右对齐。

1. 初始化ADC

1.1 使能RCU

switch(port)
{
    case HW_ADC0:
        rcu_periph_clock_enable(RCU_ADC0);
        break;
    case HW_ADC1:
        rcu_periph_clock_enable(RCU_ADC1);
        break;
    case HW_ADC2:
        rcu_periph_clock_enable(RCU_ADC2);
        break;
    case HW_ADC_MAX:
        return;
}

1.2 设置频率

ADC的频率设置是设置寄存器同步控制寄存器 ADC_SYNCCT的16-18位。

PCLK2最大100MHz,HCLK最大200M,对应ADC的时钟为:50M,25M,16.67M,12.5M,40M,33.33M,  20M,10M。为了兼容其他芯片的设定,取前面4种设定。

switch(clkDiv)
{
    case ADC_CLK_DIV2:
    default:
        adc_clock_config(ADC_ADCCK_PCLK2_DIV2);
        break;
    case ADC_CLK_DIV4:
        adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
        break;
    case ADC_CLK_DIV6:
        adc_clock_config(ADC_ADCCK_PCLK2_DIV6);
        break;
    case ADC_CLK_DIV8:
        adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
        break;
}

1.3 设置分辨率

switch(resolutin)
{
    case ADC_RESOLUTION_8BIT:
        adc_resolution_config(adcGroup[port], ADC_RESOLUTION_12B);
        break;
    case ADC_RESOLUTION_10BIT:
        adc_resolution_config(adcGroup[port], ADC_RESOLUTION_10B);
        break;
    case ADC_RESOLUTION_6BIT:
        adc_resolution_config(adcGroup[port], ADC_RESOLUTION_6B);
        break;
    case ADC_RESOLUTION_12BIT:
    default:
        adc_resolution_config(adcGroup[port], ADC_RESOLUTION_12B);
        break;
}

1.4 设置数据对齐方式

adc_data_alignment_config(adcGroup[port], ADC_DATAALIGN_RIGHT)

默认选择右对齐(最常用的方式)

1.5 使能扫描模式

adc_special_function_config(adcGroup[port], ADC_SCAN_MODE, ENABLE);

1.6 设置触发模式

adc_external_trigger_config(adcGroup[port], ADC_INSERTED_CHANNEL, DISABLE);
adc_external_trigger_config(adcGroup[port], ADC_REGULAR_CHANNEL, DISABLE);

 默认将2种规则通道的触发都Disable,由软件启动或另外的API函数设置对应的触发方式。

1.6 使能ADC

adc_enable(adcGroup[port]);
adc_calibration_enable(adcGroup[port]);

 使能ADC并使能校准功能。

2. 初始化通道规则

void adcCHInit(uint8_t port, uint8_t *pRegualer, uint8_t regualerLen, uint8_t *pInserted, uint8_t insertedLen)
{
    uint8_t i;
    if(port > HW_ADC_MAX)
        return;
    
    adc_channel_length_config(adcGroup[port], ADC_REGULAR_CHANNEL, regualerLen);
    for (i = 0; i < regualerLen; i++)
    {
        adc_regular_channel_config(adcGroup[port], i, pRegualer[i], ADC_SAMPLETIME_480);
    }
    
    adc_channel_length_config(adcGroup[port], ADC_INSERTED_CHANNEL, insertedLen);
    for (i = 0; i < insertedLen; i++)
    {
        adc_inserted_channel_config(adcGroup[port], i, pInserted[i], ADC_SAMPLETIME_480);
    }
}

定义哪些通道属于规则通道还是注入通道,这里默认采样率为480个时钟。

3.  通道使能

if(ch > 15)
{
    if(port == HW_ADC0)
    {
        if(ch == 18)
            adc_channel_16_to_18(ADC_VBAT_CHANNEL_SWITCH, ENABLE);
        else 
            adc_channel_16_to_18(ADC_TEMP_VREF_CHANNEL_SWITCH, ENABLE);
    }
    else
        return;
}

ADC0的通道16,17,18是特殊的,需要特殊使能。

4. 软件触发使能

void adcSoftwareTrigger(uint8_t port, uint8_t ch)
{
    uint8_t i;
    adc_flag_clear(adcGroup[port], ADC_FLAG_EOC);
    adc_flag_clear(adcGroup[port], ADC_FLAG_EOIC);
    for (i = 0; i < 4; i++)
    {
        if(ch == ((ADC_ISQ(adcGroup[port]) >> (5 * i)) & 0x1F))
        {
            adc_software_trigger_enable(adcGroup[port], ADC_INSERTED_CHANNEL);
            return;
        }
    }
    for (i = 0; i < 6; i++)
    {
        if(ch == ((ADC_RSQ2(adcGroup[port]) >> (5 * i)) & 0x1F))
        {
            adc_software_trigger_enable(adcGroup[port], ADC_REGULAR_CHANNEL);
            return;
        }
    }
    for (i = 0; i < 6; i++)
    {
        if(ch == ((ADC_RSQ1(adcGroup[port]) >> (5 * i)) & 0x1F))
        {
            adc_software_trigger_enable(adcGroup[port], ADC_REGULAR_CHANNEL);
            return;
        }
    }
    for (i = 0; i < 4; i++)
    {
        if(ch == ((ADC_RSQ0(adcGroup[port]) >> (5 * i)) & 0x1F))
        {
            adc_software_trigger_enable(adcGroup[port], ADC_REGULAR_CHANNEL);
            return;
        }
    }
}

根据初始化通道规则配置判断通道属于哪种规则,然后使能对应的触发。

每次触发前需要先把EOC(规则通道转换完成)和EOIC(注入通道转换完成)清0。

5.  获取ADC的值

uint16_t adcGetValue(uint8_t port, uint8_t ch)
{
    uint16_t adcValue = 0;
    uint8_t i;
    uint16_t timeout = 0;
    uint8_t isqIndex = 0;

    for (i = 0; i < 4; i++)
    {
        if(ch == ((ADC_ISQ(adcGroup[port]) >> (5 * i)) & 0x1F))
        {
            while(adc_flag_get(adcGroup[port], ADC_FLAG_EOIC) == 0)
            {
                delayms(1);
                timeout++;
                if(timeout > 2000)
                    return 0;
            }
            adcValue = adc_inserted_data_read(adcGroup[port], isqIndex);
            return adcValue;
        }
        if(((ADC_ISQ(adcGroup[port]) >> (5 * i)) & 0x1F) > 0)
            isqIndex++;
    }
    
    while(adc_flag_get(adcGroup[port], ADC_FLAG_EOC) == 0)
    {
        delayms(1);
        timeout++;
        if(timeout > 2000)
            return 0;
    }
    adcValue = adc_regular_data_read(adcGroup[port]);
    return adcValue;
}

这里有个奇怪的设定,寄存器ADC_ISQ中通道序列排列比较特别,比如这里ADC_ISQ的值为0x294600, 从高位到低位的含义以此为:0x2表示3组注入通道, 通道18,通道17,通道16,0b00000表示没使用。

另外,官方的用户手册EOC的描述也有问题。

5.1 等待转换结束

通过读取寄存器ADC_STAT的EOC是否为1判断ADC转换是否结束。等待EOC为1后需要软件清0。

5.2 读入数值

 先判断当前通道是否是注入通道,如果是,则读入对应注入通道的ADC值(寄存器ADC_IDATA0 - ADC_IDATA3)。

多规则通道如果需要每个通道正确的读到ADC值,必须采用DMA的方式。这里只读入ADC_RDATA的值,只会是最后一个通道的ADC值。

6. 实例

GD32450i-EVAL的外部输入是ADC通道13,GPIOC3.

6.1 GPIO初始化

#define ADC_VR1                         ADC0
#define ADC_CH_VR1                      GPIOC
#define PIN_ADC_CH_VR1                  3

#define ADCCHSetANI()                   gpio_mode_set(IO_ADC_CH_VR1, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ((uint32_t)1 << PIN_ADC_CH_VR1))

6.2 初始化ADC

这里把外部输入设为规则通道,其他3个内部的ADC通道16,17,18设置为注入通道。

#define ADC_CH_TEMP                     16
#define ADC_CH_VREF                     17
#define ADC_CH_VBAT                     18

uint8_t Inserted[3];
uint8_t Regualer[1];
Regualer[0] = ADC_CH_VR1;
Inserted[0] = ADC_CH_TEMP;
Inserted[1] = ADC_CH_VREF;
Inserted[2] = ADC_CH_VBAT;
adcCHInit(ADC_VR1, Regualer, 1, Inserted, 3);
adcCHEnable(ADC_VR1, ADC_CH_VR1, ADC_SAMPLETIME_144);
adcCHEnable(HW_ADC0, ADC_CH_TEMP, ADC_SAMPLETIME_144);
adcCHEnable(HW_ADC0, ADC_CH_VREF, ADC_SAMPLETIME_144);
adcCHEnable(HW_ADC0, ADC_CH_VBAT, ADC_SAMPLETIME_144);
adcInit(ADC_VR1, ADC_CLK_DIV2, ADC_RESOLUTION_12BIT);

6.3 软件触发

adcSoftwareTrigger(ADC_VR1, ADC_CH_VR1);
adcSoftwareTrigger(HW_ADC0, ADC_CH_TEMP);
adcSoftwareTrigger(HW_ADC0, ADC_CH_VREF);
adcSoftwareTrigger(HW_ADC0, ADC_CH_VBAT);

6.4 打印ADC结果

Printf("VR1 Value:%d mV\r\n", (uint32_t)(((float)adcGetValue(ADC_VR1, ADC_CH_VR1) / 4095) * 3.3f * 1000));
Printf("Temperature Value:%d mC\r\n",  (uint32_t)((1.42f - (float)adcGetValue(HW_ADC0, ADC_CH_TEMP) * 3.3f / 4096) * 1000 / 4.35f + 25) * 1000);
Printf("Reference Voltage:%d mV\r\n", (uint32_t)(((float)adcGetValue(HW_ADC0, ADC_CH_VREF) / 4095) * 3.3f * 1000));
Printf("VBAT Voltage:%d mV\r\n", (uint32_t)(((float)adcGetValue(HW_ADC0, ADC_CH_VBAT) / 4095) * 3.3f * 4 * 1000));

得到的打印结果如下:

************ ADC Result *************
VR1 Value:1481 mV
Temperature Value:35000 mC
Reference Voltage:1200 mV
VBAT Voltage:3284 mV

扭动VR1可以看到VR1 Value的值会变化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GD32450i-EVAL学习笔记 6 - ADC 的相关文章

  • MCU震荡电路的晶振边的22pf电容的作用

    振荡电路用于实时时钟RTC 对于这种振荡电路只能用32 768KHZ 的晶体 晶体被连接在OSC3 与OSC4 之间而且为了获得稳定的频率必须外加两个带外部电阻的电容以构成振荡电路 32 768KHZ的时钟晶振产生的振荡信号经过石英钟内部分
  • (3)numpy数组的索引和切片操作

    在开始之前 先导入numpy第三方包 import numpy as np 索引 谈到索引 我们就应该想到 在python语言中 是如何对列表进行索引的 接下来将会对python列表索引和numpy数组索引进行比较 先定义一个numpy数组
  • 查看linux中的TCP连接数

    一 查看哪些IP连接本机 netstat an 二 查看TCP连接数 1 统计80端口连接数 netstat nat grep i 80 wc l 2 统计httpd协议连接数 ps ef grep httpd wc l 3 统计已连接上的
  • 一招秒开GitHub,永久解决!

    步骤 目录 步骤 1 打开电脑 进入如下的路径 2 将hosts 复制到桌面 3 把hosts文件移动到桌面后etc文件夹下的hosts文件不存在 已经被移动到桌面了 4 在移到桌面的hosts文件里面进行修改 5 再把修改好的hosts文
  • mysql tomcat 自动重连_Java开发网 - tomcat连接池支持重新连接数据库吗?

    Posted by pigengler Posted on 2006 04 20 15 23 我做了一个测试 程序使用tomcat的连接池 factory org apache commons dbcp BasicDataSourceFac
  • 微信api ----统一下单

    应用场景 除被扫支付场景以外 商户系统先调用该接口在微信支付服务后台生成预支付交易单 返回正确的预支付交易回话标识后再按扫码 JSAPI APP等不同场景生成交易串调起支付 状态机 支付状态转变如下 接口链接 URL地址 https api
  • pandas中的data.corr()函数方法说明及使用

    数据相关性分析中 经常用到data corr 函数 data corr 表示了data中的两个变量之间的相关性 取值范围为 1 1 取值接近 1 表示反相关 类似反比例函数 取值接近1 表正相关 DataFrame corr 函数使用说明如
  • 国际版阿里云/腾讯云:阿里云流量包是用来做什么

    阿里云流量包是用来做什么 阿里云同享流量包是一种通用流量套餐 同享流量包具有多地域和多产品流量抵扣的优势 同享流量包不仅能够抵扣云服务器ECS发生的流量 还能够抵扣弹性公网IP和负载均衡SLB发生的流量 同享流量包掩盖产品规模广 同享流量包
  • Qt 设置:两个窗口位置重合

    目录 Qt 设置 两个窗口位置重合 QT向界面中嵌套新的界面 QT向界面中嵌套新的界面 https www cnblogs com bob jianfeng p 11609012 html 第一步 先进入ui编辑界面 加入一个水平或者垂直的
  • 数据预处理与特征工程—10.图像切割与特征提取

    文章目录 引言 一 图像切割 二 特征提取 1 各阶颜色矩的计算公式 三 python实现 水质图像数据 百度网盘链接提取码 1234 引言 本文以水质图像为例 进行图像切割与特征提取 一 图像切割 一般情况下 采集到的水样图片包含盛水容器
  • 深入研究C++多态(虚函数和虚继承)

    文章目录 多态的引入 虚函数表 几种常见继承关系中的类内存分布 单继承 多继承 菱形继承 总结 作者 狗子孙 链接 https www jianshu com p 02183498a2c2 来源 简书 简书著作权归作者所有 任何形式的转载都
  • 如何彻底删除JetBrains系列软件教程

    mac安装JetBrains系列软件后 如果JetBrains系列软件出了问题需要重新安装 有时候软件删除重装后 JetBrains系列软件仍然会打不开的问题 很是困扰 接下来为您带来了mac上如何彻底删除IntelliJ IDEA等软件的
  • Char.IsDigit与Char.IsNumber的区别

    需要判断Char是否为数字 查看了下MSDN 发现有三种方法 Char IsDigit aChar 指示指定字符串中位于指定位置处的字符是否属于十进制数字类别 Char IsNumber aChar 指示指定字符串中位于指定位置的字符是否属
  • redis cluster知识

    一 架构 Redis Cluster使用 Slot 的概念 作为一个KV系统 它把每个key的值hash成0 16383之间的一个数 这个hash值被用来确定对应的数据存储在哪个节点中 集群中的每个节点都存储了一份类似路由表的东西 描述每个
  • 你知道bdsm吗

    是的 我知道 BDSM BDSM 是一种性癖好 通常指一组相关的性癖好 包括 较强的角色扮演 较轻的或较重的身体触摸 以及在性活动中的安全词 BDSM 也可以包括授权和自我控制 以及建立信任和良好的沟通 BDSM 可能涉及各种形式的挑逗 包
  • 4. Spring Boot Security角色管理持久化实现

    1 概述 在第三章里大家学会了怎么初步使用Spring Boot 结合Spring Security来实现权限控制和角色管理 但是我们发现无论是使用那种方式角色管理和权限控制全部是在 xml中或则 配置类中写的 没有实现持久化 本次就为大家
  • Conversion to Dalvik format failed with error

    Conversion to Dalvik format failed with error 1解决方法 第一种情况包导入错误 点击工程 gt build path gt libraries gt 选中android1 x 或者android

随机推荐

  • 解决 Android App 上架 Google play后 ,签名变更,第三方sdk无法登录

    1 将google 管理后台的 sha 1 证书值 记录下来 2 根据Google sha 1 证书值 获取 Facebook 的登录需要使用的散列值 使用以下工具 http tomeko net online tools hex to b
  • MySQL——idea连接MySQL

    选择MySQL 连接数据库 选择数据库 编写SQL语句
  • Anaconda 命令行常用指令

    Anaconda 命令行指令 Anaconda Prompt 命令行 一 基础指令 1 查看Anaconda安装版本 conda version 2 查看已经安装的环境 conda env list 方法1 conda info env 方
  • 网络基础知识

    网络编程 2 网络的体系结构 七层模型 四层模型 因为网络通信比较麻烦 所以网络采用分层思想 OSI开放系统互联网模型 七层模型 高层 应用层 表示层 会话层 低层 传输层 网络层 数据链路层 物理层 驱动 网卡 仅仅是一种理想状态 现实中
  • 文本情感分析竞赛(首次提交排名第6)

    之前花了半个小时做了个DataCastle上的基础竞赛题 然后提交结果后直接第六名 因此来分享一下 该文章之前记录在我的公众号上 原文链接 https mp weixin qq com s nIJ2begF2 5i WnT1PEM3w 数据
  • 变量的存储类型 auto register extern static

    说明 在C语言中 变量和函数都有数据类型和存储类型两个属性 数据类型规定了取值范围和运算 存储类型规定了占用内存的方式 变量的存储类型可分为静态存储和动态存储 静态存储 生命周期为程序的运行时间 动态存储 动态分配内存 用完就放 内存的区域
  • 每日一问:你想如何破坏单例模式?

    前言 1 单例是什么 单例模式 是一种创建型设计模式 目的是保证全局一个类只有一个实例对象 分为懒汉式和饿汉式 所谓懒汉式 类似于懒加载 需要的时候才会触发初始化实例对象 而饿汉式正好相反 项目启动 类加载的时候 就会创建初始化单例对象 1
  • ThreadLocal的理解和使用

    1 ThreadLocal初步 早在JDK 1 2的版本中就提供java lang ThreadLocal ThreadLocal为解决多线程程序的并发问题提供了一种新的思路 使用这个工具类可以很简洁地编写出优美的多线程程序 ThreadL
  • LightGBM算法详解(教你一文掌握LightGBM所有知识点)

    LightGBM Light Gradient Boosting Machine 是一款基于决策树算法的分布式梯度提升框架 为了满足工业界缩短模型计算时间的需求 LightGBM的设计思路主要是两点 减小数据对内存的使用 保证单个机器在不牺
  • Ubuntu 切换工作区快捷键失效

    首先安装 Compiz Config Settings Manager sudo apt get install compizconfig settings manager 在 桌面 板块下勾选Desktop Wall 以启用 点开Desk
  • 信息安全管理(CISP)—— 部分重点内容总结

    目录 一 风险评估方法 定量分析计算 原理 公式 例题 二 风险评估要素之间的关系 三 GB Z 24364 2009信息安全风险管理指南 四阶段 两过程 四 能力成熟度模型SSE CMM 域维 能力维 五 等级保护2 0的工作流程 系统定
  • 利用Intellij IDEA创建Spring的Helloworld

    引言 Spring 作为一款轻量级的框架 自然会赢得大多数开发者的信赖 笔者今天也开始学习Spring框架了 那么如何利用当今非常火的IDEA来开发Spring呢 按照国际惯例 先从Spring的HelloWorld开始吧 准备环境 Int
  • validation query

    public static void mySQLConfigPlugin Plugins me C3p0Plugin dbplugin createC3p0Plugin DruidPlugin dbplugin createDruidPlu
  • sql优化

    SQL总结 优化部分 1 应尽量避免在 where 子句中使用 或 lt gt 操作符 否则将引擎放弃使用索引而进行全表扫描 2 对查询进行优化 应尽量避免全表扫描 首先应考虑在 where 及 order by 涉及的列上建立索引 3 应
  • 模糊数学Python(一)模糊运算

    代码 import numpy as np def istype a 判断模糊矩阵a的类型 a np array a s np eye a shape 0 a shape 1 if a gt s all and a T a all retu
  • 安装12.04lts的两个问题总结

    因为在win7下有很多bug 老师叫我用Linux来完成项目的最后一步 啊啊啊 之前一直是在虚拟机里面搞 安装Ubuntu的过程中遇到了好多个问题 好吧好吧 下面总结一下 让遇到同样问题的朋友少走点弯路吧 1 分区问题 建立 主分区 之后
  • 数据操作之-dataframe常见操作:取行、列、切片、统计特征值

    import numpy as np import pandas as pd from pandas import from numpy import data DataFrame np arange 16 reshape 4 4 inde
  • Spring Boot 学习研究笔记(十八) 添加log4j2日志文件

    Spring Boot 添加log4j2日志文件 对于一个线上程序或者服务而言 重要的是要有日志输出 这样才能方便运维 而日志的输出需要有一定的规划 如日志命名 日志大小 日志分割的文件个数等 在SpringBoot的框架下 会使用log4
  • 栈头文件C语言

    Stack ADT h 栈模型头文件 数据类型定义 typedef char Name typedef struct stack node Name name struct stack node next Stack Node typede
  • GD32450i-EVAL学习笔记 6 - ADC

    目录 1 初始化ADC 1 1 使能RCU 1 2 设置频率 1 3 设置分辨率 1 4 设置数据对齐方式 1 5 使能扫描模式 1 6 设置触发模式 1 6 使能ADC 2 初始化通道规则 3 通道使能 4 软件触发使能 5 获取ADC的