counting digital input

How do I count digital input ticks?

Im trying to get our autonomous mode to work before our regional this Thursday.  Im using the banner optical switches to count ticks on my wheel that  I painted on with reflective paint.  We have tank style right and left side steering.  I estimate I want to move 43 ticks forwared and turn say right with 4 ticks on one side and 1 tick on the other.  I then want to move both sides forward 3 ticks.  I figure from read chief delphi I can do this using 3 "states"  Forward_long, turn and forward_short.   However I dont know much C just enough to cut and paste or substitute. 

 1,  How do I make a counter that keeps track of the number of ticks the digital input gets.   
 2.  Where do I put the code for the timer?   Where do I put the code for the states?

thanks in advance!

Either use polling, meaning you check for a change in state of the digital input every loop, or use interrupts. As you don’t have much time, I would recommend the polling, as it can be done easily with no bugs.

For the polling you would have something like this:


// This is the output that anyone can read. Rename it to something better and more descriptive
int ticks = 0;

void checkDigitalIn(void)
{
    // This is used to tell us when we change states
    static char lastState = 0;

    // This does the actual checking. Make the dig_in_01 whatever input you are working with.
    if(lastState != dig_in_01)
    {
         ticks++;
         // This marks the lastState as the opposite of itself, meaning it now equals the digital input
         lastState = !lastState;
    }
}

That’s all there is to it. Just call that as often as you can in your and when it sees the input cange from high to low or low to high, it will increment the global variable.

–EDIT–
If you want it to only catch one type of state change (IE low to high), then have it check if it has reached the state you want it to before it increments.

Thanks Texan

 And which file.c do I put this code in??   
And how could I do say a case for autonomous_1 where I go left and autonomous_2 where I go right useing the digital input.  And once again which file.c do I put it in?

All Autonomous Code goes in user_routines_fast.c

Thanks CrashZero!!!

So my last question is how to I put a switch on my digital inputs so that I have one that turns left and one that turns right etc.  I imagine it is some sort of If statement but I dont know how to put all the brackets, parenthesis etc

If digitalinput15=0 then autonomous_1
else digital input16=0 then autonomous_2
else end
something like this?

and do i put the counter in each automous module?
each of my autonomous modes has three states, forwardstate
turnstate and forwardshortstate. How do I group these together with regards to brackets, parenthesis into autonomous_1 and autonomous_2?

thanks again!!!

What do you mean by turns left and turns right? If you are saying that these switches are telling the robot which side of the field it is starting on/you want it to start off going straight if both switches are off (IE one switch on is right, other switch on is left, and both off is straight, do something like:


if(dig_in_10 == 1)
{
    // Right Mode
}
else if(dig_in_ 11 == 1)
{
    // Left mode
}
else
{
    // Straight mode
}

You just need to put it where it is being called no matter what autonomous mode you are in, so if that means calling it from multiple places, do it. Put it in whereever you will be sure it will be called often, no matter what mode you are in. It doesn’t matter if it is called faster than the ticks are.

None of that is going to work if you’re going at any resonable speed. It’s going to miss ticks. Use interupts.

Here’s some of my code:

//Variables
volatile char State = 0;
volatile long Distance = 0;
volatile signed char Dir = 0;
//...

//Call while initializing
void Initialize_Interrupts(void)
{
	// initialize external interrupt 1 (INT2 on user 18F8520)
	TRISBbits.TRISB2 = 1;		// make sure the RB2/INT2 pin is configured as an input [108]
								//
	INTCON3bits.INT2IP = 0;		// 0: interrupt 1 is low priority (leave at 0 for IFI controllers) [91]
								// 1: interrupt 1 is high priority
								//
	INTCON2bits.INTEDG2 = 0;	// 0: trigger on the falling-edge [90]
								// 1: trigger on the rising-edge
								//
	INTCON3bits.INT2IE = 0;		// 0: disable interrupt	1 [91]
								// 1: enable interrupt 1
	
	// initialize external interrupt 2 (INT3 on user 18F8520)
	TRISBbits.TRISB3 = 1;		// make sure the RB3/CCP2/INT3 pin is configured as an input [108]
								//
	INTCON2bits.INT3IP = 0;		// 0: interrupt 2 is low priority (leave at 0 for IFI controllers) [90]
								// 1: interrupt 2 is high priority
								//
	INTCON2bits.INTEDG3 = 0;	// 0: trigger on the falling-edge [90]
								// 1: trigger on the rising-edge
								//
	INTCON3bits.INT3IE = 0;		// 0: disable interrupt	2 [91]
								// 1: enable interrupt 2

	// initialize external interrupts 3-6 (KBI0 - KBI3 on user 18F8520)
	TRISBbits.TRISB4 = 1;		// make sure the RB4/HBI0 pin is configured as an input [108]
	TRISBbits.TRISB5 = 1;		// make sure the RB5/KBI1/PGM pin is configured as an input [108]
	TRISBbits.TRISB6 = 1;		// make sure the RB6/KBI2/PGC pin is configured as an input [108]
	TRISBbits.TRISB7 = 1;		// make sure the RB7/KBI3/PGD pin is configured as an input	[108]
								//
  	INTCON2bits.RBIP = 0;		// 0: interrupts 3 through 6 are low priority (leave at 0 for IFI controllers) [90]
								// 1: interrupts 3 through 6 are high priority
								//
	Old_Port_B = PORTB;			// initialize the Old_Port_B variable (in user_routines_fast.c)
								//
	INTCONbits.RBIE = 1;		// 0: disable interrupts 3 through 6 [89]
								// 1: enable interrupts 3 through 6
}						  
//...

//The ISR Routine
void Int_3_Handler(unsigned char RB4_State)
{
 // wheel encoder Phase A interrupts.
 if (!ShaftA==ShaftB)
 {
  Dir = 1;
 }
 if (ShaftA==ShaftB)
 {
  Dir = -1;
 }
 Distance+=Dir; // Increment

 switch (State) {
  case 0: // A=0, B=0
   State = 1;
   break;
  case 1: // A=1, B=0
   State = 0;
   break;
  case 2: // A=1, B=1
   State = 3;
   break;
  case 3: // A=0, B=1
  State = 2;
   break;
 } // switch (State)
}

It’s based on Kevin’s interupts stuff and the Quadrature whitepaper. Hope you can figure it out!

True, it may not be the most reliable thing in the world, but it is simple. Plus, if you do the polling from outside the 26.2ms part, you shouldn’t have many problems. I went with polling after another kid on our controls team couldn’t figure the interrupts out and we haven’t had problems yet.

But, I agree with you. Use interrupts if you can.

If you use a quadrature encoder you don’t need the state machine to decode its output. Connect channel A to an interrupt configured to fire on the rising edge. Connect channel B to a regular digital input (input 10 in the example). Your ISR becomes one line:


void Int_1_Handler()
{
     Distance += (rc_dig_in10) ? 1 : -1;
}

The outputs follow the pattern AB = 00-10-11-01-00… If you look at the rising edges for channel A, going from left to right, channel B is 0. Looking at the rising edge of A from the other direction and channel B is 1. If the direction is reversed you can swap the inputs or change the signs in the ISR.

Sorry, I just copied and pasted. I don’t think I even use it.