分享:步进电机细分驱动思路及程序
微步驱动原理:细分驱动,把加在线圈上的电压 从最大到最小的过程,分四次给完,产生四个中间
状态,即四细分。伟力电机内部转子一个分步角度为60度。四细分之后,就变成
15度。外部指针则转1/12度。
细分方法:
根据电流等分,得到四个电压点,根据这四个电压点,预先计算出四个PWM值。
于是一个过程就需要24个点。
单片机需要处理的就是电流的方向控制。由伟力电机时序图,可以分析出每一个相的
电流方向。有四种情况。
正相增大,正相减小,反向增大,反向减小。
const unsigned char OCRnA_Val =
{
5,48,94,163,220,247,250,247,220,163,94,48,5,207,161,92,34,8,5,8,34,92,161,207
}; //微步码 两个线圈中电流相位是60度,
void step_moto_control(void)
{
if(direction_flag)//正转
{
if(OCRnA_Num_L==0)
{
OCRnA_Num_L = 23;
coil_1B_ON();
}
else
OCRnA_Num_L--;
if(OCRnA_Num_L<=12) coil_1B_CLE();
OCR0A=OCRnA_Val; //左线圈电流
if(OCRnA_Num_R==0)
{
OCRnA_Num_R = 23;
coil_2B_ON();
}
else
OCRnA_Num_R--;
if(OCRnA_Num_R<=12) coil_2B_CLE();
OCR0B=OCRnA_Val;
}
else//反转
{
OCRnA_Num_L++;
if(OCRnA_Num_L>=13) coil_1B_ON();
if(OCRnA_Num_L>23)
{
OCRnA_Num_L=0;
coil_1B_CLE();
}
OCR0A=OCRnA_Val;
OCRnA_Num_R++;
if(OCRnA_Num_R>=13) coil_2B_ON();
if(OCRnA_Num_R>23)
{
OCRnA_Num_R=0;
coil_2B_CLE();
}
OCR0B=OCRnA_Val;
}
}
SF SF SF SF SF 还有下文码 顶一个!期待下文! 谢谢 顶一下,谢谢分享 怎么没有下文了呀 怎么没有下文了呀 ZJSXHWL000000 发表于 2014-4-21 05:56
怎么没有下文了呀
思路,程序也都有啦。完结啦! 我来看看,别在意。 mark,谢谢分享 顶一下 还有一个台达步进电机的256细分程序。搞过仪表的人懂的。好像网上基本查不到台达步进电机细分驱动的相关知识。
有需要的人说下。共享之。 不错~~~~~~~ 能上的,能不能把台达的驱动也讲一下。 我用您的程序做实验,反转可以。正转细分不动。
还有噪声太大了。
还不如不细分。是不是PWM输出需要H桥驱动伟力的仪表用步进电机。 ZJSXHWL000000 发表于 2014-4-27 15:49
我用您的程序做实验,反转可以。正转细分不动。
还有噪声太大了。
还不如不细分。是不是PWM输出需要H桥驱动 ...
不用上面的程序 是量产的代码 都做货几年啦。
电机表示不会,还要学习 我想问:是不是PWM输出需要H桥驱动伟力的仪表用步进电机。
因为直接驱动仪表的M9S12HY内部都带,而通用单片机一般都有外部专用芯片。没有PWM直接驱动的。 ZJSXHWL000000 发表于 2014-4-29 05:24
我想问:是不是PWM输出需要H桥驱动伟力的仪表用步进电机。
因为直接驱动仪表的M9S12HY内部都带,而通用单片 ...
不是的。看我上面代码应该就知道。一个电机需要2个PWM 跟两个普通IO驱动,不需要专用IC 。我用瑞萨8路PWM的同时驱动4个电机做仪表盘 ,效果妥妥的。
如果你用飞思卡尔的 仪表专用 芯片 就不需要驱动了啊,他内部带驱动的。 楼上是汽车仪表的专家,我用ATMEL 16的两路PWM驱动都有问题。PWM电流驱动小于10ma.而步进电机为17ma,无法正常驱动。
噪声也太大。
瑞萨8路PWM没用过。
我看网上有加与门74HC08驱动。
还有楼上怎么联系。 ZJSXHWL000000 发表于 2014-4-29 17:18
楼上是汽车仪表的专家,我用ATMEL 16的两路PWM驱动都有问题。PWM电流驱动小于10ma.而步进电机为17ma,无法 ...
AVR直接驱动 电流不是问题。具体数据 我忘记了。可以很负责的告诉 你 。avr MEGA88P 直接驱动 我出货 N多。
瑞萨,357c这个 型号 的单片机 有加一个门电路 去驱动。但是门电路 仅仅是 扩充 IO 电流而已!
/**************************************************************
步进电机速度控制函数
***************************************************************/
void Speed_Control(void)
{
unsigned int angle_difference = 0;
unsigned int Speed_control_temp = 0;
if(current_angle == set_angle)
{
Speed_control_Val = 50;
return;
}
else
{
if(direction_flag==CCW)
angle_difference = current_angle - set_angle;
else if(direction_flag==CW)
angle_difference = set_angle - current_angle;
if(angle_difference>=100) //>=9
{
if(angle_difference>=1080) //>90
Speed_control_temp=1;
else if(angle_difference>=720) //60
Speed_control_temp=2;
else if(angle_difference>=540) //>45
Speed_control_temp=3;
else
Speed_control_temp=2160/angle_difference; //根据当前误差求出速度
if(Speed_control_temp>=20) Speed_control_temp = 20;
if(Speed_control_Val>Speed_control_temp) //加速
{
Speed_control_Val -= 1;
if(Speed_control_Val<=Speed_control_temp)
{
Speed_control_Val = Speed_control_temp;
}
}
else
{
if(angle_difference<=120&&Speed_control_Val<=4) //<10 减速
{
Speed_control_Val += 1;
}
}
}
}
} 本帖最后由 terencechang 于 2014-5-4 08:37 编辑
加减速控制 。梯形加减速。
const unsigned char add_speed_val= {0xac,0xcc,0xdb,0xde,0xe2,0xe5,0xe7};//,0xe9};//,0xea};//加速曲线672,417,324,276,244,221,204,190.--us
//一个全步之后换一次速度。回零最佳曲线。 ZJSXHWL000000 发表于 2014-4-29 17:18
楼上是汽车仪表的专家,我用ATMEL 16的两路PWM驱动都有问题。PWM电流驱动小于10ma.而步进电机为17ma,无法 ...
顺便说说 伟利的步进 电机噪音确实不小。想要噪音小,推荐台达步进电机。内部没有任何齿轮的。噪音基本为零。
抄小日本的技术。据说日系车上大部分用的都是这种电机。
噪音小,寿命厂。
楼上的,真心感谢您的指导,我的不细分没问题,一细分,就抖的很厉害。
细分时实验的代码。请您指导一下。
//ICC-AVR application builder : 2014-2-4 9:18:54
// Target : M16
// Crystal: 8.0000Mhz
#include <iom16v.h>
#include <macros.h>
# define unint unsigned int
# define uchar unsigned char
#define SET_BIT(io ,bit) (io |=(1<<bit) )
//置位: SET_BIT(PORTA,0);SET_BIT(DDRA,0);
#define CLR_BIT(io ,bit) (io &= ~(1<<bit) )
//清0: CLR_BIT(PORTA,0);CLR_BIT(DDRA,0);
#define GET_BIT(pin,bit) ( pin & (1<<bit) )
//读位: GET_BIT(PINA,0);
#define SET_IN( dir,bit) ( dir &= ~(1<<bit) )
//端口方向输入: SET_IN(DDRA,0);
#define SET_OUT(dir,bit) ( dir |=(1<<bit) )
//端口方向输出: SET_OUT(DDRA,0);
#define INVBIT(io,bit) ( io ^= (1<<bit) )
//反转方向
//
#define STEPPER_LN_1 SET_BIT(PORTB ,0)
#define STEPPER_LN_0 CLR_BIT(PORTB ,0)
//
#define STEPPER_RN_1 SET_BIT(PORTB ,1)
#define STEPPER_RN_0 CLR_BIT(PORTB ,1)
#define STEPPER_LR_1 SET_BIT(PORTD ,4)
#define STEPPER_LR_0 CLR_BIT(PORTD ,4)
#define STEPPER_RL_1 SET_BIT(PORTD ,5)
#define STEPPER_RL_0 CLR_BIT(PORTD ,5)
#define STEP_LN_1 SET_BIT(PORTA ,6)
#define STEP_LN_0 CLR_BIT(PORTA ,6)
#define STEP_RN_1 SET_BIT(PORTA ,4)
#define STEP_RN_0 CLR_BIT(PORTA ,4)
#define STEP_LR_1 SET_BIT(PORTA ,5)
#define STEP_RL_1 SET_BIT(PORTA ,5)
#define STEP_LR_0 CLR_BIT(PORTA ,5)
#define STEP_RL_0 CLR_BIT(PORTA ,5)
unsignedchar OCRnA_Num_L ,OCRnA_Num_R ;
unsigned char direction_flag = 1;
const unsigned char OCRnA_Val =
{
5,48,94,163,220,247,250,247,220,163,94,48,5,207,161,92,34,8,5,8,34,92,161,207
//0,65,127,180,221,246,255,246,221,180,127,65,0,190,128,75,34,9,0,9,34,75,128,190
}; //微步码 两个线圈中电流相位是60度,
void delay_1us(void) //1us延时函数
{
asm("nop");
}
void delay_nus(unsigned short int n) //N us延时函数
{
unsigned short int i=0;
for (i=0;i<n;i++)
delay_1us();
}
void Delay_1ms(void) //1ms延时函数
{
unsigned short int i;
for (i=0;i<(unsigned short int)(8*143-2);i++);
}
void Delay_nms(unint n) //n*1mS延时子函数
{
unint i=0;
while(i<n)
{
Delay_1ms();
i++;
}
}
void port_init(void)
{
PORTA = 0xFF;
DDRA= 0xFF;
PORTB = 0x0f;
DDRB= 0xFF;
PORTC = 0x0f; //m103 output only
DDRC= 0xFF;
PORTD = 0xff;
DDRD= 0xff;
}
//TIMER0 initialize - prescale:8
// WGM: Normal
// desired value: 255uSec
// actual value: 255.000uSec (0.0%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x01; //set count
OCR0= 0xFF;//set compare
TCCR0 = 0x01; //start timer
}
//TIMER1 initialize - prescale:8
void timer1_init(void)
{
TCCR1B = 0x00;
//OCR1AH = 0x01;
OCR1AL = 0xF4;
//OCR1BH = 0x01;
OCR1BL = 0xF4;
TCCR1A = 0x61;
TCCR1B = 0x02; //start Timer
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
//timer0_init();
timer1_init();
MCUCR = 0x00;
GICR= 0x00;
//TIMSK = 0x01; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
void step_moto_control(void)
{
if(direction_flag) //反转
{
if(OCRnA_Num_L==0) { OCRnA_Num_L = 23;STEPPER_LN_0;}//正负端左接1。
else OCRnA_Num_L--;
if(OCRnA_Num_L <= 12) STEPPER_LN_1; //正负端左接0。
OCR1AL=OCRnA_Val; //左线圈电流
OCR1AH = 0x00;
if(OCRnA_Num_R==0)
{OCRnA_Num_R = 23;STEPPER_RN_1; }//正负端右接1。
elseOCRnA_Num_R--;
if(OCRnA_Num_R <= 12) STEPPER_RN_0;//正负端右接0。
OCR1BL =OCRnA_Val;//右线圈电流
OCR1BH = 0x00;
}
else //正转
{
if(OCRnA_Num_L>23){OCRnA_Num_L=0;STEPPER_LN_0;} //正负端左接0。
else {OCRnA_Num_L++;}
if(OCRnA_Num_L>12) STEPPER_LN_1;//正负端左接1。
OCR1AL=OCRnA_Val;
OCR1AH = 0x00;
if(OCRnA_Num_R>23) {OCRnA_Num_R=0;STEPPER_RN_0;}//正负端右接1。
else OCRnA_Num_R++;
if(OCRnA_Num_R>12) STEPPER_RN_1;//正负端右接1。
OCR1BL=OCRnA_Val;
OCR1BH = 0x00;
}
}
/*
1个脉冲转子转60,指针转1/3度。
1/3度*90(1个周期6个脉冲)=180(个脉冲)*6/180减速比
*/
//24*90
void main(void)
{
unint k = 2250;
init_devices();
direction_flag = 0;
//逆时针
STEPPER_LN_0;
STEPPER_RN_0;
OCRnA_Num_L = 6;
OCRnA_Num_R = 10;
//顺时
STEPPER_LN_0;
STEPPER_RN_0;
OCRnA_Num_L = 4;
OCRnA_Num_R = 0;
while(1)
{
delay_nus(255);
step_moto_control();
}
}
#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
TCNT1H = 0xFF;
TCNT1L = 0x00;
//step_moto_control();
}
#pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF
void timer0_ovf_isr(void)
{
TCNT0 = 0x00; //reload counter value
//step_moto_control();
}
原理图如附件 您的程序的中间大括号有忘记,
Speed_control_temp=3;
}
else
{ 请问楼主的驱动表不是最优化驱动吧? 能不能请楼主讲一下:
梯形加减速。
一个全步之后换一次速度。回零最佳曲线。
是什么意思。 ZJSXHWL000000 发表于 2014-4-27 15:49
我用您的程序做实验,反转可以。正转细分不动。
还有噪声太大了。
还不如不细分。是不是PWM输出需要H桥驱动 ...
没看懂。你描述的问题,是LZ程序的问题,还是你没有用好? 是楼主留了一手。 ZJSXHWL000000 发表于 2014-5-10 11:31
是楼主留了一手。
LZ的程序不完整么?真是不完整的话,LZ应该明确说明。 学习学习! fengyunyu 发表于 2014-5-10 11:40
LZ的程序不完整么?真是不完整的话,LZ应该明确说明。
绝对是驱动部分完整的。量产过的。以前上班公司资料考不出来,发这个帖子目的,1纪念一下。2.把资料考出来。你懂的!!
请楼主把加速和台达电机的细分讲一下,搞技术的不要买关子。
说过:还有一个台达步进电机的256细分程序。搞过仪表的人懂的。好像网上基本查不到台达步进电机细分驱动的相关知识。
有需要的人说下。共享之。 ZJSXHWL000000 发表于 2014-5-13 13:35
请楼主把加速和台达电机的细分讲一下,搞技术的不要买关子。
说过:还有一个台达步进电机的256细分程序。搞 ...
/**********************************************************************************************
名称:
台达步进电机细分驱动:256细分
程序思想:
本电机为2相8拍5度步进电机 ,8个节拍为一个循环。本驱动,将两个节拍分为一个象限切换状态。按照
正弦波的变换方式变换
y
|
|
|---.---.---
| |
|------------------------------------------------------> x A-相电压波形
| | |
| ---.---.---.
|
|---. ---.---.
| | |
|------------------------------------------------------> x B-相电压波形
| | |
| ---.---.---.
|
|
|
| 分步驱动时序
P1 0------- |-------0 P2
$ |$
A $ |$ B
$ |$
$ |$
P3 0------- |-------0P4 电机接线图
A B 细分电流变化
P1 = 1; P2 = 1;
P3 = 0; P4 = 0; 一拍
A --> PWM 正向变高 B --> PWM 正向变低
P1 = 1; P2 = 0;
P3 = 0; P4 = 0; 二拍
P1 = 1; P2 = 0;
P3 = 0; P4 = 1; 三拍
A --> PWM 正向变低 B --> PWM 反向变高
P1 = 0; P2 = 0;
P3 = 0; P4 = 1; 四拍
P1 = 0; P2 = 0;
P3 = 1; P4 = 1; 五拍
A --> PWM 反向变高 B --> PWM 反向变低
P1 = 0; P2 = 0;
P3 = 1; P4 = 0; 六拍
P1 = 0; P2 = 1;
P3 = 1; P4 = 0; 七拍
A --> PWM反向变低B --> PWM 正向变高
P1 = 0; P2 = 1;
P3 = 0; P4 = 0; 八拍
***********************************************************************************************/
void step_moto_control(void)
{
switch(moto_state)
{
case 0://第一象限矢量方向+x +y
{
coliL_A_Clr();
coliL_B_On();
coliR_A_On();
coliR_B_Clr();
OCR0B=mirco_table-1; // 0 --->1
OCR0A=mirco_table-1;//1---->0
break;
}
case 1://第二象限矢量方向-x +y
{
coliL_B_Clr();
coliL_A_On();
coliR_B_Clr();
coliR_A_On();
OCR0A=mirco_table-1;
OCR0B=mirco_table-1;
break;
}
case 2://第三象限矢量方向-x -y
{
coliL_B_Clr();
coliL_A_On();
coliR_A_Clr();
coliR_B_On();
OCR0B=mirco_table-1;
OCR0A=mirco_table-1;
break;
}
case 3://第四象限矢量方向+x -y
{
coliR_A_Clr();
coliR_B_On();
coliL_A_Clr();
coliL_B_On();
OCR0A=mirco_table-1;
OCR0B=mirco_table-1;
break;
}
default : break;
}
} 以上驱动,我在全网都搜索过,这个绝对是首发,因为台达步进电机在国内仪表上应用非常非常少。对比VID方式的步进电机。这个电机太多优势啦
1.噪音只有VID方式的步进电机几十分之一。
2.寿命长。由于不存在齿轮结构,所以理论寿命是VID方式的N倍
3.价格便宜。
4.响应速度快。 个人认为分享程序只丢一堆代码,不是真正的分享。只有把程序思想跟设计过程写得清清楚楚 才是真正意义上的分享。
请楼主好人做到底,再讲一下加减速控制思路。 步进电机速度控制函数中换方向如何办。 mark。。。。。。。。。。。。。。。 terencechang 发表于 2014-5-14 08:29
/**********************************************************************************************
名 ...
请问楼主: coliL_A_Clr();
coliL_B_On();
coliR_A_On();
coliR_B_Clr();
这几个函数具体是什么意思,象位设定么?不怎么明白,可否解释一下? 一端用PWM驱动,一端左边线圈置位,右边线圈清0。
我的程序实验会失步。 请问楼主:PWM采用快速,相位修正,还是相频修正。
最近在捣鼓42步进电机细分的时候遇到一个问题难以理解,请大侠帮忙答疑解惑。
步进电机在取细分表的时候,是应该取π/2的弧度还是π的弧度?在网上看到大家都是取π弧度的,对此十分的疑惑。比如8细分的正余弦细分表如下:
u16sin_8_X_buf[]= //8 PWM正弦细分表
{
0,1534,2896,3770,
4096,3797,2896,1600,
};
u16cos_8_X_buf[]= //8 PWM余弦细分表
{
4096,3797,2896,1600,
0,1534,2896,3770,
};
从图片中可以看出,每相的电流变化都是按正相增大,正相减小,反向增大,反向减小的方式去变化。
如果按π弧度取细分表的话,那不是每走π/2弧度就得换相么?在下一相的时候再重新读取细分表,这样就相当于4细分。8细分是如何得到的呢?
好东西,正需要。 步进电机。代码 楼主,请问用表计算得到的PWM值控制相电流,如果达不到要比较的DA输出的值的话,或者高于DA输出的值的话,怎么处理?是斩波电流自动处理吗?还是需要调整PWM的数值? 正在研究步进电机,学习了
页:
[1]