打印
[电机控制专用MCU]

电机控制基础 - 基于PWM触发ADC采样的设计与实现

[复制链接]
104|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

引言

在电机控制、电源管理、数字电源转换等应用中,精准的时序控制高精度信号采集是核心需求。通过PWM信号触发ADC采样,可实现硬件级同步,减少CPU干预并提高系统效率。本文以通用MCU为例,解析PWM触发ADC采样的实现方法。


一、PWM触发ADC原理

1.1 核心机制

  • 硬件联动:利用MCU内部定时器(Timer)的PWM模块与ADC模块直接联动。
  • 触发时机:在PWM周期中的特定时刻(如上升沿、下降沿或中心点)生成触发信号,启动ADC转换。
  • 优势:消除软件延迟,确保采样时刻与PWM波形严格同步。

1.2 典型应用场景

  • 电机控制:在PWM驱动的逆变器中,于特定时刻采集相电流。
  • 开关电源:在MOSFET关断后采样输出电压,避免开关噪声。
  • 谐振电路:捕捉LC振荡波形的关键点。

二、硬件设计要点

2.1 MCU资源分配

  • 定时器选择:需支持PWM输出且具备触发输出(TRGO)功能,如APM32的TIM1/TIM8高级定时器。
  • ADC通道配置:选择支持外部触发的ADC模块,并与定时器触发源绑定。
  • 引脚映射:确保PWM输出引脚与ADC输入通道无冲突。

2.2 信号链设计

PWM Generation → Timer TRGO → ADC External Trigger → ADC Conversion → DMA/CPU Read

注:推荐使用DMA传输ADC数据以减少CPU负载。

2.3 APM32F035特点

image.png

image.png


三、软件实现步骤(以APM32F035库为例)

3.1 初始化PWM

(1) PWM 通用配置

    TMR_TimeBase_T    TIM_TimeBaseInitStructure; 
    TMR_OCConfig_T    TIM_OCInitStructure; 
    TMR_BDTInit_T     TIM_BDTRInitStructure;

    //使能外设时钟
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG  | RCM_APB2_PERIPH_TMR1 );

    /* 设置PWM clock 分频为1 分频,选用中心对齐模式22,设置重复计数器为11,*/
    TIM_TimeBaseInitStructure.period            = u16_Period;  //(SYSTEM_FREQUENCY/2/8000) - 1;
    TIM_TimeBaseInitStructure.div               = 0;
    TIM_TimeBaseInitStructure.counterMode       = TMR_COUNTER_MODE_CENTERALIGNED2;
    TIM_TimeBaseInitStructure.clockDivision     = TMR_CKD_DIV1;
    TIM_TimeBaseInitStructure.repetitionCounter = 1;
    TMR_ConfigTimeBase(TMR1, &TIM_TimeBaseInitStructure);



    TMR_EnableAUTOReload(TMR1);

    TMR_Enable(TMR1);
    TMR1->REPCNT = 1;
    /* Main Output Enable */
    TMR_EnablePWMOutputs(TMR1); 

(2) PWM 输出状态配置

设置PWM 上下管输出状态,并使能配置上下管P WM 输出有效,配置使能刹车,配置刹车输入极性,关闭刹车硬件自动恢复。

 /* Automatic Output enable, Break, dead time and lock configuration*/
    TIM_BDTRInitStructure.RMOS_State       = TMR_RMOS_STATE_ENABLE;//--------
    TIM_BDTRInitStructure.IMOS_State       = TMR_IMOS_STATE_ENABLE;//--------
    TIM_BDTRInitStructure.lockLevel        = TMR_LOCK_LEVEL_OFF;//00:锁定关闭,寄存器无写保护;01:锁定级别1,不能写入TIMx_BDTR寄存器的DTG、BKE、BKP、AOE位和TIMx_CR2寄存器的OISx/OISxN位;
    TIM_BDTRInitStructure.deadTime         = u16_DeadTime;//死区时间

    /**
     * Brake configuration: enable brake
     * Brake input polarity: active in low level   
     * Auto output enable configuration: Disable MOE bit hardware control
     */
    TIM_BDTRInitStructure.breakState       = TMR_BREAK_STATE_ENABLE;//TMR_BREAK_STATE_ENABLE TMR_BREAK_STATE_DISABLE;
    TIM_BDTRInitStructure.breakPolarity    = TMR_BREAK_POLARITY_HIGH;
    TIM_BDTRInitStructure.automaticOutput  = TMR_AUTOMATIC_OUTPUT_DISABLE;
    TMR_ConfigBDT(TMR1, &TIM_BDTRInitStructure);

    /*pwm driver set,channel 1,2,3,4set pwm mode*/
    TIM_OCInitStructure.OC_Mode         = TMR_OC_MODE_PWM2;
    TIM_OCInitStructure.OC_OutputState  = TMR_OUTPUT_STATE_ENABLE;  //TMR_OUTPUT_STATE_DISABLE;
    TIM_OCInitStructure.OC_OutputNState = TMR_OUTPUT_NSTATE_ENABLE; //TMR_OUTPUT_NSTATE_DISABLE;//------------
    TIM_OCInitStructure.Pulse           = u16_Period;
    TIM_OCInitStructure.OC_Polarity     = TMR_OC_POLARITY_HIGH;
    TIM_OCInitStructure.OC_NPolarity    = TMR_OC_NPOLARITY_HIGH; //互补输出极性-------
    TIM_OCInitStructure.OC_Idlestate    = TMR_OCIDLESTATE_RESET;  // TMR_OCIDLESTATE_SET; //
    TIM_OCInitStructure.OC_NIdlestate   = TMR_OCNIDLESTATE_RESET; // TMR_OCNIDLESTATE_SET;//

    //set OC1/OC1N
    TMR_OC1Config(TMR1, &TIM_OCInitStructure);
    //set oc2/oc2N
    TIM_OCInitStructure.Pulse = u16_Period;
    TMR_OC2Config(TMR1, &TIM_OCInitStructure);
    //set OC3/OC3N
    TIM_OCInitStructure.Pulse = u16_Period;
    TMR_OC3Config(TMR1, &TIM_OCInitStructure);

    TIM_OCInitStructure.OC_Mode         = TMR_OC_MODE_PWM2;              //选择定时器模式:TIM脉冲宽度调制模式2
    TIM_OCInitStructure.OC_OutputState  = TMR_OUTPUT_STATE_ENABLE;       //CH1比较输出使能
    TIM_OCInitStructure.OC_OutputNState = TMR_OUTPUT_NSTATE_ENABLE;      //CH1N比较输出使能
    TIM_OCInitStructure.OC_Polarity     = TMR_OC_POLARITY_HIGH;           //CH1输出极性:TIM输出比较极性高
    TIM_OCInitStructure.OC_NPolarity    = TMR_OC_NPOLARITY_HIGH;          //CH1N输出极性:TIM输出比较极性高
    TIM_OCInitStructure.OC_Idlestate    = TMR_OCIDLESTATE_RESET;         //CH1输出空闲状态:0
    TIM_OCInitStructure.OC_NIdlestate   = TMR_OCNIDLESTATE_SET;          //CH1N输出空闲状态:0

     //set OC4
    TIM_OCInitStructure.Pulse = 10;
    TMR_OC4Config(TMR1, &TIM_OCInitStructure);//OC4
    //enable interrupt
    TMR_EnableInterrupt(TMR1, TMR_INT_BRK);

    TMR_EnableAUTOReload(TMR1);//TIMx_ARR寄存器被装入缓冲器
    TMR_OC1PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);
    TMR_OC2PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);//比较值预装载使能
    TMR_OC3PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);
    TMR_OC4PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);

3.2 配置ADC外部触发

采用DMA 模式,ADC 量化后的数据直接搬运到ADC_ConvertedValue 数组中存储,ADC 触发条件采用TMR1 的CC4 作为触发源,开启ADC 使能及配置ADC 中断优先级及其使能。

    ADC_Config_T   ADC_InitStructure;
    DMA_Config_T   DMA_InitStructure;

    DMA_InitStructure.peripheralAddress  = (uint32_t)&(ADC->DATA);//ADC地址
    DMA_InitStructure.memoryAddress      = (uint32_t)&ADC_ConvertedValue[0]; //内存地址
    DMA_InitStructure.direction          = DMA_DIR_PERIPHERAL; //方向(从外设到内存)
    DMA_InitStructure.bufferSize         = TOTAL_CHANNEL;//TOTAL_CHANNEL; //传输内容的大小---传输次数
    DMA_InitStructure.peripheralInc      = DMA_PERIPHERAL_INC_DISABLE; //外设地址固定
    DMA_InitStructure.memoryInc          = DMA_MEMORY_INC_ENABLE;//DMA_MEMORY_INC_ENABLE; //内存地址固定  
    DMA_InitStructure.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_HALFWORD ; //外设数据单位
    DMA_InitStructure.memoryDataSize     = DMA_MEMORY_DATASIZE_HALFWORD ;    //内存数据单位
    DMA_InitStructure.circular           = DMA_CIRCULAR_ENABLE  ; //DMA模式:循环传输
    DMA_InitStructure.priority           = DMA_PRIORITY_LEVEL_VERYHIGH ; //优先级:高
    DMA_InitStructure.memoryTomemory     = DMA_M2M_DISABLE;   //禁止内存到内存的传输

    DMA_Config(DMA_CHANNEL_1, &DMA_InitStructure);  //配置DMA的1通道
    DMA_Enable(DMA_CHANNEL_1);

    ADC_Reset();
    ADC_ClockMode(ADC_CLOCK_MODE_ASYNCLK);//48M/4=12mADC_CLOCK_MODE_SYNCLKDIV4   
    ADC_ConfigStructInit(&ADC_InitStructure);
    ADC_InitStructure.convMode    = ADC_CONVERSION_SINGLE;
    ADC_InitStructure.scanDir     = ADC_SCAN_DIR_UPWARD;
    ADC_InitStructure.extTrigConv1 = ADC_EXT_TRIG_CONV_TRG1;  //  timer1 CC4
    ADC_InitStructure.extTrigEdge1 = ADC_EXT_TRIG_EDGE_RISING;
    ADC_InitStructure.dataAlign   = ADC_DATA_ALIGN_RIGHT;
    ADC_InitStructure.resolution  = ADC_RESOLUTION_12B;  
    ADC_Config(&ADC_InitStructure);
    ADC_ConfigChannel(ADC_CHANNEL_2 | ADC_CHANNEL_8 | ADC_CHANNEL_9 | ADC_CHANNEL_7| ADC_CHANNEL_5 ,ADC_SAMPLE_TIME_1_5);
    ADC->CFG1_B.OVRMAG = 1;  
    ADC_EnableInterrupt(ADC_INT_CS);
//=========================ADC中断使用=================================================
    NVIC_EnableIRQ(ADC_COMP_IRQn);
    NVIC_SetPriority(ADC_COMP_IRQn,0);  
    ADC_DMARequestMode(ADC_DMA_MODE_CIRCULAR);
    ADC_EnableDMA();
    ADC_Enable();  
    ADC_StartConversion();//必需要启动一下

3.3 中断处理与数据读取

// ADC转换完成中断回调
void ADC_COMP_IRQHandler(void) {
    //清除标志位
    ADC->STS =  ADC->STS;
    // 逻辑功能处理
}


四、调试与优化

4.1 关键验证点

  1. 触发同步性:用示波器同时捕捉PWM边沿与ADC启动信号(如ADC的 CONVERT引脚)。
  2. 时序余量:确保ADC转换时间小于PWM触发间隔。
  3. 抗干扰设计:在PWM触发后插入微小延迟(如死区时间)再采样,避开开关噪声。

4.2 常见问题

  • 触发失效:检查定时器与ADC的时钟源是否使能。
  • 数据错位:DMA传输时需配置正确的内存地址和缓冲区大小。
  • 抖动问题:优化PCB布局,避免PWM信号对ADC输入造成串扰。

五、扩展应用

  • 多通道交替采样:结合扫描模式,在单个PWM周期内采集多个传感器信号。
  • 闭环控制集成:将ADC结果实时反馈至PWM占空比调节,实现数字PID控制。

结语

通过PWM硬件触发ADC采样,可显著提升系统实时性与可靠性。实际开发中需结合具体

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

13

帖子

0

粉丝