View previous topic :: View next topic |
Author |
Message |
Jim McBride
Joined: 24 Mar 2004 Posts: 21
|
Open loop stepper controller. |
Posted: Mon Jul 19, 2010 10:11 am |
|
|
[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. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 19, 2010 12:32 pm |
|
|
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(). |
|
![](templates/subSilver/images/spacer.gif) |
Jim McBride
Joined: 24 Mar 2004 Posts: 21
|
|
Posted: Mon Jul 19, 2010 1:12 pm |
|
|
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? |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 19, 2010 1:18 pm |
|
|
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 |
|
|
![](templates/subSilver/images/spacer.gif) |
Jim McBride
Joined: 24 Mar 2004 Posts: 21
|
|
Posted: Mon Jul 19, 2010 1:36 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19368
|
|
Posted: Mon Jul 19, 2010 2:25 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Jim McBride
Joined: 24 Mar 2004 Posts: 21
|
|
Posted: Mon Jul 19, 2010 5:29 pm |
|
|
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!! |
|
![](templates/subSilver/images/spacer.gif) |
|