[CODE] [TUT] [C] Stepper Motor Controller with ACC and DEC

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am providing this code to show how I was able to avhieve fixed acceleration and deceleration using the Mega64 and a GeckoDrive G210 stepper motor controller. This stepper motor controller is a STEP/DIRECTION controller dirving an Automation Direct 270 Oz/In 3 amp bi-polar stepping motor.

These are found in my C:/iccv7avr/include/macros.h directory

#ifdef __iom64v_h
#define UART1_TRANSMIT_ON() UCSR1B |= 0x08
#define UART1_TRANSMIT_OFF() UCSR1B &= ~0x08
#define UART1_RECEIVE_ON() UCSR1B |= 0x10
#define UART1_RECEIVE_OFF() UCSR1B &= ~0x10
#endif __iom64v_h

#define ESC 0x1B
#define NULL 0x00

This is the main() program code:

// This program was written by Carl W Livingston, KC5OTL. 
// I freely grant permission to use this program for personal use only. 
// No commercial use of this program is allowed unless written authorization
// is granted by the author, Carl W. Livingston, KC5OTL. 
// If changes are made to this program, due credit must be given to the
// original author, Carl W. Livingston, KC5OTL. 

// While this program may migrate to the global public domain, this program 
// was written for my personal use and is released to www.AVRFreaks.net for 
// the personal use of the members of www.AVRFreaks.net.  If this program is 
// posted on web-sites other then www.AVRFreaks.net, full, and due credit MUST be 
// given to the Author known as microcarl, who is a www.AVRFreaks.net member, 
// and whose full and legal name is Carl W. Livingston. 

/********************************************************************************* 
// DISCLAIMER!!! 
// The author of this program assumes no liability for damage, monitary loss, or 
// programming errors in this program.  The use of this program is at the risk 
// of the end user. 
    

/* 
This stepper motor program is currently set up on an Atmel STK500/STK501 development borad running at 21.855 MHz and driving a GeckoDrive G210 stepper motor drive.  See http://www.geckodrive.com/
The GeckoDrive stepper motor controller uses STEP/DIRECTION inputs to control the stepper motor velocity and direction. 

The program was written using the ImageCraft ICCAVR V7.xx C complier.  Code compression was used during compilation of the program. 

This program has been tested on the Mega64.  I have also added conditional compilation clauses to use the Mega16 and Mega32 microcontrollers. 

Using the ImageCraft ICCAVR V7.00 compiler with code compression, the Mega16 compiles out at about 60% usage of its FLASH memory, the Mega32 at about 40% and, the Mega64 compiles at about 11%. 

While this program uses the STEP/DIRECTION output format it can be easily converted to utilize a bi-polar steppr motor with the use of two appropriately sized H-Bridge and a uni-polar stepper motor using four appropriately sized power MOS-FETS.  Future releases of this program will be released showing the use of bi-polar and uni-polar stepper motors. 

While configuring a stepper motor to move in a forward or reverse direction is somewhat trivial, I found that the acceleration and deceleration aspects was not. 

This stepper motor program uses fixed acceleration and deceleration rates. 
Future releases will also include adjustable acceleration and deceleration.

If the sum of the fixed acceleration and deceleration counts (T1 + T3) is greater then the total move counts, the move velocity is controlled, along with the fixed acc/dec counts to form a triangle move profile rather then the typical trapazoid move profile. 

In addition, if the commanded move velocity is slower then the minimum velocity that will reliably move the stepper motor, no acceleration/deceleration is used. 

There are conditional compilation statements, as well, that allow the use of HyperTerminal to display the basic position, step rate and other useful status information.  The program line containing "debug" define at the top of the StepCon.c 
program (this file) file headder area can be blocked out to turn off the debug code. 

The command protocol is as follows: 

m xxxxx = set axis move count, where, xxxxx is the number of counts to move. 
v xxxxx = set axis velocity count, where, xxxxx is the inverse of axis velocity.  
h = home axis at zero position count. 
c = cycle start. 
s = controlled axis stop. 
p = display axis position. 
r = report axis status. 

The stepper motor is a 1.8 degree per step motor.  I.E. 200 steps per motor shaft revolution.
The axis lead screw pitch is 18 turns per inch.
The maxamum physical axis travel is ~13 inches.

Typical command entry would be:


m40000  Move axis ~12 inches
v100  Velocity ~55 inches per minute
c  Start axis move.

s  Controlled axis stop.

p  Reprot current axis position.

r  Report current axis status, in hexidecmal.



Axis moves are in step counts.  A signed long integer is used for position accumulation. 
Axis velocity is in counts and is based on the microcontroller clock frequency.
Timer1 is used along with OCR1A for step and velocity control. 
*/ 

// FILE NAME:     StepCon.c 

/*************************************************************/ 
// Standard C library Includes 
// Change the following line to iom16v.h or iom32v.h 
#include  
#include  
#include  
#include  
#include  

// StepCon motion controller Includes 
// The following two files should reflect changes to support the USART 
// differences between the Mega16, Mega32 and Mega64. 
// The Mega16 and Mega32 use the generic USART defines. 
// The Mega64 USART has USART0 and USART1.  For the Mega64, USART1 is used 
// to output axis and status information to HyperTerminal. 

#include "getchar.c" 
#include "putchar.c" 

/*************************************************************/ 
/*********************** DEBUG CONTROL ***********************/ 
/*************************************************************/ 
#ifndef DEBUG 
// Block out the following line to turn off the debug features. 
#define DEBUG 
#endif DEBUG 
/*************************************************************/ 
/*************************************************************/ 
/*************************************************************/ 

/*************************************************************/ 
// StepCon motion controller Defines 

// Axis status byte flags 
#define FIRST_HOME_FLAG      0x01   // Not homed after power up 
#define AT_HOME_FLAG         0x02   // Axis Home Flag 
#define IN_POSITION_FLAG   0x04   // Axis In Position Flag 
// #define Future use      0x08   // Future use 
#define MOVE_FLAG            0x10   // Axis Move Enable Flag 
#define ACC_FLAG            0x20   // Axis Acceleration Enable 
#define DEC_FLAG            0x40   // Axis Deceleration Enable 
#define   DIR_FLAG         0x80   // Axis Direction FLAG 

// PORTC I/O definitions 
#define AXIS_NOT_HOMED      0x01   // Not homed after power up 
#define AXIS_AT_HOME         0x02   // Axis Home 
#define AXIS_IN_POSITION   0x04   // Axis In position 
#define AXIS_PLUS_LIMIT      0x08   // (+) Axis limit switch 
#define AXIS_MINUS_LIMIT   0x10   // (-) Axis limit switch 
#define AXIS_ENABLED      0x20   // Future use 
#define   AXIS_STEP      0x40   // Axis "STEP" Control Bit 
#define   AXIS_DIR      0x80   // Axis "DIRECTION" Control Bit 


#ifdef DEBUG 
/****************************************************************************/ 
// Macro definitions 

// Clear the communications terminal 
#define CLEAR_SCREEN (printf("%c[2J", ESC)) 

// Position cursor on communications terminal. Macro inputs, x = column, y = row 
#define PUT_CURSOR(x, y)  (printf("%c[%d;%dH", ESC, y, x)) 

/****************************************************************************/ 
#endif DEBUG 

void InitDevices(void); 
void SetVelocity(void); 
char *GetData(char *); 

char AxisStatus; 
char cmd = NULL; 
char COMMAND_DATA[10]; 

unsigned int   T1 = 250;               // Acceleration time. Default = 250 counts 
unsigned int   T3 = 250;              // Deceleration time. Default = 250 counts 
unsigned int   CommandVelocity = 100;  // Commanded velocity. Default = 100 
unsigned int   TargetVelocity;          // Final move velocity. Processed by command input 
unsigned int     StartingVelocity = 500; // Starting velocity for move. Default = 500 

#ifdef DEBUG 
long int      TempCount; 
#endif DEBUG 

long int      TargetCount = 0; 
long int      CurrentCount = 0; 
long int      TriggerCount; 

/****************************************************************************/ 
// This is the Stepping motor controller main program. 

void main(void) 
{   // Initialize the microcontroller hardware function blocks. 
    InitDevices(); 

   // Initialize system variables. 
#ifdef __iom16v_h 
   UDR = NULL; 
#endif __iom16v_h 

#ifdef __iom32v_h 
   UDR = NULL; 
#endif __iom32v_h 

#ifdef __iom64v_h 
   UDR1 = NULL; 
#endif __iom64v_h 

   cmd = NULL; 

   AxisStatus = NULL; 
   PORTC = NULL; 
    
#ifdef DEBUG    
   CLEAR_SCREEN; 

   // Set up the communications terminal screen text. 
   PUT_CURSOR (20, 14); 
   printf("Feed Rate = "); 

   PUT_CURSOR(20, 16); 
   printf("Target Position = "); 

   PUT_CURSOR(20, 18); 
   printf("Current Position = "); 

   PUT_CURSOR(1, 16); 
   printf("Home: "); 
    
   PUT_CURSOR(1, 18); 
   printf("In Position: "); 
#endif DEBUG 

   SEI(); // Enable the global interrupts. 
                       
   // Repeat this loop forever! 
   do 
   { 

#ifdef DEBUG    
     // Update axis status to the communications terminal. 
     PUT_CURSOR(40, 14); 
     TempCount = CommandVelocity; 
       printf("%6u ", TempCount); 
    
     PUT_CURSOR(40, 16); 
     TempCount = TargetCount; 
       printf("%6ld ", TempCount); 
     
     PUT_CURSOR(40, 18); 
     TempCount = CurrentCount; 
       printf("%6ld ", TempCount); 

     PUT_CURSOR(14, 16); 
     if (AxisStatus & AT_HOME_FLAG) 
         printf("Y"); 
     else printf("N"); 
       
     PUT_CURSOR(14, 18); 
       if (AxisStatus & IN_POSITION_FLAG) 
        printf("Y"); 
     else printf("N");       
#endif DEBUG 
         
/*
  :                        if (TARGET_COUNT > (T1 + T2))                       :  
  :                     TARGET_VELOCITY = COMMAND_VELOCITY                     :  
  :      :                                                              :      :  
  :  T1  :                              T2                              :  T3  :  
  :      :                                                              :      :  
V :      :                                                              :      :  
E :      :                                                              :      :  
L :      :______________________________________________________________:      :  
O :     /:                                                           ___:\     :  
C :    / :                                    DECELERATION WINDOW __/   : \    :  
I :   /  :___                                                           :  \   :  
T :  /   :   \__ TARGE VELOCITY = COMMAND VELOCITY                      :   \  :  
Y : /    :                                                              :    \ :  
  :/     :                                                              :     \:  
  :------:--------------------------------------------------------------:------:  
  :                                                                            :  
  :    __ STARTING VELOCITY                                                    :  
  :___/                                                                        :  
  :   \__ STARTING COUNT                                                       :  
  :                                                                            :  
  :         >----------------------- DISTANCE ----------------------->         :  

  :                     if (abs(TARGET_COUNT) <= (T1 + T2))                    :  
  :        TARGET_VELOCITY = STARTING_VELOCITY - (abs(TARGET_COUNT) / 2)       :  
  :                                                                            :  
  :      :      :                                                              :  
  :  T1  :  T3  :                                                              :  
  :      :      :                                                              :  
V :      :  ____:_________________ COMMAND VELOCITY ______________________     :  
E :      : /    :                                                              :  
L :      :/    _:_ TARGET VELOCITY                                             :  
O :      /____/ :                                                              :  
C :     /:\   \_:_ MODIFIED DECELERATION WINDOW                                :  
I :    / : \    :                                                              :  
T :   /  :  \   :                                                              :  
Y :  /   :   \  :___                                                           :  
  : /    :    \ :   \__ TARGET COUNT                                           :  
  :/     :     \:                                                              :  
  :------:------:--------------------------------------------------------------:  
  :                                                                            :  
  :    __ STARTING VELOCITY                                                    :  
  :___/                                                                        :  
  :   \__ STARTING COUNT                                                       :  
  :                                                                            :  
  :         >----------------------- DISTANCE ----------------------->         :  

 ******************************************************************************* 
 *          Target                  Reference                   Target         * 
 *          Count                     Count                     Count          * 
 *            |                         |                         |            * 
 *       (-)  |  (+)               (-)  |  (+)               (-)  |  (+)       * 
 * -------|---N---|-----------------|---0---|-----------------|---N---|--------* 
 *      __|       |__             __|       |__             __|       |__      * 
 *     |             |           |             |           |             |     * 
 *  Forward       Reverse     Forward       Reverse     Forward       Reverse  * 
 *   Decel         Decel       Decel         Decel       Decel         Decel   * 
 *  Trigger       Trigger     Trigger       Trigger     Trigger       Trigger  * 
 *                                                                             * 
 *          >-----------------  Forward  Direction  ----------------->         * 
 ******************************************************************************* 

  If the axis is moving forward, the "Forward Deceleration Trigger" value must be 
  subtracted from the "Target Count", as indicated by the (-). 

  If the axis is moving in reverse, the "Reverse Deceleration Trigger" value must be added 
  to the "Target Count", as indicated by the (+). 

  The result of the above addition or subtraction then becomes the forward or 
  reverse deceleration trigger point. 

  The distance between the "Target Count" and the "Forward" or "Reverse" trigger 
  count is the deceleration window and is where the axis deceleration takes place. 
*/ 
       // Check for a character, but don't wait.    
#ifdef __iom16v_h 
     if (UCSRA & (1<<RXC)) 
         cmd = UDR; 
#endif __iom16v_h 
    
#ifdef __iom32v_h 
     if (UCSRA & (1<<RXC)) 
         cmd = UDR; 
#endif __iom32v_h 
     
#ifdef __iom64v_h 
     if (UCSR1A & (1<<RXC1)) 
         cmd = UDR1; 
#endif __iom64v_h 

      switch (cmd) 
      { 
         case 'm':   // Get the new axis target count. 
                   if (!(AxisStatus & MOVE_FLAG)) 
                  {  
                     TargetCount = strtol(GetData(COMMAND_DATA),0,NULL); 

                     if (TargetCount > CurrentCount)                      
                     {  // Go forward. 
                          PORTC &= ~AXIS_DIR; 
                          AxisStatus &= ~DIR_FLAG; 
                     } 
                     else 
                     {  // Go reverse. 
                             PORTC |= AXIS_DIR; 
                          AxisStatus |= DIR_FLAG;    
                     } 
                      
                     SetVelocity(); 
                  } 
                  cmd = NULL; 
                  break; 

         case 'p':   // Report the current step count. 
                   #ifdef DEBUG 
                  PUT_CURSOR(40, 18); 
                  #endif DEBUG 
                   
                  printf("%6ld  ", CurrentCount);                   
                  cmd = NULL; 
                  break; 

         case 'r':   // Report the current axis status. 
                   #ifdef DEBUG 
                   PUT_CURSOR(1, 20); 
                  #endif DEBUG 
                   
                  printf("%x ", AxisStatus); 
                  cmd = NULL; 
                  break; 
                   
         case 'c':   // Cycle Start. 
                   if (!(AxisStatus & MOVE_FLAG)) 
                     if (TargetCount != CurrentCount)                            
                     { 
                       if (CommandVelocity > 500) 
                           OCR1A = CommandVelocity; 
                       else 
                               OCR1A = StartingVelocity; 
                          
                          AxisStatus |= (ACC_FLAG | MOVE_FLAG); 
                          TIMSK |= (1<<OCIE1A); // Enable timer 1, OCR1A interrupt 
                      } 
                   cmd = NULL; 
                   break; 

         case 's':   // Controlled axis Stop. 
                  if (AxisStatus & MOVE_FLAG) 
                  { 
                     if (AxisStatus & DIR_FLAG) // Axis moving reverse? 
                          TargetCount = CurrentCount - T3;       
                     else   // The axis is moving forward. 
                        TargetCount = CurrentCount + T3;       
                                                          
                     AxisStatus |= DEC_FLAG; 
                     AxisStatus &= ~ACC_FLAG; 
                  }    
                  cmd = NULL; 
                  break; 

         case 'h':   // Home the axis. 
                   if (!(AxisStatus & MOVE_FLAG)) 
                  { 
                      CurrentCount = 0; 
                      TargetCount = 0; 
                     AxisStatus |= (FIRST_HOME_FLAG | AT_HOME_FLAG | IN_POSITION_FLAG); 
                  } 
                  cmd = NULL; 
                  break; 

         case 'v':   // Set the axes velocity. 
                   if (!(AxisStatus & MOVE_FLAG)) 
                   { 
                     CommandVelocity = (unsigned int)atoi(GetData(COMMAND_DATA)); 
                   
                     // Limit the "Target Velocity" to a value of 100, "~55 IPM". 
                     if (CommandVelocity < 100) 
                          CommandVelocity = 100; 
                   
                     SetVelocity(); 
                  }     
                  cmd = NULL; 
                  break; 
      } 
   } while (1); // Repeat this loop forever! 
} 

void SetVelocity (void) 
{ 
   TargetVelocity = CommandVelocity; 

   if (AxisStatus & AXIS_DIR) 
   {  // Reverse direction 
      if (abs(TargetCount - CurrentCount) < (T1 + T3)) 
      { 
           TargetVelocity = StartingVelocity - (CurrentCount - TargetCount) / 2; 
           TriggerCount = TargetCount - (TargetCount - CurrentCount) / 2; 
      } 
      else TriggerCount = TargetCount + T3; 
   } 
   else 
   {   // Forward direction 
      if (abs(TargetCount - CurrentCount) < (T1 + T3)) 
         { 
         TargetVelocity = StartingVelocity - (TargetCount - CurrentCount) / 2; 
            TriggerCount = TargetCount - (TargetCount - CurrentCount) / 2; 
      } 
      else TriggerCount = TargetCount - T3; 
   }    
} 

/****************************************************************************/ 
// Retrieve a character string from the "Host" controller. 
// This character string is in ASCII format. 

char *GetData(char *d) 
{ 
     int n = 0; 
    char Temp = NULL; 

    // Clear the character string buffer. 
    memset(d, NULL, 10); 

    do 
    {    // Check for character, but don't wait! 
#ifdef __iom16v_h 
         if (UCSRA & (1<<RXC)) 
      { 
         Temp = UDR; 
#endif __iom16v_h 

#ifdef __iom32v_h 
         if (UCSRA & (1<<RXC)) 
      { 
         Temp = UDR; 
#endif __iom32v_h 
          
#ifdef __iom64v_h       
         if (UCSR1A & (1<<RXC1)) 
      { 
         Temp = UDR1; 
#endif __iom64v_h 
         
       // If the current character is not a "Carrage Return", 
       // save the current character. 
       if (Temp != '\r') 
          d[n++] = Temp; 
      } 
      // Keep looping until the entire character string is retrieved. 
    } while (Temp != '\r'); 

    return(d); 
} 

/****************************************************************************/    
// Timer 1 Output Compare Register 1A, OCR1A intrrupt vector. 
#ifdef __iom16v_h 
#pragma interrupt_handler SteppingIRQ:7 
#endif __iom16v_h 

#ifdef __iom32v_h 
#pragma interrupt_handler SteppingIRQ:8 
#endif __iom32v_h 

#ifdef __iom64v_h 
#pragma interrupt_handler SteppingIRQ:13 
#endif __iom64v_h 

// The rate of intrrupt is inversely proportional to the value in OCR1A.  That is, 
// axis velocity is inversely proportional to current value stored in OCR1A. 
// Large values cause the axis to go slow, small values cause the axis to go fast. 

void SteppingIRQ(void) 
{ 
      PORTC |= AXIS_STEP; // Turn the STEP output on. 

      if (AxisStatus & DIR_FLAG) 
      {  // The axis is moving in reverse, decrement axis position counter. 
           if (--CurrentCount <= TriggerCount)    
           { 
                AxisStatus |= DEC_FLAG; 
               AxisStatus &= ~ACC_FLAG; 
        } 
      } 
      else   // The axis is moving forward, increment axis position counter. 
          if (++CurrentCount >= TriggerCount)    
            { 
                  AxisStatus |= DEC_FLAG; 
               AxisStatus &= ~ACC_FLAG; 
         }    

      if (CurrentCount == TargetCount) 
      {  // At target count, disable OCR1A intrrupt 
           TIMSK &= ~(1<<OCIE1A); 
        // Clear "MOVE_FLAG", "ACC_FLAG" & "DEC_FLAG". 
        AxisStatus &= ~(MOVE_FLAG | ACC_FLAG | DEC_FLAG); 
        // Set "IN_POSITION_FLAG". 
        AxisStatus |= IN_POSITION_FLAG; 
       
           if (CurrentCount == 0) 
               // Axis is at "Home", set the "HOME_FLAG" bit. 
               if (AxisStatus & FIRST_HOME_FLAG) 
               AxisStatus |= AT_HOME_FLAG; 
      } 
      else 
      { 
               if (CurrentCount != 0) 
            AxisStatus &= ~AT_HOME_FLAG; 

         if (CurrentCount != TargetCount) 
            AxisStatus &= ~IN_POSITION_FLAG; 
                                     
            // Acceleration control. 
            if (CommandVelocity < 500) 
            if (AxisStatus & ACC_FLAG) 
                      if (--OCR1A < TargetVelocity) 
                          AxisStatus &= ~ACC_FLAG; 
          
         // Deceleration control. 
            if (CommandVelocity < 500) 
            if (AxisStatus & DEC_FLAG) 
                 OCR1A ++; 
      } 

      PORTC &= ~AXIS_STEP; // Turn the STEP output off. 
} 

// Initialization file StepCon_INIT.c

#include  
#include  

// I/O Port initialization 
void port_init(void) 
{ 
 PORTA = 0x00; 
 DDRA  = 0x00; 
 PORTB = 0x00; 
 DDRB  = 0x00; 
 PORTC = 0x00; 
 DDRC  = 0xE4; 
 PORTD = 0x00; 
 DDRD  = 0xE2; 
} 

// TIMER1 initializatio - prescale:1 
void timer1_init(void) 
{ 
 TCCR1B = 0x00;        // Stop Timer Counter 1 
 TCNT1 = 0;           // Clear Timer Counter 1 
 OCR1A = 0x21; 
 OCR1B = 0x10;        // 10 miliseconds 
 TCCR1A = 0x00;        // Generate no outputs 
 TCCR1B = 0x0B;        // Start Timer Counter 1 with OCR1A, CLK / 1 
} 

// UART1 initialization 
void uart1_init(void) 
{ 
// For a 14.745600MHz crystal 
// #define BAUD115_2K   7 

// For a 16.000MHz crystal 
// #define BAUD115_2K   8 

// For a 21.855MHz crystal 
#define BAUD115_2K   11 

#ifdef __iom16v_h 
 UCSRB = NULL; // Disable while setting baud rate 
 UCSRA = NULL; // 0x00; 
 UCSRC = 0x06; // 8 bit data 
 UBRRL = BAUD115_2K;    // Set baud rate lo 
 UBRRH = NULL;       // Set baud rate hi 
 UART_TRANSMIT_ON(); // Turn on the UART transmitter 
 UART_RECEIVE_ON(); // Turn on the UART receiver 
#endif __iom16v_h 

#ifdef __iom32v_h 
 UCSRB = NULL; // Disable while setting baud rate 
 UCSRA = NULL; // 0x00; 
 UCSRC = 0x06; // 8 bit data 
 UBRRL = BAUD115_2K;    // Set baud rate lo 
 UBRRH = NULL;       // Set baud rate hi 
 UART_TRANSMIT_ON(); // Turn on the UART transmitter 
 UART_RECEIVE_ON(); // Turn on the UART receiver 
#endif #ifdef __iom32v_h 

#ifdef __iom64v_h 
 UCSR1B = NULL; // Disable while setting baud rate 
 UCSR1A = NULL; // 0x00; 
 UCSR1C = 0x06; // 8 bit data 
 UBRR1L = BAUD115_2K;    // Set baud rate lo 
 UBRR1H = NULL;       // Set baud rate hi 

 UART1_TRANSMIT_ON(); // Turn on the UART transmitter 
 UART1_RECEIVE_ON(); // Turn on the UART receiver 
#endif __iom64v_h 
} 

// Initialize required controller peripherals 
void init_devices(void) 
{ 
 CLI(); // Disable global interrupts 
 port_init(); 
 timer1_init(); 
 uart1_init(); 
        
 MCUCR = NULL; 
  
#ifdef __iom64v_h 
 EICRA = NULL; 
 EICRB = NULL; 
 EIMSK = NULL; 
#endif 
  
 // Controller peripherals are now initialized 
} 

// Modified getchar() function

#ifdef __iom16_h 
#include  
int getchar(void) 
    { 
    while ( !(UCSRA & (1<<RXC)) );      // RXC: USART Recieve Complete 
        
    return UDR; 
    } 
#endif __iom16_h 
  
#ifdef __iom32_h 
#include  
int getchar(void) 
    { 
    while ( !(UCSRA & (1<<RXC)) );      // RXC: USART Recieve Complete 
        
    return UDR; 
    } 
#endif __iom32v_h    

#ifdef __iom64_h 
#include  
int getchar(void) 
    { 
    while ( !(UCSR1A & (1<<RXC1)) );      // RXC: USART Recieve Complete 
        
    return UDR1; 
    } 
#endif __iom64v_h    

// Modified putchar() function

extern int _textmode; 

#ifdef __iom16v_h 
#include  
   int putchar(char c) 
    { 
    if (_textmode && c == '\n') 
        putchar('\r'); 
    // Wait for empty transmit buffer 
    while ( !(UCSRA & (1<<UDRE)) ); 
                         
    //Putting data into buffer , sends the data 
    UDR = c;  
    return c; 
    } 
#endif __iom16v_h    

#ifdef __iom32v_h 
#include  
int putchar(char c) 
    { 
    if (_textmode && c == '\n') 
        putchar('\r'); 
    // Wait for empty transmit buffer 
    while ( !(UCSRA & (1<<UDRE)) ); 
                         
    // Putting data into buffer , sends the data 
    UDR = c;  
    return c; 
    } 
#endif __iom32v_h    

#ifdef __iom64v_h 
#include  
int putchar(char c) 
    { 
    if (_textmode && c == '\n') 
        putchar('\r'); 
    /* Wait for empty transmit buffer */ 
    while ( !(UCSR1A & (1<<UDRE1)) ); 
                         
    /* Putting data into buffer , sends the data */ 
    UDR1 = c;  
    return c; 
    } 
#endif __iom64v_h    

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fantastic work! I'd say that it's large enough to warrant an academy project of it's own (with accompanying text in the academy forum) - as a bonus you'd get more exposure. I can see an amazing amount of work has gone into this, including the ASCII art :D.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Carl.... is the velocity in steps per second? Whats the max steps/sec of the motor? If you clamp a big old heavy disc with a lot of inertia on the motor shaft, does it mess up the acceleration time constants? f=ma and all that. I tried to figure out how to 'ramp' the acceleration up thru the resonance region and run it like a synchronous motor, but I never figured it all out.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bob,

I'm at work right now, but I'll try to post a PDF file that has the math that will answer some of your questions.

It is incomplete, as I am still working on it so, please bare with me until I am able to complete the document.

As I am moving an axis whis is basically a linear actuator, I won't be able to speak to the resonance of a masive disk, though, I have seen heavy disks used exactly for the purpose of dampening the resonance issues that come up with stepper motors.

I'd like some feedback on the document though, both technical and structural.

Oh! And too! I have not implemented the equations shown in the PDF document into the program yet. I hope to do that this weekend, if mama's "Honey Do" list isn't too large.

If you are interested, I would be willing to convert it over to an H-Bridge for a Bi-Polar motor or Uni-polar output so you can play with it. I'll need a little time, though.

Attachment(s): 

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atmel has made an application note on the same thing:
AVR446: Linear speed control of stepper motor

It dosn't use a stepper motor controller, but should be fairly easy to adapt.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BillTheCat wrote:
Atmel has made an application note on the same thing:
AVR446: Linear speed control of stepper motor

It dosn't use a stepper motor controller, but should be fairly easy to adapt.

Actually, it's not the same thing. The Atmel application note is running a motor. I'm actually positiong an axis test bed. The axis velocity is about 70 inches per minute using a 18 turn per inch lead screw and a 170 inch-ounce 200 pulse per revolution (1.8 degrees) stepper motor.

The stepper motor controller that is used in this example is a Gecko G210, Step/Direction style stepper motor control.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, I was a bit quick I guess :)
The appnote demo allows you to command speed, acceleration, deceleration and steps to move so it was a bit similar.