[活动专区] 【杰发科技AC7802x测评】3.基于AC7802 PWM实现直流电机开环控制

[复制链接]
 楼主| GrootBrain 发表于 2023-6-3 09:13 | 显示全部楼层 |阅读模式
<
本帖最后由 GrootBrain 于 2023-6-3 09:13 编辑

#申请原创# #有奖活动#

基于AC7802 PWM实现直流电机开环控制


在电子控制领域,低压直流电机速度控制应用十分广泛,比如只能小车的速度控制、四轴飞行器的高度控制及转弯控制、洗衣机脱水转速等等,电机速度控制无处不在。

直流电机速度控制基本原理
我们知道,直流电机两端给一定的电压,电机就会转起来。降低电机两端的电压,电机就会降速,增加电机两端的电压,电机就会升速。当有一个电路,它随着输入变量的变化,输出电压也会随之变化,就能控制电机的转速。
通常,我们会使用PWM作为控制电路的输入,控制直流电源电压值输出。当然,也可以设计AD值控制电源的电压值输出。至于原理和电路,大家去百度查找吧。
PWM控制直流电压方案,那么7802可以轻易胜任,因为7802有3个PWM模块,可选用APB做时钟源,有16位预分频器和16位计数器,有很大的PWM带宽设置,而且PWM占空比可调,轻松实现PWM控制直流电压的输出。
AD控制直流电压方案,7802就会稍微逊色一点。7802有1路ADC输出,输出精度只有6bit,也就只有64段电压输出,显然精度不高。
难得出了一款DAC的MCU,本想采用此方案测试一下DAC输出的。奈何购买的电机控制模块不支持AD值控制直流电源电压输出。一般用PWM控制电压输出较为简单,多数MCU都能实现,而且硬件实现成本较低。在此将用PWM实现直流电源电压控制。

7802的PWM模块特性挑几个说说吧,别的也不常用
  • 16位预分频器支持165536分频
  • 16位计数器
  • 每个通道都可以配置为输入捕获、输出比较或边沿对齐PWM模式、中心对齐PWM模式
  • 死区插入可用于每一对组合通道,互补/非互补模式均可插入死区
  • 每个通道的极性可配置
  • 用于脉冲和周期宽度测量的双边沿捕获
  • 支持正交解码(AB输入引脚映射每个PWM模块的CH0CH1


电机控速实验
输入:PA10作为ADC采样输入,输出对应PWM占空比
输出:PA3作为PWM输出,控制电机转速
因为AD是12bit精度的,最到值是4095,我们在配置PWM的时候,最大值设置位4095,将读取到的AD值直接配置到PWM的ChlVal寄存器内,直接输出对应占空比。
本任务分为三个小模块,分别是ADC模块、PWM模块和电机模块。
ADC模块为ADC驱动,为上层提供ADC初始化接口和获取ADC值接口
  1. void adc_motor_ctrl_input_init(void);
  2. uint16_t adc_motor_ctrl_get_adc_Val(void);


ADC 初始化
  1. void adc_motor_ctrl_input_init(void)
  2. {
  3.     ADC_ConfigType adcConfig;                    /*! ADC初始化配置*/
  4.     memset(&adcConfig, 0x00, sizeof(adcConfig)); /*! 清空结构体*/

  5.     /*! ADC输入端口(电位器)配置*/
  6.     GPIO_SetFunc(GPIOA, GPIO_PIN10, GPIO_FUN2); /*! PA10复用为FUN2,为ADC_IN1 ,对应电位器VR1*/

  7.     /*! ADC配置
  8.     ADC固定为12位分辨率,工作模式为MODE3(工作模式内容见参考手册8.4.2章节),规则组扫描+注入组扫描模式多通道单次转换,规则组长度为3,注入组长度为0
  9.     每触发一次进行一次ADC转换,每次转换规则组中的3个通道。
  10.     */
  11.     adcConfig.clkPsc                     = ADC_CLK_PRESCALER_2;  /*! ADC时钟分频设置,Set ADC Clk = APB时钟频率/(clkPsc + 1) = 16M/2 = 8M */
  12.     adcConfig.scanModeEn                 = ENABLE;               /*! 模式配置SCAN:扫描模式使能位 多通道需使能扫描模式,单通道则不需要使能*/
  13.     adcConfig.continuousModeEn           = DISABLE;              /*! 模式配置CONT:连续模式使能位 0:触发一次后只转换一次,1:触发后可连续转换*/
  14.     adcConfig.regularDiscontinuousModeEn = DISABLE;              /*! 模式配置DISCEN:打开规则组间断转换模式*/
  15.     adcConfig.injectDiscontinuousModeEn  = DISABLE;              /*! 模式配置IDISEN:打开注入组间断转换模式*/
  16.     adcConfig.injectAutoModeEn           = DISABLE;              /*! 模式配置IAUTO:自动注入模式*/
  17.     adcConfig.intervalModeEn             = DISABLE;              /*! 模式配置INTERVAL:注入组为间隔转换模式*/
  18.     adcConfig.regularDiscontinuousNum    = 0;                    /*! 规则组子组长度,用于Mode7和Mode8*/
  19.     adcConfig.interruptEn                = DISABLE;              /*! 总中断使能*/
  20.     adcConfig.voltageRef                 = ADC_VOLTAGEREF_VDDA;  /*! ADC参考源选择 */
  21.     adcConfig.regularTriggerMode         = ADC_TRIGGER_INTERNAL; /*! 规则组触发源类型选择*/
  22.     adcConfig.injectTriggerMode          = ADC_TRIGGER_INTERNAL; /*! 注入组触发源类型选择*/
  23.     adcConfig.regularSequenceLength      = 1;                    /*! 规则组长度*/
  24.     adcConfig.injectSequenceLength       = 0;                    /*! 注入组长度*/
  25.     adcConfig.dataAlign                  = ADC_DATA_ALIGN_RIGHT; /*! 数据右对齐*/
  26.     adcConfig.callBack                   = NULL;                 /*! ADC回调函数*/
  27.     adcConfig.powerMode                  = ADC_POWER_ON;         /*! ADC上电*/
  28.     ADC_Init(ADC0, &adcConfig);                                  /*! ADC works Mode Config*/

  29.     /*!
  30.         ADC转换率计算公式:
  31.         总转换时间=(SPT+ 12)/ADC时钟频率+5个APB时钟周期
  32.         备注:
  33.         1.SPT为采样周期个数,具体见下面ADC_SPT_CLK_x。
  34.         2.ADC时钟频率 = APB时钟频率 /(分频系数+1)
  35.         3.7802x ADC支持的最高采样率为250Ksps(即转换时间不低于4us),如果配置采样率高于该值,可能会导致采样结果精度显著减低。
  36.     */
  37.     /*规则组通道转换序列和转换速率配置*/
  38.     ADC_SetRegularGroupChannel(ADC0, ADC_CH_1, ADC_SPT_CLK_33, 0);   /*! 采样&转换时间= (33+12)/8000000 + 5/16000000 ≈ 5.94us */
  39.     /*! Bandgap或T-sensor内部通道配置*/
  40.     //ADC_SetInternalChannel(ADC0, ADC_INTERNAL_TSENSOR); /*! 内部电压信号选择(仅在使用了ADC_CH_VIN 时配置) */
  41.     ADC_SetVBufEnableFlag(ADC0, ENABLE);                /*! Bandgap和T-sensor内部通道使能(仅在使用了ADC_CH_VIN 时配置) */

  42. }
ADC值读取
  1. uint16_t adc_motor_ctrl_get_adc_Val(void)
  2. {
  3.     uint16_t adcVal = 0;

  4.     ADC_SoftwareStartRegularConvert(ADC0); /*! 软件触发规则组采样*/

  5.     while (!ADC_GetEOCFlag(ADC0, 0)) /*! 等待规则组最后一个通道转换完成*/
  6.     {
  7.         /* Wait */
  8.     }

  9.     adcVal = ADC_GetRegularData(ADC0, 0); /*! 获取规则组0的转换值*/

  10.     return adcVal;
  11. }

PWM模块是PWM模块驱动代码,为上层提供PWM初始化以及配置占空比驱动函数。接口如下:
  1. void PWM_motor_ctrl_output_init( void );
  2. void PWM_motor_ctrl_ouput_duty_val(uint16_t pwm_duty);



PWM 输出初始化
  1. void PWM_motor_ctrl_output_init( void )
  2. {
  3.    /* USER CODE BEGIN PWM2_Init 0 */

  4.     /* USER CODE END PWM2_Init 0 */

  5.     PWM_ConfigType pwmConfig;
  6.     memset(&pwmConfig, 0, sizeof(pwmConfig));
  7.     PWM_ModulationConfigType initModeStruct;
  8.     memset(&initModeStruct, 0, sizeof(initModeStruct));

  9.     /* USER CODE BEGIN PWM2_Init 1 */
  10.     GPIO_SetFunc(GPIOA, GPIO_PIN3, GPIO_FUN1);
  11.     /* USER CODE END PWM2_Init 1 */

  12.     pwmConfig.mode = PWM_MODE_MODULATION;
  13.     pwmConfig.clkSource = PWM_CLK_SOURCE_APB;
  14.     pwmConfig.clkPsc = 0;
  15.     pwmConfig.initValue = 0;
  16.     pwmConfig.maxValue = 4095;
  17.     pwmConfig.overflowInterrupEn = DISABLE;
  18.     pwmConfig.cntOverflowFreq = 0;
  19.     pwmConfig.interruptEn = DISABLE;

  20.     initModeStruct.countMode = PWM_UP_COUNT;
  21.     initModeStruct.deadtime = 0;
  22.     initModeStruct.deadtimePsc = PWM_DEADTIME_DIVID_1;
  23.     initModeStruct.initChOutputEn = ENABLE;
  24.     initModeStruct.initTriggerEn = DISABLE;

  25.     PWM_IndependentChConfig independentChConfig[1];

  26.     /* independent channel 0 configuration */
  27.     independentChConfig[0].channel = PWM_CH_0;
  28.     independentChConfig[0].chValue = 0;
  29.     independentChConfig[0].levelMode = PWM_LOW_TRUE;
  30.     independentChConfig[0].polarity = PWM_OUTPUT_POLARITY_ACTIVE_LOW;
  31.     independentChConfig[0].interruptEn = DISABLE;
  32.     independentChConfig[0].initLevel = PWM_HIGH_LEVEL;
  33.     independentChConfig[0].triggerEn = DISABLE;

  34.     initModeStruct.independentChannelNum = 1;
  35.     initModeStruct.independentChConfig = independentChConfig;

  36.     pwmConfig.initModeStruct = &initModeStruct;

  37.     PWM_Init(PWM2, &pwmConfig);

  38.     /* USER CODE BEGIN PWM2_Init 2 */

  39.     /* USER CODE END PWM2_Init 2 */
  40. }
PWM 占空比设置
  1. void PWM_motor_ctrl_ouput_duty_val(uint16_t pwm_duty)
  2. {
  3.   PWM_SetChannelCountValue(PWM2, PWM_CH_0, pwm_duty);
  4. }


电机任务是上层应用层接口,调用ADC模块读取ADC数值,写入PWM占空比设置函数。

电机控制任务
  1. void motor_Task( void *pvParameters )
  2. {
  3.     pvParameters = pvParameters;

  4.     adc_motor_ctrl_input_init();
  5.     PWM_motor_ctrl_output_init();

  6.     while (1) {
  7.         PWM_motor_ctrl_ouput_duty_val( adc_motor_ctrl_get_adc_Val() );
  8.         vTaskDelay( pdMS_TO_TICKS(100) );
  9.     }
  10. }
最终文件结构如下:
20230603-083404.jpg

演示
飞书20230603-084516(1).gif


代码:
AC7802_FreeRTOS_Motor.zip (2.51 MB, 下载次数: 23)

cdb1235 发表于 2023-6-20 09:18 | 显示全部楼层
厉害,大佬用的啥示波器感觉小巧便捷
yangjiaxu 发表于 2023-7-6 23:25 | 显示全部楼层
cdb1235 发表于 2023-6-20 09:18
厉害,大佬用的啥示波器感觉小巧便捷

正点原子的便携式示波器
cdb1235 发表于 2023-7-10 08:33 | 显示全部楼层
yangjiaxu 发表于 2023-7-6 23:25
正点原子的便携式示波器

好的,感谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

93

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部

17

主题

93

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部