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

Reversing Direction in For() statement
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

Reversing Direction in For() statement
PostPosted: Wed Jul 15, 2020 2:18 pm     Reply with quote

I need to drive a stepper motor and graphic sweep in sync.
Integer i is used to calculate angles and step sets.
Running CCW I can use:
Code:
for(i=0; i<20; i++)      // 0 to 19, total 20
 {
   // code here same as running forward
 }

Running CW this works:
Code:
for(i=19; i>=0; i--)      // 19 to 0, total 20
// for(i=20; i>0; i--)      // 20 to 1, total 20
 {
   // code here same as running backward
 }

Note that the line commented out will mess up i for the following code in the CW direction.
How can I write this using a simple
Code:
if(direction)
 {run CCW}
else
 {run CW}

to select the correct loop where direction is just a one bit flag.
I also need to use other start and stop points between 0 and 180 degrees
This (partial) code is an example that works but I don't want to repeat a whole lot of identical code. I can use a function if I use global variables or it becomes complicated.
Code:
  for (i=7;i<15;i++)          // lines to be drawn CCW
  {
    angle=i*.175;               // 10i deg converted to radians
    xx=63*cos(angle);       // use floating
    x=63+xx;                    // but convert to integer
    xx=63*sin(angle);       // 63 is the radius
    y=63-xx;
    draw_line(63,63,x,y);   // start bottom middle,
                                      // the LCD has 0,0 top left
  }

This section of code will become more complicated as only sections, or none, of the line will be drawn representing echos from sonar.
Don't worry about the code, it works. I need a suggestion on how to deal with the general challenge of changing direction. I cannot easily use a start and stop integer in the for() statement unless math is allowed as in
Code:
for(i=stop-1; i>=start; i--)
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Jul 15, 2020 2:46 pm     Reply with quote

Will something along the lines of (not in CCS code):-

if i> stop then i = start;
if i< start then i =stop;

Someone here may have a clever way of reducing it one line of code.

Mike
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Wed Jul 15, 2020 2:49 pm     Reply with quote

Maybe something similar to how I reverse the motor
Code:
// Step the motor 10 degrees, 25 steps
   for(j=0;j<25;j++)
   {
   if (direction)            // CW
    {
     if (n == 4)
      n=0;
     else
      n++;
    output_c (step[n]);
    }
   else                     // CCW
    {
    if (n == 0)
     n=4;
    else
     n--;
    output_c (step[n]);
    }
    delay_ms(10);
   }

This sequences thru a pattern of 4 codes a number of times to turn 10 degrees forward of backward.

Edit: No this still duplicates the code but in this case it is only one line so does not matter.
I tried to mirror x as in
Code:
if(direction)
    x=63+xx;
   else
    x=63-xx;

but it does not redraw the same sector in reverse, it just flips it left to right.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Wed Jul 15, 2020 6:16 pm     Reply with quote

I found a way to do it. I just had to think differently. Sorry for wasting anyone's time.
Code:
 
// set start and stop
 i=start;
 while(1)
 {
  for (k=start;k<=stop;k++)          // lines to be drawn
  {
// LCD Stuff
     angle=i*.175;          // 10 deg/scan, convert to radians
    xx=64*cos(angle);    // 63 is radius of scan lines
    x=63+xx;
    xx=64*sin(angle);    // xx is floating point
    y=63-xx;                 // converted to integer
    draw_line(63,63,x,y);    // LCD function

// Step the motor 10 degrees, 24 steps
   for(j=0;j<25;j++)     // geared stepper motor
   {
   if (direction)            // CW
    {
     if (n == 4)
      n=0;
     else
      n++;
    output_c (step[n]);     // step codes
    }
   else               // CCW
    {
    if (n == 0)
     n=4;
    else
     n--;
    output_c (step[n]);
    }
    delay_ms(20);               // time for stepper motor
   }
// set i according to direction, keep within start/stop
   if(direction)
   {
    i++;
    if(i>stop)
     i=stop;
   }
    else
   {
    i--;
    if(i<start)
     i=start;
   }
  }                                       // end of for loop
   clear_LCD();                     // clear the LCD
   direction = direction ^ 1;   // alternate direction CW & CCW
 }                         // end of while loop

There is a slight problem that start cannot be 0 unless i is a signed integer.
start and stop reset was wrong, now corrected


Last edited by rovtech on Thu Jul 16, 2020 1:49 pm; edited 1 time in total
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Thu Jul 16, 2020 1:48 pm     Reply with quote

When i=0 in the code below, why does y end up being 62 instead of 63?
angle is float and so is xx. So when i is 0, angle should be 0, sin(0) is 0, so xx should be 0, and 63-0 should be 63, not 62.
Am I wrong in using this to convert floating to integer?
Code:
// LCD Stuff
     angle=i*.175;          // 10 deg/scan, convert to radians

    xx=64*sin(angle);    // xx is floating point
    y=63-xx;                 // converted to integer, add offset
    draw_line(63,63,x,y);    // LCD function

I have to be careful of my units. For the coordinates the LCD is 0 to 63 but for the radius length to use in the equations it is 64.
The LCD is mapped 0,0 at top left so I have to add 63 to x and subtract y from 63 to get to the locations in normal coordinates.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Thu Jul 16, 2020 2:27 pm     Reply with quote

Try printing out the values of all variables which change as you go line by line through the code.

Should tell you where the error is!

Mike
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Thu Jul 16, 2020 3:03 pm     Reply with quote

Thats how I found the problem, xx displayed in float is 0.00 and y is displayed in integer as 0.
If I plug in 0 for xx I get 63-0=63.
With the program the way it is above I get 63-y=62.
C promotes the right side float to the left side integer I thought, and it seems to do that.

Edit: actually I get 0.004 for xx going one way, as i is incremented, and 0.00 going the other way.
As i changes from 0,1,2 then 2,1,0 these values for xx are displayed consistently.

0.00
11.14
21.94
21.94
11.14
0.004
0.00 etc

This is how I display on the LCD:
Code:
    angle=i*.175;               // 10 deg = 0.175 radians
    xx=64*cos(angle);           // x in floating point
    x=63+xx;                    // convert x to integer, add offset
    xx=64*sin(angle);           // y in floating point
  text_position(0,0);          // line, column
  sprintf(buff, "xx = %f", xx);
  send_str(buff);
  delay_ms(1500);             // for testing
    y=63-xx;                    // convert y to integer, add offset
    draw_line(63,63,x,y);       // draw line from bottom center of LCD

and I move below "y=63-xx;" and adjust to display y in integer format.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Thu Jul 16, 2020 6:32 pm     Reply with quote

Someone please help.
If 64*sin(0) = 0.004 then 63-0.004 = 62.996
When 62.996 is promoted to integer is the fractional part just dropped giving 62?
That does not make much sense. How do I round a small number to 0?
Code:
    i=0
    angle=i*.175;               // 10 deg = 0.175 radians
    xx=64*sin(angle);           // y in floating point
    n=xx;                         // to drop the fractional part
    y=63-n;                    // convert y to integer, add offset
    draw_line(63,63,x,y);       // draw line from bottom center of LCD

now I get for y compared to the original calculation in the second column and fraction dropped in the third column
63 62.996 62
52 51.86 51
42 41.06 41
that seems to be what is happening. sin(0) is resulting in a very small number but a big error when used then promoted to integer.
this is really dumb! There has to be a better way.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 16, 2020 7:07 pm     Reply with quote

The program below will display the following in MPLAB vs. 8.92 simulator:
Quote:
value = -63
value = 63

Test program:
Code:
#include <18F46K22.h>
#fuses NOWDT 
#use delay(internal=4M)
#use rs232(UART1, baud=9600, ERRORS)

#define round(x) (signed int16)(x<0.0 ? x-0.5 : x+0.5)

//=================================
void main()
{
float temp = -62.996;
printf("value = %ld \r", round(temp));


temp = 62.996;
printf("value = %ld \r", round(temp));

while(TRUE);
}
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Fri Jul 17, 2020 7:47 am     Reply with quote

Thanks PCM programmer.
I looked for a rounding function in several of my C books including K&R and it is not in any index. Casting and Promoting are in the index but no Round.
I just found it by googling but that should not be where to find it. Maybe we should all throw our books out.
https://fresh2refresh.com/c-programming/c-arithmetic-functions/c-round-function/
No wonder the Boeing 737 Max are crashing and please, everyone, don't trust those auto features on your car. My auto braking in cruise control works most of the time but not always. Same with lane keeping and other alerts.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Fri Jul 17, 2020 9:01 am     Reply with quote

OK, I'm stupid. I cannot get round() to work. I tried all the variations below and get
"Error 12 "Scanning Sonar.c" Line 91(13,14): Undefined identifier -- round"

Code:
   xx=64*sin(angle);           // y in floating point
    xx=round(64*sin(angle));
    round(xx)=64*sin(angle);
    xx=round(xx);
    y=63-xx;                    // convert y to integer, add offset

How am I supposed to use it?
My program has #include <math.h>
Maybe this function does not exist in PCM. I don't see it in the manual.
I just saw your
Code:
#define round(x) (signed int16)(x<0.0 ? x-0.5 : x+0.5)

What is all that about? I will have to study on it.
I was looking at the google reference on how to use it. I cannot find it in my books.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 17, 2020 10:12 am     Reply with quote

Do you understand #define statements ? Just copy and paste that line
above main() in your program. You've been on this forum since 2006.
How can you don't know this ?
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Fri Jul 17, 2020 11:21 am     Reply with quote

Give me a break I'm 80 years old and not a professional programmer.
Sure I could do that but I don't understand it and it may not work, although it seems to.
What I am understanding is that
1. The function round() does not exist for the CCS C compiler, and maybe not in the K&R definition, so you wrote one
2. Google shows round() as a regular function so it must exist for some compilers.
3. In the function you created round(x) is replaced with (signed int16)(x<0.0 ? x-0.5 : x+0.5)
which means
Code:
if(x<0)
 x=x-0.5
else
 x=x+0.5

then cast it to a 16 bit signed integer?? I don't understand the () () pair of brackets together. I have not run into that.
So it will do this for a floating point number? Yes it appears to
I am using 8 bit integers so I changed to int8 and it still works.
I appreciate the help but I do like to understand what I'm doing
So my code is now working
Code:
 #define round(x) (signed int8)(x<0.0 ? x-0.5 : x+0.5)

    angle=i*.175;               // 10 deg = 0.175 radians
    x=63+round(64*cos(angle));  // calculate x, convert to integer, add offset
    y=63-round(64*sin(angle));  // calculate y, convert to integer, add offset
    draw_line(63,63,x,y);       // draw line from bottom center of LCD
gaugeguy



Joined: 05 Apr 2011
Posts: 303

View user's profile Send private message

PostPosted: Fri Jul 17, 2020 11:49 am     Reply with quote

Programming and C aside:
When converting a float number to an integer there are different methods. One is truncating. Anything after the decimal point is dropped and only the whole number remains. Another method is to do rounding. There are different forms of rounding but the most common is if the decimal portion is 0.5 or larger then the number goes to the next higher integer, if the decimal portion is less than 0.5 then the decimal portion is discarded, or truncated.
One way to implement this type of rounding is to add 0.5 to the number before truncating the decimal portion.
Ttelmah



Joined: 11 Mar 2010
Posts: 19535

View user's profile Send private message

PostPosted: Fri Jul 17, 2020 12:16 pm     Reply with quote

It casts the result into a signed int8.
This truncates.

The 'result' is the result of if the value is <0, it subtracts 0.5 from this.
otherwise it adds 0.5.

So if you start with a float value of (say) 1.4, 0.5 is added to give 1.9,
then you get 1 as the integer.. If howver you have 1.5, 0.5 added gives
2.0, which then truncates to '2'.
Similarly, -0.5 has 0.5 subtracted, so gives -1 after the truncation, while
-0.4, still gives 0.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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