加入交流群  

扫一扫,添加管理员微信
备注:参考设计,即可被拉入群
和也在搞设计小伙伴们碰一碰

收藏 

评论 

桂花蒸 发布

下推式磁悬浮月球灯-stm32f10x

 
设计简介

1.工作原理

本方案中采用单片机PID调节的下推式磁悬浮控制原理,四周强磁铁产生向上推力,线圈通电产生吸力磁场,使浮子达到动态平衡,从而稳定漂浮。

2.硬件介绍

同样采用了3颗线性霍尔传感器,用于浮子移动位置检测,减法器放大后通过单片机ADC通道采集,如图1所示。

图1

 

根据ADC采集数据单片机4组PWM通道产生驱动控制信号,驱动2片DRV8870,用于X轴和Y轴的线圈磁场力和方向改变,如图2所示。

图2

 

触摸开关、无线发射、Z轴驱动电源开关不多作介绍,如图3和图4所示。

图3

 

图4

 

3.软件设计

单片机工程文件采用ST cubemx生成,主要配置如下图所示。

a. 时钟配置

 

 

b. ADC通道配置,并启用ADC通道DMA功能

 

 

c.开启FreeRTOS操作系统,并创建3个任务,分别作为Z轴检测(含运行指示)、X轴处理和Y轴处理任务。系统基本时钟建议选择定时器时钟。

 

 

e.定时器PWM配置,频率20kHz,PWM 0~100对于占空比0~100%。

 

 

4.软件代码

a.默认任务处理,做了Z轴开关,PWM清0和运行指示的操作。

void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN StartDefaultTask */
    uint8_t BTH_cnt=0;
    
    uint16_t Z_ADC_table[Buf_windows];
    
  /* Infinite loop */
  for(;;)
  {
    
        for(uint16_t i;i<Buf_windows;i++)
        {
            Z_ADC_table[i]=User_PAR.ADC1_Value[i*3+2];
        }
        User_PAR.PAR_Z_ADC_value=Moving_average_filter(Z_ADC_table,Buf_windows);
        
        if(User_PAR.PAR_Z_ADC_value>1300)   //Z轴磁铁靠近
        {
            HAL_GPIO_WritePin(PA7_PW_SWITCH_GPIO_Port, PA7_PW_SWITCH_Pin, GPIO_PIN_SET);    //Z轴
            User_PAR.PW_ON_flag=SET;
        }
        else
        {
            HAL_GPIO_WritePin(PA7_PW_SWITCH_GPIO_Port, PA7_PW_SWITCH_Pin, GPIO_PIN_RESET);  //Z轴
            User_PAR.PW_ON_flag=RESET;
            
            User_PAR.X_PWM_CCR=0;
            User_PAR.Y_PWM_CCR=0;
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,User_PAR.X_PWM_CCR);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,User_PAR.X_PWM_CCR);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_3,User_PAR.Y_PWM_CCR);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_4,User_PAR.Y_PWM_CCR);
        }
        
        HAL_GPIO_TogglePin(PA11_RUN_LED_GPIO_Port, PA11_RUN_LED_Pin);
        if(BTH_cnt++/4==1)
        {
            HAL_GPIO_TogglePin(PA8_BTH_LED_CTR_GPIO_Port, PA8_BTH_LED_CTR_Pin);
            BTH_cnt=0;
        }
        osDelay(500);
  }
  /* USER CODE END StartDefaultTask */
}

 

b.X轴任务,做了ADC数据采集和PID调用。

 

void XPID_Task(void const * argument)
{
  /* USER CODE BEGIN XPID_Task */
    
//    uint16_t X_PWM_CCR=50;
    uint16_t X_ADC_table[Buf_windows];
    
    XPID.set_adc_value=SET_X_Value;
    XPID.actual_adc_value=0;
    XPID.err=0;
    XPID.err_last=0;
    XPID.Kp=0.50f;
    XPID.Ki=0.03f;
    XPID.Kd=1.0f;
    XPID.sum_err=0;
    XPID.PWM_duty=0;
    
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
    
//    __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,50);
//    __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,0);
  /* Infinite loop */
  for(;;)
  {
          
        for(uint16_t i;i<Buf_windows;i++)
        {
            X_ADC_table[i]=User_PAR.ADC1_Value[i*3];
        }
        
        User_PAR.PAR_X_ADC_value=Moving_average_filter(X_ADC_table,Buf_windows);
        
        if(User_PAR.PW_ON_flag)
        PID_CALC(&XPID,User_PAR.PAR_X_ADC_value,1);
        else
        {
            XPID.actual_adc_value=0;
            XPID.err=0;
            XPID.err_last=0;
            XPID.sum_err=0;
            XPID.PWM_duty=0;
            XPID.pid_Voltage=0;
        }
        
        osDelay(1);
  }
  /* USER CODE END XPID_Task */
}

 

c. Y轴任务,,做了ADC数据采集和PID调用。

 

void YPID_Task(void const * argument)
{
  /* USER CODE BEGIN YPID_Task */
    
//    uint16_t Y_PWM_CCR=50;
    uint16_t Y_ADC_table[Buf_windows];
    
    YPID.set_adc_value=SET_Y_Value;
    YPID.actual_adc_value=0;
    YPID.err=0;
    YPID.err_last=0;
    YPID.Kp=0.50f;
    YPID.Ki=0.03f;
    YPID.Kd=1.0f;
    YPID.sum_err=0;
    YPID.PWM_duty=0;
    
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);
    
//    __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_3,Y_PWM_CCR);
//    __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_4,Y_PWM_CCR);
  /* Infinite loop */
  for(;;)
  {
    
        
        for(uint16_t i;i<Buf_windows;i++)
        {
            Y_ADC_table[i]=User_PAR.ADC1_Value[i*3+1];
        }
        
        User_PAR.PAR_Y_ADC_value=Moving_average_filter(Y_ADC_table,Buf_windows);
        
        if(User_PAR.PW_ON_flag)
        PID_CALC(&YPID,User_PAR.PAR_Y_ADC_value,0);
        else
        {
            YPID.actual_adc_value=0;
            YPID.err=0;
            YPID.err_last=0;
            YPID.sum_err=0;
            YPID.PWM_duty=0;
            YPID.pid_Voltage=0;
        }
        
        osDelay(1);
  }
  /* USER CODE END YPID_Task */
}

 

d. 滑动滤波以及PID调节,

typedef struct
{

    #define Buf_windows 20
    uint16_t ADC1_Value[Buf_windows*3];
    
    uint16_t PAR_X_ADC_value;   //X轴ADC数据
    uint16_t PAR_Y_ADC_value;   //X轴ADC数据
    uint16_t PAR_Z_ADC_value;   //X轴ADC数据
    uint16_t X_PWM_CCR;         //X轴占空比 
    uint8_t  X_IS_N;            //X轴N偏 
    uint16_t Y_PWM_CCR;         //Y轴占空比     
    uint8_t  Y_IS_N;            //Y轴N偏 
    uint8_t PW_ON_flag;         //电源打开标志
    
}User_TypeDef_PAR;

typedef struct
{
    uint16_t set_adc_value;            //
    uint16_t actual_adc_value;    //
    float err;                                //
    float err_last;                    //
    float Kp,Ki,Kd;                    //
    float sum_err;                        //
    float pid_Voltage;        //
    uint16_t PWM_duty;                    //
    uint8_t Kd_cnt;
       
}PID_TypeDef;

/*****************************************************************************
函数名称: uint16_t Moving_average_filter(uint16_t *table_value,uint16_t length)
函数功能: 滑动均值滤波
@param  :table_value ,length
@retval :uint16_t
******************************************************************************/
uint16_t Moving_average_filter(uint16_t *table_value,uint16_t length)
{
    uint16_t Value_MAX,Value_Min;
    uint32_t Temp_value=0,Return_value;
    
    Value_MAX=-0;
    Value_Min= 65535;
    for(uint16_t i=0;i<length;i++)
    {
        if(table_value[i]>=Value_MAX)
        Value_MAX  =table_value[i];else{/*无操作*/}
        if(table_value[i]<=Value_Min)
        Value_Min  =table_value[i];else{/*无操作*/}
        Temp_value+=table_value[i];   //求和
    }
    Return_value=(Temp_value-Value_MAX-Value_Min)/(length-2);//求平均
    
  return     (uint16_t)Return_value;
}

/*****************************************************************************
函数名称: void PID_CALC(PID_TypeDef *PID,uint16_t ADC_value,uint8_t IS_X)
函数功能: PID调节
@param  :PID_TypeDef *PID,uint16_t ADC_value,uint8_t IS_X
@retval :NULL
******************************************************************************/

void PID_CALC(PID_TypeDef *PID,uint16_t ADC_value,uint8_t IS_X)
{
    
    PID->actual_adc_value=ADC_value;
    PID->err=PID->actual_adc_value-PID->set_adc_value;
    PID->sum_err+=PID->err;
    if(PID->sum_err>PID_i_MAX)
    PID->sum_err=PID_i_MAX;
    else if(PID->sum_err<-PID_i_MAX)
    PID->sum_err=-PID_i_MAX;    
    else;
    
    PID->pid_Voltage=PID->Kp*PID->err+PID->Ki*PID->sum_err+PID->Kd*(PID->err-PID->err_last);
    
    PID->pid_Voltage=PID->pid_Voltage*1.0f;
    
    if(PID->Kd_cnt++>=5)  //减缓微分调节速度,防止震荡放大
    {
        PID->err_last=PID->err;
        PID->Kd_cnt=0;
    }
    else;
    
    if(IS_X)//X轴
    {
        if(PID->pid_Voltage>0)  //N向偏置    
        {
            User_PAR.X_IS_N=SET;
            User_PAR.X_PWM_CCR=(uint16_t)PID->pid_Voltage;
            if(User_PAR.X_PWM_CCR>PWM_Duty_Value)
            User_PAR.X_PWM_CCR=PWM_Duty_Value;    
            
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,0);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,User_PAR.X_PWM_CCR);
        }
        else if(PID->pid_Voltage<0)               //S向偏置    
        {
            User_PAR.X_IS_N=RESET;
            User_PAR.X_PWM_CCR=(uint16_t)(fabs(PID->pid_Voltage)) ;
            if(User_PAR.X_PWM_CCR>PWM_Duty_Value)
            User_PAR.X_PWM_CCR=PWM_Duty_Value;    
            
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,User_PAR.X_PWM_CCR);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,0);
        }    
        else
        {
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,0);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,0);
        }
        
    }
    else    //Y轴
    {
        if(PID->pid_Voltage>0)  //N向偏置    
        {
            User_PAR.Y_IS_N=SET;
            User_PAR.Y_PWM_CCR=(uint16_t)PID->pid_Voltage;
            if(User_PAR.Y_PWM_CCR>PWM_Duty_Value)
            User_PAR.Y_PWM_CCR=PWM_Duty_Value;    
            
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_3,0);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_4,User_PAR.Y_PWM_CCR);
        }
        else if(PID->pid_Voltage<0)              //S向偏置    
        {
            User_PAR.Y_IS_N=RESET;
            User_PAR.Y_PWM_CCR=(uint16_t)(fabs(PID->pid_Voltage)) ;
            if(User_PAR.Y_PWM_CCR>PWM_Duty_Value)
            User_PAR.Y_PWM_CCR=PWM_Duty_Value;    
            
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_3,User_PAR.Y_PWM_CCR);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_4,0);
        }    
        else
        {
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_3,0);
            __HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_4,0);
        }
    }
    
}

5.软件调试

a.X轴和Y轴中心值的确认,将浮子放置在中心位置距离合适高度,编译器在线观察X值和Y值并记录;

b.先调PID中的比例P,一手拿浮子,一手通过编译器SW在线设置,从大往小调,当浮子从很大拉扯力变得微弱就行;

c.调节PID中的微分D,微分调节数据预判,参数最容易调节,切记代码中需减缓微分调节速度防止震荡加剧,否则无法调试成功;

d.PID代码中的积分必须限幅,否则容易超调,导致不稳;

e.PID调试需要耐心,调节到一个比较合适的参数后,浮子振动会明显变小。

6.测试效果

实测效果如下图所示。

 

 

 

 

7.总结

a.单片机PID调节明显比硬件三极管驱动效率高很多,功耗明显降低,线圈基本不发热;

b. 12V/2A条件下,浮子悬浮高度高于2cm,载重与底部磁铁有关(可采用环形100*60*10mm或1组圆形强磁15*5 3只共计8组),浮子可以采用15*5mm 1只、30*5mm 1只、40*5mm 2只,从小到大叠放(可稳定载重100g左右)。也可以网上购买专用浮子(500g版本,可稳定载重130g左右);

c.触摸开关接触线圈和无线LED线圈可以漆包线手工绕制;

d.附件中提供源代码、月球贴图和磁悬浮底座外壳stl文件,月球灯可以采用白色PLA材料打印,具体制作可以参考B站,若文件有误请自行修改。

参考设计图片
×

!注意:请使用浏览器自带下载,迅雷等下载软件可能无法下载到有效资源。

 
相关器件
器件 类型 描述 数据手册
STM32F103RBT6 ST(意法半导体) 工作电压:2V ~ 3.6V CPU位数:32-Bit CPU内核:ARM® Cortex®-M3 主频(MAX):72MHz ROM类型:FLASH ST 32位 ARM内核 MCU芯片 整包960PCS 点击下载
DC-005-20A AC/DC电源插座 触点外径:2.0mm 触点内径:6.4mm 点击下载
VT1C221M0607 贴片型铝电解电容 容值:220uF 精度:±20% 额定电压:16V 点击下载
CC0805KRX7R9BB104 贴片电容 精度:±10% 容值:100nF 额定电压:50V 温漂系数(介质材料):X7R 材质:X7R 点击下载
SMBJ12CA TVS二极管 反向关断电压(典型值):12V 击穿电压(最小值):13.3V 极性:Bidirectional 箝位电压:19.9V @ 30.2A 峰值脉冲电流(10/1000us):30.2A TVS管 Pppm: 600W, VRWM: 12V 点击下载
78M05 线性稳压芯片 输出类型:固定 最大输入电压:25V 输出电流:500mA 输出电压(最小值/固定值):5V 5V,0.5A 点击下载
CL21A106KOQNNNE 贴片电容 精度:±10% 容值:10uF 额定电压:16V 温漂系数(介质材料):X5R 材质:X5R 点击下载
NCD0805R1 发光二极管 照明颜色:红色 主波长/色坐标:615~630nm 红色,亮度值Iv=67~195mcd @IF=20mA 点击下载
0805W8F1001T5E 贴片电阻 阻值(欧姆):1K 精度:±1% 功率:1/8W 温度系数:±100ppm/°C 点击下载
BL9110-330BPFB 低压差线性稳压(LDO) 输出类型:固定 最大输入电压:6V 输出电流:1A 输出电压(最小值/固定值):3.3V 输出3.3V,1A电流压降350mV,超低压差线性稳压器LDO 点击下载
PZ2012D800-3R0TF 磁珠 阻抗 @ 频率:80Ω @ 100MHz 线路数:1 额定电流(最大):3A 直流电阻(DCR)(最大):40mΩ 3.0A 点击下载
1N4148W 开关二极管 反向恢复时间(trr):8ns 直流反向耐压(Vr):75V 平均整流电流(Io):150mA 正向压降(Vf):1V @ 10mA 点击下载
0805W8F0000T5E 贴片电阻 阻值(欧姆):0 精度:±1% 功率:1/8W 温度系数:±800ppm/°C 点击下载
0805W8F1002T5E 贴片电阻 阻值(欧姆):10K 精度:±1% 功率:1/8W 温度系数:±100ppm/°C 点击下载
CL21B105KBFNNNE 贴片电容 精度:±10% 容值:1uF 额定电压:50V 温漂系数(介质材料):X7R 材质:X7R 点击下载
0805W8F200JT5E 贴片电阻 阻值(欧姆):20 精度:±1% 功率:1/8W 温度系数:±200ppm/°C 点击下载
DRV8870DDAR 电机驱动 点击下载
X6521WV-2x01H-C30D60 排针 点击下载
S8050 三极管 晶体管类型:NPN 集电极电流Ic:500mA 集射极击穿电压Vce:25V 额定功率:225mW NPN 点击下载
AO3401A MOS(场效应管) 漏源电压(Vdss):30V 连续漏极电流(Id)(25°C 时):4.1A 栅源极阈值电压:1.3V @ 250uA 漏源导通电阻:65mΩ @ 4.2A,10V 最大功率耗散(Ta=25°C):350mW 类型:P沟道 - 点击下载
0805W8F4702T5E 贴片电阻 阻值(欧姆):47K 精度:±1% 功率:1/8W 温度系数:±100ppm/°C 点击下载
1210W2J030KT5E 贴片电阻 阻值(欧姆):0.3 精度:±5% 功率:1/3W 温度系数:±800ppm/°C 点击下载
RH6030 触摸芯片 单按键触摸感应开关 点击下载
0603WAF5100T5E 贴片电阻 阻值(欧姆):510 精度:±1% 功率:1/10W 温度系数:±100ppm/°C 点击下载
0805W8F7502T5E 贴片电阻 阻值(欧姆):75K 精度:±1% 功率:1/8W 温度系数:±100ppm/°C 点击下载
0805W8F2003T5E 贴片电阻 阻值(欧姆):200K 精度:±1% 功率:1/8W 温度系数:±100ppm/°C 点击下载
0805W8F3301T5E 贴片电阻 阻值(欧姆):3.3K 精度:±1% 功率:1/8W 温度系数:±100ppm/°C 点击下载
SZYY0805B 发光二极管 0805 蓝灯 贴片LED 发光二极管 点击下载
TAJD227K010RNJ 钽电容 精度:±10% 容值:220uF 额定电压:10V ESR串联电阻:500 mΩ @ 100kHz 工作温度:-55℃ ~ +125℃ 点击下载
S3B-PH-K-S(LF)(SN) 线对板/线对线连接器 针脚数:3 连接器类型:针座 触头类型:公形引脚 间距:0.079"(2.00mm) 系列:PH PH接插件 PH2.0 点击下载
3296W-1-103 精密可调电阻 阻值(欧姆):10K 精度:±10% 温度系数:±250ppm/℃ 点击下载
CC0805JRNPO9BN270 贴片电容 精度:±5% 容值:27pF 额定电压:50V 温漂系数(介质材料):NP0 材质:NP0 点击下载
0805W8F5101T5E 贴片电阻 阻值(欧姆):5.1K 精度:±1% 功率:1/8W 温度系数:±100ppm/°C 点击下载
CC0805KRX7R9BB103 贴片电容 精度:±10% 容值:10nF 额定电压:50V 温漂系数(介质材料):X7R 材质:X7R 点击下载
LM324 通用运放 点击下载
群聊设计,与管理员及时沟通

欢迎加入EEWorld参考设计群,也许能碰到搞同一个设计的小伙伴,群聊设计经验和难点。 入群方式:微信搜索“helloeeworld”或者扫描二维码,备注:参考设计,即可被拉入群。 另外,如您在下载此设计遇到问题,也可以微信添加“helloeeworld”及时沟通。

 
查找数据手册?

EEWorld Datasheet 技术支持

论坛推荐 更多
更新时间2024-11-17 06:51:03

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版 版权声明

EEWORLD参考设计中心

站点相关: TI培训 德州仪器(TI)官方视频课程培训

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved