| 模数转换器(ADC)的主要功能是将模拟量转换为数字量,方便MCU进行处理。下面以CW32L083为例介绍CW系列的模数转换器的特点和功能,并提供演示实例。 
 概述 CW32L083内部集成一个12位精度、最高1M SPS转换速度的逐次逼近型模数转换器(SAR ADC),最多可将16路模拟信号转换为数字信号。现实世界中的绝大多数信号都是模拟量,如光、电、声、图像信号等,都要由ADC转换成数字信号,才能由MCU进行数字化处理。 
 主要特性 •12位精度  •可编程转换速度,最高达1M SPS  •16路输入转换通道:13路外部引脚输入-内置温度传感器-内置BGR 1.2V基准-1/3 VDDA电源电压  •4路参考电压源(Vref):-VDDA电源电压-ExRef(PB00)引脚电压-内置1.5V参考电压-内置2.5V参考电压  •采样电压输入范围:0~Vref 多种转换模式,全部支持转换累加功能-单次转换-多次转换-连续转换-序列扫描转换-序列断续转换  •支持单通道、序列通道两种通道选择,最大同时支持8个序列  •支持输入通道电压阈值监测 •内置信号跟随器,可转换高阻抗输入信号  •支持片内外设自动触发ADC转换  •支持ADC转换完成触发DMA 
 转换时序 ADC的转换时序如下图所示: 
 图 1 向ADC控制寄存器ADC_CR0的EN位域写入1,使能ADC模块。  ADC_CR0.EN由0变为1约40μs后ADC_ISR.READY标志位置1,表示模拟电路初始化完成,可以开始进行ADC转换。  向ADC启动寄存器ADC_START的START位域写入1,启动ADC转换,转换完成后硬件自动清零。  ADC工作时钟ADCCLK,由系统时钟PCLK经预分频器分频得到,通过控制寄存器ADC_CR0的CLK位域可选择1~128分频 
 
 工作模式 ADC控制寄存器ADC_CR0的MODE位域配置ADC工作模式 表 1
 
 启动ADC转换,可通过向ADC启动寄存器ADC_START的START位域写1;也可通过其他外设来触发。 
 实际案例 GTIM1定时器定时1S,定时器1S中断触发启动ADC转换,采样AIN1,并通过GTIM2以PWM方波输出ADC采样值:PWM占空比50%,周期为1Hz-5000Hz,对应ADC的0-4095采样值。 1.配置ADC测试IO口voidADC_PortInit(void) {     REGBITS_SET(CW_SYSCTRL->AHBEN, SYSCTRL_AHBEN_GPIOA_Msk); //打开GPIO时钟     REGBITS_SET(CW_SYSCTRL->APBEN2, SYSCTRL_APBEN2_ADC_Msk); //打开ADC时钟     PA01_ANALOG_ENABLE();//set PA01 as AIN1 INPUT } 
 
 2.LED初始化 void LED_Init(void) {     GPIO_InitTypeDef GPIO_InitStructure = {0};     REGBITS_SET(CW_SYSCTRL->AHBEN, SYSCTRL_AHBEN_GPIOC_Msk); //打开GPIO时钟     /* Configure the GPIO_LED pin */     GPIO_InitStructure.Pins = GPIO_PIN_2 | GPIO_PIN_3;     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;     GPIO_Init(CW_GPIOC, &GPIO_InitStructure);     PC02_SETLOW();//LEDs are off.     PC03_SETLOW(); } 3.PWM IO初始化
 void PWM_PortInit(void) {     GPIO_InitTypeDef GPIO_InitStructure = {0};     /* PA5 PWM 输出 */     __RCC_GPIOA_CLK_ENABLE();     /* Configure the PWM output pin */     GPIO_InitStructure.Pins = GPIO_PIN_5;     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;     GPIO_Init(CW_GPIOA, &GPIO_InitStructure);     PA05_AFx_GTIM2CH1(); } 
 4.GTIM初始化 void GTIM_Init(void) { GTIM_InitTypeDef GTIM_InitStruct = {0}; 
 //REGBITS_SET(CW_SYSCTRL->APBEN1, SYSCTRL_APBEN1_GTIM1_Msk); //打开GTIM1  __RCC_GTIM1_CLK_ENABLE(); //打开GTIM1时钟     GTIM_InitStruct.Mode = GTIM_MODE_TIME;     GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;     GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV1024;     GTIM_InitStruct.ReloadValue = 62499ul; //T=1s.     GTIM_InitStruct.ToggleOutState = DISABLE;     GTIM_TimeBaseInit(CW_GTIM1, >IM_InitStruct);     GTIM_ITConfig(CW_GTIM1, GTIM_IT_OV, ENABLE);     NVIC_ClearPendingIRQ(GTIM1_IRQn);     NVIC_EnableIRQ(GTIM1_IRQn);     NVIC_SetPriority(GTIM1_IRQn, 0x03); 
     __RCC_GTIM2_CLK_ENABLE();//打开GTIM2时钟     GTIM_InitStruct.ReloadValue = 0xFFFFu;     GTIM_InitStruct.ToggleOutState = ENABLE;     GTIM_TimeBaseInit(CW_GTIM2, >IM_InitStruct);     valuePeriod = GTIM_InitStruct.ReloadValue;     valuePosWidth = valuePeriod >> 1u;     GTIM_OCInit(CW_GTIM2, GTIM_CHANNEL1, GTIM_OC_OUTPUT_PWM_HIGH);     GTIM_SetCompare1(CW_GTIM2, valuePosWidth);     GTIM_Cmd(CW_GTIM2, ENABLE); } 
 5.主程序main uint16_t valueAdc; uint32_t valueAdcAcc; volatile uint8_t gFlagIrq; uint16_t gCntEoc = 0; uint8_t cntSample; float fTsDegree; uint32_t valuePeriod; uint32_t valuePosWidth; uint32_t valueReload = 0xFFFFu; int main(void) {   uint8_t res;     ADC_InitTypeDef ADC_InitStructure = {0};     ADC_WdtTypeDef ADC_WdtStructure = {0};     ADC_SingleChTypeDef ADC_SingleChStructure = {0};     RCC_HSI_Enable(RCC_HSIOSC_DIV6); //以下从HSI切换到PLL RCC_PLL_Enable(RCC_PLLSOURCE_HSI, 8000000UL, RCC_PLL_MUL_8);  //开启PLL,PLL源为HSI __RCC_FLASH_CLK_ENABLE();//打开FLASH时钟     FLASH_SetLatency(FLASH_Latency_3);     res = RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL); //切换系统时钟到PLL:64MHz。     ADC_PortInit();//配置ADC测试IO口     LED_Init();//LED初始化     PWM_PortInit();     GTIM_Init();     ADC_StructInit(&ADC_InitStructure); //ADC默认值初始化     ADC_WdtInit(&ADC_WdtStructure); //ADC模拟看门狗通道初始化     ADC_InitStructure.ADC_ClkDiv = ADC_Clk_Div128;    //ADCCLK:500KHz.     ADC_InitStructure.ADC_InBufEn = ADC_BufEnable;     ADC_InitStructure.ADC_SampleTime = ADC_SampTime10Clk;     ADC_SingleChStructure.ADC_DiscardEn = ADC_DiscardNull; //配置单通道转换模式     ADC_SingleChStructure.ADC_Chmux = ADC_ExInputCH1; //选择ADC转换通道     ADC_SingleChStructure.ADC_InitStruct = ADC_InitStructure;     ADC_SingleChStructure.ADC_WdtStruct = ADC_WdtStructure;     ADC_SingleChOneModeCfg(&ADC_SingleChStructure);     ADC_ITConfig(ADC_IT_EOC, ENABLE);     ADC_EnableIrq(ADC_INT_PRIORITY);     ADC_ClearITPendingAll();     ADC_Enable();//ADC使能     ADC_ExtTrigCfg(ADC_TRIG_GTIM1, ENABLE); //ADC外部中断触发源配置     GTIM_Cmd(CW_GTIM1, ENABLE);     while (1)     {         while (!(gFlagIrq & ADC_ISR_EOC_Msk));         gFlagIrq = 0u;         PC03_TOG();         valueAdc = ADC_GetConversionValue();         valueReload = ((4095u * 125000ul) / (4999u * valueAdc + 4095u) + 1) >> 1;         GTIM_SetCounterValue(CW_GTIM2, 0u);     //reset.         GTIM_SetReloadValue(CW_GTIM2, valueReload);         GTIM_SetCompare1(CW_GTIM2, valuePosWidth);         //等待ADC外部中断触发源启动下一次ADC转换     } } 
 6.实验展示 通用定时器GTIM1定时1s自动触发ADC模块进行转换,ADC通道为AIN1:PA01。 通用定时器GTIM2将AIN1的ADC采样值转换成频率可变的PWM方波,占空比50%,使用PA05作为PWM输出。ADC采样值为0时,PWM方波频率为1Hz;ADC采样值为4095时,PWM方波频率为5KHz。 
 图 2 
 |