Delay10KTCYx in C18

Hello everyone I’m back again,

First of I would like to thank all who has helped me out on the recent question, and yet I’m here to bug you guys again…

Currently I’m using mplab v7.60 C18 v2.40 I’ve successfully built VexUserCode.mcw right now I would like to run my robot autonomously

I’m under the “user_routines_fast.c” and I was trying to program my robot to go straight for 5 seconds and stop using the Delay10KTCYx function in “delay.h” I tried with the code below, how did I come up with the 5000?

my chip is PIC18f8520 and I check the datasheets the Fosc is 40MHz

so Delay10KTCYx (5000); // should give me a delay of 10000 x 5000 x 4/40M = 5 seconds

and after 5 seconds I want it to stop so I added

pwm02=127;
pwm03=127;

is there something wrong with my code or am I using the Delay10KTCYx wrong? Thank you for your time!


void User_Autonomous_Code(void)
{
  /* Initialize all PWMs and Relays when entering Autonomous mode, or else it
     will be stuck with the last values mapped from the joysticks.  Remember, 
     even when Disabled it is reading inputs from the Operator Interface. 
  */
  pwm01 = pwm02 = pwm03 = pwm04 = 127;
  pwm05 = pwm06 = pwm07 = pwm08 = 127;
  pwm09 = pwm10 = pwm11 = pwm12 = 127;

  while (autonomous_mode)   /* DO NOT CHANGE! */
  {
    if (statusflag.NEW_SPI_DATA)      /* 18.5ms loop area */
    {
      Getdata(&rxdata);   /* DO NOT DELETE, or you will be stuck here forever! */

     /* Add your own code here. */


pwm02=100;
pwm03=155;

Delay10KTCYx(5000);

pwm02=127;
pwm03=127;



      printf("%2x : %2x %2x %2x %2x %2x %2x
",(int)rxdata.rc_receiver_status_byte.allbits,
        (int)PWM_in1,(int)PWM_in2,(int)pwm01,(int)pwm02,(int)pwm03,(int)pwm04);

 




  Putdata(&txdata);   /* DO NOT DELETE, or you will get no PWM outputs! */
    }
  }
}

Your code is in the middle of a loop that NEEDS to get data every 18.5ms and return back a I’m alive message. If you wait for 5 seconds the master CPU is going to think there is a problem and reset the slave.

What you want to do is count the number of times you’ve been through the loop and when it’s been 5 seconds (5 sec / 18.5 ms) then set the PWM values.

autoseconds = autoseconds + 185;

If autoseconds > 5000 then pwm = 127.

You’ve got lots of options we can help you with. Time can be based on counting the number of loops within the 18.5ms loop area or based on a hardware timer.

You can learn about state machines - what we typically use in cases like these.


static int counter=0; //keep track of loops to use as a crude timer - static keeps it around from call to call and isn't necessary if you never leave the subroutine.
static int autostate=1;   //keep track of what step we're supposed to be doing
 
  switch (autostate)
  {
    case 1:   // Drive forward
        pwm02 = 100;
        pwm03 = 155;  //motor is reversed
        if (counter>54)  //1 second (1 sec divided by 18.5ms = 54 loops per second)
        {  
           autostate = 2;  // move on to the next step
           counter = 0;    // reset our timer for the next step
        }
 
    case 2:   // Turnaround
        pwm02 = 100;
        pwm03 = 100;  //motor is reversed
        if (counter>108)  //2 seconds
        {  
           autostate = 3;
           counter = 0;
        }
 
    case 3:   // Drive forward (returning now)
        pwm02 = 100;
        pwm03 = 155;  //motor is reversed
        if (counter>54)  //1 second
        {  
           autostate = 4;
           counter = 0;
        }
 
     case 4:   // Stop - What to do when everything else is done
     default:  // also what to do if an invalid autostate occurs
 
       pwm02 = pwm03= 127;   // Make sure the last thing you do is always stop
  }
  counter++;

You can also write your own WAIT subroutine to do what you want if you prefer to flow through one set of commands. There’s an easy way to do this for Autonomous based on the User_Autonomous_Code structure and counting the way Foster suggested. It’s not something you would use in Teleop where you want to respond to driver commands instantaneously.

I have it to work thank you!!

This is what I did



static int counter=0;


pwm02=100;
pwm03=155;

counter= ++counter ;

if(counter>271){   (5/18.5ms)
  pwm02=127;
  pwm03=127; 
}

and the robot moved for 5 seconds and it stopped! What I’m doing right here is the way Foster suggested right ? I think the both of you are doing the same thing right? I have a question about the 18.5ms is it true that no matter how long the code, it will always take 18.5ms in the loop?

Also MARK can you show me how to write the Wait subroutine?

I can’t thank you guys enough! You’ve been such great help!

That looks good.
Yes, I was just showing an elaboration on what Foster told you. Instead of the Case statement you can use If statements like you did.

The only way the loop will take longer than 18.5ms is if the code you add takes more than 18.5ms to execute and slows everything down so you don’t get to the “if (statusflag.NEW_SPI_DATA)” statement in time. That would take an intense time-consuming internal loop, not the sets and checks you’re doing.

For a simple Wait just duplicate the structure you already recognize. You want to repeat all the work that routine does, so the system doesn’t lockup while you wait.
I just dashed this off and haven’t checked it, but this is the general idea using what you’ve already learned. You’d add something like this before User_Autonomous_Code.


void My_Wait(int milliseconds)
{
  int elapsedtime=0;  // in increments of 18.5ms
  int elapsedcount=0;  // in units of 18.5ms
 
  while((elapsedtime < milliseconds) & autonomous_mode)  // also quit if Auto mode happens to end
  {
    if (statusflag.NEW_SPI_DATA)      /* 18.5ms loop area */
    {
      elapsedcount++;
      elapsedtime = elapsedcount * 185 / 10; //the Vex PIC processor doesn't have floating point
      Getdata(&rxdata); // tells us when Auto Mode is over
      Putdata(&txdata); // Lets the master controller know we're alive and well
    }
  }
}

And then in User_Autonomous_Code you can do something like this:pwm02 = 100;
pwm03 = 155;
My_Wait(5000);
pwm02 = 127;
pwm03 = 127;

I had similar code for when I was doing MPLabs. I had a fancy one that would let you have multiple threads and time a few things at the same time.

Ahhhh the days of rolling your own components, the sweet smell of 1’s and 0’s .

Anyway today the RobotC compiler does all of that for you. It also has tasks that you can spawn off to do specific functions and not wait in the main line.

Marks ‘case’ code is a good example of how we would put state machines together and have them do the heavy lifting of what the robot code needed to do. A little work with Google will get you some good tutorials on state machines.

But it looks like you are on the right track of getting your robot to move.

Thank you so much! Mark and Foster ! I seem to get the idea of controlling the timer , but the 18.5 milisecond loop is really an enigma to me, like, how did they come up with the number 18.5ms (in the code that Mark provided me there is also an if loop and it was also stated /* 18.5ms loop area */ how did you know that?)and how will we know that the code that I’ve written had exceeded 18.5ms

But anyway right now I’ve moved on, I’m using the sensors! Using Limit Switch Sensors and Bumper Sensors

and here is what I did the first time



static int counter=0;
static int signal=0;

void User_Autonomous_Code(void)
{
  /* Initialize all PWMs and Relays when entering Autonomous mode, or else it
     will be stuck with the last values mapped from the joysticks.  Remember, 
     even when Disabled it is reading inputs from the Operator Interface. 
  */
  pwm01 = pwm02 = pwm03 = pwm04 = 127;
  pwm05 = pwm06 = pwm07 = pwm08 = 127;
  pwm09 = pwm10 = pwm11 = pwm12 = 127;

  while (autonomous_mode)   /* DO NOT CHANGE! */
  {
    if (statusflag.NEW_SPI_DATA)      /* 18.5ms loop area */
    {
      Getdata(&rxdata);   /* DO NOT DELETE, or you will be stuck here forever! */

     /* Add your own code here. */


pwm02=100;
pwm03=155;

counter= ++counter ;
if(counter>541){   
  pwm02=127;
  pwm03=127; 
}

signal=Get_Analog_Value(rc_ana_in02);

if (signal!=0){
  pwm02=127;
  pwm03=127; 
}


      printf("%2x : %2x %2x %2x %2x %2x %2x
",(int)rxdata.rc_receiver_status_byte.allbits,
        (int)PWM_in1,(int)PWM_in2,(int)pwm01,(int)pwm02,(int)pwm03,(int)pwm04);

      Putdata(&txdata);   /* DO NOT DELETE, or you will get no PWM outputs! */
    }
  }
}

and here’s what happened it was stationed initially, when I press the button the robot moved forward… which I think there is nothing wrong with that but when I tried to do the other way around



static int counter=0;
static int signal=1;

void User_Autonomous_Code(void)
{
  /* Initialize all PWMs and Relays when entering Autonomous mode, or else it
     will be stuck with the last values mapped from the joysticks.  Remember, 
     even when Disabled it is reading inputs from the Operator Interface. 
  */
  pwm01 = pwm02 = pwm03 = pwm04 = 127;
  pwm05 = pwm06 = pwm07 = pwm08 = 127;
  pwm09 = pwm10 = pwm11 = pwm12 = 127;

  while (autonomous_mode)   /* DO NOT CHANGE! */
  {
    if (statusflag.NEW_SPI_DATA)      /* 18.5ms loop area */
    {
      Getdata(&rxdata);   /* DO NOT DELETE, or you will be stuck here forever! */

     /* Add your own code here. */


pwm02=100;
pwm03=155;

counter= ++counter ;
if(counter>541){   
  pwm02=127;
  pwm03=127; 
}

signal=Get_Analog_Value(rc_ana_in02);

if (signal=0){
  pwm02=127;
  pwm03=127; 
}


      printf("%2x : %2x %2x %2x %2x %2x %2x
",(int)rxdata.rc_receiver_status_byte.allbits,
        (int)PWM_in1,(int)PWM_in2,(int)pwm01,(int)pwm02,(int)pwm03,(int)pwm04);
 
      Putdata(&txdata);   /* DO NOT DELETE, or you will get no PWM outputs! */
    }
  }
}

and it completely ignored me pressing button. What I was trying to do is let the robot move forward for 10 seconds and during the period of time I want it to stop when I pressed the botton. I understand that when I press the button it will convert the voltage at the connection point to a 10 bit (0 to 1023) value representing that voltage.And when the button is press it will generate a Electrical gound 0 voltage. I assigned a variable of type unsigned int it should be used when reading the value. And somehow it was bypassing the the “if” loop I assigned

I’ve been growing so dependent on you guys…Thank you so much for your help…

The problem is that the buttons go from approximately 0 to ~255 and it’s the approximate part that is the issue.

Try:


if (signal < 20){  
  pwm02=127;
  pwm03=127;
}

The other button would be

if (signal > 235){
  pwm02=127;  
  pwm03=127; 
}

While it’s supposed to be zero, there are analog components in the circuit, and they could be adding just a little resistance to the circuit to make it not be exactly zero. You could print the value of signal out to see what it really is.

The 18.5 ms has to do with how long it takes the control signals from the transmitter to get to the master CPU. The signals from the transmitters are PWM with a fixed length channel. On my wiki there is the following note that I’ve copied from someone named Tinkerman.

The measured separation pulse (high pulse) is a fixed 400usec long. Pushing the stick up shortens the channel’s “low” pulse about 400usec.

Pushing the stick down lengthens the pulse about 420usec.

No deflection on the stick gives a 1.12msec low pulse (for a total of 1.52msec from the beginning of the separation pulse.)

Every five counts of channel trim adjusts the pulse length 6usec. Minus trim values shorten the “low” pulse time. The top button (chans. 5 and 6) shortens the “low” pulse time 560usec and the bottom button lengthens the “low” pulse 560usec. Each packet of 6 channels repeats roughly every 18.5msec.

Edited: I found Tinkerman’s orginal article and there are links in it that may be useful.

http://www.vexfan.com/viewtopic.php?t=227

In addition to what Foster covered…

if statement comparisons need double equal signs (==).
A single equal sign doesn’t compare, it changes the value.
Soif (signal=0)
changes the value of signal to zero, then evaluatesif(0)
which will always be False.

The correct way is:if (signal==0) {
The 18.5ms is more of a design choice for how often transmission packets are sent. Through the years FIRST has had some variation in packet rates, for instance, the predecessor of the Vex controller used a packet rate of 17ms, and the larger version used for FRC at that time had a rate of 26.2ms.
Whenever you use something like this as a crude timer you’ll have to investigate and determine what transmission rate was used.

Thank you guys so much! I have it working!! After reading I did some adjustments and it worked just as I wanted: When the button is pressed the robot will reverse and make a turn and go straight. Here is my code for that!



static int counter2=0;
static int counter3=0;
static int signal=1;
static int trigger=0;

pwm02=100;
pwm03=155;

signal=Get_Analog_Value(rc_ana_in02);

if (signal==0){
  trigger=1;
}

if(trigger==1){
   pwm02=155;
   pwm03=100;
counter2=++counter2;   
 if (counter2>109){
         pwm02=155;
         pwm03=155; 
      counter3=++counter3;
      if (counter3>109){
           pwm02=155;
           pwm03=100;
           trigger=0;
           counter2=0;
           counter3=0;
     }	
  }  
}

To Foster I forgot to mention that in the Vex instruction manual says that the buttons are digital sensors, which sends a voltage, but instead of sending a voltage between zero and max, it will send only zero or maximum.And the Signal pin is HIGH when the switch is open, Pushing Switch brings the signalpin voltage to LOW. I wish I can show you guys what I’ve done, thank you so much, I will move on to the next chapter the light sensors!