amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
查看: 67544|回复: 162

用ATmega8制作的下推式磁悬浮

  [复制链接]
发表于 2009-12-24 18:46:30 | 显示全部楼层 |阅读模式
最近这段时间在坛里溜达,闲来无事,参照《STM8下推式磁悬浮实验 》,用Mega8+L298N+3503做了个下推式磁悬浮, 现将图片发上来,供参考。


(原文件名:1.jpg)


(原文件名:2.jpg)


(原文件名:3.jpg)


(原文件名:4.jpg)

没有大环形磁铁,就用小磁铁围一圈代替,效果很好。

(原文件名:7.jpg)
霍尔器件位于四个电磁铁中间位置。


(原文件名:HR.jpg)
 楼主| 发表于 2009-12-24 18:48:47 | 显示全部楼层
磁铁位于电磁铁的下方:

(原文件名:5.jpg)
发表于 2009-12-24 19:02:52 | 显示全部楼层
呵呵,那一圈小磁铁效果也很好啊。
发表于 2009-12-24 19:19:48 | 显示全部楼层
祝贺楼主。

外圈磁铁再少点,应该也可。

咕唧霖,赶快把你的那个CPU改一下并公开原码,这样动手的人会更多的。

LZ能公开原理图和原码吗?
发表于 2009-12-24 20:37:38 | 显示全部楼层
高人
发表于 2009-12-24 21:06:59 | 显示全部楼层
【3楼】 elder60 60岁老头
咕唧霖,赶快把你的那个CPU改一下并公开原码,这样动手的人会更多的。
--------------------------
我的电路、代码和设计要点都已经在STM8下推式磁悬浮实验里公开了。
STM8 Minikit的图纸在论坛的STM8/STM32区置顶帖里有,其实我就是用了最小系统,STM8接上电源就能跑了,晶振都不用。
不过现在玩STM8的人确实不多,如果楼主能公开M8的代码,估计动手的人就真的会多起来了(其实STM8移植到M8也不难,移植到STM32也很容易)。


STM8S Minikit 线路图 (原文件名:STM8S Minikit.PNG)
发表于 2009-12-25 12:21:01 | 显示全部楼层
高手,佩服
 楼主| 发表于 2009-12-25 13:02:15 | 显示全部楼层
原理图和源程序都是参照《STM8下推式磁悬浮实验 》中的,只是改里一下端口,手头没有L293,就用L298代替,效果一样,磁铁用8个也可以,只是浮上来的距离短一些,下面是《STM8下推式磁悬浮实验 》中的原理图,我还没画成型的原理图,等整理一下传上来:

(原文件名:ourdev_511868.png)
 楼主| 发表于 2009-12-25 17:32:48 | 显示全部楼层
用ATmega8制作的下推式磁悬浮原理图:点击此处下载 ourdev_518751.pdf(文件大小:137K) (原文件名:下推式磁悬浮.pdf)
 楼主| 发表于 2009-12-25 18:12:20 | 显示全部楼层
源程序公开:
//--------------------------------------------------------------------------
//下推式磁悬浮源程序  2009.12.18
//liguang70217
//liguang70217@126.com
//http://liguang70217.blog.hexun.com/
//ICC-AVR application builder : 2009-12-17 17:27:22
// Target : M8
// Crystal: 12.000Mhz
//--------------------------------------------------------------------------
#include <iom8v.h>
#include <macros.h>
#include"BIT.h"

#define  LED_A _PB0
#define  LED_B _PB1

#define  CA   _PD0
#define  CB   _PD1

#define  N  7

#define MAX_PID_OUTPUT                             950
#define MAX_INTEGRATION_ERROR                100
#define X_DIRECTION_FLAG                0x01
#define Y_DIRECTION_FLAG                0x02
//--------------------------------------------------------------------------
typedef struct {
        int targetValue;
        int Kp;
        int Ki;
        int Kd;
        int integrationError;
        int prevError;
} PID;

PID xPID,yPID;

unsigned char direction;

unsigned int value_buf_x[N],value_buf_y[N];
unsigned char ix=0,iy=0;

unsigned int xpos,ypos;  //AD转换后存放采集值
unsigned char HH;

unsigned int  xError, yError;
unsigned int  xPWM, yPWM;
//--------------------------------------------------------------------------
//------------延时子程序----------------------------------------------------
void                delay(unsigned int h)
{
unsigned char j;
while(h--){
               for(j=190;--j;)        continue;
          }
}
//--------------------------------------------------------------------------
// PID calculation routine
int calcPID(PID *pid, int error)
{
int output;

if (pid->Ki != 0)
        {
                pid->integrationError += error;
                // Limit the maximum integration error
                if (pid->integrationError > MAX_INTEGRATION_ERROR)
                {
                        pid->integrationError = MAX_INTEGRATION_ERROR;
                }
                else if (pid->integrationError < -MAX_INTEGRATION_ERROR)
                {
                        pid->integrationError = -MAX_INTEGRATION_ERROR;
                }
        }

        output = pid->Kp * error + pid->Ki * pid->integrationError + pid->Kd * (error - pid->prevError);

        // Limit the maximum output
        if (output > MAX_PID_OUTPUT)
        {
                output = MAX_PID_OUTPUT;
        }
        else if (output < -MAX_PID_OUTPUT)
        {
                output = -MAX_PID_OUTPUT;
        }

        pid->prevError = error;
  return output;
}
//--------------------------------------------------------------------------
void port_init(void)
{
PORTB = 0xff;
DDRB  = 0xff;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0x00;
DDRD  = 0xff;
}
//--------------------------------------------------------------------------
//TIMER1 initialize - prescale:1
// WGM: 7) PWM 10bit fast, TOP=0x03FF
// desired value: 2KHz
// actual value: 11.719KHz (82.9%)
void timer1_init(void)
{
TCCR1B = 0x00;//停止定时器
TIMSK |= 0x00;//中断允许
TCNT1H = 0x00;
TCNT1L = 0x00;//初始值
OCR1AH = 0x01;
OCR1AL = 0xFF;//匹配A值
OCR1BH = 0x01;
OCR1BL = 0xFF;//匹配B值
ICR1H  = 0xFF;
ICR1L  = 0xFF;//输入捕捉匹配值
TCCR1A = 0xA3;
TCCR1B = 0x09;//启动定时器
}
//--------------------------------------------------------------------------
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
MCUCR  = 0x00;
MCUCSR = 0x80;//禁止JTAG
GICR   = 0x00;

port_init();
timer1_init();

// TIMSK = 0x04; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
//-----------------------------------------------------------------------------
//ADC采样函数,采样第0通道信号,采样分辨率256
//x为ad端口号
unsigned int get_ad(unsigned char x)
{
union        adres{ int y1; unsigned  char  adre[2]; }adresult;
unsigned int i;
ADMUX = 0xc0+x;                           /*基准AVCC、左对齐、通道7*/  
ADCSRA = 0xC3;                                   /*使能、开启、8分频*/
while(!(ADCSRA & (1 << ADIF)));   /*等待*/
adresult.adre[0]=ADCL;            //读取并存储A/D转换结果,A/D转换的结果通过共
adresult.adre[1]=ADCH;            //用体的形式放入了变量y1中         
ADCSRA &= ~(1 << ADIF);                   /*清标志*/
ADCSRA &= ~(1 << ADEN);                   /*关闭转换*/
return adresult.y1;
}
//--------------------------------------------------------------------------
//滑动平均滤波
unsigned int filter_x(void)
{
   unsigned char count;
   unsigned long  sum=0;
   value_buf_x[ix] = get_ad(0);
   ix=ix+1;
   if ( ix == N ) ix = 0;
   for ( count=0;count<N;count++)
             sum = sum + value_buf_x[count];
   return (unsigned int)(sum/N);
}
//--------------------------------------------------------------------------
//滑动平均滤波
unsigned int filter_y(void)
{
   unsigned char count;
   unsigned long  sum=0;
   value_buf_y[iy] = get_ad(1);
   iy=iy+1;
   if ( iy == N ) iy = 0;
   for ( count=0;count<N;count++)
           sum = sum + value_buf_y[count];
   return (unsigned int)(sum/N);
}
//-----------------------------------------------------------------------------
void main(void)
{
unsigned int ZD;
unsigned int ccc;
init_devices();

ZD=511;
// PID Parameter Initialization
xPID.Kp = 4;
xPID.Ki = 0;
xPID.Kd = 30;
xPID.integrationError = 0;
xPID.prevError = 0;
xPID.targetValue = ZD;

yPID.Kp = 4;
yPID.Ki = 0;
yPID.Kd = 30;
yPID.integrationError = 0;
yPID.prevError = 0;
yPID.targetValue = ZD;



  while(1)
  {
   xpos=filter_x();
   ypos=filter_y();
   
   if(xpos>ZD)
   {
    xpos=xpos-ZD;
    CA=1;
    xError = xPID.targetValue - xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;   
   }
   else
   {
    xpos=ZD-xpos;
        CA=0;
        xError = xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;
   }
                     
   if(ypos>ZD)
   {
    ypos=ypos-ZD;
        CB=1;
    yError = yPID.targetValue - ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;  
   }
   else
   {
    ypos=ZD-ypos;
        CB=0;
    yError = ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;   
   }
  }
}
//----------------------------------------------------------------------------
发表于 2009-12-25 20:18:49 | 显示全部楼层
谢谢!
发表于 2009-12-25 20:25:17 | 显示全部楼层
L298N内部没有集成二极管,外部最好加上。
我的L293D是有的,就是看上这点而没用L298N,一个字懒。 ^v^
发表于 2009-12-25 20:30:45 | 显示全部楼层
这个猛
发表于 2009-12-26 08:24:47 | 显示全部楼层
liguang70217

是否有兴趣,再接再厉,做一个上拉的(霍尔在上)。可能你会发现,好象更难。

另外,现在这个电路中,可以去掉2个线圈,也可实现悬浮。不过,稳态时,电流较大。
发表于 2009-12-26 09:41:08 | 显示全部楼层
难道传说中的彩票摇奖机就是用这个原理做的,GC-D想开什么号就开什么号。
发表于 2009-12-26 15:18:48 | 显示全部楼层
elder60:---"另外,现在这个电路中,可以去掉2个线圈,也可实现悬浮。不过,稳态时,电流较大."

  我觉得,  理论上可以只要一个线圈控制一个方向,  但是一个线圈力很弱,比如线圈在左边,
悬浮物太靠右边时,  要往左边拉, 一个线圈力度不够
发表于 2009-12-26 17:05:08 | 显示全部楼层
请教楼主和咕唧:

楼主的电路和咕唧霖的电路都用了LM324/LM358, 没有把3503直接接入MPU(或加分压电阻),是否是灵敏度不够?
发表于 2009-12-26 20:13:11 | 显示全部楼层
回复【16楼】my2009
楼主的电路和咕唧霖的电路都用了LM324/LM358, 没有把3503直接接入MPU(或加分压电阻),是否是灵敏度不够?
-----------------------------------------------------------------------

是的,我做了30倍放大,楼主做了21倍,MCU的PID算法P=4,即再放大4倍。
假设磁铁移动1mm ADC采样结果变化30,如果不放大30倍,那ADC就只变化1,0-30中间细节全丢失了,即使PID的P做得再大也无法弥补丢失的信号。
最理想的模拟放大倍数就是在线圈最大控制范围内,ADC采样值刚好从0到满幅,我试验出来是30倍比较恰当。
发表于 2009-12-26 20:25:25 | 显示全部楼层
不知道这样的磁铁哪里能买到?
发表于 2009-12-26 20:31:06 | 显示全部楼层
发表于 2009-12-26 23:11:34 | 显示全部楼层
谢谢咕唧霖的解答, 我明白了.

【18楼】: 淘宝有这种小磁铁, 深圳的电子市场也有, 其他城市的电子元器件市场估计也会有
 楼主| 发表于 2009-12-28 13:33:44 | 显示全部楼层
在这之前做过一个上拉式磁悬浮:
 楼主| 发表于 2009-12-28 13:35:43 | 显示全部楼层
上拉式磁悬浮照片:

(原文件名:1.jpg)


(原文件名:5.jpg)


(原文件名:3.jpg)


(原文件名:4.jpg)
发表于 2009-12-28 15:07:17 | 显示全部楼层
哈,好。
请楼主和咕唧霖在“★请已实验基本成功的先行者在下面回贴,以便今后网友查找。”一贴中登记一下。
最好再加上磁铁重量,悬浮高度(距离)和工作电流。
楼主请登记2种。

另请忘了登记者,尽快补上。
发表于 2010-3-12 15:04:46 | 显示全部楼层
ji
发表于 2010-3-29 09:14:30 | 显示全部楼层
很动心....
发表于 2010-4-4 19:24:27 | 显示全部楼层
努力实践中
发表于 2010-4-7 18:20:01 | 显示全部楼层
24v稳压 用 7824 可以吗
发表于 2010-4-7 18:36:37 | 显示全部楼层
回复【9楼】liguang70217
-----------------------------------------------------------------------

dddddddddddddd
发表于 2010-4-7 18:38:57 | 显示全部楼层
回复【1楼】liguang70217
-----------------------------------------------------------------------

24v稳压 用 7824 可以吗
 楼主| 发表于 2010-4-9 13:04:30 | 显示全部楼层
7824发热量大,其实整流滤波直接驱动即可,对电压要求不严。
发表于 2010-4-9 20:40:43 | 显示全部楼层
回复【30楼】liguang70217
-----------------------------------------------------------------------

谢谢
但是我一测都37v了
发表于 2010-4-10 21:56:57 | 显示全部楼层
回复【30楼】liguang70217
-----------------------------------------------------------------------

298 非常热????????
发表于 2010-4-12 09:47:48 | 显示全部楼层
为什么要用24V的电压? 其实12V--15V 就够了, 换一个电源试试
发表于 2010-4-12 12:36:37 | 显示全部楼层
mark
 楼主| 发表于 2010-4-12 13:06:22 | 显示全部楼层
298要加足够的散热器,M8的晶振最好上16MHz的。
发表于 2010-4-13 13:57:06 | 显示全部楼层
谢谢大家  我从焊电路 用 293 298 不好焊
发表于 2010-4-30 14:07:24 | 显示全部楼层
mark
发表于 2010-5-3 15:22:11 | 显示全部楼层
回复【35楼】liguang70217
-----------------------------------------------------------------
两个滑动变阻器 怎么调啊 谢谢
发表于 2010-5-3 16:15:47 | 显示全部楼层
强力顶!!!!!!!!!!!1
发表于 2010-5-4 10:46:14 | 显示全部楼层
学习中。
发表于 2010-5-4 11:13:40 | 显示全部楼层
记号
 楼主| 发表于 2010-5-4 11:41:04 | 显示全部楼层
回复 【38楼】 crazy b-boy
-----------------------------------------------------------------
在初始状态下,调至运放输出电压的1/2的AD基准电压。
发表于 2010-5-9 17:59:44 | 显示全部楼层
回复【42楼】liguang70217
-----------------------------------------------------------------------

在初始状态下,调至运放输出电压1.65v对吧? 我的mage8会热好像又烧了 还涨价了!! 298不热  线圈不用加铁芯吗?我缠了六层够用吗?
 楼主| 发表于 2010-5-10 12:51:02 | 显示全部楼层
回复 【43楼】 crazy b-boy  
-----------------------------------------------------------------
是要调到1.65V,M8应该不会热,应该是线路连接问题,298输出应接保护二极管,这在电路图中忘画了,参见【11楼】 gzhuli 咕唧霖。
发表于 2010-5-11 12:01:09 | 显示全部楼层
回复【44楼】liguang70217
-----------------------------------------------------------------------

哦 谢谢 努力中 。。。。。。。。。。。。。。
发表于 2010-5-11 20:14:26 | 显示全部楼层
回复【44楼】liguang70217
-----------------------------------------------------------------------

也不知道如何称呼 有时间能加我qq吗 我刚学单片机一年多 天天要去上那不太有用的课  现在有很多不懂地方  望您不吝赐教 QQ:393441746 (左手)
发表于 2010-5-15 21:39:38 | 显示全部楼层
不用了 最近 进展不错
发表于 2010-5-30 16:42:16 | 显示全部楼层
回复【9楼】liguang70217
-----------------------------------------------------------------------

楼主:liguang70217
请教你公开得程序:
#include"BIT.h"
这个头函数怎么来得呀?
#define  LED_A _PB0
#define  LED_B _PB1
这两行电路上怎么体现?
#define  CA   _PD0
#define  CB   _PD1
它们是不是就是:PD0  PD1端口?
#define  N  7

#define MAX_PID_OUTPUT       950
#define MAX_INTEGRATION_ERROR 100

#define X_DIRECTION_FLAG         0x01
#define Y_DIRECTION_FLAG         0x02
这两个标志没用呀?
请留下你得联系方式,请教学校呀!!!
本人qq:910266897
 楼主| 发表于 2010-5-31 13:02:35 | 显示全部楼层
回复【48楼】 chongcao  
-----------------------------------------------------------------------
#include"BIT.h"  记得就在本站下载的,可以搜一下。
发表于 2010-5-31 16:22:28 | 显示全部楼层
谢谢楼主的回复,找到了:RD_UseAVRPORTBit.h AVR通用位操作支持库。
本人对单片机了解不多,真诚向各位大师请教学习,请不吝赐教!

看了程序,感觉L293 的驱动很费解,PWM怎么工作的?
//源程序公开:
//--------------------------------------------------------------------------
//下推式磁悬浮源程序  2009.12.18
//liguang70217
//liguang70217@126.com
//http://liguang70217.blog.hexun.com/
//ICC-AVR application builder : 2009-12-17 17:27:22
// Target : M8
// Crystal: 12.000Mhz
//--------------------------------------------------------------------------
#include <iom8v.h>
#include <macros.h>
//#include"BIT.h"
#include <ioinit.h>
//#define  LED_A _PB0
//#define  LED_B _PB1

//#define  CA   _PD0
//#define  CB   _PD1







//----端口初始化----------------------------------------------------------------------
void port_init(void)
{
PORTB = 0xff; //=1     感觉成了单向磁场控制了!!!!
DDRB  = 0xff; //OUTPUT

PORTC = 0x00; //m103 output only
DDRC  = 0x00; //INPUT

PORTD = 0x00; //=0
DDRD  = 0xff; //OUTPUT
}




//--------------------------------------------------------------------------
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
MCUCR  = 0x00;
MCUCSR = 0x80;//禁止JTAG
GICR   = 0x00;
  
port_init();  //端口初始化
timer1_init();//T1初始化

//////usart_init(); //串口初始化

// TIMSK = 0x04; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}



//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范围内即可。


//1.ADC0采样完成(EOC)中断
//EOC中断轮流采集CH6和CH7通道的数据,
//并对采样值进行7阶移动平均滤波,结果存放于xPos和yPos变量。
//-----------------------------------------------------------------------------
//ADC采样函数,采样第0通道信号,采样分辨率256
//x为ad端口号
unsigned int get_ad(unsigned char x)  
{
union adres{ int y1; unsigned  char  adre[2]; }adresult;
unsigned int i;
ADMUX = 0xc0+x;            /*基准AVCC、左对齐、通道7*/   
ADCSRA = 0xC3;            /*使能、开启、8分频*/
while(!(ADCSRA & (1 << ADIF)));   /*等待*/
adresult.adre[0]=ADCL;            //读取并存储A/D转换结果,A/D转换的结果通过共
adresult.adre[1]=ADCH;            //用体的形式放入了变量y1中   
ADCSRA &= ~(1 << ADIF);    /*清标志*/
ADCSRA &= ~(1 << ADEN);    /*关闭转换*/
return adresult.y1;
}


//--------------------------------------------------------------------------
// x---滑动平均滤波
unsigned int filter_x(void)
{
   unsigned char  count;
   unsigned long  sum=0;
   value_buf_x[ix] = get_ad(0);
   ix=ix+1;
   if ( ix == N ) ix = 0;
   for ( count=0;count<N;count++)
             sum = sum + value_buf_x[count];
   return (unsigned int)(sum/N);
}


//--------------------------------------------------------------------------
//y----滑动平均滤波
unsigned int filter_y(void)
{
   unsigned char  count;
   unsigned long  sum=0;
   value_buf_y[iy] = get_ad(1);
   iy=iy+1;
   if ( iy == N ) iy = 0;
   for ( count=0;count<N;count++)
           sum = sum + value_buf_y[count];
   return (unsigned int)(sum/N);
}

//****************************************************************************
//-----------------------------------------------------------------------------
void main(void)
{
unsigned int  ZD;
unsigned int ccc;

init_devices(); //initialize all peripherals

  //+++++++GUO-TEST-TEST--TEST-TESTTEST-TEST--TEST-TEST-+++++++++++++++++++++
uart_charsend( 0x88 );//串口发送数据测试
PORTD=0<<PD0;//端口测试
PORTD=1<<PD1;//端口测试
  //TEST-TEST--TEST-TESTTEST-TEST--TEST-TEST-TEST-TEST--TEST-TESTTEST-TEST--TEST-TEST-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



ZD=511;
// PID Parameter Initialization ------PID参数初始化
//本系统只使用了PD控制,Ki为0,积分项不参与计算。
//Kp, Kd的值需要根据悬浮物的质量调整,整定方法可参考有关资料

//-----------X PID参数
xPID.Kp = 4; //LM324/LM35830倍放大, MCU的PID算法P=4,即再放大4倍。
xPID.Ki = 0;
xPID.Kd = 30;
xPID.integrationError = 0;
xPID.prevError = 0;
xPID.targetValue = ZD;

//-----------Y  PID参数
yPID.Kp = 4; //LM324/LM35830倍放大, MCU的PID算法P=4,即再放大4倍。
yPID.Ki = 0;
yPID.Kd = 30;
yPID.integrationError = 0;
yPID.prevError = 0;
yPID.targetValue = ZD;


  
  while(1)  
  {
   xpos=filter_x();
   ypos=filter_y();
   
   if(xpos>ZD)
   {  
    xpos=xpos-ZD;  
    //CA=1;
        PORTD=1<<PD0;//PD0
    xError = xPID.targetValue - xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;   
   }
   else  
   {  
    xpos=ZD-xpos;  
//CA=0;
PORTD=0<<PD0;//PD0
xError = xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;
   }
   
//......................................................................
      
   if(ypos>ZD)
   {
    ypos=ypos-ZD;  
//CB=1;
PORTD=1<<PD1;//PD1  
    yError = yPID.targetValue - ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;   
   }
   else  
   {  
    ypos=ZD-ypos;  
//CB=0;
PORTD=0<<PD1;//PD1  
    yError = ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;   
   }
  }
}
//----------------------------------------------------------------------------
发表于 2010-5-31 19:31:03 | 显示全部楼层
有意思
发表于 2010-5-31 20:41:04 | 显示全部楼层
厉害,学习了
发表于 2010-6-3 14:49:20 | 显示全部楼层
回复【50楼】chongcao
-----------------------------------------------------------------------

PWM部分你哪里不明白?能具体点吗?
发表于 2010-6-3 16:26:02 | 显示全部楼层
if(xpos>ZD)  
   {   
    xpos=xpos-ZD;   
    //CA=1;  
PORTD=1<<PD0;//PD0
    xError = xPID.targetValue - xpos;  
    xPWM   = calcPID(&xPID, xError);  
    OCR1A  = xPWM;     
   }  
这里的误差计算:xError = xPID.targetValue - xpos=xPID.targetValue -xpos+ZD=2*ZD-xpos   怎么会是这样?
xPWM   = calcPID(&xPID, xError);  
OCR1A  = xPWM;
这两行怎么理解?
发表于 2010-6-3 16:55:37 | 显示全部楼层
回复【54楼】chongcao
-----------------------------------------------------------------------

ZD是中点,即PID的目标值,所以xPID.targetValue = ZD。
我的STM8代码中,是先计算误差xError = xPID.targetValue - xPos,然后将绝对误差输入calcPID(),计算出修正量xPWM,然后判断xPWM的正负,设置PWM波形和GPIO的极性。
简单点讲,我的xError和xPWM是有极性的,中点值是0,当xPWM < 0时,PWM波是反相的(看我的帖子里面的波形图)。

LZ的代码计算出的xPWM是没极性的,所以他要以2 * ZD - xPos来算出没极性的,中点在ZD的误差值xError。
如果中点是ADC半量程,那么LZ的代码和我的代码是一样的,但如果中点不在ADC半量程处,我的xError就不等效于2 * ZD - xPos。
在我的原型设计中带自校准功能,中点是可调的,只是后来发现不用自校准也工作得挺好,所以发布出来的代码就把中点固定在511了。
LZ的代码基于我的代码修改过来,这部分没有简化,所以看起来像在绕圈。
发表于 2010-6-3 17:01:47 | 显示全部楼层
谢谢楼主的回复,由于本人水平不是很高,你的程序原理勉强看的懂,那个PWM时序图很容易理解。到了这里就费解了许多。

“LZ的代码计算出的xPWM是没极性的,所以他要以2 * ZD - xPos来算出没极性的,中点在ZD的误差值xError。
如果中点是ADC半量程,那么LZ的代码和我的代码是一样的,但如果中点不在ADC半量程处,我的xError就不等效于2 * ZD - xPos。”
理解不了?xError怎么理解? 它不是以ZD=511 为中心吗?xPos>ZD,xError=xPos-ZD  xPos<ZD,xError=ZD-xPos  这样理解不对吗?   

请问搂主,下面两行是怎么实现 PWM 输出的?
xPWM   = calcPID(&xPID, xError);   
OCR1A  = xPWM;
发表于 2010-6-3 17:11:09 | 显示全部楼层
xPWM是PID运算结果,OCR1A是TIMER1的比较寄存器,OCR1A = xPWM就是设置PWM输出的占空比。TIMER1有两个输出比较寄存器,正好分别用于X和Y通道,所以 OCR1A = xPWM 和 OCR1B = yPWM 就分别实现了两个PWM输出的设置。
发表于 2010-6-3 17:38:34 | 显示全部楼层
回复【57楼】gzhuli 咕唧霖
-----------------------------------------------------------------------

你的意思是:TIMER1 初始化后,按照设定值就可以自动输出PWM波形,不需要额外的代码;而波形的占空比受控于PID运算结果。
霍尔输出-->采集ADC-->PID 运算,得到控制偏移量-->TIMER1自动产生PWM波形,占空比受控于PID函数的运算结果-->X,Y电磁铁产生双向磁场,纠正悬磁铁的偏移或倾斜
这样理解对吗?
发表于 2010-6-3 17:51:03 | 显示全部楼层
回复【58楼】chongcao
-----------------------------------------------------------------------

是的。
发表于 2010-6-3 18:03:12 | 显示全部楼层
再次感谢楼主的指导,光自学还是不行的。单片机的控制原理大致搞清楚了,我可以组织电路实验了。
前期我实验了模拟L324的上拉式悬浮,接下来,我看也从  M8的上拉式 PID控制实验 开始,等到成功了,再实验下推式悬浮。
我实验了,上拉式:下霍尔,上霍尔,双霍尔,加铁心,加辅助磁铁。都通过了,感谢各位大师的知道,特别是楼主大量的帖子的指导。
发表于 2010-6-4 16:29:21 | 显示全部楼层
回复【55楼】gzhuli 咕唧霖
-----------------------------------------------------------------------


(原文件名:ZD.GIF)

楼上讲的已经很好了,可惜我对PID 不是很了解,只是想当然理解。
当  if(xpos>511) //采集值与平衡值比较
   {
    PORTD=1<<PD0;//PD0=1  
   
        xpos=xpos-511;  
    xError = 511 - xpos; //计算误差:采集数据和设定的平衡值比较(减法),得出一个差值,通过pid算法后得出控制量输出,就能达到目的。
        OCR1A= calcPID(&xPID, xError); //PB1 output
    //xPWM   = calcPID(&xPID, xError);
    //OCR1A  = xPWM;  //设置PWM输出的占空比  
   }
   else  
   {  
    PORTD=0<<PD0;//PD0=0
   
        xError = 511-xpos;   
    OCR1A  =calcPID(&xPID, xError);
        //xPWM   = calcPID(&xPID, xError);
    //OCR1A  = xPWM; //设置PWM输出的占空比
   }
对于:xpos>511-->xError=2*ZD-xPOS 为什么把误差取在那??,直接xpos>511-->xError=xpos-511 或 xpos<511-->xError=511-xpos 不行吗?
xError 与 PID函数calcPID(&xPID, xError) 的关系,怎样通俗的理解?
那程序是如何产生双极性的PWM波形呢?
发表于 2010-6-4 17:08:35 | 显示全部楼层
回复【61楼】chongcao
-----------------------------------------------------------------------

似有悟,不知对否?

(原文件名:ZD.GIF)
  T1 T2 期间:PORTD=0<<PD1;//PD1=0  
              yError = 511-ypos;  
           OCR1B  = calcPID(&yPID, yError);
             可以理解为:          偏差愈大,占空比越高;
  T3 T4 期间:PORTD=1<<PD1;//PD1=1
           ypos=ypos-511;  
              yError = 511 - ypos;
              OCR1B  = calcPID(&yPID, yError);
              PWM波形极性没变,但是误差越大,占空比越小,此时起作用的是,PWM波形的低电平,“空”越宽,从而最终加到电磁铁上的波形极性是反转的!
发表于 2010-6-5 16:09:52 | 显示全部楼层
回复【62楼】chongcao
-----------------------------------------------------------------------

是的。
发表于 2010-6-6 09:24:54 | 显示全部楼层
谢谢楼上的指导!
    LM324 m8电路,面包板已制作完毕,遗憾的是,下载源程序时,可能是并口下载线制作有问题,烧坏了台式机的并口。好在用笔记本下载通过。以后再做个,USB-ISP 下载线吧。
   1.65V,调试很敏感,直接用10K调,太敏感,回头上下加10K电阻试试。
   没有接电磁铁,用示波器观察某一组的波形,当1.65V正确时,能够得到设计的波形,且能够随着磁体-霍尔的相对位置的变化而变化,但是如果1.65V偏离太大,控制波形就不是理想设计的了。
   霍尔上端没有磁铁时,为什么PD0 PB1仍然有方波输出?
   根据示波器波形画出如下波形示意图:


(原文件名:实验波形动画.GIF)
     从中可以看出,上磁铁左--右移动时,PB1的波形“极性”发生了变化(有个界线),占空比也随磁铁的移动变化,与程序的原理相吻合。
发表于 2010-6-6 09:48:15 | 显示全部楼层
方波输出肯定有的,哪有1.65V一点不差的?
发表于 2010-6-6 10:00:56 | 显示全部楼层
噢,大师在线呀!谢谢了,我那实验波形对吗?
理论上,如果1.65V准确就应该是一条线?既然有误差,是不是不必刻意追求1.65V的准确?
1.65V,调试很敏感,直接用10K调,太敏感,回头上下加10K电阻试试。 ---可行否?
把10K 可变电阻接到3.3v试试。
    通过实验我还发现,实际的情况与我原来的想象还是有出入的。原以为,上磁铁倾斜才会有霍尔反映的,实际是,上磁铁水平移动到一定距离霍尔才反映的,霍尔检测的主要是上磁铁的水平移动!
发表于 2010-6-6 10:28:30 | 显示全部楼层
磁悬浮是一个闭环控制系统,电磁铁控制悬浮磁铁,霍尔检测磁铁位置反馈给控制电路,最终使霍尔输出和中点电压相等,所以其实1.65V并不需要绝对精准,系统能自动调节过来的。
4个电磁铁控制的是悬浮磁铁的水平位置,不能控制倾斜,所以有可能还要加适当的配重物,使悬浮磁铁保持稳定。
发表于 2010-6-8 10:06:32 | 显示全部楼层
谢谢楼主的指导,我把M8做下推悬浮的程序直接用于上拉式悬浮,程序没改,用了一个通道,功率驱动用了一只场效应管,霍尔检测先放在下端(这种方法最简单,容易理解、调试),悬浮成功。
    实验发现,场效应管的输入电容效应还是比较明显的,把方波拉弯了,好在不影响工作。
    不知何故,稳定性没有模拟的好,原来实验的模拟电路,可以说一丝不动,放2个小时也没问题,单片机反而不是很理想,原以为会更好。
    提高悬距不知从何下手?
    提高功放供电电压?增加电磁铁的圈数?用更大更强的悬浮磁铁?
发表于 2010-6-8 11:11:29 | 显示全部楼层
原来的程序是控制磁铁水平位置的,上拉式是控制垂直距离的,PID参数需要重新调整才能工作在最佳状态。
由于上拉式是单向的,没有一个中点位置,应该要把I参数也用上,以修正累积误差,否则时间长了累积误差不断增大,就不能悬浮了。
发表于 2010-6-8 15:49:01 | 显示全部楼层
谢谢大师的指导!
由于有前期制作模拟电路的经验,对单片机的实验,想了半天才想明白其中的原理(没改程序)。但是只是对整个程序工作原理有大致了解,对其中的P、I、D参数还真不明白,不知道他们做何用?
我现在的实验,I 取何值比较合适?程序其他地方还动吗?
发表于 2010-6-9 09:42:24 | 显示全部楼层
gzhuli 咕唧霖 同志,你有:elder60 60岁老头的联系方式吗?我有事情想请教他,一直没他的消息。
发表于 2010-6-9 22:23:46 | 显示全部楼层
回复【71楼】chongcao
-----------------------------------------------------------------------

没有啊……
发表于 2010-6-23 20:11:21 | 显示全部楼层
好酷  我回来了
发表于 2010-6-23 20:35:07 | 显示全部楼层
线圈不会热吗
发表于 2010-6-23 20:58:05 | 显示全部楼层
狠人啊
发表于 2010-6-24 16:37:15 | 显示全部楼层
请教!LZ的源程序,其中unsigned int ccc; 是什么意思


//-----------------------------------------------------------------------------
void main(void)
{
unsigned int ZD;
unsigned int ccc;
init_devices();
  
ZD=511;
// PID Parameter Initialization
xPID.Kp = 4;
xPID.Ki = 0;
xPID.Kd = 30;
xPID.integrationError = 0;
xPID.prevError = 0;
xPID.targetValue = ZD;

yPID.Kp = 4;
yPID.Ki = 0;
yPID.Kd = 30;
yPID.integrationError = 0;
yPID.prevError = 0;
yPID.targetValue = ZD;


  
  while(1)  
  {
发表于 2010-7-27 15:23:16 | 显示全部楼层
mark
发表于 2010-10-25 12:38:24 | 显示全部楼层
一上电就有输出?霍尔高吗?电压不是中间值?线圈还热?511要改吗?
 楼主| 发表于 2010-10-25 13:15:29 | 显示全部楼层
上电就有输出,电磁铁不放上的话理论上霍尔无信号,先调节运放输出电压为参考电压的1/2值,线圈温热属正常,511不需要改。
发表于 2010-10-25 16:52:15 | 显示全部楼层
回复【79楼】liguang70217
-----------------------------------------------------------------------

谢谢楼主
发表于 2010-10-26 17:18:23 | 显示全部楼层
//--------------------------------------------------------------------------
//下推式磁悬浮源程序  2009.12.18
//liguang70217
//liguang70217@126.com
//http://liguang70217.blog.hexun.com/
//ICC-AVR application builder : 2009-12-17 17:27:22
// Target : M8
// Crystal: 12.000Mhz
//--------------------------------------------------------------------------
#include <iom8v.h>
#include <macros.h>
#define  N  7
#define MAX_PID_OUTPUT       950
#define MAX_INTEGRATION_ERROR 100
#define X_DIRECTION_FLAG         0x01
#define Y_DIRECTION_FLAG         0x02
//--------------------------------------------------------------------------
typedef struct {
int targetValue;
int Kp;
int Ki;
int Kd;
int integrationError;
int prevError;
} PID;

PID xPID,yPID;

unsigned char direction;

unsigned int value_buf_x[N],value_buf_y[N];
unsigned char ix=0,iy=0;

unsigned int xpos,ypos;  //AD转换后存放采集值
unsigned char HH;

unsigned int  xError, yError;
unsigned int  xPWM, yPWM;
//--------------------------------------------------------------------------
//------------延时子程序----------------------------------------------------
void delay(unsigned int h)
{
unsigned char j;
while(h--){
       for(j=190;--j;) continue;
          }
}
//--------------------------------------------------------------------------
// PID calculation routine  
int calcPID(PID *pid, int error)
{
int output;

if (pid->Ki != 0)
{
pid->integrationError += error;
// Limit the maximum integration error
if (pid->integrationError > MAX_INTEGRATION_ERROR)
{
pid->integrationError = MAX_INTEGRATION_ERROR;
}
else if (pid->integrationError < -MAX_INTEGRATION_ERROR)
{
pid->integrationError = -MAX_INTEGRATION_ERROR;
}
}

output = pid->Kp * error + pid->Ki * pid->integrationError + pid->Kd * (error - pid->prevError);

// Limit the maximum output
if (output > MAX_PID_OUTPUT)
{
output = MAX_PID_OUTPUT;
}
else if (output < -MAX_PID_OUTPUT)
{
output = -MAX_PID_OUTPUT;
}

pid->prevError = error;
  return output;
}
//--------------------------------------------------------------------------
void port_init(void)
{
PORTB = 0xff;
DDRB  = 0xff;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0x00;
DDRD  = 0xff;
}
//--------------------------------------------------------------------------
//TIMER1 initialize - prescale:1
// WGM: 7) PWM 10bit fast, TOP=0x03FF
// desired value: 2KHz
// actual value: 11.719KHz (82.9%)
void timer1_init(void)
{
TCCR1B = 0x00;//停止定时器
TIMSK |= 0x00;//中断允许
TCNT1H = 0x00;
TCNT1L = 0x00;//初始值
OCR1AH = 0x01;
OCR1AL = 0xFF;//匹配A值
OCR1BH = 0x01;
OCR1BL = 0xFF;//匹配B值
ICR1H  = 0xFF;
ICR1L  = 0xFF;//输入捕捉匹配值
TCCR1A = 0xA3;
TCCR1B = 0x09;//启动定时器
}
//--------------------------------------------------------------------------
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
MCUCR  = 0x00;
MCUCSR = 0x80;//禁止JTAG
GICR   = 0x00;
  
port_init();
timer1_init();

// TIMSK = 0x04; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
//-----------------------------------------------------------------------------
//ADC采样函数,采样第0通道信号,采样分辨率256
//x为ad端口号
unsigned int get_ad(unsigned char x)  
{
union adres{ int y1; unsigned  char  adre[2]; }adresult;
unsigned int i;
ADMUX = 0xc0+x;            /*基准AVCC、左对齐、通道7*/   
ADCSRA = 0xC3;            /*使能、开启、8分频*/
while(!(ADCSRA & (1 << ADIF)));   /*等待*/
adresult.adre[0]=ADCL;            //读取并存储A/D转换结果,A/D转换的结果通过共
adresult.adre[1]=ADCH;            //用体的形式放入了变量y1中   
ADCSRA &= ~(1 << ADIF);    /*清标志*/
ADCSRA &= ~(1 << ADEN);    /*关闭转换*/
return adresult.y1;
}
//--------------------------------------------------------------------------
//滑动平均滤波
unsigned int filter_x(void)
{
   unsigned char count;
   unsigned long  sum=0;
   value_buf_x[ix] = get_ad(0);
   ix=ix+1;
   if ( ix == N ) ix = 0;
   for ( count=0;count<N;count++)
             sum = sum + value_buf_x[count];
   return (unsigned int)(sum/N);
}
//--------------------------------------------------------------------------
//滑动平均滤波
unsigned int filter_y(void)
{
   unsigned char count;
   unsigned long  sum=0;
   value_buf_y[iy] = get_ad(1);
   iy=iy+1;
   if ( iy == N ) iy = 0;
   for ( count=0;count<N;count++)
           sum = sum + value_buf_y[count];
   return (unsigned int)(sum/N);
}
//-----------------------------------------------------------------------------
void main(void)
{
unsigned int ZD;
unsigned int ccc;
init_devices();
  
ZD=511;
// PID Parameter Initialization
xPID.Kp = 4;
xPID.Ki = 0;
xPID.Kd = 30;
xPID.integrationError = 0;
xPID.prevError = 0;
xPID.targetValue = ZD;

yPID.Kp = 4;
yPID.Ki = 0;
yPID.Kd = 30;
yPID.integrationError = 0;
yPID.prevError = 0;
yPID.targetValue = ZD;


  
  while(1)  
  {
   xpos=filter_x();
   ypos=filter_y();
   
   if(xpos>ZD)
   {  
    xpos=xpos-ZD;  
PORTD|=(1<<0);  //CA=1
    xError = xPID.targetValue - xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;   
   }
   else  
   {  
    xpos=ZD-xpos;  
PORTD&=~(1<<0);   //CA=0  
xError = xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;
   }
      
   if(ypos>ZD)
   {
    ypos=ypos-ZD;  
PORTD|=(1<<1);  //CB=1  
    yError = yPID.targetValue - ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;   
   }
   else  
   {  
    ypos=ZD-ypos;  
PORTD&=~(1<<1);   //CB=0
    yError = ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;   
   }
  }
}

仿造没成功  线圈电阻大约多少啊 有反馈 硬件也不用太精确啊 郁闷
发表于 2010-10-26 17:20:06 | 显示全部楼层
仿造不成功啊 线圈电阻多大啊 有反馈 硬件不用太苛刻吧 郁闷
发表于 2010-10-26 18:49:29 | 显示全部楼层
//--------------------------------------------------------------------------
//下推式磁悬浮源程序  2009.12.18
//liguang70217
//liguang70217@126.com
//http://liguang70217.blog.hexun.com/
//ICC-AVR application builder : 2009-12-17 17:27:22
// Target : M8
// Crystal: 12.000Mhz
//--------------------------------------------------------------------------
#include <iom8v.h>
#include <macros.h>
#define  N  7
#define MAX_PID_OUTPUT       950
#define MAX_INTEGRATION_ERROR 100
#define X_DIRECTION_FLAG         0x01
#define Y_DIRECTION_FLAG         0x02
//--------------------------------------------------------------------------
typedef struct {
int targetValue;
int Kp;
int Ki;
int Kd;
int integrationError;
int prevError;
} PID;

PID xPID,yPID;

unsigned char direction;

unsigned int value_buf_x[N],value_buf_y[N];
unsigned char ix=0,iy=0;

unsigned int xpos,ypos;  //AD转换后存放采集值
unsigned char HH;

unsigned int  xError, yError;
unsigned int  xPWM, yPWM;
//--------------------------------------------------------------------------
//------------延时子程序----------------------------------------------------
void delay(unsigned int h)
{
unsigned char j;
while(h--){
       for(j=190;--j;) continue;
          }
}
//--------------------------------------------------------------------------
// PID calculation routine  
int calcPID(PID *pid, int error)
{
int output;

if (pid->Ki != 0)
{
pid->integrationError += error;
// Limit the maximum integration error
if (pid->integrationError > MAX_INTEGRATION_ERROR)
{
pid->integrationError = MAX_INTEGRATION_ERROR;
}
else if (pid->integrationError < -MAX_INTEGRATION_ERROR)
{
pid->integrationError = -MAX_INTEGRATION_ERROR;
}
}

output = pid->Kp * error + pid->Ki * pid->integrationError + pid->Kd * (error - pid->prevError);

// Limit the maximum output
if (output > MAX_PID_OUTPUT)
{
output = MAX_PID_OUTPUT;
}
else if (output < -MAX_PID_OUTPUT)
{
output = -MAX_PID_OUTPUT;
}

pid->prevError = error;
  return output;
}
//--------------------------------------------------------------------------
void port_init(void)
{
PORTB = 0xff;
DDRB  = 0xff;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0x00;
DDRD  = 0xff;
}
//--------------------------------------------------------------------------
//TIMER1 initialize - prescale:1
// WGM: 7) PWM 10bit fast, TOP=0x03FF
// desired value: 2KHz
// actual value: 11.719KHz (82.9%)
void timer1_init(void)
{
TCCR1B = 0x00;//停止定时器
TIMSK |= 0x00;//中断允许
TCNT1H = 0x00;
TCNT1L = 0x00;//初始值
OCR1AH = 0x01;
OCR1AL = 0xFF;//匹配A值
OCR1BH = 0x01;
OCR1BL = 0xFF;//匹配B值
ICR1H  = 0xFF;
ICR1L  = 0xFF;//输入捕捉匹配值
TCCR1A = 0xA3;
TCCR1B = 0x09;//启动定时器
}
//--------------------------------------------------------------------------
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
MCUCR  = 0x00;
MCUCSR = 0x80;//禁止JTAG
GICR   = 0x00;
  
port_init();
timer1_init();

// TIMSK = 0x04; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
//-----------------------------------------------------------------------------
//ADC采样函数,采样第0通道信号,采样分辨率256
//x为ad端口号
unsigned int get_ad(unsigned char x)  
{
union adres{ int y1; unsigned  char  adre[2]; }adresult;
unsigned int i;
ADMUX = 0xc0+x;            /*基准AVCC、左对齐、通道7*/   
ADCSRA = 0xC3;            /*使能、开启、8分频*/
while(!(ADCSRA & (1 << ADIF)));   /*等待*/
adresult.adre[0]=ADCL;            //读取并存储A/D转换结果,A/D转换的结果通过共
adresult.adre[1]=ADCH;            //用体的形式放入了变量y1中   
ADCSRA &= ~(1 << ADIF);    /*清标志*/
ADCSRA &= ~(1 << ADEN);    /*关闭转换*/
return adresult.y1;
}
//--------------------------------------------------------------------------
//滑动平均滤波
unsigned int filter_x(void)
{
   unsigned char count;
   unsigned long  sum=0;
   value_buf_x[ix] = get_ad(0);
   ix=ix+1;
   if ( ix == N ) ix = 0;
   for ( count=0;count<N;count++)
             sum = sum + value_buf_x[count];
   return (unsigned int)(sum/N);
}
//--------------------------------------------------------------------------
//滑动平均滤波
unsigned int filter_y(void)
{
   unsigned char count;
   unsigned long  sum=0;
   value_buf_y[iy] = get_ad(1);
   iy=iy+1;
   if ( iy == N ) iy = 0;
   for ( count=0;count<N;count++)
           sum = sum + value_buf_y[count];
   return (unsigned int)(sum/N);
}
//-----------------------------------------------------------------------------
void main(void)
{
unsigned int ZD;
unsigned int ccc;
init_devices();
  
ZD=511;
// PID Parameter Initialization
xPID.Kp = 4;
xPID.Ki = 0;
xPID.Kd = 30;
xPID.integrationError = 0;
xPID.prevError = 0;
xPID.targetValue = ZD;

yPID.Kp = 4;
yPID.Ki = 0;
yPID.Kd = 30;
yPID.integrationError = 0;
yPID.prevError = 0;
yPID.targetValue = ZD;


  
  while(1)  
  {
   xpos=filter_x();
   ypos=filter_y();
   
   if(xpos>ZD)
   {  
    xpos=xpos-ZD;  
PORTD|=(1<<0);  //CA=1
    xError = xPID.targetValue - xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;   
   }
   else  
   {  
    xpos=ZD-xpos;  
PORTD&=~(1<<0);   //CA=0  
xError = xpos;
    xPWM   = calcPID(&xPID, xError);
    OCR1A  = xPWM;
   }
      
   if(ypos>ZD)
   {
    ypos=ypos-ZD;  
PORTD|=(1<<1);  //CB=1  
    yError = yPID.targetValue - ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;   
   }
   else  
   {  
    ypos=ZD-ypos;  
PORTD&=~(1<<1);   //CB=0
    yError = ypos;
    yPWM   = calcPID(&yPID, yError);
    OCR1B  = yPWM;   
   }
  }
}
望高手指教
发表于 2010-11-16 14:17:35 | 显示全部楼层
我放上上去上面的磁铁一直在抖 一会就掉了 非常不稳定 有时候还转得非常快
 楼主| 发表于 2010-11-18 13:34:03 | 显示全部楼层
晶振多大的?我用的是16M,底下的磁铁要和电磁铁平行,电磁铁在上,环形磁铁在下,电磁铁中心部分下半节可以放入半截磁芯,以加强磁力,一般的抖动的原因:一是单片机运行速度不够快,二是电磁铁磁力不够,三是永磁铁和电磁铁的位置偏差较大。
发表于 2010-11-18 17:40:30 | 显示全部楼层
12M的晶振 ADCSRA = 0xC3;            /*使能、开启、8分频*/这是采样频率吧 用手拿着可以感觉到个方向的阻力
xPID.Kp = 4;  
xPID.Ki = 0;  
xPID.Kd = 30; 参数调的时候我怎么看震荡啊  位置的偏差也就是霍尔了 洞洞板两个洞之间的距离吧
 楼主| 发表于 2010-11-18 18:28:21 | 显示全部楼层
PID参数凭经验而定,但一定要理解到位三个参数的作用,设置就简单了;悬浮磁铁应加配重,如果悬浮磁铁较轻的话同样不稳;我的那个是直径25的。
发表于 2010-11-18 19:49:02 | 显示全部楼层
我的是19  可能是小了 线圈距离有些大
发表于 2010-11-21 19:23:53 | 显示全部楼层
熔丝位是1111吧 16M 晶振 PID 不合适 他就会一直抖吗?
发表于 2010-11-21 19:28:57 | 显示全部楼层
会不会是 电阻放大的21倍 就很大了 pwm占空比输出就很大啊
发表于 2010-11-21 21:28:37 | 显示全部楼层
回复【楼主位】liguang70217
-----------------------------------------------------------------------

你好,能给我多指导吗?我是外行,但我相信我能。
发表于 2010-11-21 21:33:03 | 显示全部楼层
楼主:你好!
    我想同你联系,如果可以请给我来电:13064607808,或来个短信,谢谢!
发表于 2010-11-26 15:45:29 | 显示全部楼层
为什么我测量线圈两端只有一个方向的电压啊
不是双极性吗?
发表于 2010-11-30 21:33:49 | 显示全部楼层
发表于 2010-12-1 09:26:49 | 显示全部楼层
回复【94楼】crazy b-boy
-----------------------------------------------------------------------

成功了?
发表于 2010-12-1 20:36:03 | 显示全部楼层
回复【95楼】gzhuli 咕唧霖
-----------------------------------------------------------------------


谢谢您
发表于 2010-12-1 20:36:32 | 显示全部楼层
http://v.youku.com/v_show/id_XMjI2NjMxMTI4.html 我做的优酷视频
发表于 2010-12-1 21:15:07 | 显示全部楼层
很不错呀,能说说最后参数是怎么样的吗?
另外,L298N那么大个散热还要加风扇?应该没这么大功耗的吧?我DIP16的L293D都没上散热片。
发表于 2010-12-2 00:10:20 | 显示全部楼层
mark
友情提示:标题不合格、重复发帖,将会被封锁ID。详情请参考:论坛通告:封锁ID、获得注册邀请码、恢复被封ID、投诉必读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|阿莫电子论坛(原ourAVR/ourDEV) ( 工信部备案:粤ICP备09047143号 公安备案:44190002001997(交互式论坛) )

GMT+8, 2018-7-23 11:31

阿莫电子论坛, 原"中国电子开发网"

© 2004-2018 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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