天天看點

[單片機架構][bsp層][cx32l003][bsp_adc] ADC配置和使用

  1. ADC是模數轉換器轉換器 的供應商的英文簡稱,是一種能将模拟信号轉變為數字信号的電子元件。通常是将信号采樣并保持以後,再進行量化和編碼,這兩個過程是在轉化的同時實作的。

分辨率-說明AD對輸入信号的分辨能力,及數值部分的精度。一般模拟采樣中使用16位還是24位的AD晶片說的就是分辨率.

例如:輸入模拟電壓的變化範圍為0~3.3 V,輸出16位二進制數可以分辨的最小模拟電壓為3.3V / 216=0.05 mV;

  1. 轉化誤差-表示AD實際電壓與理論電壓的偏差,一般用最低有效位來表示,機關LSB,通常以相對誤差的形式出現,比如相對誤差≤±LSB/2,表明實際輸出的數字量和理論量誤差小于最低位的一半。

轉換精度-這裡一般用轉化誤差和分辨率來表述,具體就是AD最大量化過程中采用了四舍五入的方法及模拟處理部分的精度問題。

轉化時間-即從信号輸入開始到輸出穩定的信号所經過的時間。不同的AD準換的速度不同,根據實際要求來選型。

工作電壓和基準電壓(内部或者外部基準):工作電壓是AD晶片工作的額定電壓,關鍵的是基準電壓,又叫參考電壓,可以來之晶片内部又或者外部接入,其決定了AD的分辨率,所有基準電壓一定要穩。

子產品簡介

本晶片内部內建了一個 12 位高精度、高轉換速率的逐次逼近(SAR)型模數轉換器(ADC)子產品。具

有以下特性:

⚫ 12 位轉換精度

⚫ 1Msps 轉換速度

⚫ 8 路轉換通道:7 個引腳通道、1 個 VCAP 校準通道

⚫ 參考電壓(Refence Voltage)為電源電壓

⚫ ADC 的電壓輸入範圍:0-VREF

⚫ 3 種轉換模式:單次轉換、連續轉換、累加轉換

⚫ ADC 的轉換速率軟體可配

/********************************************************************************
* @file    bsp_adc.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-10
* @brief   NULL
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "RTE_Components.h"
#include CMSIS_device_header

#include "bsp_gpio.h"
#include "bsp_exti.h"
#include "bsp_adc.h"

/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private Define ------------------------------------------------------------*/
#define ADC0_CH_NUM                   8

#define CH_NUM  (BS_ADC0_CH0 + BS_ADC0_CH1 + BS_ADC0_CH2 + BS_ADC0_CH3 + BS_ADC0_CH4 + BS_ADC0_CH5 + BS_ADC0_CH6 + BS_ADC0_CH7)
/* Private Variables ---------------------------------------------------------*/
// ADC初始化狀态(0--deinit 1--init)
static bool g_adc_init = false;
// ADC采集資料存儲buff
uint16_t bsp_adc0_val[ADC0_CH_NUM] = {0};

// 定義ADC采集完畢回調函數
typedef void(*bsp_adc0_callback)(void);
static bsp_adc0_callback irq_callback;

/****************結構體定義****************/
#if BS_ADC0_EN
ADC_HandleTypeDef adc0_handle_t =
{
    .Instance                = BS_ADC0_BASE,
    .Init.SamplingTime       = ADC_SAMPLE_8CYCLE,           // 采樣周期
    .Init.ClkSel             = ADC_CLOCK_PCLK_DIV32,        // ADC時鐘分頻
    .Init.SingleContinueMode = ADC_MODE_CONTINUE,           // 連續轉換模式
    .Init.NbrOfConversion    = BS_ADC0_SAMPLING_TIMES,      // 連續轉換次數
    .Init.AutoAccumulation   = ADC_AUTOACC_DISABLE,         // 禁止ADC轉換結果自動累加
    .Init.CircleMode         = ADC_MULTICHANNEL_NONCIRCLE,  // 禁止ADC循環轉換模式
    .Init.ExternalTrigConv1  = ADC_SOFTWARE_START,          // 禁用自動觸發ADC轉換
};
#endif
/* External Variables --------------------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
#if BS_ADC0_EN
/**
 * @brief  ADC0初始化,并使能通道
 * @note   NULL
 * @retval None
 */
void bsp_adc0_init(void)
{
#if CH_NUM
    if (g_adc_init)
    {
        return;
    }
    __HAL_RCC_ADC_CLK_ENABLE();

    // 使能通道
    adc0_handle_t.Init.ContinueChannelSel =
#if BS_ADC0_CH0
                                           ADC_CONTINUE_CHANNEL_0|
#endif
#if BS_ADC0_CH1
                                           ADC_CONTINUE_CHANNEL_1|
#endif
#if BS_ADC0_CH2
                                           ADC_CONTINUE_CHANNEL_2|
#endif
#if BS_ADC0_CH3
                                           ADC_CONTINUE_CHANNEL_3|
#endif
#if BS_ADC0_CH4
                                           ADC_CONTINUE_CHANNEL_4|
#endif
#if BS_ADC0_CH5
                                           ADC_CONTINUE_CHANNEL_5|
#endif
#if BS_ADC0_CH6
                                           ADC_CONTINUE_CHANNEL_6|
#endif
#if BS_ADC0_CH7
                                           ADC_CONTINUE_CHANNEL_7|
#endif
                                           0;
    HAL_ADC_Init(&adc0_handle_t);

    // ADC comparison settings
    ADC_ThresholdConfTypeDef adc0_threshold_conf_t;
    adc0_threshold_conf_t.ITMode          = DISABLE;
    adc0_threshold_conf_t.CompareMode     = ADC_COMP_THRESHOLD_NONE;      // 禁止 ADC比較中斷控制
    HAL_ADC_ThresholdConfig(&adc0_handle_t, &adc0_threshold_conf_t);
    HAL_NVIC_SetPriority(BS_ADC0_IRQn, 2);
    HAL_NVIC_EnableIRQ(BS_ADC0_IRQn);       // 使能ADC中斷
    g_adc_init = true;
#endif
}

/**
 * @brief  ADC0功能關閉,并移除
 * @note   NULL
 * @retval None
 */
void bsp_adc0_deinit(void)
{
#if CH_NUM
    if (!g_adc_init)
    {
        return;
    }
    HAL_NVIC_DisableIRQ(BS_ADC0_IRQn);      // 關閉ADC中斷
    HAL_ADC_DeInit(&adc0_handle_t);
    g_adc_init = false;
#endif
}

/**
 * @brief  ADC0 啟動采樣功能
 * @note   NULL
 * @retval None
 */
void bsp_adc0_start(void)
{
#if CH_NUM
    if (!g_adc_init)
    {
        return;
    }
    HAL_ADC_Start_IT(&adc0_handle_t);    // 啟動ADC中斷轉換
#endif
}

#else
void bsp_adc0_init(void)
{
}

void bsp_adc0_deinit(void)
{
}

void bsp_adc0_start(void)
{
}
#endif

/**
  * @brief  Initializes the ADC MSP.
  * @param  hadc: ADC handle
  * @retval None
  */
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
#if BS_ADC0_CH0
    BS_ADC0_CH0_GPIO_CLK_ENABLE();
    bsp_gpio_init_adc(BS_ADC0_CH0_GPIO_PORT, BS_ADC0_CH0_PIN);
#endif
#if BS_ADC0_CH1
    BS_ADC0_CH1_GPIO_CLK_ENABLE();
    bsp_gpio_init_adc(BS_ADC0_CH1_GPIO_PORT, BS_ADC0_CH1_PIN);
#endif
#if BS_ADC0_CH2
    BS_ADC0_CH2_GPIO_CLK_ENABLE();
    bsp_gpio_init_adc(BS_ADC0_CH2_GPIO_PORT, BS_ADC0_CH2_PIN);
#endif
#if BS_ADC0_CH3
    BS_ADC0_CH3_GPIO_CLK_ENABLE();
    bsp_gpio_init_adc(BS_ADC0_CH3_GPIO_PORT, BS_ADC0_CH3_PIN);
#endif
#if BS_ADC0_CH4
    BS_ADC0_CH4_GPIO_CLK_ENABLE();
    bsp_gpio_init_adc(BS_ADC0_CH4_GPIO_PORT, BS_ADC0_CH4_PIN);
#endif
#if BS_ADC0_CH5
    BS_ADC0_CH5_GPIO_CLK_ENABLE();
    bsp_gpio_init_adc(BS_ADC0_CH5_GPIO_PORT, BS_ADC0_CH5_PIN);
#endif
#if BS_ADC0_CH6
    BS_ADC0_CH6_GPIO_CLK_ENABLE();
    bsp_gpio_init_adc(BS_ADC0_CH6_GPIO_PORT, BS_ADC0_CH6_PIN);
#endif
// #if BS_ADC0_CH7
//     BS_ADC0_CH7_GPIO_CLK_ENABLE()
//     bsp_gpio_init_adc(BS_ADC0_CH7_GPIO_PORT, BS_ADC0_CH7_PIN);
// #endif
}

#if BS_ADC0_CH0
void HAL_ADC_MultiChannel0_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[0] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_0);
    }
}
#endif

#if BS_ADC0_CH1
void HAL_ADC_MultiChannel1_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[1] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_1);
    }
}
#endif

#if BS_ADC0_CH2
void HAL_ADC_MultiChannel2_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[2] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_2);
    }
}
#endif

#if BS_ADC0_CH3
void HAL_ADC_MultiChannel3_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[3] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_3);
    }
}
#endif

#if BS_ADC0_CH4
void HAL_ADC_MultiChannel4_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[4] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_4);
    }
}
#endif

#if BS_ADC0_CH5
void HAL_ADC_MultiChannel5_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[5] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_5);
    }
}
#endif

#if BS_ADC0_CH6
void HAL_ADC_MultiChannel6_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[6] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_6);
    }
}
#endif

#if BS_ADC0_CH7
void HAL_ADC_MultiChannel7_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        bsp_adc0_val[7] = HAL_ADC_GetValue(hadc, ADC_CONTINUE_CHANNEL_7);
    }
}
#endif

/**
 * @brief  [重定義] ADC采樣完畢回調函數
 * @note   NULL
 * @param  hadc: ADC handle
 * @retval None
 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == BS_ADC0_BASE)
    {
        if (irq_callback)
        {
            irq_callback();
        }
    }
}

/**
 * @brief  得到ADC0采樣值
 * @note   NULL
 * @param  ch_num: 通道值
 * @retval 通道對應的ADC值
 */
uint16_t bsp_adc0_get_ch_val(uint8_t ch_num)
{
    if (ch_num >= ADC0_CH_NUM)
    {
        return 0xFFFF;
    }
    return bsp_adc0_val[ch_num];
}

/**
 * @brief  注冊ADC0采樣完畢回調函數
 * @note   NULL
 * @param  *event: 綁定回調事件
 * @retval 0--失敗 1--成功
 */
bool bsp_adc0_irq_callback(void *event)
{
    if (irq_callback != NULL)
    {
        return false;
    }
    else
    {
        irq_callback = (bsp_adc0_callback)event;
    }
    return true;
}      
/********************************************************************************
* @file    bsp_adc.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-10
* @brief   ADC操作
********************************************************************************/

#ifndef __BSP_ADC_H
#define __BSP_ADC_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

/* Public Function Prototypes -----------------------------------------------*/

void bsp_adc0_init(void);
void bsp_adc0_deinit(void);

void bsp_adc0_start(void);

uint16_t bsp_adc0_get_ch_val(uint8_t ch_num);

bool bsp_adc0_irq_callback(void *event);

#endif