ADC简介
ADC 就是将模拟信号转换成数字信号的电路,我们也称其为模数转换器。
目前我使用的ADC是12位的,而12位的ADC模拟量范围是是2^12也就是4096,也就是说我的12位ADC模拟量的范围是0~4096.
具体实现
.h头文件编写
#include "hc32_ddl.h"
//Pin角定义
#define BOARD_ADC_CH0_PORT (PortC)
#define BOARD_ADC_CH0_PIN (Pin03)
#define BOARD_ADC_CH0_CH (ADC1_CH13)
#define BOARD_ADC_CH1_PORT (PortC)
#define BOARD_ADC_CH1_PIN (Pin01)
#define BOARD_ADC_CH1_CH (ADC1_CH11)
#define BOARD_ADC_CH2_PORT (PortC)
#define BOARD_ADC_CH2_PIN (Pin02)
#define BOARD_ADC_CH2_CH (ADC1_CH12)
extern void adc_init(void);
extern uint16_t adc_value[3];
c文件编写
#include "bsp_adc.h"
#include "bsp_irq.h"
#define ADC_CH_COUNT 3 //adc采集通道数量
uint16_t adc_value[3]; //存储采集数值buf
static void adc_pin_init(void); //ADC init pin
static void AdcClockConfig(void); //ADC intit clk
static void AdcInitConfig(void); //ADC initial configuration.
static void AdcChannelConfig(void); //ADC channel configuration.
static void AdcTriggerConfig(void); //ADC trigger source configuration.
static void adc_dma_config(void); //ADC config DMA
void adc_init(void)
{
AdcInitConfig();
adc_pin_init();
AdcChannelConfig();
AdcTriggerConfig();
adc_dma_config();
ADC_StartConvert(M4_ADC1);
}
static void adc_pin_init(void)
{
stc_port_init_t stcPortInit;
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPullUp = Disable;
stcPortInit.enPinMode = Pin_Mode_Ana;
PORT_Init(BOARD_ADC_CH0_PORT, BOARD_ADC_CH0_PIN, &stcPortInit);
PORT_Init(BOARD_ADC_CH1_PORT, BOARD_ADC_CH1_PIN, &stcPortInit);
PORT_Init(BOARD_ADC_CH2_PORT, BOARD_ADC_CH2_PIN, &stcPortInit);
}
/**
*******************************************************************************
** \brief ADC clock configuration.
**
** \note 1) ADCLK max frequency is 60MHz.
** 2) If PCLK2 and PCLK4 are selected as the ADC clock,
** the following conditions must be met:
** a. ADCLK(PCLK2) max 60MHz;
** b. PCLK4 : ADCLK = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4
**
******************************************************************************/
static void AdcClockConfig(void)
{
#if (ADC_CLK == ADC_CLK_PCLK)
stc_clk_sysclk_cfg_t stcSysclkCfg;
/* Set bus clock division, depends on the system clock frequency. */
stcSysclkCfg.enHclkDiv = ClkSysclkDiv1; // 168MHz
stcSysclkCfg.enExclkDiv = ClkSysclkDiv2; // 84MHz
stcSysclkCfg.enPclk0Div = ClkSysclkDiv1; // 168MHz
stcSysclkCfg.enPclk1Div = ClkSysclkDiv2; // 84MHz
stcSysclkCfg.enPclk2Div = ClkSysclkDiv4; // 42MHz
stcSysclkCfg.enPclk3Div = ClkSysclkDiv4; // 42MHz
stcSysclkCfg.enPclk4Div = ClkSysclkDiv1; // 84MHz.
CLK_SysClkConfig(&stcSysclkCfg);
CLK_SetPeriClkSource(ClkPeriSrcPclk);
#elif (ADC_CLK == ADC_CLK_MPLLQ)
stc_clk_xtal_cfg_t stcXtalCfg;
stc_clk_mpll_cfg_t stcMpllCfg;
if (CLKSysSrcMPLL == CLK_GetSysClkSource())
{
/*
* Configure MPLLQ(same as MPLLP and MPLLR) when you
* configure MPLL as the system clock.
*/
}
else
{
/* Use XTAL as MPLL source. */
stcXtalCfg.enFastStartup = Enable;
stcXtalCfg.enMode = ClkXtalModeOsc;
stcXtalCfg.enDrv = ClkXtalLowDrv;
CLK_XtalConfig(&stcXtalCfg);
CLK_XtalCmd(Enable);
/* Set MPLL out 240MHz. */
stcMpllCfg.pllmDiv = 1u;
/* mpll = 8M / pllmDiv * plln */
stcMpllCfg.plln = 30u;
stcMpllCfg.PllpDiv = 16u;
stcMpllCfg.PllqDiv = 16u;
stcMpllCfg.PllrDiv = 16u;
CLK_SetPllSource(ClkPllSrcXTAL);
CLK_MpllConfig(&stcMpllCfg);
CLK_MpllCmd(Enable);
}
CLK_SetPeriClkSource(ClkPeriSrcMpllp);
#elif (ADC_CLK == ADC_CLK_UPLLR)
stc_clk_xtal_cfg_t stcXtalCfg;
stc_clk_upll_cfg_t stcUpllCfg;
MEM_ZERO_STRUCT(stcXtalCfg);
MEM_ZERO_STRUCT(stcUpllCfg);
/* Use XTAL as UPLL source. */
stcXtalCfg.enFastStartup = Enable;
stcXtalCfg.enMode = ClkXtalModeOsc;
stcXtalCfg.enDrv = ClkXtalLowDrv;
CLK_XtalConfig(&stcXtalCfg);
CLK_XtalCmd(Enable);
/* Set UPLL out 240MHz. */
stcUpllCfg.pllmDiv = 2u;
/* upll = 8M(XTAL) / pllmDiv * plln */
stcUpllCfg.plln = 60u;
stcUpllCfg.PllpDiv = 16u;
stcUpllCfg.PllqDiv = 16u;
stcUpllCfg.PllrDiv = 16u;
CLK_SetPllSource(ClkPllSrcXTAL);
CLK_UpllConfig(&stcUpllCfg);
CLK_UpllCmd(Enable);
CLK_SetPeriClkSource(ClkPeriSrcUpllr);
#endif
}
/**
*******************************************************************************
** \brief ADC initial configuration.
**
******************************************************************************/
static void AdcInitConfig(void)
{
stc_adc_init_t stcAdcInit;
MEM_ZERO_STRUCT(stcAdcInit);
stcAdcInit.enResolution = AdcResolution_12Bit;
stcAdcInit.enDataAlign = AdcDataAlign_Right;
stcAdcInit.enAutoClear = AdcClren_Enable;
stcAdcInit.enScanMode = AdcMode_SAContinuous;
stcAdcInit.enRschsel = AdcRschsel_Restart;
/* 1. Enable ADC1. */
PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
/* 2. Initialize ADC1. */
ADC_Init(M4_ADC1, &stcAdcInit);
}
/**
*******************************************************************************
** \brief ADC channel configuration.
**
******************************************************************************/
static void AdcChannelConfig(void)
{
stc_adc_ch_cfg_t stcChCfg;
uint8_t au8Adc1SaSampTime[3] = { 0x60, 0x60, 0x60 };
MEM_ZERO_STRUCT(stcChCfg);
stcChCfg.u32Channel = BOARD_ADC_CH0_CH | BOARD_ADC_CH1_CH | BOARD_ADC_CH2_CH;
stcChCfg.u8Sequence = ADC_SEQ_A;
stcChCfg.pu8SampTime = au8Adc1SaSampTime;
ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
// ADC_ConfigAvg(M4_ADC1, AdcAvcnt_64);
// ADC_AddAvgChannel(M4_ADC1, BOARD_ADC_CH0_CH | BOARD_ADC_CH1_CH | BOARD_ADC_CH2_CH);
}
/**
*******************************************************************************
** \brief ADC trigger source configuration.
**
******************************************************************************/
static void AdcTriggerConfig(void)
{
stc_adc_trg_cfg_t stcTrgCfg;
MEM_ZERO_STRUCT(stcTrgCfg);
/*
* If select an event(@ref en_event_src_t) to trigger ADC,
* AOS must be enabled first.
*/
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
/* ADC1 sequence A will be started by software. */
ADC_TriggerSrcCmd(M4_ADC1, ADC_SEQ_A, Disable);
}
/**
*******************************************************************************
** \brief Config the pin which is mapping the channel to analog or digit mode.
**
******************************************************************************/
static void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx,
uint32_t u32Channel,
en_pin_mode_t enMode)
{
uint8_t u8ChIndex;
#if (ADC_CH_REMAP)
uint8_t u8AdcPin;
#else
uint8_t u8ChOffset = 0u;
#endif
if (M4_ADC1 == ADCx)
{
u32Channel &= ADC1_PIN_MASK_ALL;
}
else
{
u32Channel &= ADC2_PIN_MASK_ALL;
#if (!ADC_CH_REMAP)
u8ChOffset = 4u;
#endif
}
u8ChIndex = 0u;
while (0u != u32Channel)
{
if (u32Channel & 0x1ul)
{
#if (ADC_CH_REMAP)
u8AdcPin = ADC_GetChannelPinNum(ADCx, u8ChIndex);
AdcSetPinMode(u8AdcPin, enMode);
#else
AdcSetPinMode((u8ChIndex + u8ChOffset), enMode);
#endif
}
u32Channel >>= 1u;
u8ChIndex++;
}
}
/**
*******************************************************************************
** \brief Set an ADC pin as analog input mode or digit mode.
**
******************************************************************************/
static void AdcSetPinMode(uint8_t u8AdcPin, en_pin_mode_t enMode)
{
en_port_t enPort = PortA;
en_pin_t enPin = Pin00;
bool bFlag = true;
stc_port_init_t stcPortInit;
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = enMode;
stcPortInit.enPullUp = Disable;
switch (u8AdcPin)
{
case ADC1_IN0:
enPort = PortA;
enPin = Pin00;
break;
case ADC1_IN1:
enPort = PortA;
enPin = Pin01;
break;
case ADC1_IN2:
enPort = PortA;
enPin = Pin02;
break;
case ADC1_IN3:
enPort = PortA;
enPin = Pin03;
break;
case ADC12_IN4:
enPort = PortA;
enPin = Pin04;
break;
case ADC12_IN5:
enPort = PortA;
enPin = Pin05;
break;
case ADC12_IN6:
enPort = PortA;
enPin = Pin06;
break;
case ADC12_IN7:
enPort = PortA;
enPin = Pin07;
break;
case ADC12_IN8:
enPort = PortB;
enPin = Pin00;
break;
case ADC12_IN9:
enPort = PortB;
enPin = Pin01;
break;
case ADC12_IN10:
enPort = PortC;
enPin = Pin00;
break;
case ADC12_IN11:
enPort = PortC;
enPin = Pin01;
break;
case ADC1_IN12:
enPort = PortC;
enPin = Pin02;
break;
case ADC1_IN13:
enPort = PortC;
enPin = Pin03;
break;
case ADC1_IN14:
enPort = PortC;
enPin = Pin04;
break;
case ADC1_IN15:
enPort = PortC;
enPin = Pin05;
break;
default:
bFlag = false;
break;
}
if (true == bFlag)
{
PORT_Init(enPort, enPin, &stcPortInit);
}
}
// DMA2 CH0 ~ CH2
static void adc_dma_config(void)
{
stc_dma_config_t stcDmaCfg;
MEM_ZERO_STRUCT(stcDmaCfg);
stcDmaCfg.u16BlockSize = ADC_CH_COUNT;
stcDmaCfg.u16TransferCnt = 0u;
stcDmaCfg.u32SrcAddr = (uint32_t)(&M4_ADC1->DR11);
stcDmaCfg.u32DesAddr = (uint32_t)(&adc_value[0]);
stcDmaCfg.u16DesRptSize = ADC_CH_COUNT;
stcDmaCfg.u16SrcRptSize = ADC_CH_COUNT;
stcDmaCfg.u32DmaLlp = 0u;
stcDmaCfg.stcSrcNseqCfg.u16Cnt = 0u;
stcDmaCfg.stcSrcNseqCfg.u32Offset = 0u;
stcDmaCfg.stcDesNseqCfg.u16Cnt = 0u;
stcDmaCfg.stcDesNseqCfg.u32Offset = 0u;
stcDmaCfg.stcDmaChCfg.enSrcInc = AddressIncrease;
stcDmaCfg.stcDmaChCfg.enDesInc = AddressIncrease;
stcDmaCfg.stcDmaChCfg.enSrcRptEn = Enable;
stcDmaCfg.stcDmaChCfg.enDesRptEn = Enable;
stcDmaCfg.stcDmaChCfg.enSrcNseqEn = Disable;
stcDmaCfg.stcDmaChCfg.enDesNseqEn = Disable;
stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma16Bit;
stcDmaCfg.stcDmaChCfg.enLlpEn = Disable;
stcDmaCfg.stcDmaChCfg.enIntEn = Disable;
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_DMA2, Enable);
DMA_InitChannel(M4_DMA2, DmaCh3, &stcDmaCfg);
DMA_Cmd(M4_DMA2, Enable);
DMA_ChannelCmd(M4_DMA2, DmaCh3, Enable);
DMA_ClearIrqFlag(M4_DMA2, DmaCh3, TrnCpltIrq);
/* AOS must be enabled to use DMA */
/* AOS enabled at first. */
/* If you have enabled AOS before, then the following statement is not needed. */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
DMA_SetTriggerSrc(M4_DMA2, DmaCh3, EVT_ADC1_EOCA);
}
具体使用
int main()
{
// ..... //init other config
adc_init(); //init adc
while(1)
{
//deal adc value (adc_value)
}
}