ADC输入&PWMDAC亮度输出

由于总项目中涉及到ADC采集电压信息,因此必须调通ADC外设,而与ADC相对应的自然就是DAC了,在单片机中,非音频项目的DAC一般都用PWMDAC代替,也就是输出频率高且固定,占空比可变的PWM波,来实现改变LED灯亮度。


本次两个实验的外设都很好移植,为了节省时间,也因为项目中不需要用到PWM而只作为指示输出用,因此PWM输出的代码直接参考@一代睡神的崛起的帖子,不深究,着重分析ADC外设。


首先看看ADC的硬件连接,根据原理图可知,SDK默认的ADC引脚是H14(BGA编号),通过一个跳帽接到了一个精密电位器上面,如果是要看出明显效果的话当然不可能用精密电位器,应该选用平常使用的10K普通电位器,这种电位器也有3个接口,中间的接口连接ADC,两边的接口连接VCC和GND,由于板上没有输出VCC的2.54mm引脚,因此从UART2十针接口处取出5V电压:
<ignore_js_op> <ignore_js_op>

ADC外设选用SDK例程中的polling即循环阻塞采集例程,因为我的项目中ADC采集是循环进行的,为了不让CPU有太大的负担因此使用此例程,并将阻塞采集模式改成非阻塞轮询采集方式,下面再贴代码:
<ignore_js_op>

ADC初始化函数,直接使用SDK里面的默认参数进行初始化即可:
    /*
    *  config->enableAsynchronousClockOutput = true;
     *  config->enableOverWrite =               false;
       *  config->enableContinuousConversion =    false;
       *  config->enableHighSpeed =               false;
       *  config->enableLowPower =                false;
       *  config->enableLongSample =              false;
       *  config->referenceVoltageSource =        kADC_ReferenceVoltageSourceVref;
       *  config->samplePeriodMode =              kADC_SamplePeriod2or12Clocks;
       *  config->clockSource =                   kADC_ClockSourceAD;
       *  config->clockDriver =                   kADC_ClockDriver1;
       *  config->resolution =                    kADC_Resolution12Bit;
       */


  adc_config_t adcConfigStrcut;
  adc_channel_config_t adcChannelConfigStruct;
  ADC_GetDefaultConfig(&adcConfigStrcut);
  adcConfigStrcut.enableHighSpeed=true;
  ADC_Init(ADC1, &adcConfigStrcut);
  adcChannelConfigStruct.channelNumber = 3;
  adcChannelConfigStruct.enableInterruptOnConversionCompleted = false;


启用ADC1的通道3,组别0,12位数据,直接使用内部AD时钟不分频,直接使用VREF参考电压,使用高低速模式看不出区别,就用高速模式。连续采集


模式应该跟多通道有关,遵循官方SDK配置为false,不乱动。复写模式也遵循配置不动。


采集时改为轮询采集,不占用CPU时间片等待:
while (1)
{


                if(ADC_GetChannelStatusFlags(ADC1,0)==0)
                {
                        ADC_SetChannelConfig(ADC1,0,&adcChannelConfigStruct);
                        printf("ADC Value: %d\r\n",ADC1->R[0]);
                        QTMER4CH3_PWM_DutySet(14,5000,ADC1->R[0]/40.95);
                }
        }
}




然后是PWM输出代码,直接参考@一代睡神的崛起的代码:


qtmr_config_t qtimer4pwm_config;


unsigned char Calcu_2invo(unsigned char time)
{
    unsigned char i=0,value=1;
   
    if(time>7)time=7;
   
    if(time==0)
        value=1;
    else
    {
        for(i=0;i<time;i++)
        {
            value*=2;
        }
    }
        
    return value;
}


void QTMR4_CH3_PWM_Init(unsigned char prisrc,int clk, unsigned char duty)
{
    unsigned char fredivi=1;
   
    qtmr_primary_count_source_t qtimer_source;
    qtimer_source=(qtmr_primary_count_source_t)prisrc;
   
        //配置GPIO_B1_11为QTIMER3_TIMER1的输出引脚
        IOMUXC_SetPinMux(IOMUXC_GPIO_B1_11_QTIMER4_TIMER3,0);        
        
        //配置IO引脚GPIO_AD_B1_11的功能
        //低转换速度,驱动能力为R0/6,速度为100Mhz,关闭开路功能,使能pull/keepr
        //选择keeper功能,下拉100K Ohm,关闭Hyst
        IOMUXC_SetPinConfig(IOMUXC_GPIO_B1_11_QTIMER4_TIMER3,0x10B0);
   
    fredivi=Calcu_2invo(prisrc-8);
    //初始化QTIMER4
    QTMR_GetDefaultConfig(&qtimer4pwm_config);                  //先设置为默认配置,后面在根据实际情况配置
    qtimer4pwm_config.primarySource=qtimer_source;              //设置第一时钟源
    QTMR_Init(TMR4,kQTMR_Channel_3,&qtimer4pwm_config);         //初始化TIM4通道3
    QTMR_SetupPwm(TMR4,kQTMR_Channel_3,clk,duty,false,CLOCK_GetFreq(kCLOCK_IpgClk)/fredivi); //初始化PWM
    QTMR_StartTimer(TMR4,kQTMR_Channel_3,kQTMR_PriSrcRiseEdge); //通道3在primary时钟源的上升沿计数
}


void QTMER4CH3_PWM_DutySet(unsigned char prisrc,int clk, unsigned char duty)
{
    unsigned char fredivi=1;
    int srcclk,period,hightime,lowtime;
   
    fredivi=Calcu_2invo(prisrc-8);
    srcclk=CLOCK_GetFreq(kCLOCK_IpgClk)/fredivi;
   
    period=(srcclk/clk);                //一个PWM周期需要的计数值
    hightime=(period*duty)/100;         //一个PWM周期中高电平时间(计数值)
    lowtime=period-hightime;            //一个PWM周期中低电平时间(计数值)
   
    TMR4->CHANNEL[kQTMR_Channel_3].CMPLD1=lowtime;
    TMR4->CHANNEL[kQTMR_Channel_3].CMPLD2=hightime;
}


看看效果:
<ignore_js_op> <ignore_js_op>

posted on 2022-06-15 22:10  张凌001  阅读(394)  评论(0编辑  收藏  举报

导航