| 
 | 
 
  
极简陋的模拟电路 (原文件名:磁悬浮(STM8 PWM).png)  
 
源代码(STVD + Cosmic)ourdev_511866.zip(文件大小:53K) (原文件名:maglev_stm8.zip)  
 
悬浮视频ourdev_511458.zip(文件大小:1.41M) (原文件名:maglev.zip) 
  
电路基于ST三合一开发板的STM8S Mini Kit,ADC基准电压3.3V。 
STM8使用内部16MHz RC振荡,分频比为1,核心频率16MHz。 
ADC2时钟分频比为12,频率1.333MHz,工作在单次采样模式,采样时间为14 * 0.75?s + 7?s = 17.5?s,加上中断处理时间,采样率约为55KS/s。 
TIM1时钟分频比为4,频率4MHz,计数器TOP值(ARR)为999,因此PWM频率为4KHz。 
 
完成初始化后,主程序进入死循环,系统完全依赖中断服务例程运作。 
 
设计要点详解: 
1.ADC2采样完成(EOC)中断 
<pre>/* 
* ADC2 End Of Conversion interrupt handler 
* Positions are filtered by a 7th-order moving average filter. 
*/ 
@far @interrupt void ADC2_IRQHandler(void) 
{ 
        static u8 xFilterPos, yFilterPos; 
        static s16 xFilterBuf[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 
        static s16 yFilterBuf[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 
 
        s16 adcValue, acc = 0; 
        u8 i; 
 
        adcValue = ADC2_GetConversionValue(); 
        if (currentChannel == ADC2_CHANNEL_6) 
        { 
                xFilterBuf[xFilterPos & 7] = adcValue; 
                xFilterPos++; 
                for (i = 0; i < 8; i++) 
                { 
                        acc += xFilterBuf; 
                } 
                xPos = acc >> 3; 
                currentChannel = ADC2_CHANNEL_7; 
        } 
        else 
        { 
                yFilterBuf[yFilterPos & 7] = adcValue; 
                yFilterPos++; 
                for (i = 0; i < 8; i++) 
                { 
                        acc += yFilterBuf; 
                } 
                yPos = acc >> 3; 
                currentChannel = ADC2_CHANNEL_6; 
        } 
 
        // Switch the channel and start new conversion. 
        ADC2_ClearFlag(); 
        ADC2_ConversionConfig(ADC2_CONVERSIONMODE_SINGLE, currentChannel, ADC2_ALIGN_RIGHT); 
        ADC2_StartConversion(); 
}</pre> 
 
EOC中断轮流采集CH6和CH7通道的数据,并对采样值进行7阶移动平均滤波,结果存放于xPos和yPos变量。 
 
 
2.TIM1更新/溢出中断 
<pre>/* 
* TIM1 update/overflow interrupt handler 
* This IRQ is executed every 250us. 
*/ 
@far @interrupt void TIM1_UPD_OVF_TRG_BRK_IRQHandler(void) 
{ 
        static u8 direction; 
        s16 xError, yError; 
        s16 xPWM, yPWM; 
 
        // Change X direction 
        if (direction & X_DIRECTION_FLAG) 
        { 
                GPIO_WriteHigh(GPIOC, GPIO_PIN_3); 
        } 
        else 
        { 
                GPIO_WriteLow(GPIOC, GPIO_PIN_3); 
        } 
 
        // Change Y direction 
        if (direction & Y_DIRECTION_FLAG) 
        { 
                GPIO_WriteHigh(GPIOC, GPIO_PIN_5); 
        } 
        else 
        { 
                GPIO_WriteLow(GPIOC, GPIO_PIN_5); 
        } 
 
        // PID calculation 
        xError = xPID.targetValue - xPos; 
        yError = yPID.targetValue - yPos; 
        xPWM = calcPID(&xPID, xError); 
        yPWM = calcPID(&yPID, yError); 
 
        // Set the direction and OC polarity based on the PID output (takes effect on next PWM cycle) 
        if (xPWM >= 0) 
        { 
                direction &= (u8) ~X_DIRECTION_FLAG; 
                TIM1_OC1PolarityConfig(TIM1_OCPOLARITY_LOW); 
        } 
        else 
        { 
                direction |= X_DIRECTION_FLAG; 
                xPWM = -xPWM; 
                TIM1_OC1PolarityConfig(TIM1_OCPOLARITY_HIGH); 
        } 
 
        if (yPWM >= 0) 
        { 
                direction &= (u8) ~Y_DIRECTION_FLAG; 
                TIM1_OC2PolarityConfig(TIM1_OCPOLARITY_LOW); 
        } 
        else 
        { 
                direction |= Y_DIRECTION_FLAG; 
                yPWM = -yPWM; 
                TIM1_OC2PolarityConfig(TIM1_OCPOLARITY_HIGH); 
        } 
 
        // Update the PWM (takes effect on next PWM cycle) 
        TIM1_SetCompare1(xPWM); 
        TIM1_SetCompare2(yPWM); 
 
        TIM1_ClearITPendingBit(TIM1_IT_UPDATE); 
}</pre> 
 
TIM1更新/溢出中断每个PWM周期开始时(250?s)执行一次,每次执行会根据当前xPos和yPos进行PID运算和更新PWM占空比。10-bit ADC采样范围0~1023,因此PID的参考点设在中点511。 
为了防止更新占空比造成当前PWM周期占空比不正常,输出比较器使用了预载功能,即更新会在下一个PWM周期才生效。 
控制方向根据PID运算结果的符号来判断,保存在direction变量中,在下一个PWM周期才对应更新GPIO的输出状态,与PWM占空比更新同步。 
 
PWM控制时序如下图(只画了X轴,Y轴同理): 
  
PWM时序 (原文件名:磁悬浮(PWM时序).png)  
当PID输出为正数时,PC3输出低电平,PC1/TIM1_CC1输出高电平有效的PWM脉冲。 
当PID输出为负数时,PC3输出高电平,PC1/TIM1_CC1输出低电平有效的PWM脉冲,图中T3为占空比20%的PWM,T4为占空比40%的反向输出PWM。 
结合L293D,图中T1, T2周期输出占空比20%的正向PWM至线圈,而T3, T4周期分别输出20%和40%占空比的反向PWM至线圈,从而实现双向磁场控制。 
 
 
3.PID参数 
<pre>        xPID.Kp = 4; 
        xPID.Ki = 0; 
        xPID.Kd = 30; 
        xPID.integrationError = 0; 
        xPID.prevError = 0; 
        xPID.targetValue = 511;</pre> 
 
由上面的代码可见,本系统只使用了PD控制,Ki为0,积分项不参与计算。Kp, Kd的值需要根据悬浮物的质量调整,整定方法可参考有关资料,这里就不详述了。 
 
 
4.霍尔采样电路 
霍尔采样电路采用了2片有源线性霍尔UGN3503,后接一级运放反相放大器,放大倍数为30倍,并且由一个10K多圈电位器调整输出中点电平。 
运放和霍尔使用5V单电源供电,UGN3503的输出中点电压约2.5V,运放LM324输出电压范围约50mV~3.6V,因此STM8的ADC参考电压使用3.3V,分别调整10K电位器使LM324输出1.65V,此时STM8的ADC采样结果应该接近511,误差虽然越小越好,但不需要绝对准确(霍尔、运放都有温漂,不可能绝对准确),一般调整至480~550范围内即可。 
 
 
5.硬件安装 
  
线圈及霍尔安装 (原文件名:磁悬浮(线圈及霍尔安装).png)  
每组两个线圈同名端相连(即反向串接)。霍尔置于4个线圈中间的空隙,高度约在线圈中部,需注意霍尔作用面应位于线圈中轴线上,不应采用图中虚线标示的安装方式,否则会造成定位误差。 
磁环置于电路板下面,需要注意的是磁环的放置会影响霍尔输出,因此运放输出中点调节最好配合磁环定位同时调节。 
 
 |  
  
 |   
 
 
 
 |