acquire stepper motor steps and display as distance

Discussion in 'Embedded Systems and Microcontrollers' started by graham2550, Jul 21, 2015.

  1. graham2550

    Thread Starter New Member

    Jun 24, 2014
    11
    1
    Hi everyone.
    I'm building a 3 axis router/mill using nema23 steppers.
    The parallel breakout board has outputs of step and direction for all axis.
    I want to utilize this to build a display unit (7 segs) showing where the axis is in respect to home or zero.
    I coded a PIC18F2550 to do this and utilized the MAX7219 display driver to output to the 7 x 7 segment displays using hardware SPI.
    I use INT2 interrupt to capture the step pulse and convert to millimeters at 1/1000mm resolution. Each step travels the axis 0.025mm.
    THE PROBLEM I HAVE: on the breadboard setup I can use my signal generator to input the pulses (5v square wave 20% duty).
    unfortunately anything over ~600Hz the display does not increment any faster, it still displays but not going any faster.
    I need to be able to get up to 4kHz and display in real time as the axis can move at 100mm/sec which is 4000 steps/sec
    I'm running the uP at 48MHz which at Fosc/4 is 12MHz = 83nS per instruction. 4kHz is 250uS and I feel there is plenty of time to do the calcs and display between interrupts.
    Any help and suggestions greatly appreciated.
    circuit and code below. I'm using MikroC pro for PIC.



    Code (Text):
    1. //**************** // CODE FOR X & Y AXIS ******************************
    2. //****************************************************************************
    3. // Stepper motor step counter, converted to millimeter and display
    4. // For PIC 18F2550
    5. // EXT osc @ 20MHz PLL to 48MHz
    6. // Graham Payne commenced 17/7/2015
    7. //****************************************************************************
    8.  
    9. //Port Declarations
    10. //****************************************************************************
    11. sbit X_Step at RB2_bit;                //step input external INT2
    12. sbit X_Dir at RA0_bit;                 //direction input
    13. sbit X_Step_Direction at TRISB2_bit;
    14. sbit X_Dir_Direction at TRISA0_bit;
    15.  
    16. // SPI module connections for MAX7912
    17. sbit CS at RC0_bit;
    18. sbit Spi_SDO at RC7_bit;
    19. sbit Spi_CLK at RB1_bit;
    20. sbit Spi_SDI at RB0_bit;
    21. sbit CS_direction at TRISC0_bit;
    22. sbit Spi_SDO_Direction at TRISC7_bit;
    23. sbit Spi_CLK_Direction at TRISB1_bit;
    24. sbit Spi_SDI_Direction at TRISB0_bit;
    25.  
    26. //****************************************************************************
    27. //Variables
    28. //****************************************************************************
    29. const unsigned long Step_MM = 25;   //step amount in millimeters x 1000
    30. unsigned long MM;
    31. unsigned char init_MAX_Flag;
    32.  
    33. //****************************************************************************
    34. //Send character to the MAX7219
    35. void send_to_max7219(char address, char dat)
    36. {
    37.   CS = 0;                             // LOAD(CS) LINE LOW
    38.   SPI1_Write(address);
    39.   SPI1_Write(dat);
    40.   CS = 1;                             // LOAD(CS) LINE HIGH
    41. }
    42.  
    43. //****************************************************************************
    44. //initiallise the MAX7219
    45. void init_MAX7219() {
    46.   send_to_max7219(0x09,0xFF);         // BCD Mode Code B
    47.   send_to_max7219(0x0A,0x09);         // INTENSITY 19/32 th's
    48.   send_to_max7219(0x0B,0x06);         // SCAN 7 DIGITS
    49.   send_to_max7219(0x0C,0x01);         // TURN ON
    50.   send_to_max7219(0x0F,0x00);         // TEST OFF
    51. }
    52.  
    53. //****************************************************************************
    54. void Step()
    55. {
    56.     if(init_MAX_Flag == 0){           //have to init MAX7219 here as cannot have 2 threads.
    57.      init_MAX7219();
    58.      init_MAX_Flag = 1;
    59.      delay_ms(1);
    60.      }
    61.  
    62.     //check direction, add/subtract a Step amount (*1000, no problems with decimal places & rounding errors)
    63.     if(X_Dir == 1) {MM += Step_MM;} else {MM -= Step_MM;}
    64.  
    65.     //if(MM < 0) MM = fabs(MM);                   //if goes negative
    66.  
    67.     send_to_max7219(0x01, MM/1000000);          //extract 1000s
    68.     send_to_max7219(0x02, (MM/100000)%10);      //extract 100s
    69.     send_to_max7219(0x03, (MM/10000)%10);       //extract 10s
    70.     send_to_max7219(0x04, ((MM/1000)%10)+128);  //extract 1s, add decimal point
    71.     send_to_max7219(0x05, (MM/100)%10);         //extract .1s
    72.     send_to_max7219(0x06, (MM/10)%10);          //extract .01s
    73.     send_to_max7219(0x07, MM%10);               //extract .001s
    74.  
    75. }
    76.  
    77. //****************************************************************************
    78. void interrupt()
    79. {
    80.   if(INT2IF_bit == 1)
    81.   {
    82.     INT2IF_bit = 0;                       // clear the flag
    83.     Step();                               // do a step and calculate output
    84.   }
    85. }
    86.  
    87. //****************************************************************************
    88. void main() {
    89.  
    90.   CMCON = 7;                              //turn off comparators
    91.   ADCON0 = 0b00000000;                    //turn off A/D converters
    92.   ADCON1 = 0b00001111;                    //all digital
    93.  
    94.   PORTA = 0;
    95.   PORTB = 0;
    96.   PORTC = 0;
    97.   TRISA = 0b00000001;                     //RA0 dir input
    98.   TRISB = 0b00000100;                     //RB2 int2 for step input
    99.   TRISC = 0b00000000;
    100.  
    101.   SPI1_Init();                            // Initialize SPI for MAX7912
    102.   delay_ms(100);
    103.  
    104.   MM = 0;
    105.   init_MAX_Flag = 0;
    106.  
    107.   GIE_bit = 1;                            // global interrupt enabled
    108.   INTEDG2_bit = 1;                        // rising edge detection on INT2
    109.   INT2IF_bit = 0;                         // clear INT2 flag
    110.   INT2IE_bit = 1;                         // INT2 enabled
    111.  
    112.   do {
    113.  
    114.   } while(1);
    115.  
    116. }
     
    Last edited: Jul 21, 2015
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Your interrupt routine is huge!

    I wouldn't be surprised if the length of your ISR was the limiting factor here.

    You aren't doing anything in the main loop once you've initialized the device, use that to calculate the data and send it outout to the display. Use the interrupt to increment the counter (MM) and do all of the heavy lifting in main().

    Always keep your ISRs to a minimum.
     
  3. JWHassler

    Member

    Sep 25, 2013
    201
    33
    The display unit doesn't need to update the display at 4KHz, it just has to not miss any steps... the ISR catches the steps, and the display-routine can run as leisurely as it needs to. It's just for you to see, and you can't follow it if it's moving
     
  4. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    ...and the count and the display is done within the ISR...
     
  5. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,544
    2,370
    Why reinvent the wheel, Mach3 Mach4 is a cheap way to do it?
    Otherwise you need a trajectory planner for axis interpolation etc?
    Max.
     
  6. graham2550

    Thread Starter New Member

    Jun 24, 2014
    11
    1
    Thanks JWHasler, I think That is the solution.
    I will just catch the steps and increment the MM variable in the ISR and put the all the calcs and display routine in the while loop.

    Just to be clear, the incoming frequency varies from 0 (stopped) to 4kHz (max feedrate).
    I am using Mach3 of course, what else is there.
    But I wanted a heads-up display on the machine, I am not always sitting at the monitor.
    I will get back to you and let you all know the results.
     
  7. graham2550

    Thread Starter New Member

    Jun 24, 2014
    11
    1
    I tried your suggestion and it works great. Thanks.
    I had to flag the display routine on the interrupt as there are timing constraints on the MAX7219.
    Sometimes you cant see the wood for the trees!
    New code:
    Code (Text):
    1. //**************** // CODE FOR X or Y AXIS ******************************
    2. //****************************************************************************
    3. // Aquire Stepper motor steps, convert to millimeter and Display.
    4. // Suitable 1 axis only.
    5. // For PIC 18F2550
    6. // EXT osc @ 20MHz PLL to 48MHz
    7. // Graham Payne commenced 17/7/2015
    8. //****************************************************************************
    9.  
    10. //Port Declarations
    11. //****************************************************************************
    12. sbit X_Step at RB2_bit;                //step input external INT2
    13. sbit X_Dir at RA0_bit;                 //direction input
    14. sbit X_Step_Direction at TRISB2_bit;
    15. sbit X_Dir_Direction at TRISA0_bit;
    16.  
    17. // SPI module connections for MAX7912
    18. sbit CS at RC0_bit;
    19. sbit Spi_SDO at RC7_bit;
    20. sbit Spi_CLK at RB1_bit;
    21. sbit Spi_SDI at RB0_bit;
    22. sbit CS_direction at TRISC0_bit;
    23. sbit Spi_SDO_Direction at TRISC7_bit;
    24. sbit Spi_CLK_Direction at TRISB1_bit;
    25. sbit Spi_SDI_Direction at TRISB0_bit;
    26.  
    27. //****************************************************************************
    28. //Variables
    29. //****************************************************************************
    30. const unsigned long Step_MM = 25;   //step amount in millimeters x 1000
    31. unsigned long MM;
    32. unsigned char Flag;
    33.  
    34.  
    35. //****************************************************************************
    36. //Send character to the MAX7219
    37. void send_to_max7219(char address, char dat)
    38. {
    39.   CS = 0;                             // LOAD(CS) LINE LOW
    40.   SPI1_Write(address);
    41.   SPI1_Write(dat);
    42.   CS = 1;                             // LOAD(CS) LINE HIGH
    43. }
    44.  
    45. //****************************************************************************
    46. //initiallise the MAX7219
    47. void init_MAX7219() {
    48.   send_to_max7219(0x09,0xFF);         // BCD Mode Code B
    49.   send_to_max7219(0x0A,0x09);         // INTENSITY 19/32 th's
    50.   send_to_max7219(0x0B,0x06);         // SCAN 7 DIGITS
    51.   send_to_max7219(0x0C,0x01);         // TURN ON
    52.   send_to_max7219(0x0F,0x00);         // TEST OFF
    53. }
    54.  
    55. //****************************************************************************
    56. void interrupt()
    57. {
    58.   if(INT2IF_bit == 1)
    59.   {
    60.  
    61.     INT2IF_bit = 0;                       // clear the flag
    62.     //check direction, add/subtract a Step amount (*1000, no problems with decimal places & rounding errors)
    63.     if(X_Dir == 1) {MM += Step_MM;} else {MM -= Step_MM;}
    64.  
    65.     //if(MM < 0) MM = fabs(MM);                   //if goes negative
    66.     Flag = 1;
    67.   }
    68. }
    69.  
    70. //****************************************************************************
    71. void Display()
    72. {
    73.     send_to_max7219(0x01, MM/1000000);          //extract 1000s
    74.     send_to_max7219(0x02, (MM/100000)%10);      //extract 100s
    75.     send_to_max7219(0x03, (MM/10000)%10);       //extract 10s
    76.     send_to_max7219(0x04, ((MM/1000)%10)+128);  //extract 1s, add decimal point
    77.     send_to_max7219(0x05, (MM/100)%10);         //extract .1s
    78.     send_to_max7219(0x06, (MM/10)%10);          //extract .01s
    79.     send_to_max7219(0x07, MM%10);               //extract .001s
    80. }
    81.  
    82. //****************************************************************************
    83. void main() {
    84.  
    85.   CMCON = 7;                              //turn off comparators
    86.   ADCON0 = 0b00000000;                    //turn off A/D converters
    87.   ADCON1 = 0b00001111;                    //all digital
    88.  
    89.   PORTA = 0;
    90.   PORTB = 0;
    91.   PORTC = 0;
    92.   TRISA = 0b00000001;                     //RA0 dir input
    93.   TRISB = 0b00000100;                     //RB2 int2 for step input
    94.   TRISC = 0b00000000;
    95.  
    96.   SPI1_Init();                            // Initialize SPI for MAX7912
    97.   delay_ms(100);
    98.   init_MAX7219();
    99.   delay_ms(100);
    100.  
    101.   MM = 0;
    102.  
    103.   GIE_bit = 1;                            // global interrupt enabled
    104.   INTEDG2_bit = 1;                        // rising edge detection on INT2
    105.   INT2IF_bit = 0;                         // clear INT2 flag
    106.   INT2IE_bit = 1;                         // INT2 enabled
    107.  
    108.   do {
    109.  
    110.     if (Flag)
    111.     {
    112.       Flag = 0;
    113.       Display();
    114.     }
    115.    
    116.   } while(1);
    117.  
    118. }
     
Loading...