用ATmega8制作的下推式磁悬浮-制作求解
依照“用ATmega8制作的下推式磁悬浮”制作,实验过程遇到困惑,有情大师帮忙:不接最终电磁线圈时,晃动待悬浮磁铁,PWM 波形(示波器观察)合乎原理要求,且随着悬铁水平移动,脉宽和极性都可以变化。
一旦接上电磁线圈,波形便不再变化,且不再受电磁铁的控制,似乎单片机“死机”一样,PWM脚有波形输出。此时,即使断开线圈,“死机”依旧,只有断开电源,再上电,才可以有PWM输出。
供电:3.3V5V12V
线圈每只:0.4mm 700圈,线圈绕的多!!
问题在哪里呢? 电源问题??是不是你电源功率不足啊?影响单片机工作~ 电源是电脑电源,12V直接供电,5V 没有用电脑电源,而是用7805 把12V降压得到的。 L298输出端接二极管了吗? 上图… 二极管接了,8个IN4017.
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_602902Q7B53F.jpg
(原文件名:L298N.jpg)
仅画了3个二极管。
24V 实际试验时是12V。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_602903SNHQ6K.jpg
(原文件名:了吗24.jpg)
运放使用的是LM324 输出调为:1.65V, 4.7K 改为3.3K。
程序根据电路图做了适当的调整:
//#defineCA _PD1 //对应 PB1 控制一组线圈
//#defineCB _PD0 //对应 PB2 控制一组线圈
不需要的代码,在原始的基础上,禁止了!!!
=====================================================================
//源程序公开:
//--------------------------------------------------------------------------
//下推式磁悬浮源程序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"
//#defineLED_A _PB0
//#defineLED_B _PB1 //发光二极管指示
//#defineCA _PD1 //对应 PB1 控制一组线圈
//#defineCB _PD0 //对应 PB2 控制一组线圈
#defineN7
#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 char ix=0,iy=0;
unsigned intvalue_buf_x,value_buf_y;
unsigned intxpos,ypos;//AD转换后存放采集值
//unsigned char HH;
//unsigned intxError, yError;
//unsigned intxPWM, 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; //输入,adc采集
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
//----------------------------------
//unsigned int ZD;
//unsigned int ccc;
//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;
//------------------------------------
}
//ADC,Analog-to-Digital Converter的缩写,指模/数转换器或者模拟/数字转换器-----------------------------------------------------------------------------
unsigned int get_ad(unsigned char k)//k 为ADC采样端口号
{
union adres{ int k1; unsignedcharadre; }adresult;
//unsigned int i;
ADMUX = 0xc0+k; /*基准AVCC、左对齐、通道7*/
ADCSRA = 0xC3; /*使能、开启、8分频*/
while(!(ADCSRA & (1 << ADIF))); /*等待*/
adresult.adre=ADCL; //读取并存储A/D转换结果,A/D转换的结果通过共
adresult.adre=ADCH; //用体的形式放入了变量k1中
ADCSRA &= ~(1 << ADIF); /*清标志*/
ADCSRA &= ~(1 << ADEN); /*关闭转换*/
return adresult.k1;
}
//--------------------------------------------------------------------------
//x:滑动平均滤波
unsigned int filter_x(void)
{
unsigned char count;
unsigned longsum=0;
value_buf_x = get_ad(0); //ADC采样函数,采样第0通道信号,采样分辨率256
ix=ix+1;
if ( ix == N ) ix = 0;
for ( count=0;count<N;count++)
sum = sum + value_buf_x;
return (unsigned int)(sum/N);
}
//--------------------------------------------------------------------------
//y:滑动平均滤波
unsigned int filter_y(void)
{
unsigned char count;
unsigned longsum=0;
value_buf_y = get_ad(1);//ADC采样函数,采样第1通道信号,采样分辨率256
iy=iy+1;
if ( iy == N ) iy = 0;
for ( count=0;count<N;count++)
sum = sum + value_buf_y;
return (unsigned int)(sum/N);
}
//-----------------------------------------------------------------------------
void main(void)
{
init_devices();
//OCR1A 和 TCNT1 比较匹配发生时OC1A 寄存器将产生相应的清零或置位操作,从而产生PWM 波形。
//OCR1B 和 TCNT1 比较匹配发生时OC1B 寄存器将产生相应的清零或置位操作,从而产生PWM 波形。
//工作于相位修正PWM 模式时,比较单元可以在OC1x 引脚(PB1,PB2)输出PWM 波形。要真正从物理引脚上输出信号还必须将OC1x 的数据方向设置为输出。
while(1)
{
xpos=filter_x(); //x轴位置检测
//xpos=555;
ypos=filter_y();// y轴位置检测
//ypos=555;
//PB1 OC1A (T/C1 输出比较匹配 A 输出 )
//OC1A – 端口 B, Bit 1
//OC1A ,输出比较匹配输出:PB1 引脚作为 T/C1 比较匹配 A 的外部输出。此时,PB1 引脚 将设置为输出。
//OC1A 引脚在 PWM 模式定时器功能时作为输出引脚。
if(xpos>511)
{
//xpos = xpos-ZD;
//xError = xPID.targetValue - xpos;
//xPWM = calcPID(&xPID, xError);
//OCR1A= xPWM; //输出比较器 PB1
//OCR1A= calcPID(&xPID, xPID.targetValue - (xpos-ZD)); //输出比较器 PB1
//OCR1A= calcPID(&xPID, 2*ZD - xpos); //输出比较器 PB1
OCR1A= calcPID(&xPID, 2*511 - xpos); //输出比较器 PB1
//........................
//CA=1;//_PD1 //对应 PB1 控制一组线圈
//_PD1=1;
//PORTD=1<<PD1;//PD1=1
PORTD|=(1<<1);//CA=1
}
else
{
//xpos = ZD-xpos;
//xError = xpos;
//xPWM = calcPID(&xPID, xError);
//OCR1A= xPWM; //输出比较器 PB1
OCR1A= calcPID(&xPID, 511-xpos); //输出比较器 PB1
//.........................................
//CA=0; //_PD1 //对应 PB1 控制一组线圈
//_PD1=0;
//PORTD=0<<PD1;//PD1=0
PORTD&=~(1<<1); //CA=0
}
//------------------------------------------------------
if(ypos>511)
{
//ypos = ypos-ZD;
//yError = yPID.targetValue - ypos;
//yPWM = calcPID(&yPID, yError);
//OCR1B= yPWM; //输出比较器PB2
//OCR1B= calcPID(&yPID, yPID.targetValue - (ypos-ZD)); //输出比较器PB2
//OCR1B= calcPID(&yPID, 2*ZD - ypos); //输出比较器PB2
OCR1B= calcPID(&yPID, 2*511 - ypos); //输出比较器PB2
//..........................
//CB=1; //_PD0 //对应 PB2控制一组线圈
//_PD0=1;
//PORTD=1<<PD0;//PD0=1
PORTD|=(1<<0);//CB=1
}
else
{
//ypos = ZD-ypos;
//yError = ypos;
//yPWM = calcPID(&yPID, yError);
//OCR1B= yPWM; //输出比较器PB2
//OCR1B= calcPID(&yPID, ZD-ypos); //输出比较器PB2
OCR1B= calcPID(&yPID, 511-ypos); //输出比较器PB2
//.................................................
//CB=0;//_PD0 //对应 PB2 控制一组线圈
//_PD0=0;
//PORTD=0<<PD0;//PD0=0
PORTD&=~(1<<0); //CB=0
}
}
}
//---------------------------------------------------------------------------- 回复【5楼】chongcao
-----------------------------------------------------------------------
进一步的实验:(怀疑线圈磁场反馈到霍尔,影响单片机工作)
把中间的霍尔断开。另外接一个霍尔(远离线圈),不接驱动线圈,一切正常,一旦接入线圈,PWM输出 便不再受霍尔控制,固定方波输出。
莫名其妙,线圈接入怎么影响到单片机的工作? 1. 二极管不要用4007,换5817
2. 5V/12V独立供电 回复【8楼】gzhuli 咕唧霖
-----------------------------------------------------------------------
感谢gzhuli 咕唧霖的指导。
试验中一直怀疑LM298 线圈干扰了单片机。尝试在LM298的4脚 12V供电脚加接一个330u/35V 电解电容器(表面搭接),问题立刻解决了
!于是在洞洞板合适位置焊好电容器(离4脚稍远),咦!又不行了!!用根飞线接到4脚,又好了。真是奇怪,不得其解。数字电路,对布线还有这么要求,好像回到了高频模拟电路时代。
于是乎,又在5V端接了330U电解,原来已接了一10U电解,一切好多了。
我的电源+12V直接取自电脑开关电源又通过7805得到5V,一直以来对电源性能不怀疑的。不明白LM298接个线圈就干扰M8的工作。
纠其原因,因该是7805 去耦不足,干扰是通过5V电源线引入的,LM298也使用+5V电源,单片机与它共线。
回到楼主建议:
1. 二极管不要用4007,换5817
2. 5V/12V独立供电
前期,没加电解之前,我曾经用3.7V锂电代替5V,12V还用原来的线路,没解决问题。现在想来,因该是LM298 M8公用5V,LM298接入线圈后引起5V异常而使M8 异常。PD0 PD1 还可以受控于悬铁-霍尔-ADC的控制,只是PWM不受控制,固定方波输出,单片机的故障也莫名其妙。
真是“知其然不知其所以然”,还望各位大师辟解。 数字电路对布线的要求一点都不比模拟低,只是关键点有点不同而已。
正确的走线应该是12V到板上就接1000uF电解,330uF还是不太够。然后从这个电解的两个脚分别拉线到L298和7805(单点接地原则),在L298和7805的引脚处就近接0.1uF电容。L298供电的线要尽可能粗。
M8有没有开BOD?如果没开,那很可能就是线圈工作时对5V造成干扰使M8死机了。PWM是硬件控制,CPU死机了也继续跑的。 感谢楼主的及时回复。受教匪浅!
1、我在试验时,连接线路用的是洞洞板,管脚之间喜欢用细漆包线连接,近的用裸线搭接,漆包线在洞孔川来穿去,随意性很强,但方便。以后的注意。
2、正确的走线应该是12V到板上就接1000uF电解,330uF还是不太够。
然后从这个电解的两个脚分别拉线到L298和7805(单点接地原则),----地线也再拉一根?我连线时往往就近找地线。
在L298和7805的引脚处就近接0.1uF电容。没有接这样的电容,见许多商品板,每一个芯片旁边就有个小电容,总觉得可有可无,手头还拆了不少,但没想到用!
L298供电的线要尽可能粗。呜呼,我用0.2的漆包线。
我实验的洞洞板连线示意图:
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_603409A81PVC.JPG
(原文件名:ssss.JPG)
确实问题较多,5V旁的电解10U/35V太小。特别是后来接的330电解,尽管是接在了12V上,远离了LM298的4脚供电端,它没起到作用。实验时用根短线直接再连到4脚,就可以了。看来细节不可忽视呀。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_603421SAPOT9.jpg
(原文件名:7777.jpg)
原始图纸的滤波电解就是用的大:两个1000U。
0.1u电容在使用:
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_603422B2BWNB.jpg
(原文件名:33.jpg)
3、BOD,回头看看是什么。
http://ludikn.blog.163.com/blog/static/49228912010103101516809/
那网友讲的事情好像是在讲我的故事,我翻车的过程有可能同他一样,只是我没看到那低落的12V。
查看我烧写时的熔丝位,有BOD项,选定是2.7V,但没有使能!
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_603445N8NHJK.jpg
(原文件名:bod.jpg)
4、PWM是硬件控制,CPU死机了也继续跑的。所谓“死机”是接入线圈后,PWM不再受悬浮磁铁的控制,但悬铁的控制可以改变PD0 PD1,的极性,看来M8没有死,是PWM通道发生了故障。
谢谢,我制作的下推式磁悬浮也可以工作了。 其实LM1117可以不用,因为是参照gzhuli 咕唧霖的《STM8下推式磁悬浮实验 》改的,懒得计算,正好手头有这个元件,就焊上了,如果楼主有兴趣的话,不妨改一下,用内部参考电压,重新调整运放放大倍数,程序相应的改一下,应该更稳定些。 回复【12楼】liguang70217
-----------------------
感谢楼上的指导!
那3.3V 我是拆了U盘上的一个芯片实现的。回头我研究下M8 的资料,看看怎么初始化使用内部参考电压的。
还望楼上,liguang70217gzhuli 咕唧霖 更多的指导。
有请liguang70217,经核实,你那原始程序:
//ADC,Analog-to-Digital Converter的缩写,指模/数转换器或者模拟/数字转换器-----------------------------------------------------------------------------
unsigned int get_ad(unsigned char k)//k 为ADC采样端口号
{
union adres{ int k1; unsignedcharadre; }adresult;
//unsigned int i;
ADMUX= 0xc0+k; /*基准AVCC、左对齐、通道7*/
//D7 D6 =1 1:2.56V 的片内基准电压源, AREF 引脚外加滤波电容
ADCSRA = 0xC3; /*使能、开启、8分频*/
while(!(ADCSRA & (1 << ADIF))); /*等待*/
adresult.adre=ADCL; //读取并存储A/D转换结果,A/D转换的结果通过共
adresult.adre=ADCH; //用体的形式放入了变量y1中
ADCSRA &= ~(1 << ADIF); /*清标志*/
ADCSRA &= ~(1 << ADEN); /*关闭转换*/
return adresult.k1;
}
======================================
其中已定义了:
ADMUX= 0xc0+k; /*基准AVCC、左对齐、通道7*/
这里应该是:
//D7 D6 =1 1 (对应0xc0) :2.56V 的片内基准电压源, AREF 引脚外加滤波电容。不应该是:/*基准AVCC、左对齐、通道7*/
也不应该再外接3.3基准的,内外基准说是会短路的。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_603545GS6TI3.jpg
(原文件名:ci-xuan-fu.jpg) 我用3.3V是因为STM8的内部基准是3.3V的,M8内部参考电压好象是2.56V吧,把324的中点输出调到1.28V就可以了。
如果用5V参考电压,LM324就要改用12V供电才行。 感谢gzhuli 咕唧霖的及时回复。
M8 内参考就是2.56V,事实上程序()已经初始化为:内参考2.56 ,我看没必要再接3.3基准。
问题是现在接着3.3,运放调为1.65V,忽忽悠悠也工作着。晚上回家我去掉3.3V,调运放1.28V。 电路改进实验通过:
ADMUX= 0xc0+k; /*基准//D7 D6 =1 1 (对应0xc0) :2.56V 的片内基准电压源、左对齐、通道7*/
去掉外3.3基准,接一个100U滤波电解,测得该脚(内基准电压)2.56V左右,调运放1.28V,一切工作良好。
实验时,没接外电解时,直接测量Vref脚电压,很低,不到1V,奇怪。用示波器观察该脚,没有交流波形。接上了电解电容器,该脚才有2.56V左右的电压。 恭喜恭喜。 感谢liguang70217的不断指导。
我想提高悬浮距离,请指点方向。
1、现在12V供电,用调压器提升电压,稳定性变差。
2、想把线圈下落。我用的也是10CM直径的强磁柱,可以不受磁环内径的限制。
磁柱之间的距离越大,虚浮距离应该更小;
如果变小,有可能悬浮不了;
把线圈放外面,磁柱放里面;
把磁柱放到线圈里。
3、尝试在线圈中加大螺丝,想增加电磁铁的磁性,但悬浮磁铁吸引它。用半截铁芯试试。
4、不知非晶材料会起到什么作用? 回复【3楼】liguang70217
-----------------------------------------------------------------------
请问输出端要接二极管?? 回复【20楼】3243166
回复【3楼】liguang70217
-----------------------------------------------------------------------
请问输出端要接二极管??
-----------------------------------------------------------------------
这是老帖了,没人在.
咱回答你吧.这8只不能省.
应该要的.除保护相关器件外,
还可以减少不必要的干扰,使整个电路自身稳定. 请问一下这个头文件#include"BIT.h"那里有啊,可以分享一下吗?谢谢了。 http://cache.amobbs.com/bbs_upload782111/files_39/ourdev_639865TIYK6X.jpg
(原文件名:E039141C-C6B9-4A6F-90CC-9C0A98522CCC.jpg)
请问图中画红圈的是什么元件?望指教 比较复杂,很难改 chongcao 发表于 2010-12-7 14:37 static/image/common/back.gif
二极管接了,8个IN4017.
(原文件名:L298N.jpg)
请问有include ''BIT.H“文件吗? xuexi学习了 这个帖子还有人吗 qq 372702413 貌似都七楼了呵呵 楼主是我:QQ:910266897 chongcao 发表于 2013-7-20 10:08 static/image/common/back.gif
楼主是我:QQ:910266897
看到了 要反反复复的多看 谢谢 标记一下,以后学习 chongcao 发表于 2013-7-20 10:08 static/image/common/back.gif
楼主是我:QQ:910266897
楼主你好 我准备用mega16做一个 明天去买零件了 遇到不会的还得问您 但愿您能时常来论坛里指点指点呀 呵呵!另外 我看了坛子里的好几个磁悬浮的帖子 嗯 下推的4个电磁铁 一般都在线径0.5mm 700匝左右就行没有特殊的讲究吗?还是需要根据浮子的重量和高度来计算线径和匝数呀? 看看
页:
[1]