Archive for the ‘PIC’ Category
Three New, Unique VEX Creations
We’re always happy to see ‘outside-the-box’ robotics inventions, so when we were contacted by a local high school teacher (Dana Clay from Baldwin-Whitehall School District) with a couple of youtube videos, we were more than curious to see what his class had cooked up. We were not let down. The first video shows a VEX contraption that shoots ping-pong balls through a pipe “hoop” with surprising accuracy. It even has a degree of human interaction; the light sensor can be covered/uncovered to control how far the attached arm rotates.
The second video is a very cool movie of a VEX-built robot typing “I LOVE ROBOTS” on a keyboard. Robots controlling computers; now that’s an awesome idea!
The final video is of a looped track with a VEX tank tread/catapult combo providing the upwards momentum to keep things rolling smoothly. This is the Ball That Never Stops, people, and it has a catapult; how can you not love it? All three were programmed in ROBOTC, of course. Enjoy!
Announcing ROBOTC 3.5! Beta Version Available Today
The ROBOTC Development team is proud to announce thatROBOTC 3.5 for the LEGO Mindstorms, VEX Cortex and PIC, Arduino, and Robot Virtual World platforms will be available on September 7th, 2012. The new ROBOTC 3.5 update will be free-of-charge for ALL existing ROBOTC 3.0 license holders. Download a Beta version (3.45) today to get a sneak peak at all of the new features and enhancements available in ROBOTC 3.5!
ROBOTC 3.5 has a number of new features and enhancements:
- Full ANSI-C support to support pointers, recursion, and stacks with an updated compiler and updated robot firmware.
- New and Updated Debugger Windows:
- “Local Variables” to monitor variables in the current task or function.
(Note: Local variables are only available when your program is suspended) - “Global Variables” to monitor variables available to your entire program.
- “Call Stacks” to monitor function calls in the currently selected task.
- “Local Variables” to monitor variables in the current task or function.
- Updated Documentation and Wiki (www.robotc.net/wiki) – Still in progress!
- Support for Standard C commands – sprintf(), sscanf(), support for character arrays, unsigned variables, etc.
- Support for the Arduino family of controllers (Uno, Mega, Mega 2560) with future support and expanded functionality for the Arduino Leonardo and Due controllers.
- Updated Robot Virtual Worlds support to include additional sensors and motors.
- Improved Robot Virtual Worlds performance to simulate more realistic physics and robot behaviors.
- Support for the new MATRIX building system with the NXT.
- Many general enhancements and bug fixes – more in-depth change log to come with the ROBOTC 3.5 official release.
Please remember that the Beta available today should not be installed across entire school sites–this is a beta version, so install at your own risk!
You can participate in the ROBOTC 3.45 Beta version by downloading a copy here. Please note that the Beta version will uninstall your existing version of ROBOTC; the Beta will use your existing licensing so there is no need to ‘Deactivate’ before installing. If you have any issues/questions with the ROBOTC Beta, please e-mail betasupport [at] robotc [dot] net for assistance and to alert us of any issues to be fixed between now and release day.
Full Set of Possible Characters for VEX LCD
Full credit for the work behind this post goes to ROBOTC user Matthieu V. Thanks Matthieu!
The VEX LCD is a fantastic tool, allowing you to display messages and values on the robot with very little effort. Some programmers even use a combination of the screen and input buttons to create a basic user interface on their robots – allowing them to choose between multiple autonomous routines, choose a specific sensor and display its values, and more.
What many programmers don’t know, is that there’s a wider selection of symbols that can be displayed with the LCD! Shown below is a full list of characters that can be displayed, along with their numerical equivalents, in a useful table Matthieu put together.
Full character look-up table:
You can download a printable PDF of the table, along with some additional notes, here.
To display any of these custom characters, you should use either the displayLCDChar(); or displayNextLCDChar(); commands as you normally would, but specify the numerical value instead of an actual character in single quotes. For example, the following code will display a right arrow on the very first position (0,0) on the LCD:
task main()
{
//Create and initialize variable x
//Value stored in x must be between 16 and 255
int x = 199;
//Clear Line 0
clearLCDLine(0);
//Display the character associated with the value in x
displayLCDChar(0, 0, x);
//Wait 5 seconds before the program ends, clearing the screen
wait1Msec(5000);
}
Programming with the new VEX Integrated Encoder Modules
ROBOTC 3.06 now includes functionality to support the new VEX Integrated Encoder Modules!
The VEX Integrated Encoder Modules (IEMs) replace the plastic caps on the backs of 2-Wire Motors (269 and 393) with quadrature encoders. Unlike the existing VEX Shaft Encoders, they connect to the Cortex Microcontroller using the I2C port and provide feedback directly from the motor (with the added benefit of not hogging up your digital ports). These encoders will allow you to identify and control how fast the motors spin, how far the robot travels, and what direction it should move.
For more information and assembly instructions for the Integrated Motor Encoder for the VEX 2-wire 393 Motor, click here.
For more information and assembly instructions for the Integrated Motor Encoder for the VEX 2-wire 269 Motor, click here.
I2C Overview
As stated above, these new encoders connect to the single I2C port on the Cortex:

Unlike the DIGITAL and ANALOG ports on the Cortex, having only one I2C port does not limit you to only one I2C device. I2C ports allow multiple devices to be connected in a manner frequently referred to as daisy-chaining:

The Integrated Encoder Modules support this by having built-in sets of input and output pins. A 4-wire cable connects the Cortex to Motor 1, another 4-wire cable connects Motor 1 to Motor 2, another 4-wire cable connects Motor 2 to Motor 3, and so on. In fact, ROBOTC 3.06 will support up to 8 devices on the single I2C port!

Programming Overview
Motors and Sensors Setup
ROBOTC has undergone substantial changes to support the new encoders. Some of the most visually noticeable changes are in the Motors and Sensors Setup. On the Motors tab, the Type drop-down box allows you to choose from the different motors available in the VEX Robotics System:

This is significant because each of the new IEMs return a different number of encoder counts per revolution. Specifically, the IEM for the 2-wire 269 motor measures 240.448 counts per revolution of the motor output shaft. The 2-wire 393 motor measures 627.2 counts per revolution of the output shaft in its default high-torque configuration and 392 counts per revolution of the output shaft in its modified high-speed configuration.
Let’s take a look at a physical robot and configure it using the Motors and Sensors Setup.

- This robot has two 269 motors with encoders.
- The right motor is connected on MOTOR port 1. The left motor is connected on MOTOR port 10.
- The encoder on the right motor is the first device plugged into the I2C port.
- The encoder on the left motor is the second device, daisy-chained off of the right motor.
We can configure this in ROBOTC by going to the Robot > Motors and Sensors Setup menu.
On the motors tab, we can enter all of the information necessary so that it matches our physical robot:

Note that:
- “rightMotor” was configured in port1 as a VEX 269 Motor.
- rightMotor was “Reversed” so that positive power levels will allow the robot to move forward.
- The “Encoder” box was checked and “I2C_1″ was chosen since it is the first device plugged in to the Cortex.
- “leftMotor” was configured in port10 as a VEX 269 Motor.
- The “Encoder” box was checked and “I2C_2″ was chosen since it is the second device along the daisy-chain.
- It is not necessary that the order of your motor ports correspond with the order of the I2C ports, although doing so will reduce confusion. It is necessary that your Motors and Sensors Setup perfectly match the physical setup of your robot.
Additionally, you’ll notice that there is also a new “I2C Sensors” tab in the Motors and Sensors Setup:

The additional configuration you can do here is optional. Like existing VEX Sensors, you can use this tab to name your I2C devices and monitor their values in the Sensor Debug Window. Note that these values are the raw values – not adjusted for polarity or the “Reversed” checkbox on the Motors tab.
When you’re done configuring your motors and encoders, you can press OK to apply your changes.
Function Library
In addition to the Motors and Sensors Setup, you’ll also notice new commands available in the Function Library. Most notably, we’ve included the “nMotorEncoder[]” command.

Those of you familiar with the NXT system will be very familiar with the nMotorEncoder[] command. To those who are not, it acts very similarly to the SensorValue[] command you may be more used to. The nMotorEncoder[] command gives you read-write access the value of the encoder associated with the motor specified within the brackets.
Sample Code
For example, in the sample code below, the nMotorEncoder[] command is used to clear the values of the encoders on lines 19 and 20, and then also control the distance the robot moves in the while loop on line 23. This program will cause the robot to move forward for a specified number of encoder counts (1000), while displaying encoder values to the VEX LCD.
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, I2C_1, rightIEM, sensorQuadEncoderOnI2CPort, , AutoAssign)
#pragma config(Sensor, I2C_2, leftIEM, sensorQuadEncoderOnI2CPort, , AutoAssign)
#pragma config(Motor, port1, rightMotor, tmotorVex269, openLoop, reversed, encoder, encoderPort, I2C_1, 1000)
#pragma config(Motor, port10, leftMotor, tmotorVex269, openLoop, encoder, encoderPort, I2C_2, 1000)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
task main
{
wait1Msec(2000);
//Setup the VEX LCD for displaying encoder values
clearLCDLine(0);
clearLCDLine(1);
displayLCDString(0, 0, "R: ");
displayLCDString(1, 0, "L: ");
//Clear the encoders associated with the left and right motors
nMotorEncoder[rightMotor] = 0;
nMotorEncoder[leftMotor] = 0;
//While less than 1000 encoder counts of the right motor
while(nMotorEncoder[rightMotor] < 1000)
{
//Display the right and left motor encoder values
displayLCDNumber(0, 3, nMotorEncoder[rightMotor], 6);
displayLCDNumber(1, 3, nMotorEncoder[leftMotor], 6);
//Move forward at half power
motor[rightMotor] = 63;
motor[leftMotor] = 63;
}
}
You can see the code running on an the robot here:
For a more detailed explanation of how this code and encoders work, you should check out the videos in the Movement > Shaft Encoders section of the VEX Cortex Video Trainer. For more information on the nMotorEncoder[] command and how it is used in the NXT system, check out this video.
Motors Debug Window
Yet another change in ROBOTC to support the new encoders was made in the Motors debug window, found by going to Robot > Debug Windows > Motors. ROBOTC will now display the Type of motor you have connected and the Encoder value as your robot runs.

This window, unlike the Sensor Debug window, will take the motor “Reversed” setting and polarity into account; positive motor powers will always result in positive encoder values and negative motor powers will always result in negative encoder values. In other words, the Encoder column displays the same value that gets returned by the nMotorEncoder[] command.
Conclusion and Future Development
The new VEX Integrated Encoder Modules are a fantastic addition to the VEX Robotics System, which we’re thrilled to support in ROBOTC. That being the case, we have additional improvements with the encoders coming down the pipeline. With integrated encoders, we’ll be able to implement “Encoder Targets” and “PID Control” like we have available for the NXT Platform. With Encoder Targets, you’ll be able to specify a “target” encoder value for the motors to spin to, and the robot will actually slow to a stop at that value, rather than letting its momentum carry it too far. With PID, we’ll be able to use feedback from the encoders to constantly adjust the power levels of the motors so that their physical performance matches what you set in the code – all with no extra effort on your part! Again for lots of additional information on both Encoder Targets and PID Control, check out the Movement > Improved Movement section of Teaching ROBOTC for Mindstorms.
Finally, if the VEX IEM’s seem like something you’d like to have (and they should) you can purchase them for the 2-wire 393 Motors here, and the 2-wire 269 Motors here.
Michigan VEX Regionals
A few weeks ago I came to the VEX Regionals over at Monroe, Michigan which was held at Monroe High School. This was their first year hosting the VEX competition, and Steve Ketron did a nice job organizing the event.
There were about two dozen teams, and the robots that were built by the teams were phenomenal.
I’ve been fortunate enough to go to several VEX competitions over the years, and this one had a very friendly and relaxed atmosphere. I’d chalk that up to the friendly teams surrounding Monroe that came, and also Steve’s planning for the competition.
Photos
I took several hundred photos AND video for the event. I will post the video as soon as I can get all of them onto youtube.
Note: If you want a photo removed, I completely understand! Just comment on this post letting me know which photo to remove and I will remove it immediately. Your comment will not show up below so it will be anonymous.




























































3rd Party Sensors with VEX: Sharp IR Rangefinder
The VEX Robotics System includes a growing, powerful set of official sensors. That said, the electronics world is overflowing with other types of cool and useful sensors. The great news is, both the VEX PIC and the VEX Cortex microcontrollers are extremely versatile and can be used with many of these sensors. Both the VEX PIC and VEX Cortex can be used with Analog Sensors that operate between 0 and 5 volts (+/- .5 volts), and have Power, Ground, and Signal lines.
One such sensor is the Sharp GP2D12 IR Rangefinder.
The Sharp IR Rangefinder allows your robot to determine distance from the nearest object, much like the VEX Ultrasonic Rangefinder. Unlike the VEX Ultrasonic Rangefinder, which uses sound waves to measure distance, the Sharp IR Rangefinder uses infrared light. On one side of the sensor an infrared LED shines a beam of light, which is reflected back by the closest object, and detected by the receiver on the other side of the sensor. The sensor then uses a method called triangulation to determine how far away the object was.
The basis for triangulation is that objects at different distances will reflect the infrared beam back to the receiver at different angles. The varying angles produce different voltage levels in the sensor, and in turn sensor values that can be used to calculate distance. See below:
The Sharp IR Rangefinder provides very reliable distance values ranging from 10 to 80 centimeters away. One big advantage with using the IR Rangefinder is that it’s not affected by soft for angled objects that cause the VEX Ultrasonic Rangefinder to fail.
One challenge with using the sensor is that the raw values provided do not directly correlate to useful distance values, and they’re also non-linear. This means that we must perform a calculation on the raw sensor data first. Documentation for the sensor tells us that we can calculate the distance using the following formula:
Voltage = 1 / ( Distance + 0.42 )
Which, when rearranged gives us:
Distance = (1/Voltage) – 0.42
One additional challenge is that we can’t directly access the voltage returned by the sensor in our program. What we can access is the sensor value, which is proportional to the voltage – we’ll just have to take a conversion factor into account.
Below is a sample program written for the Sharp IR Rangefinder. It contains the function “IRValue()” which will perform the necessary calculation and return the useful distance data, in centimeters. Note that the “sensorPotentiometer” type was used, since there is no “IR Rangefinder” sensor type in ROBOTC, and the Potentiometer type will return the full, unmodified analog data (unlike other sensor types like the Gyro).
#pragma config(Sensor, in5, sharp, sensorPotentiometer)
#pragma config(Motor, port2, rightMotor, tmotorNormal, openLoop, reversed)
#pragma config(Motor, port3, leftMotor, tmotorNormal, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
//Function uses data from the IR Rangerinder to calculate and return distance
int IRValue(tSensors sensorPort, float conversionFactor = .0000469616, float k = .42)
{
return (1.0 / (SensorValue[sensorPort] * conversionFactor)) - k;
}
task main()
{
wait1Msec(2000);
clearLCDLine(0);
clearLCDLine(1);
//While true...
while(true)
{
//If the robot is greater than 25 cm away...
if(IRValue(sharp) > 25)
{
//Move Forward
motor[rightMotor] = 30;
motor[leftMotor] = 30;
}
else
{
//Stop
motor[rightMotor] = 0;
motor[leftMotor] = 0;
}
//Display IR Sensor Data to LCD
displayLCDString(0, 0, "IR Value:");
displayLCDNumber(0, 9, IRValue(sharp), 3);
displayNextLCDString("cm");
}
}
Our Sharp IR Rangefinder was previously configured wired for an older microcontroller called the Handy Board. Like the VEX Cortex and PIC, it had wires for Power, Ground, and Signal, so we were able to use simple jumper wires to adapt it for the Cortex.
Front of the robot with Sharp IR Rangefinder:

Top of the robot, with connection from Sharp IR Rangefinder to VEX Cortex Analog Port 5:

And finally, here’s a video of the code from above running on the robot:
For more information on interpreting and using the data provided by the Sharp IR Rangefinder, check out this tutorial.
New Materials added to the VEX Cortex Video Trainer!
Exciting news! We’ve updated the VEX Cortex Video Trainer with two new sections.
First, we’ve added a section for ROBOTC’s new Natural Language Library. You’ll find tons of print materials, ranging from guides describing each Natural Language command available for the VEX PIC and Cortex to dedicated helper guides for each of the VEX Sensors. You can find the new page in the VEX Cortex Video Trainer by going to the Fundamentals section and choosing Natural Language.
Second, there are 4 new tutorial videos that show how to use the Ultrasonic Rangefinder, complete with helper guides and programming challenges. You can find them by going to Sensing and choosing Forward until Near.
The VEX Cortex Video Trainer is available for free, online. To purchase a copy that you can install on each computer in your classroom, visit the RoboMatter store.
New VEX Robot Building Instructions Available!
Tired of the same old robot models? Look no further! We’re proud to present a new set of classroom-ready robot building instructions.
First up, we have the new and improved Squarebot 4.0:
Squarebot 4.0 features:
- 1 VEX Cortex
- 2 Shaft Encoders
- 1 Limit Switch
- 1 Bumper Switch
- 1 Ambient Light Sensor
- 1 Ultrasonic Rangefinder
- 1 Potentiometer
- 1 VEX LCD Screen
- 2 Driving Motors
- 1 Arm Motor
And second, we’ve augmented our popular Swervebot model with an arm!
The Swervebot has a more slender wheelbase and rear caster, making it more suitable for line tracking and fitting in small spaces. It also features:
- 1 VEX Cortex
- 2 Shaft Encoders
- 2 Bumper Switches
- 3 Line Tracking Sensors
- 1 Ultrasonic Rangefinder
- 1 Potentiometer
- 1 VEX LCD Screen
- 2 Driving Motors
- 1 Arm Motor
Note that having all of the sensors isn’t required to take advantage of these great robot models. Build them using the parts that you have – or just use the instructions for your own inspiration.
These models along with many others can always be found at the Robotics Academy site.
ROBOTC Interview with Robotics Trends
Down in Orlando, Florida a few weeks ago at the VEX World Championships, Rich Erb from Robotics Trends interviewed me about ROBOTC. We discussed ROBOTC and our future developments with Robot Virtual Worlds and Multi-Robot communications projects. Take a look!
Cortex “View Mode” Program
In an earlier blog post, we introduced the VEX LCD and showed how to print custom messages and values to it. Being able to print messages and sensor values adds some awesome functionality to your robot… but why stop there, when there’s so much more potential?
Many NXT (and even RCX!) users are familiar with the “View Mode” on their microcontrollers, that allows them to specify what sensors are connected to which ports, and then view those values on the screen. Without a built-in screen, VEX users haven’t had access to this functionality… that is, until now! If you have the VEX LCD, the code in this post will allow you to specify a sensor, specify which port it’s on, and then watch the sensor values update in real-time.
Step 1: Download and run the sample program on your robot (see below).
Step 2: Select the type of sensor connected to your robot. The left and right buttons cycle through the options. The middle button selects the current sensor.

Step 3: Select the port the sensor is connected to. For sensors with more than one wire, choose the FIRST port the sensor is plugged into (remember, sensors with more than two wires must be plugged in on neighboring ports on the Cortex). There is also a “Back to Sensors” option that will take you back to the sensor option menu.

Step 4: View the sensor data! Pressing the center button will exit, and return you to the sensor selection menu.

The sample code can be copied into ROBOTC, or you can download a copy here. Note: This code has not been fully optimized, but should work fine as-is.
//Global Variable Declarations
const short leftButton = 1;
const short centerButton = 2;
const short rightButton = 4;
short sensorChoice;
short portChoice;
short count;
//Task and Function Prototypes
void waitForPress();
void waitForRelease();
void clearPorts();
task sensorChooser();
task digitalPortChooser();
task analogPortChooser();
void menuTracker();
task display();
void analogSensorSetup(tSensors sensorPort);
void digitalSensorSetup(tSensors sensorPort);
//Main------------------------------------------------------------
task main()
{
StartTask(sensorChooser);
while(true)
{
wait1Msec(50);
}
}
//----------------------------------------------------------------
//sensorChooser - allows you to choose which sensor you'd like to pick
task sensorChooser()
{
//Junk Cleanup from previous runs
clearLCDLine(0);
clearLCDLine(1);
clearPorts();
waitForRelease();
StopTask(display);
StopTask(digitalPortChooser);
StopTask(analogPortChooser);
hogCPU();
count = 0;
while(true)
{
switch(count){
case 0:
//Touch
displayLCDCenteredString(0, "Touch Sensor");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
sensorChoice = 0;
releaseCPU();
StartTask(digitalPortChooser);
}
else if(nLCDButtons == leftButton)
{
waitForRelease();
count = 6;
}
else if(nLCDButtons == rightButton)
{
waitForRelease();
count++;
}
break;
case 1:
//Quadrature Encoder
displayLCDCenteredString(0, "Quad Encoder");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
sensorChoice = 1;
releaseCPU();
StartTask(digitalPortChooser);
}
else
menuTracker();
break;
case 2:
//Ultrasonic
displayLCDCenteredString(0, "Ultrasonic");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
sensorChoice = 2;
releaseCPU();
StartTask(digitalPortChooser);
}
else
menuTracker();
break;
case 3:
//Light
displayLCDCenteredString(0, "Light Sensor");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
sensorChoice = 3;
releaseCPU();
StartTask(analogPortChooser);
}
else
menuTracker();
break;
case 4:
//Line Tracker
displayLCDCenteredString(0, "Line Tracker");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
sensorChoice = 4;
releaseCPU();
StartTask(analogPortChooser);
}
else
menuTracker();
break;
case 5:
//Potentiometer
displayLCDCenteredString(0, "Potentiometer");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
sensorChoice = 5;
releaseCPU();
StartTask(analogPortChooser);
}
else
menuTracker();
break;
case 6:
//Accelerometer
displayLCDCenteredString(0, "Accelerometer");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
sensorChoice = 6;
releaseCPU();
StartTask(analogPortChooser);
}
else if(nLCDButtons == leftButton)
{
waitForRelease();
count--;
}
else if(nLCDButtons == rightButton)
{
waitForRelease();
count = 0;
}
break;
}
}
}
//----------------------------------------------------------------
//digitalPortChooser - allows you to choose which port you'd like to pick
task digitalPortChooser()
{
StopTask(sensorChooser);
hogCPU();
count = 1; //Chooses the starting point
while(true)
{
switch(count){
case 0:
//Back Option
displayLCDCenteredString(0, "Back to Sensors");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
releaseCPU();
StartTask(sensorChooser);
}
else if(nLCDButtons == leftButton)
{
waitForRelease();
count = 12;
}
else if(nLCDButtons == rightButton)
{
waitForRelease();
count++;
}
break;
case 1:
//Digital 1
displayLCDCenteredString(0, "DIGITAL 1");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 1;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 2:
//Digital 2
displayLCDCenteredString(0, "DIGITAL 2");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 2;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 3:
//Digital 3
displayLCDCenteredString(0, "DIGITAL 3");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 3;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 4:
//Digital 4
displayLCDCenteredString(0, "DIGITAL 4");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 4;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 5:
//Digital 5
displayLCDCenteredString(0, "DIGITAL 5");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 5;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 6:
//Digital 6
displayLCDCenteredString(0, "DIGITAL 6");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 6;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 7:
//Digital 7
displayLCDCenteredString(0, "DIGITAL 7");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 7;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 8:
//Digital 8
displayLCDCenteredString(0, "DIGITAL 8");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 8;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 9:
//Digital 9
displayLCDCenteredString(0, "DIGITAL 9");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 9;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 10:
//Digital 10
displayLCDCenteredString(0, "DIGITAL 10");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 10;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 11:
//Digital 11
displayLCDCenteredString(0, "DIGITAL 11");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 11;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 12:
//Digital 12
displayLCDCenteredString(0, "DIGITAL 12");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 12;
releaseCPU();
StartTask(display);
}
else if(nLCDButtons == leftButton)
{
waitForRelease();
count--;
}
else if(nLCDButtons == rightButton)
{
waitForRelease();
count = 0;
}
break;
}
}
}
//----------------------------------------------------------------
//analogPortChooser - allows you to choose which port you'd like to pick
task analogPortChooser()
{
StopTask(sensorChooser);
hogCPU();
count = 1;//Chooses the starting point
while(true)
{
switch(count){
case 0:
//Back Option
displayLCDCenteredString(0, "Back to Sensors");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
releaseCPU();
StartTask(sensorChooser);
}
else if(nLCDButtons == leftButton)
{
waitForRelease();
count = 8;
}
else if(nLCDButtons == rightButton)
{
waitForRelease();
count++;
}
break;
case 1:
//Analog 1
displayLCDCenteredString(0, "ANALOG 1");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 13;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 2:
//Analog 2
displayLCDCenteredString(0, "ANALOG 2");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 14;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 3:
//Analog 3
displayLCDCenteredString(0, "ANALOG 3");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 15;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 4:
//Analog 4
displayLCDCenteredString(0, "ANALOG 4");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 16;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 5:
//Analog 5
displayLCDCenteredString(0, "ANALOG 5");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 17;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 6:
//Analog 6
displayLCDCenteredString(0, "ANALOG 6");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 18;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 7:
//Analog 7
displayLCDCenteredString(0, "ANALOG 7");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 19;
releaseCPU();
StartTask(display);
}
else
menuTracker();
break;
case 8:
//Analog 8
displayLCDCenteredString(0, "ANALOG 8");
displayLCDCenteredString(1, "< Enter >");
waitForPress();
if(nLCDButtons == centerButton)
{
waitForRelease();
portChoice = 20;
releaseCPU();
StartTask(display);
}
if(nLCDButtons == leftButton)
{
waitForRelease();
count--;
}
else if(nLCDButtons == rightButton)
{
waitForRelease();
count = 0;
}
break;
}
}
}
//----------------------------------------------------------------
//Clear Ports-----------------------------------------------------
void clearPorts()
{
hogCPU();
SensorType[in1] = sensorNone;
SensorType[in2] = sensorNone;
SensorType[in3] = sensorNone;
SensorType[in4] = sensorNone;
SensorType[in5] = sensorNone;
SensorType[in6] = sensorNone;
SensorType[in7] = sensorNone;
SensorType[in8] = sensorNone;
SensorType[dgtl1] = sensorNone;
SensorType[dgtl2] = sensorNone;
SensorType[dgtl3] = sensorNone;
SensorType[dgtl4] = sensorNone;
SensorType[dgtl5] = sensorNone;
SensorType[dgtl6] = sensorNone;
SensorType[dgtl7] = sensorNone;
SensorType[dgtl8] = sensorNone;
SensorType[dgtl9] = sensorNone;
SensorType[dgtl10] = sensorNone;
SensorType[dgtl11] = sensorNone;
SensorType[dgtl12] = sensorNone;
releaseCPU();
}
//----------------------------------------------------------------
//Wait for Press--------------------------------------------------
void waitForPress()
{
while(nLCDButtons == 0);
{
wait1Msec(5);
}
}
//----------------------------------------------------------------
//Wait for Release------------------------------------------------
void waitForRelease()
{
while(nLCDButtons != 0);
{
wait1Msec(5);
}
}
//----------------------------------------------------------------
//Function to increment and decriment count - small savings on space
void menuTracker()
{
if(nLCDButtons == leftButton)
{
waitForRelease();
count--;
}
else if(nLCDButtons == rightButton)
{
waitForRelease();
count++;
}
}
//----------------------------------------------------------------
//Display---------------------------------------------------------
task display()
{
StopTask(analogPortChooser);
StopTask(digitalPortChooser);
hogCPU();
switch(portChoice){
case 1:
//Digital Port 1
digitalSensorSetup(dgtl1);
break;
case 2:
//Digital Port 2
digitalSensorSetup(dgtl2);
break;
case 3:
//Digital Port 3
digitalSensorSetup(dgtl3);
break;
case 4:
//Digital Port 4
digitalSensorSetup(dgtl4);
break;
case 5:
//Digital Port 5
digitalSensorSetup(dgtl5);
break;
case 6:
//Digital Port 6
digitalSensorSetup(dgtl6);
break;
case 7:
//Digital Port 7
digitalSensorSetup(dgtl7);
break;
case 8:
//Digital Port 8
digitalSensorSetup(dgtl8);
break;
case 9:
//Digital Port 9
digitalSensorSetup(dgtl9);
break;
case 10:
//Digital Port 10
digitalSensorSetup(dgtl10);
break;
case 11:
//Digital Port 11
digitalSensorSetup(dgtl11);
break;
case 12:
//Digital Port 12
digitalSensorSetup(dgtl12);
break;
case 13:
//Analog Port 1
analogSensorSetup(in1);
break;
case 14:
//Analog Port 2
analogSensorSetup(in2);
break;
case 15:
//Analog Port 3
analogSensorSetup(in3);
break;
case 16:
//Analog Port 4
analogSensorSetup(in4);
break;
case 17:
//Analog Port 5
analogSensorSetup(in5);
break;
case 18:
//Analog Port 6
analogSensorSetup(in6);
break;
case 19:
//Analog Port 7
analogSensorSetup(in7);
break;
case 20:
//Analog Port 8
analogSensorSetup(in8);
break;
}
releaseCPU();
StartTask(sensorChooser);
}
//----------------------------------------------------------------
//Creates the analog sensor to be displayed
void analogSensorSetup(tSensors sensorPort)
{
switch(sensorChoice){
case 3:
SensorType[sensorPort] = sensorLineFollower; //Change to sensorReflection
clearLCDLine(0);
displayLCDPos(0,0);
displayNextLCDString("Light:");
while(nLCDButtons != 2)
{
clearLCDLine(1);
displayLCDPos(1,0);
displayNextLCDNumber(SensorValue[sensorPort], 4);
wait1Msec(100);
}
break;
case 4:
SensorType[sensorPort] = sensorLineFollower;
clearLCDLine(0);
displayLCDPos(0,0);
displayNextLCDString("Line Tracker:");
while(nLCDButtons != 2)
{
clearLCDLine(1);
displayLCDPos(1,0);
displayNextLCDNumber(SensorValue[sensorPort], 4);
wait1Msec(100);
}
break;
case 5:
SensorType[sensorPort] = sensorPotentiometer;
clearLCDLine(0);
displayLCDPos(0,0);
displayNextLCDString("Potentiometer:");
while(nLCDButtons != 2)
{
clearLCDLine(1);
displayLCDPos(1,0);
displayNextLCDNumber(SensorValue[sensorPort], 4);
wait1Msec(100);
}
break;
case 6:
SensorType[sensorPort] = sensorAccelerometer;
clearLCDLine(0);
displayLCDPos(0,0);
displayNextLCDString("Accelerometer:");
while(nLCDButtons != 2)
{
clearLCDLine(1);
displayLCDPos(1,0);
displayNextLCDNumber(SensorValue[sensorPort], 4);
wait1Msec(100);
}
break;
}
}
//----------------------------------------------------------------
//Creates the digital sensor to be displayed----------------------
void digitalSensorSetup(tSensors sensorPort)
{
switch(sensorChoice){
case 0:
SensorType[sensorPort] = sensorTouch;
clearLCDLine(0);
displayLCDPos(0,0);
displayNextLCDString("Touch:");
while(nLCDButtons != 2)
{
clearLCDLine(1);
displayLCDPos(1,0);
displayNextLCDNumber(SensorValue[sensorPort], 1);
wait1Msec(100);
}
break;
case 1:
SensorType[sensorPort] = sensorQuadEncoder;
clearLCDLine(0);
displayLCDPos(0,0);
displayNextLCDString("Quad Encoder:");
while(nLCDButtons != 2)
{
clearLCDLine(1);
displayLCDPos(1,0);
displayNextLCDNumber(SensorValue[sensorPort], 6);
wait1Msec(100);
}
break;
case 2:
SensorType[sensorPort] = sensorSONAR_cm;
clearLCDLine(0);
displayLCDPos(0,0);
displayNextLCDString("Ultrasonic (cm):");
while(nLCDButtons != 2)
{
clearLCDLine(1);
displayLCDPos(1,0);
displayNextLCDNumber(SensorValue[sensorPort], 4);
wait1Msec(100);
}
break;
}
}
//----------------------------------------------------------------















