Parallax MX2125 and RobotC

All,

I am working to put together a set of simple gadgets for a VEX Robot. When I have this complete I plan to post information on what I have learned so that others can build on it if they so desire.

I have a pretty good software development background but very little experience with building component level electronic equipment. As a result my first step was to find out what other folks were through a series of Internet searches using Google.

I am using a modified squarebot with the RobotC programming kit.

So far here is what I have successfully completed:

  1. LED controlled from software.
  2. LED interfaced to a simple switch.
  3. Potentiometer sensor using a stock potentiometer from Radio Shack.

After my success with the Potentiometer I was excited to move on to an sensor using an MX2125 Parallax chip.

I found a good bit of information on the Parallax website including a tutorial interfacing the MX2125 to the Parallax Basic Stamp:

http://www.parallax.com/dl/docs/prod/compshop/SICMemsicTut.pdf

I took the information from this guide along with information posted in the VEX forums on interfacing a Sparkfun ADXL32x to the VEX:

[

I compiled and downloaded the program. The result is that the value of in3 and in4 fluxuates between 256 and -255 with a few other numbers thrown in no matter what the angle of tilt or axis of the tilt of the breadboard.

If anyone has any experience with this chip or any ideas I would be interested in hearing from you.

Thanks,

digitalhack
Rockville, MD](https://vexforum.com/gallery/showimage.php?i=1136&catid=searchresults&searchid=236826)

I took the information from this guide along with information posted in the VEX forums on interfacing a Sparkfun ADXL32x to the VEX:

https://vexforum.com/gallery/showimage.php?i=1136&catid=searchresults&searchid=236826

I compiled and downloaded the program. The result is that the value of in3 and in4 fluxuates between 256 and -255 with a few other numbers thrown in no matter what the angle of tilt or axis of the tilt of the breadboard.

If anyone has any experience with this chip or any ideas I would be interested in hearing from you.

I don’t have any experience with this chip, but from page 6 of the pdf, it looks like the signals on Xout and Yout are PWM pulse trains rather than analog voltages. That would explain why you are seeing the numbers you get.

You will either have to write some fairly advanced timer code to decode the PWM signals or you will need to convert the PWM signals into an analog signals.

As a first attempt at converting the signals to analog, you could wire capacitors between the each signal and ground. That would be a low-pass filter acting as an [integrator.

The exact value of the capacitor will depend on the pulse width and frequency, as well as the current source and sink characteristics of the sensor outputs and the VEX ADC inputs. With a capacitor that is too small, it’ll not integrate over a long enough time and will be pretty useless. If you get a one too large, it’ll integrate over too long of a time and make the sensor respond too slowly.

I’d start with 10uf and see how that behaves. It won’t ever be perfect, but it may at least get you a reading that somewhat correlates to the movement of your breadboard…

Hope that helps,

You could just implement the Parallax PULSIN function in PIC18 C or Easy C and use it to read the pulse trains using the PIC18F8520’s CCP (Capture Input) peripheral. Here is some code that uses the CCP hardware to read Sony SIRC IR Signals from a TV Remote Control that worked on a PIC18F452 MCU, which could be modified to run on a PIC18F8520 MCU used on the Vex Controller.

.
.
.

#define SYSTEM_FREQUENCY 20 // System frequency, Fs = 20 MHz

// Compute timer clock frequency which depends on the system frequency. This constant is
// used by DelayUs function.

#define CLOCK_FREQUENCY (SYSTEM_FREQUENCY / 4) // Fc = Fs / 4

#define TIME_SCALE_FACTOR 100 // 100 micro-second granularity for delays

// Define IR remote control constants for the PIC18C452 at the System frequency, Fs of 20 MHz here

#define T 426 // Delay of 0.55 milli-seconds.
#define Zero T // Delay 0.55 milli-seconds for sending a “0”
#define One 1114 // Delay 1.10 milli-seconds for sending a “1”
#define Leader 2497 // Delay 2.20 milli-seconds for sending a leader
#define Sync T // Delay 0.55 milli-seconds for sending a sync

#define T_400_Us (400 / TIME_SCALE_FACTOR * CLOCK_FREQUENCY) // 0.40 milli-second (400 micro-second) delay
#define T_600_Us (600 / TIME_SCALE_FACTOR * CLOCK_FREQUENCY) // 0.60 milli-second (600 micro-second) delay
#define T_1200_Us (1200 / TIME_SCALE_FACTOR * CLOCK_FREQUENCY) // 1.20 milli-second (1200 micro-second) delay
#define T_2400_Us (2400 / TIME_SCALE_FACTOR * CLOCK_FREQUENCY) // 2.40 milli-second (2400 micro-second) delay

#define TRUE 1 // Boolean TRUE value
#define FALSE 0 // Boolean FALSE value

#define INPUT 1 // Input pin direction
#define OUTPUT 0 // Output pin direction

// // Port C Bits

#define IRDetectorPin 17 // IR detector Pin (RC2/CCP1)

// PORT D Bits

#define LeftEmitter PORTDbits.RD0 // Left IR emitter
#define RightEmitter PORTDbits.RD1 // Right IR emitter

//********************************************************************************
// Type definitions
//********************************************************************************

typedef volatile union
{
byte Value;
struct
{
unsigned Bit0:1; // LSB
unsigned Bit1:1;
unsigned Bit2:1;
unsigned Bit3:1;
unsigned Bit4:1;
unsigned Bit5:1;
unsigned Bit6:1;
unsigned Bit7:1; // MSB

} ;

} UnsignedByte_T ;

typedef volatile union
{
word Value;
struct
{
byte Byte0; // LSB
byte Byte1; // MSB
} ;

} UnsignedWord_T ;

//********************************************************************************
// Variable declarations
//********************************************************************************

UnsignedByte_T ByteValue;
UnsignedWord_T WordValue;
byte Byte_1;
word Word_1;

byte TheCommand = 0; // The IR remote control IRCommand read from host
extern char Ch; // Character read from USART
extern byte HexNumber]; // Hex string

byte SonyDevice = 0; // Current Sony IR Device code received from TV remote control
byte SonyCommand = 0; // Current Sony IR Command code received from TV remote control

//********************************************************************************
// Function Prototypes
//********************************************************************************

// IR Remote Control tests

void InitializeSonyRC(void); // Initialize Sony remote control receiver variables
void ReceiveIRCommand(byte *Device, byte *Command); // Receive Sony TV remote control commands and device codes

//********************************************************************************
//* main - Receives Sony IR codes from TV remote control and displays the
//* Command and device code.
//********************************************************************************

void main(void)
{

    unsigned int result;
    char str[7];
    

    // Configure Capture1
    
    //OpenCapture1(C1_EVERY_4_RISE_EDGE&CAPTURE1_CAPTURE);
    
    // Configure Capture1 for falling edge (1 -> 0 transition)

    OpenCapture1(C1_EVERY_FALL_EDGE);
    
    // Configure Capture1 for rising edge (0 -> 1 transition)

    //OpenCapture1(C1_EVERY_RISE_EDGE&CAPTURE1_CAPTURE);
    
    // Configure Timer3
    OpenTimer3(TIMER_INT_OFF&T3_SOURCE_INT);
    
    // Configure USART for 9600 Baud at 4 MHz
    OpenUSART(USART_TX_INT_OFF&USART_RX_INT_OFF&
    USART_ASYNCH_MODE&USART_EIGHT_BIT&
    USART_CONT_RX, 25);

// Display message to operator

printf(“PIC18C452 Sony IR TV Remote Control Application \r\n”);

while (TRUE)

{
//printf(“trace 1: \r\n”);

  CapStatus.Cap1OVF  = 0;
  
  while(!PIR1bits.CCP1IF); // Wait for event
   

  result = ReadCapture1(); // read result
   
     
  if(!CapStatus.Cap1OVF)
  {
    printf("trace 3: result = ");
    hex4(result);
    printf("\r\n");
    CloseCapture1(); // to USART
  }

}

CloseTimer3();
CloseUSART();

}

//******************************************************************************
//* ReceiveIRCommand - Receive the Sony IR command and device codes transmitted
//* from the Sony TV remote control and return them to the caller, using the
//* Sharp IR receiver. The device code is currently ignored in this version.
//******************************************************************************
void ReceiveIRCommand(byte *Device, byte *Command)
{
word IRWord[12]; // Array containing IR signal counts
byte BitValue; // Bit value (1 or 0)
//byte Level = 1; // 1 to 0 transition
byte Level = 0; // 0 to 1 transition

byte i; // Loop index

// Get latest IR command from Sony TV remote

printf(“trace 4: \r\n”);

do
{
pulsin(IRDetectorPin, Level, &IRWord[0]); // Wait for valid start bit at end of leader (2.2 milli-seconds)
}
while (IRWord[0] < Leader);
pause(20); // Wait 20 milli-seconds to allow data to settle

printf(“trace 5: \r\n”);

//do
//{
// pulsin(IRDetectorPin, Level, &IRWord[0]); // Wait for valid start bit at end of leader (2.2 milli-seconds)
//}
//while (IRWord[0] < Leader);
//pause(20); // Wait 20 milli-seconds to allow data to settle

// Get IR data (7-Bits)

pulsin(IRDetectorPin, Level, &IRWord[0]); // Wait for third valid start bit

printf(“trace 6: \r\n”);

// Read each data bit using inline code. for loops are too slow

pulsin(IRDetectorPin, Level, &IRWord[1]); // Get bit 0
pulsin(IRDetectorPin, Level, &IRWord[2]); // Get bit 1
pulsin(IRDetectorPin, Level, &IRWord[3]); // Get bit 2
pulsin(IRDetectorPin, Level, &IRWord[4]); // Get bit 3
pulsin(IRDetectorPin, Level, &IRWord[5]); // Get bit 4
pulsin(IRDetectorPin, Level, &IRWord[6]); // Get bit 5
pulsin(IRDetectorPin, Level, &IRWord[7]); // Get bit 6

printf(“trace 7: \r\n”);

// Determine if bit is one or zero by comparing it to thresholds and set
// corresponding bit in the command word.

*Command = 0;

for (i=0; i<7; i++)
{
if (IRWord* > One)
{
BitValue = 1;
}
else
{
BitValue = 0;
}

  // Set the appropriate bit 

  switch (i)
  {
     case 0:
     {
        ByteValue.Bit0 = BitValue;
     } 
     case 1:
     {
        ByteValue.Bit1 = BitValue;
     } 
     case 2:
     {
        ByteValue.Bit2 = BitValue;
     } 
     case 3:
     {
        ByteValue.Bit3 = BitValue;
     } 
     case 4:
     {
        ByteValue.Bit4 = BitValue;
     } 
     case 5:
     {
        ByteValue.Bit5 = BitValue;
     } 
     case 6:
     {
        ByteValue.Bit6 = BitValue;
     } 
     case 7:
     {
        ByteValue.Bit7 = 0;
     } 
  }

}

*Command = ByteValue.Value;

}*

Here is the code for the pulsin function…

//******************************************************************************
//* Pulsin - PIC version of pulsin function. Currently this function is limited
//* to capturing input from PIC/Stamp BS2/BSX pins 16 (RC1/CCP2), 17 (RC2/CCP1) and
//* pin 36 (RB3/CCP2 alternate, PIC18C452 only). It so happens that pin numbering for
//* pins 16 and 17 are the same for the PIC and the Stamp. Timers 1 and 3 may be
//* used to count pulses.
//******************************************************************************
void Pulsin(byte PortID, byte Pin, byte State, word *Result)
{
byte PinID; // Pin ID

// Make pin an input

//input(Pin);

PORTCbits.RC1 = INPUT; // RC1/CCP2
PORTCbits.RC2 = INPUT; // RC2/CCP1

// Determine which port (A..E) and pin (0..7) 

//PinLookup (Pin, &PortID, &PinID);

if (Pin == 16)
{
	// 
	// Use Capture 2 register (CCP2) which has been assigned to PIC18C452 Pin 16 (RC1/CCP2)

	if (State == 1)
	{

		// Configure Capture 2  for rising edge (0 -> 1 transitions)

		OpenCapture2(C2_EVERY_RISE_EDGE);
	}
	else
	{
		// Configure Capture 2 for falling edge (1 -> 0 transitions)

		OpenCapture2(C2_EVERY_FALL_EDGE);
	}

	// Configure Timer3
	OpenTimer3(TIMER_INT_OFF&T3_SOURCE_INT);

	while(!PIR2bits.CCP2IF);					// Wait for event

  PIR2bits.CCP2IF = 0;                   // Clear the capture interrupt flag bit 
  //PIE2bits.CCP2IE = 0;                   //  Clear the capture interrupt enable bit  (CloseCapture2 function does this !)

	*Result = ReadCapture2();				// read result from Capture 2 register

	if(!CapStatus.Cap2OVF)
	{
		CloseCapture2();					// Close Capture 2  
	}
	else
	{
		*Result = 0;						// Capture 1 register overflow
	}
}
else
if (Pin == 17)
{
	// Use Capture 1 register (CCP1) which is assigned to PIC18C452 Pin 17 (RC2/CCP1) 

	if (State == 1)
	{

		// Configure Capture1 for rising edge (0 -> 1 transition)

		OpenCapture1(C1_EVERY_RISE_EDGE);
	}
	else
	{
		// Configure Capture1 for falling edge (1 -> 0 transition)

		OpenCapture1(C1_EVERY_FALL_EDGE);
	}

	// Configure Timer3
   OpenTimer3(TIMER_INT_OFF&T3_SOURCE_INT);

	while(!PIR1bits.CCP1IF);					// Wait for event

  PIR1bits.CCP1IF = 0;                   // Clear the capture interrupt flag bit 
  //PIE1bits.CCP1IE = 0;                   //  Clear the capture interrupt enable bit  (CloseCapture1 function does this !)
       
	*Result = ReadCapture1();				// read result from capture 1 register

	if(!CapStatus.Cap1OVF)
	{
		CloseCapture1();					// Close capture 1  
	}
	else
	{
		*Result = 0;						// Capture 1 register overflow
	}

}
else 
if (Pin == 36)
{
	// Use Capture 2 alternate registers (CCP2)
}

}

Using a CCP module to measure the pulses is a good idea, but a couple caveats:
[LIST=1]
*]The CCP modules are on Motor ports 1-4, so if you use two CCP modules to decode your X & Y signals then you will loose two motor ports.
*]The motor ports provide higher voltage than this sensor can take. If you use the CCP approach, you will either need to provide your own voltage regulator (7805) to bring the voltage down to a safe level, or you will need to draw power from a third cable plugged into one of the digital I/O ports.
[/LIST]

As for the analog approach, I happened across this document that provides a simple schematic on page 5. They show using a 10K series resistor and a 1uf capacitor to convert the digital signal to analog.

Cheers,

  • Dean

Dean/tswift1:

Thanks for all the help and ideas. I think for now I am going to try the 10K series resistor and a 1uf capacitor to convert the digital signal to analog. I will let you know how it goes.

digitalhack
Rockville, MD