查看: 2650|回复: 0
打印 上一主题 下一主题

STM8下推式磁悬浮实验

[复制链接]
跳转到指定楼层
沙发
发表于 2015-4-9 19:13:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

极简陋的模拟电路 (原文件名:磁悬浮(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个线圈中间的空隙,高度约在线圈中部,需注意霍尔作用面应位于线圈中轴线上,不应采用图中虚线标示的安装方式,否则会造成定位误差。
磁环置于电路板下面,需要注意的是磁环的放置会影响霍尔输出,因此运放输出中点调节最好配合磁环定位同时调节。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入中科因仑

本版积分规则

快速回复 返回顶部 返回列表