my little lab

John P

Joined Oct 14, 2008
2,025
You can do it, people have written big complex programs in assembly--but you'll end up with code that you can understand or explain to someone else if you use a higher-order language. That includes dealing with the program again after a few months away from it!
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Use a four (4) element array of "duty cycle" and TRIS values for the four (4) unique steps... 60 steps gets you 360 degress... Maintain a "position" variable and increment or decrement it by one, according to a "direction" flag, when you get a new "step" flag. Use "position % 4" as the array index...
Sounds very good!!! I like it Mike...BUT won't be easy for me but I think I can try to cook something...

I have to read how to create an array in assembly and most importantly is the TRIs register as it will have 4 different values due to the 4 different duty cycle value...

Will it be a good idea to make a routine for the initialisation and call it each time we move to the next step??

I also believe that there should be some kind of delay before the 1st step when the breadboard is powered, right? Will 2 second be ok??

Regards,
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Thx John P for your encouragement...but i only have 1.5 month experience with PIC...

anyways...im sleeping on it...hopefully tomorow i'll be able to write something

@Sarge: that 500Hz of PWM frequency, is it a guess or what!?

regards,
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
@Sgtwookie:

- in your reply #56, I would like to know that 'wait' waits for how long!???
- Also, that '500Hz' you suggested...how did u fing it? Is it a guess? Does that have to do with the '1 second' of '6 degree/1 second'??

Regards,
 

SgtWookie

Joined Jul 17, 2007
22,230
The time to wait is 1 second, less the time it took to set the I/O pins and the PWM percent.

You wanted 1 second per 6° step, right? Well, that's how you'll do it.
 

John P

Joined Oct 14, 2008
2,025
I'm crazy to have done this, but I looked around and realized that I have all the parts, so I built this thing. My 48-step motor has 90 ohm coils, and my guess was that the expected power supply was 15V, and it seems OK. The power driver is a ULN2003, and it gets just slightly warm. Writing the code turned out to be very simple. I did some mechanical work that I just couldn't resist!

Here's the setup, with added LEDs to show what's energized. The PIC16F690 is on the left and the ULN2003 on the right.
http://files.myopera.com/John98wbr/albums/661338/DSCN0149.JPG

Here's a movie of the thing in action, with an X-acto blade rigged up as a pointer to show how consistent the step sizes are (not exactly, but probably good enough):
http://www.youtube.com/watch?v=EGwNYo69y2o

And here is the most important part of the code. Sgtwookie made one small mistake, which was assuming that the torque for any phase is linear with position, when instead it follows a sinusoid. I made up a spreadsheet to do the calculation, and it said for a 60% position the duty cycle should be 58%, and for a 20% position, it should be 25%, so I used those numbers. It worked out most easily to use a 625Hz PWM drive (4000000 / (4 * 16 *100)). There is a fair amount of audible noise at that frequency, but of course one step out of five is silent as the PWM is at 100%. Note that when there's no noise, there is only one LED on.

One thing I worried about was the speed of the freewheeling diodes in the ULN2003. I couldn't find a spec anywhere, and I worried that if the chip is intended to drive relays rather than driving an inductive load with PWM, the diodes might be very slow. Luckily it doesn't seem to be a problem.

Eric, if you ask me nicely, I'll send you the C code and hex files.

Rich (BB code):
#int_timer2													// 125 Hz
tmr2_isr()	
{
  tick = 1;
}


main(){
  int ct, stepc;

  set_tris_a(0b00111111);                   // 			
  set_tris_b(0b00010000);                   // 			
  set_tris_c(0b00000000);                   //			

  ansel = 0b00000000;
  anselh = 0;                                    // No analogs
  bit_clear(option_reg, 7);                  // Global enable for weak pullups

  setup_timer_2( T2_DIV_BY_16, 100, 5);	      // 125 Hz (1000000/(16 * 100 * 5)) 
  bit_set(intcon, 6);                         // Periph enable
  enable_interrupts(INT_TIMER2);	       // Interrupt on timer 2
  enable_interrupts(GLOBAL);

  ccp1con = 0b00001101;                 // PWM, B and D are inverted
  portc = 0;

  while (1) 
  {
    restart_wdt();                            // Feed the watchdog
    if (!tick)
      continue;                                // Should be 125 times/sec

    tick = 0;

    if (++ct < 125)
      continue;
    ct = 0;                                     // We get here once per second

    switch(stepc)
    {
      case 4:
        pstrcon = 0b00000011;
        ccpr1l = 100;
        break;

      case 3:
        pstrcon = 0b00000011;
        ccpr1l = 25;
        break;

      case 2:
        pstrcon = 0b00000110;
        ccpr1l = 58;
        break;

      case 1:
        pstrcon = 0b00001100;
        ccpr1l = 58;
        break;

      case 0:
        pstrcon = 0b00001001;
        ccpr1l = 25;
    }

    if (++stepc >= 5)
      stepc = 0;
  }
}
 

SgtWookie

Joined Jul 17, 2007
22,230
Fun, wasn't it? ;)

I figured I was going to be off a bit on the calculations, as you can feel the stiction from the permanent magnets in those pancake steppers even when there's no power applied. Roman Black has a writeup on his website about testing steppers for torque and deviations from phase angles:
http://www.romanblack.com/stepper.htm

Roman also has a zero-error 1-second timer routine which would also come in quite handy for this:
http://www.romanblack.com/one_sec.htm
when combined with his $1 OCXO (oven controlled crystal oscillator):
http://www.romanblack.com/xoven.htm

I was trying to keep things fairly simple so that Eric didn't get too confused; I figured that there was enough stuff to keep track of already. ;)

Your ULN2003 stayed relatively cool because you were only sinking ~156mA per phase @ 100% duty cycle; Eric's stepper would have required sinking about 2.2 times that much, and Vce would've been much higher.
 

MMcLaren

Joined Feb 14, 2010
861
Nicely done, John!

Since the PWM duty cycle gets updated from the CCPR1L "duty cycle" register at end-of-period, shouldn't you set the STRSYNC bit in PSTRCON so that the steering change occurs at the same time (at end-of-period)?

<added>

Eric, I wonder if you might benefit from an explanation of the following line of code from John's program?

Rich (BB code):
     setup_timer_2(T2_DIV_BY_16, 100, 5);       // 125 Hz (1000000/(16*100*5)
This line is calling a C library function. The function is setting up TMR2 with a 1:16 prescaler setting to generate 16 us timer 'ticks'. The function also sets up the PR2 "period" register to use one hundred of these 'ticks' for a 1.6 ms (625 Hz) period for the PWM module. Please note that the PWM module ignores the TMR2 postscaler setting but the postscaler can still be used to generate an interrupt at some multiple (1..15) of the PWM period. In this case, John is using a 1:5 postscaler setting to generate an interrupt every 8 ms (every five PWM periods) which he uses, along with a simple counter, for detecting one second intervals. If John had not used the 'setup_timer_2()' library function, his code may have looked something like this (which may be a little easier to convert to assembly language);

Rich (BB code):
   /* 
    *  setup TMR2 for 1.6 ms PWM period and 8 ms interrupts (4 MHz clock)
    */
    T2CON = 0b00100110;       // -0100---  TOUTPS<3:0> postscale 5
                              // -----1--  TMR2ON "on"
                              // ------10  T2CKPS<1:0> prescale 16
                              // generate 16 us timer 'ticks'
    PR2 = 100-1;              // period = 100 x 16 us 'ticks' (625 Hz)
 
Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
i just wrote a piece of code...
And just when i was about to post for critics and comments i saw John P code for his motor...and as i wrote mine already so decided to post it anyway...

please find attached my code...i know there might be some mistakes...

Any comments would be appreciate...

i just want to make it work and discuss about some other stuffs...

regards, Eric
 

Attachments

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
@John P: Bravo!! i watched that video...good job!

so if getting this right, i should use a 625Hz PWM frequency and 100%, 25%, 58%, 58%, 25% for step1, step2, step3, step4, step5 respectively, ?

but the output/input pins configuration for the above steps still stands?

regards,
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Rich (BB code):
   /* 
    *  setup TMR2 for 1.6 ms PWM period and 8 ms interrupts (4 MHz clock)
    */
    T2CON = 0b00100110;       // -0100---  TOUTPS<3:0> prescale 16
                              // -----1--  TMR2ON "on"
                              // ------10  T2CKPS<1:0> postscale 5
                              // generate 16 us timer 'ticks'
    PR2 = 100-1;              // period = 100 x 16 us 'ticks' (625 Hz)

Mike, are you sure of your T2CON configuration?

isn' it TOUTPS<3:0> for postcale and T2CKS<1:0> for prescale?
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I would love to see an assembly code as well and have some critics on my code...I'll edit that with John P values of PWM frequency and duty cycle and post it later
 

Markd77

Joined Sep 7, 2009
2,806
Just from a quick look it is nicely structured and commented.
I think you probably need a "goto main" after this
Rich (BB code):
main      
    call pwm_dutystep
As a cosmetic feature, instead of using "bsf _flag, 2" you can do "bsf _flags, one_second" if you put "one_second equ 2" after the cblock section, or you can use "bsf one_second" if you put "#define one_second _flag, 2". I prefer the first method, but both are common.
 

John P

Joined Oct 14, 2008
2,025
Here's what that control command for Timer 2 compiles to (when you compile your C code, you get a Hex file that you use to program the chip, and also a List file, which shows you how each line of C code gets translated):

Rich (BB code):
0000                00527 .................... 	setup_timer_2( T2_DIV_BY_16, 100, 5);			// Should be 125 Hz (1000000/(16 * 100 * 5))  
006F 3020           00528 MOVLW  20
0070 00F8           00529 MOVWF  78
0071 0878           00530 MOVF   78,W
0072 3806           00531 IORLW  06
0073 0092           00532 MOVWF  12
0074 3064           00533 MOVLW  64
0075 1683           00534 BSF    03,5
0076 0092           00535 MOVWF  12
I use a very old version of the CCS compiler. Others might vary.
 

John P

Joined Oct 14, 2008
2,025
@John P: Bravo!! i watched that video...good job!

so if getting this right, i should use a 625Hz PWM frequency and 100%, 25%, 58%, 58%, 25% for step1, step2, step3, step4, step5 respectively, ?

but the output/input pins configuration for the above steps still stands?

regards,
There's nothing magic about the 625Hz frequency. It was just convenient for the code, and I thought it was as good as anything. That audible noise isn't very pleasant, and now I'm wondering if a higher frequency would be better. But then, that would be tougher on the driver components, and whatever else it is, the ULN2003 isn't a sophisticated chip, and I don't know what its limits are. But those percentages are what Microsoft Excel calculated for me, and the video suggests they're pretty much right. They wouldn't change even if you use a different frequency. And yes, bits 2-5 of Port C are the pins you need to connect to.
 
Top