• [单片机框架][bsp层][N32G4FR][bsp_adc] ADC配置和使用


    ADC 介绍

    12 位 ADC 是一种高速逐次逼近型模拟数字转换器。它有多个通道。各通道的 A/D 转换可以单次、连续、
    扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
    模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
    ADC 的输入时钟不得超过 72MHz。

    ADC 主要特征

     支持最多 2 个 ADC,支持单端输入和差分输入,可测量 16 个外部和 3 个内部信号源
     ADC1 支持 9 个外部通道,ADC2 支持 7 个外部通道
     支持 12 位、10 位、8 位、6 位分辨率可配置
     12bit 分辨率下最高采样速率 5.14MSPS
     10bit 分辨率下最高采样速率 6MSPS
     8bit 分辨率下最高采样速率 7.2MSPS
     6bit 分辨率下最高采样速率 9MSPS
     ADC 时钟源分为工作时钟源、采样时钟源和计时时钟源
     仅可配置 AHB_CLK 作为工作时钟源,最高可到 144MHz
     可配置 PLL 作为采样时钟源,最高可到 72MHz,支持分频 1,2,4,6,8,10,12,16,32, 64,128,256
     可配置 AHB_CLK 作为采样时钟源,最高可到 72MHz,支持分频 1,2,4,6,8,10,12,16,32
     计时时钟用于内部计时功能,频率必须配置成 1MHz
     支持定时器触发 ADC 采样
     转换结束、注入转换结束和发生模拟看门狗事件时产生中断
     单次和连续转换模式
     从通道 0 到通道 N 的自动扫描模式
     支持自校准
     带内嵌数据一致性的数据对齐
     采样间隔可以按通道分别编程
     规则转换和注入转换均有外部触发选项
     间断模式
     双重模式,ADC1 和 ADC2 组合
     ADC 供电要求:1.8V 到 3.6V
     ADC 输入范围:VREF-≤ VIN ≤ VREF+
     规则通道转换期间有 DMA 请求产生。

    ADC 功能描述

    下图为一个 ADC 模块的框图,表 9-1 为 ADC 引脚的说明。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    ADC 开关控制

    用户必须等待 PowerUp 过程完成才可以进入下一步的操作,可以通过查询 ADC_CTRL3 里面的 RDY 确认
    是否上电完成。
    通过设置 ADC_CTRL2 寄存器的 ON 位可给 ADC 上电。当第一次设置 ON 位时,它将 ADC 从断电状态下
    唤醒。ADC 上电延迟一段时间后(tSTAB),再次设置 ON 位时开始进行转换。
    通过清除 ON 位可以停止转换,并将 ADC 置于断电模式。在这个模式中,ADC 几乎不耗电(仅几个 μA)。
    用户可以通过查询 ADC_CTRL3 里面的 PDRDY 确认是否下电完成。
    在 ADC Disable 的时候默认都是 PowerDown 模式,这个模式下只要不断电,不需要重新校正,校正值会在ADC 自动保持。为了进一步的降低功耗 ,ADC 有设计一个深睡眠模式。会在 ADC Disable 进入深睡眠模式,ADC 内部的校正值会丢失,需要重新校正。深睡眠模式可以省大概 0.2μA 的功耗 ,注意,当在双 ADC 模式时,最好双 ADC 都选同一种睡眠模式。控制 ADC 深睡眠模式的寄存器ADC_CTRL3.DPWMOD。

    内部通道

     温度传感器和通道 ADC1_IN16 相连接
     VBAT/2 和通道 ADC1_IN17 相连接
     内部参照电压 VREFINT 和 ADCx_IN18 相连接
    可以按注入或规则通道对内部通道进行转换。
    注意:温度传感器,VBAT/2 只能出现在主 ADC1 中。

    #include "n32g4fr.h"
    #include "n32g4fr_adc.h"
    #include "errorno.h"
    #include "bsp_adc.h"
    
    #define ADC_REGU_CH_SEQ_LEN     1
    #define ADC_WAIT_RET_TIMEOUT    1000
    #define ADC_RET_INIT_VALUE      0xAB
    #define ADC_VDD_POWER_MV        3299
    #define ADC_DATA_MAX            4095
    #define ADC_READ_INVALID_TIMES  5
    /*******************************ADC1 config*****************************/
    #define ADC1_MODULE              ADC1
    #define ADC1_IN_PORT             GPIOA
    #define ADC1_IN_PIN              (GPIO_PIN_2 | GPIO_PIN_6)
    #define ADC1_IN_PORT_RCC         RCC_APB2_PERIPH_GPIOA
    #define ADC1_RCC                 RCC_AHB_PERIPH_ADC1
    
    /*******************************ADC2 config*****************************/
    #define ADC2_MODULE              ADC2
    #define ADC2_IN_PORT             GPIOA
    #define ADC2_IN_PIN              (GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_7)
    #define ADC2_IN_PORT_RCC         RCC_APB2_PERIPH_GPIOA
    #define ADC2_RCC                 RCC_AHB_PERIPH_ADC2
    
    typedef struct {
        ADC_Module* ADCx;
        GPIO_Module* gpio_x;
        uint16_t gpio_pin;
        uint32_t gpio_rcc;
        uint32_t adcx_rcc;
    } adc_config_t;
    
    const adc_config_t g_adc_configs[BSP_ADC_NUM] =
    {
        {
            .ADCx = ADC1,
            .gpio_x = ADC1_IN_PORT,
            .gpio_rcc = ADC1_IN_PORT_RCC,
            .gpio_pin = ADC1_IN_PIN,
            .adcx_rcc = ADC1_RCC,
        },
        {
            .ADCx = ADC2,
            .gpio_x = ADC2_IN_PORT,
            .gpio_rcc = ADC2_IN_PORT_RCC,
            .gpio_pin = ADC2_IN_PIN,
            .adcx_rcc = ADC2_RCC,
        }
    };
    
    void bsp_adc_io_rcc_enable(bsp_adc_t bsp_adc)
    {
        RCC_EnableAPB2PeriphClk(g_adc_configs[bsp_adc].gpio_rcc, ENABLE);
    }
    
    void bsp_adc_io_config(bsp_adc_t bsp_adc)
    {
        GPIO_InitType GPIO_InitStruct;
    
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStruct.Pin = g_adc_configs[bsp_adc].gpio_pin;
        GPIO_InitPeripheral(g_adc_configs[bsp_adc].gpio_x, &GPIO_InitStruct);
    }
    
    void bsp_adc_rcc_enable(bsp_adc_t bsp_adc)
    {
        RCC_EnableAHBPeriphClk(g_adc_configs[bsp_adc].adcx_rcc, ENABLE);
        RCC_ConfigHclk(RCC_SYSCLK_DIV1);
        RCC_ConfigAdcHclk(RCC_ADCHCLK_DIV32);
        RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSI, RCC_ADC1MCLK_DIV8);
    }
    
    void bsp_adc_init(bsp_adc_t bsp_adc)
    {
        ADC_InitType ADC_InitType_data;
        ADC_Module* ADCx = g_adc_configs[bsp_adc].ADCx;
        int timeout = 0;
    
        bsp_adc_io_rcc_enable(bsp_adc);
        bsp_adc_io_config(bsp_adc);
        bsp_adc_rcc_enable(bsp_adc);
    
        ADC_InitType_data.WorkMode = ADC_WORKMODE_INDEPENDENT;
        ADC_InitType_data.ContinueConvEn = DISABLE;
        ADC_InitType_data.ChsNumber = ADC_REGU_CH_SEQ_LEN;
        ADC_InitType_data.DatAlign = ADC_DAT_ALIGN_R;
        ADC_InitType_data.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE;
        ADC_InitType_data.MultiChEn = ENABLE;
        ADC_DeInit(ADCx);
        ADC_Init(ADCx, &ADC_InitType_data);
    
        ADC_Enable(ADCx, ENABLE);
        timeout = 0;
        while (RESET == ADC_GetFlagStatusNew(ADCx, ADC_FLAG_RDY))
        {
            timeout ++;
            if (timeout > ADC_WAIT_RET_TIMEOUT)
            {
                return ;
            }
        }
    
        ADC_StartCalibration(ADCx);
        timeout = 0;
        while (SET == ADC_GetCalibrationStatus(ADCx))
        {
            timeout ++;
            if (timeout > ADC_WAIT_RET_TIMEOUT)
            {
                return ;
            }
        }
    }
    
    uint16_t bsp_adc_get_one_data(bsp_adc_t bsp_adc, uint8_t ADC_Channel)
    {
        int32_t timeout = 0;
        uint32_t adc_data = ADC_RET_INIT_VALUE;
        ADC_Module* ADCx = g_adc_configs[bsp_adc].ADCx;
    
        ADC_ConfigRegularChannel(ADCx, ADC_Channel, 1, ADC_SAMP_TIME_239CYCLES5);
        ADC_ClearFlag(ADCx, ADC_FLAG_ENDC);
    
        //ADC_Enable(ADCx,ENABLE)
        ADC_EnableSoftwareStartConv(ADCx, ENABLE);
    
        timeout = 0;
        while (RESET == ADC_GetFlagStatus(ADCx, ADC_FLAG_ENDC))
        {
            timeout ++;
            if (timeout > ADC_WAIT_RET_TIMEOUT)
            {
                return adc_data;
            }
        }
        adc_data = ADC_GetDat(ADCx);
    
        ADC_ClearFlag(ADCx, ADC_FLAG_ENDC);
    
        return adc_data;
    }
    
    uint16_t bsp_adc_get_data(bsp_adc_t bsp_adc, uint8_t ADC_Channel)
    {
        uint32_t invalid_read_times = 0;
    
        for (invalid_read_times = 0;invalid_read_times < ADC_READ_INVALID_TIMES;invalid_read_times++)
        {
            bsp_adc_get_one_data(bsp_adc, ADC_Channel);
        }
        return bsp_adc_get_one_data(bsp_adc, ADC_Channel);
    }
    
    uint16_t bsp_adc_convert_to_mvoltage(bsp_adc_t bsp_adc, uint16_t adc_data)
    {
        uint16_t adc_vref = bsp_adc_get_data(bsp_adc, ADC_CH_0);
    
        if(adc_vref != 0)
        {
            return adc_data * ADC_VDD_POWER_MV / adc_vref;
        }
        else
        {
            return adc_data * ADC_VDD_POWER_MV / ADC_DATA_MAX;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    #ifndef __BSP_ADC_H__
    #define __BSP_ADC_H__
    
    #include "typedefs.h"
    
    typedef enum {
        BSP_ADC_1 = 0,
        BSP_ADC_2,
        BSP_ADC_NUM
    } bsp_adc_t;
    
    void bsp_adc_init(bsp_adc_t bsp_adc);
    uint16_t bsp_adc_get_data(bsp_adc_t bsp_adc, uint8_t ADC_Channel);
    uint16_t bsp_adc_convert_to_mvoltage(bsp_adc_t bsp_adc, uint16_t adc_data);
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    操作系统原理,文件系统的实现,磁盘上和内存中的内容布局,文件目录的检索过程,目录项分解法
    【设计模式】第3讲--工厂方法模式
    软考 系统架构设计师系列知识点之杂项集萃(26)
    官方mysqld_exporter支持抓取多MySQL实例监控指标
    Qt指示器设置
    设计模式-原型模式
    云可观测性安全平台——掌动智能
    机器学习期中考试
    axios 实现请求 loading 效果
    spring 事件监听使用@TransactionalEventListener,解决同一个线程中拿不到另一个事务的数据(让之前的事务提交)
  • 原文地址:https://blog.csdn.net/qq_29246181/article/details/126776193