|
|
View previous topic :: View next topic |
Author |
Message |
hayate_kun
Joined: 22 Sep 2010 Posts: 8 Location: Malaysia
|
Stepper Motor with 16F877A |
Posted: Thu Nov 18, 2010 3:15 am |
|
|
Hello!
Can anyone give me some example of motor stepper coding with 16F877A? Thank you.
I'm using LINIX 6.0kg.cm Stepping Motor. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19480
|
|
Posted: Thu Nov 18, 2010 3:37 am |
|
|
You already have an example of basic stepper control. EX_STEP.C.
99%, depends on how 'well' you actually want to drive the motor, and what speeds you want to achieve. The simplest stepper control just has transistors driving the phases from their rated voltage, and is limited to a few hundred steps per second. The problem is that the phases are massively inductive, and simple electronic theory, tells you that when you apply voltage to an inductor, the current takes time to rise. So step fast, the current goes down, and the power output of the motor declines. The solution, is to realise that the voltage 'rating' of a stepper is the continuous voltage that can be applied 'stationary', and not overheat the motor. When moving, you can massively increase the end point voltage, so long as the current doesn't rise above the motor rating. It is typical to operate a '6v' stepper, off something like a 50v supply, if you want to move the motor fast, but then you _must_ have software or hardware to limit the maximum current through the coils to the motor rating. Control at this more sophisticated level, can be done directly by some PICs (particularly those with the power PWM module, and a comparator Using the latter to control the PWM being fed to the motor phases. However with the 16F877, all you are really going to be able to do is send pulses to turn on the phases, and if you want more sophistication, you will have to provide this in your driver hardware (there are many dozens of standard chips that automatically generate the PWM signals for you).
Best Wishes |
|
|
hayate_kun
Joined: 22 Sep 2010 Posts: 8 Location: Malaysia
|
|
Posted: Thu Nov 18, 2010 6:30 am |
|
|
Hi, thank you for your reply.
I've moved the stepper motor using PWM, however my lecturer told me that is actually incorrect way to move the stepper motor.
This is my code (freq setting=145, pwm=120, delay=700ms) it will move 9 deg per step, thus takes 40 steps per revolution:
Code: |
#include <16F877A.h>
#device adc=8
#use delay(clock=20000000)
#fuses hs,noprotect,nowdt,nolvp
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,parity=N)
#byte PORTA=5
#byte PORTB=6
#byte PORTC=7
#byte PORTD=8
#byte PORTE=9
void forsmall();
void revsmall();
void stopsmall();
void delay();
void main()
{
int pwmvalue=40;
int step;
//set_tris_d(0x00);
//set_tris_b(0x00);
//set_tris_c(0x80);
setup_port_a(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
setup_ccp1(ccp_pwm);
setup_ccp2(ccp_pwm);
setup_timer_2(T2_div_by_16,145,1); //149 is Y(freq setting) max=149,min=0 (PWM value), 16 is X
//=================================
// MAIN PROGRAM
//=================================
step=0;
do
{
while(step<20){
forsmall();
stopsmall();
step++;
}
revsmall();
step=0;
} while(TRUE);
}
void forsmall()
{
//===========================
// CLOCKWISE 6.0kg.cm
//===========================
set_pwm1_duty(120); // RC2 (ccp1)
output_low(pin_d3); //DIR
output_high(pin_d2); //EN
delay_ms(700); //the higher the longer it turns
}
void revsmall()
{
//===========================
// COUNTER-CLOCKWISE 6.0kg.cm
//===========================
set_pwm1_duty(120); // RC2 (ccp1)
output_high(pin_d3); //DIR
output_high(pin_d2); //EN
delay_ms(14400); //the higher the longer it turns
}
void stopsmall()
{
//===========================
// STOP 6.0kg.cm
//===========================
set_pwm1_duty(0); // RC2 (ccp1)
//output_low(pin_d3); //DIR
output_low(pin_d2); //EN
delay_ms(2000);
}
|
For your information, I'm using a driver to drive the motor. In the datasheet it said something about microstepping, unfortunately, I can't find a clue how to program it.
Therefore, I would appreciate if you can send me some link for stepper motor microstepping.
Thank you. |
|
|
arunb
Joined: 08 Sep 2003 Posts: 492 Location: India
|
RE: |
Posted: Thu Nov 18, 2010 9:48 pm |
|
|
what driver are you using ?? Please post a link to the datasheet.. also what kind of a stepper motor are you using ?
thanks
a |
|
|
hayate_kun
Joined: 22 Sep 2010 Posts: 8 Location: Malaysia
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19480
|
|
Posted: Fri Nov 19, 2010 10:04 am |
|
|
Start with a simple statement. You don't want a stepper driver.....
You already _have_ a stepper driver. The unit you are using already generates the PWM to 'drive' the motor. This is why your instructor is pointing you away from PWM. You _can_ develop the pulse train needed by this controller using PWM, but you should start simpler. Also, there are reasons why this may _not_ be the best solution.
What you have is what is known as a 'step/direction' controller. This expects to see, two signals. Just a signal that is high for rotation in one direction, and low for rotation in the other, combined with a pulse train,who's frequency you change to specify how fast you want the motor to move.
What voltage are you driving the controller from?. It is rated for up to 40v. The voltage will affect just how fast you can step the motor. The data sheet, does not give a 'pull in' step frequency.
Now the controller you have, has a eight way DIP switch. The top three positions of this, need to be set to '101', to program 2A/phase, which is the current your motor is rated for. Then the bottom three positions need to be set according to how many micro-steps you want to use. As a general comment, unless motors are specifically designed for micro-stepping, the accuracy tends to decline when large numbers of micro-steps are used. Something like 4 to 8 micro-steps is normally reliable with good accuracy. Higher numbers become more 'dubious'....
With your existing PWM setup, the PWM will be generating a pulse train at 2140Hz (20MHz/(4*16*146)). The motor will not start with anything approaching it's maximum torque at this sort of step rate, but this might be quite acceptable, if you were using perhaps 8 micro steps.
Generally, because of the inertia in the system, you would not want to start at 'full speed', and this is why the PWM generator is not the way to go to control this motor. Normally you would start slowly, accelerate to the maximum step rate, and then a little way before you want to stop 'ramp down' to a slow rate to avoid overshoot.
One way to do this, would be to have an interrupt at perhaps 5* the maximum rate that you want to step the motor. In this interrupt, decrement a counter, and if it is zero, trigger a pulse. The pulse need only be 5uSec low, so what you do, is as soon as you 'see' that the counter is 0, pull the pulse signal low, then carry out the operations to re-load the counter, by which time > 5uSec will have passed, and you can raise the signal again. The re-load, involves using a look up table of number of counts wanted between pulses. Have it holding a linear sweep of value, from perhaps 50 to 5. Then when you decide to move a number of steps, you set the table counter to '0', load the first value (which starts the pulse train), and the interrupt automatically counts up the table, with the motor accelerating.
At the re-load, you look to see if:
1) Is the table counter above the top of the table?. If so, you just keep going at this maximum rate.
2) You are 'half way' If so, start counting the table counter _down_, instead of up.
So, something like:
Code: |
int32 table_position=0;
#define TABLE_MAX (30) //adjust to uit number of acceleration steps req'd
int8 delay_table[TABLE_MAX] = {70,66,........5}; //number of ticks per step
int32 position=0x80000000;
int32 wanted=0x80000000;
int32 distance;
//Setup to be called by a suitable interrupt - typically perhaps 8000*/sec
void ticker(void) {
static int8 pulse_count=0;
static int1 moving=FALSE;
static int1 first_half;
if (!moving) {
//Here stepper not moving
if (position!=wanted) {
//Here a movement is required
if (wanted<position) {
distance=position-wanted;
output_low(DIRECTION_PIN); //set to step 'in'
}
else {
distance=wanted-position;
output_high(DIRECTION_PIN); //set to step 'out'
}
output_low(STEP_PIN);
table_position=0;
pulse_count=delay_table(table_position);
//This array load will take several uSec
moving=TRUE;
first_half=TRUE;
output_high(STEP_PIN);
}
}
else {
//Now moving
if (--pulse_count==0) {
//Next pulse may be needed
distance--;
if (distance==0) {
//Finished
position=wanted;
moving=FALSE;
}
else {
output_low(STEP_PIN);
if (first_half) {
//Here potentially accelerating
table_position++;
if (table_position>=distance) {
//Half way
first_half=FALSE;
}
if (table_position>=TABLE_MAX) {
pulse_count=delay_table(TABLE_MAX-1);
}
else
pulse_count=delay_table(table_position);
//Now have the number of interrupts till next pulse
}
else {
if (table_position>0)
table_position--;
if (table_position>=TABLE_MAX) {
pulse_count=delay_table(TABLE_MAX-1);
}
else
pulse_count=delay_table(table_position);
//Now have the number of interrupts till next pulse
}
output_high(STEP_PIN);
}
}
}
}
|
Now, this is 'as typed', so will have errors, and needs significant 'thought' as to how it is used. You need a 'delay_table', containing a list of interrupt counts to give acceleration/deceleration, a suitable rate interrupt, and to set 'wanted' to the count you want to go to. You will also need to offset the actual positions you want to go to, by 0x80000000 - so that you can potentially move a couple of thousand million steps in both directions if wanted.....
Best Wishes |
|
|
ntc
Joined: 18 Mar 2015 Posts: 8
|
Controlling step motor |
Posted: Sun Feb 21, 2016 9:13 pm |
|
|
Hi everybody!
Today I buy 2 motor 48BYJ-5V and driver with ULN280c IC, like as a link to make a clock ( 1 motor drive a second, and another drive a minutues with a mechanics structural have before, I need to control 2 motors with gear as:
- 15 rpm with second motor
- 0.25rpm / 0.3rpm with minutes motor
I have designed a new circuit to assembly 2 driver on one board, using ULN2803 IC and tried to write a program to control them.
I have a problems when the max speed of this motor is near with second motor speed, so that I have a delay with it, also the motor is feel hot.
In this project I'm using PIC16F18345 and CCS C ver 5.051.
Thanks for yours supports.
* Motor and driver specs
https://grahamwideman.wikispaces.com/Motors-+28BYJ-48+Stepper+motor+notes
* Schematic design
https://drive.google.com/file/d/0Bz215_lkn4g-ZldzbWU2c3ZoNUk/view?usp=sharing
* Program ( write on PIC18F starter KIT, if this program is OK , Ill port into PIC16F18345 in new design schematic)
Code: |
#include <18F4680.h>
#fuses H4,PUT,NOPROTECT,NOLVP,NOWDT,NOPBADEN
#use delay(clock=40000000)
#define EEPROM_SDA PIN_C4
#define EEPROM_SCL PIN_C3
#include <ds1307.c>
#define B1 PIN_B5 // blue
#define P1 PIN_B4 // pink
#define Y1 PIN_B3 // yellow
#define O1 PIN_B2 // orange
#define O2 PIN_A0
#define Y2 PIN_A1
#define P2 PIN_A4
#define B2 PIN_A5
unsigned int8 but0=0, but1=0;
unsigned int16 step=0;
unsigned int16 limit=0;
unsigned int16 count_t0=0;
unsigned int8 stp_mt1=0, stp_mt2=0;
unsigned int1 update_mt1=0, mt1_off=0,mt2_off=0, mt1_thuan=1, mt2_nhanh=0;
unsigned int8 update_mt2=0;
void motor_025v(void)
{
//------ O=1----------------
switch(stp_mt2)
{
case 1:
output_high(O1);
output_low(B1);
output_low(P1);
output_low(Y1);
break;
case 2:
output_high(O1); //------- O=Y=1------------
output_high(Y1);
output_low(P1);
output_low(B1);
break;
case 3:
output_high(Y1); //--- Y=1------------------
output_low(P1);
output_low(O1);
output_low(B1);
break;
case 4:
output_high(P1); //--- Y=P=1------------------
output_high(Y1);
output_low(O1);
output_low(B1);
break;
case 5:
output_high(P1); //--- P=1------------------
output_low(B1);
output_low(O1);
output_low(Y1);
break;
case 6:
output_high(B1); //--- P=B=1------------------
output_high(P1);
output_low(O1);
output_low(Y1);
break;
case 7:
output_high(B1); //--- B=1-----------------
output_low(O1);
output_low(P1);
output_low(Y1);
break;
case 8:
output_high(B1); //--- 0=B=1-----------------
output_high(O1);
output_low(P1);
output_low(Y1);
break;
default:
output_low(B1);
output_low(O1);
output_low(Y1);
output_low(P1);
break;
}
}
void motor_15v(void)
{
//------ O=1----------------
switch(stp_mt1)
{
case 1:
output_high(O2);
output_low(B2);
output_low(P2);
output_low(Y2);
break;
case 2:
output_high(O2); //------- O=Y=2------------
output_high(Y2);
output_low(P2);
output_low(B2);
break;
case 3:
output_high(Y2); //--- Y=1------------------
output_low(P2);
output_low(O2);
output_low(B2);
break;
case 4:
output_high(P2); //--- Y=P=2------------------
output_high(Y2);
output_low(O2);
output_low(B2);
break;
case 5:
output_high(P2); //--- P=2------------------
output_low(B2);
output_low(O2);
output_low(Y2);
break;
case 6:
output_high(B2); //--- P=B=2------------------
output_high(P2);
output_low(O2);
output_low(Y2);
break;
case 7:
output_high(B2); //--- B=2-----------------
output_low(O2);
output_low(P2);
output_low(Y2);
break;
case 8:
output_high(B2); //--- 0=B=2-----------------
output_high(O2);
output_low(P2);
output_low(Y2);
break;
default:
output_low(B2);
output_low(O2);
output_low(Y2);
output_low(P2);
break;
}
}
#int_timer0
void ngat_t0(void)
{
set_timer0(215);
update_mt1=1;
update_mt2=1;
}
//--------------------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------------------------
void main(void)
{
set_timer0(215);
setup_timer_0 (RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);
enable_interrupts(int_timer0);
enable_interrupts (global);
delay_ms(500);
for(;;)
{
//============================================================================================================================
//============================================================================================================================
if(input(PIN_B0)==0)
{
while(input(PIN_B0)==0);
delay_ms(10);
if(mt1_thuan==0)
{
mt1_thuan=1;
}
else if(mt1_thuan==1)
{
mt1_thuan=0;
}
}
else if(input(PIN_B1)==0)
{
while(input(PIN_B1)==0);
delay_ms(10);
if(mt2_nhanh==1)
{
mt2_nhanh=0;
}
else if(mt2_nhanh==0)
{
mt2_nhanh=1;
}
}
//============================================================================================================================
//============================================================================================================================
if( update_mt1==1 )
{
if(mt1_thuan==1)
{
stp_mt1++;
if(stp_mt1==9) stp_mt1=1;
}
else if(mt1_thuan==0)
{
stp_mt1--;
if(stp_mt1==0) stp_mt1=8;
}
motor_15v();
update_mt1=0;
}
if(update_mt2==1) // motor cham
{
if(stp_mt2<9) stp_mt2++;
if( mt2_nhanh==0)
{
if(stp_mt2==9)
{
count_t0++;
if(count_t0 == 458) { count_t0=0; stp_mt2=1;}
}
}
else
{
if(stp_mt2==9) stp_mt2=1;
}
motor_025v();
update_mt2=0;
}
}
}
|
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Feb 22, 2016 12:49 pm |
|
|
I've used the step/direction type controller and must say that the NCO module in the 16f1509 make it so easy as to be laughable |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|