CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Open loop stepper controller.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Jim McBride



Joined: 24 Mar 2004
Posts: 21

View user's profile Send private message

Open loop stepper controller.
PostPosted: Mon Jul 19, 2010 10:11 am     Reply with quote

[second post attempt, sorry for possible double post]

It has been a while since I have done any coding and what seems like a simple solution is evading my little brain.

I need to drive a stepper driver via a simple pulse train depending on an ADC reading (10 bit) from a pot on a 12F675 running on its internal oscillator (4MHz). An ADC reading of 0 should set the pulse frequency to the slowest frequency (10Hz?) and a reading of 1023 would give me the fastest possible frequency. 1 pulse == 1 step.

I have code that has set pulse frequency delays for 20, 100, 500, 1k, 2k, 3k, 4k and 5k Hz by dividing the ADC value by 128 and running that results through a case statement for the 8 calculated delays. I further modified this code to ramp up to speed using those steps since there is also an enable button and enabling with a fast ADC reading stalls the motors. The end users liked that so much that now they want it to ramp up and down as well as having a full range of frequencies that the ADC can provide.

I think that writing the code the way I did in the beginning is giving me a mental block as to how to pull this off. Any help is appreciated. Here is a snipped of what I have so far:

Code:
while(1)
   {     
        delay_ms(100);
        faux_speed = 0;   
      while(!input(pin_a2))//go button = 0 (pressed)
      {
         
         output_high(pin_a1);//pulse out high
         target_speed = read_adc();//get pot reading (0 - 1023)
         output_low(pin_a1);//pulse out low
                 
         if(faux_speed < target_speed)faux_speed += gain;
         
         if(faux_speed > target_speed)faux_speed = target_speed;
         
         switch (faux_speed / 128) // (0 - 7)
         {
   
              case 0:
              {  delay_ms(49);//20 Hz
                 delay_us(341);
                 gain = 64;
              }       break;
     
              case 1:
              {   delay_us(9496);//100 Hz
                 gain = 32;
                     }       break;
     
              case 2:
              {   delay_us(1573);//500 Hz
                 gain = 12;
                     }       break;
             
              case 3:
              {   delay_us(766);//1k Hz
                 gain = 5;
                     }       break;
     
              case 4:
              {   delay_us(354);//2k Hz
                 gain = 3;
                     }       break;
             
              case 5:
              {   delay_us(182);//3k Hz
                 gain = 2;
                      }       break;
     
              case 6:
              {   delay_us(92);//4k Hz
                 gain = 1;
                      }       break;
     
              case 7:
              {   delay_us(36);//5k Hz
                 gain = 1;                 
              }       break;   
         }
      }           
   }   


To further complicate things, I need at least 5kHz max speed. So a mathematically intensive solution is a no-go.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jul 19, 2010 12:32 pm     Reply with quote

delay_us() can accept a variable as the parameter. Write some code to
convert the A/D value into a delay time in usec. (i.e., create a transfer
function). Give that result to your software PWM routine as the
parameter for delay_us().
Jim McBride



Joined: 24 Mar 2004
Posts: 21

View user's profile Send private message

PostPosted: Mon Jul 19, 2010 1:12 pm     Reply with quote

If I understand the limitations correctly, the delay_*() functions can only accept a byte as a variable. This works fine for delays in the range of 3k to, say 40kHz. It is when I want pulses all the way down to 10Hz (100,000 uS) that this no longer becomes possible. Perhaps I am misunderstanding your answer with the use of the PWM term. I am not not modulating the width of a pulse, rather the frequency of the pulses at a set width.

My most recent attempt was to just divide 65536 by the ADC term to get 1 -> 65536 and put that in value in a simple decrementing while() loop for the delay (~15 Hz). However that division takes WAY too long. However, multiplying the ADC function by multiples of x^2 is much much faster (although non-linear). I am setting myself a maximum speed limit of 10kHz. i.e the entire loop has to run in under 100uS.
I can get a delay loop number from 16 -> 16384 with this line of code in under 25uS:

Code:
delay_loop = (1024 - adc_delay) * 16;


This gets me in the ballpark. But my real problem is how to ramp this delay. Numbers used to change a delay in the 5k - 10kHz range have very little effect in the 10 -> 1kHz range. It almost seems like I need to ramp my ramp variable?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jul 19, 2010 1:18 pm     Reply with quote

Quote:

If I understand the limitations correctly, the delay_*() functions can only
accept a byte as a variable

What's your compiler version? Modern versions can do this. From the
current CCS manual:
Quote:

delay_us( )

Syntax: delay_us (time)
Parameters: time - a variable 0-65535(int16) or a constant 0-65535
Jim McBride



Joined: 24 Mar 2004
Posts: 21

View user's profile Send private message

PostPosted: Mon Jul 19, 2010 1:36 pm     Reply with quote

IDE V3.43, I guess that is a little out of date. I guess a newer version is in order. It won't solve all my problems, but it will make things much simpler. Thanks.
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Mon Jul 19, 2010 2:25 pm     Reply with quote

As a comment though, an int16 variable based delay routine, was published here back in the days when CCS didn't support these variables. It is at:
http://www.ccsinfo.com/forum/viewtopic.php?t=16656

Might help.....

Best Wishes
Jim McBride



Joined: 24 Mar 2004
Posts: 21

View user's profile Send private message

PostPosted: Mon Jul 19, 2010 5:29 pm     Reply with quote

Handy to have, but the overhead might be too much for the faster frequencies needed. This could probably work if a test was done to see how long of a delay was needed and then branch to different delay routines, again more overhead.
I think for now my solution will be a while() routine that only decrements its test variable. That takes 8uS each pass. That will give me something to work with until I can talk the bean counters into an upgrade.
Thanks for the link!!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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