PIC Control Board

YES!

SUCCESS!

I finally got my Tiny-ICD2 to work.
Apparently, my Bluetooth Dongle’s program (BlueSoliel) was hogging my COM ports.

When I tried to point MPLAB towards a COM port, it wouldn’t be able to connect, because BlueSoliel kept connecting to it.

After removing BlueSoliel, everything started falling into place.

Here’s the revised, tested, and accuracy-confirmed blinker program:

[code]//============================ Timed LED Blinker ========================//
// This program blinks an LED hooked up to RA0 every 200ms. //
// It also blinks an LED hooked up to RA1 every second. //
// The Timer0’s 200ms intervals was calculated in the following way: //
// 1 second / 5Hz = 200ms interval. //
// 10,000,000Hz / 4 instructions = 2,500,000Hz //
// 2,500,000Hz / 32 (Prescalar) = 78125Hz. //
// 78125Hz / 5Hz = 15625 (# counts needed for 200ms timer0 intervals.) //
// 15625 in hexidecimal = 3D09. //
// Thus, TMR0H = 3D and TMR0L = 09. //
//=======================================================================//

//============================ Inclusions. ==============================//
#include <p18f4620.h> // Specify the micro’s library. //
#include <timers.h> // Timer library (OpenTimer function)//
//=======================================================================//

//============================ Configurations. ==========================//
#pragma config OSC = HSPLL // 10 MHz external OSC * 4. //
#pragma config FCMEN = OFF // Fail Safe Clock Monitor. //
#pragma config IESO = OFF // Internal External OSC Switch Over.//
#pragma config PWRT = OFF // Powerup Timer. //
#pragma config BOREN = OFF // Brownout Reset. //
#pragma config BORV = 3 // Brownout Voltage = lowest setting.//
#pragma config WDT = OFF // Watch Dog Timer. //
#pragma config WDTPS = 1 // Watch Dog Timer Post Scalar = 1:1.//
#pragma config MCLRE = ON // Memory Clear. //
#pragma config LPT1OSC = OFF // T1 OSC. //
#pragma config PBADEN = OFF // Port B Analog/Digital = Digital. //
#pragma config CCP2MX = PORTBE // CCP2 Multiplex with RB3. //
#pragma config STVREN = OFF // Stack Overflow Reset. //
#pragma config LVP = OFF // Low Voltage Programming. //
#pragma config XINST = OFF // XINST. //
#pragma config DEBUG = ON // Background Debugger. //
#pragma config CP0 = OFF // Code Protection Block 0. //
#pragma config CP1 = OFF // Code Protection Block 1. //
#pragma config CP2 = OFF // Code Protection Block 2. //
#pragma config CP3 = OFF // Code Protection Block 3. //
#pragma config CPB = OFF // Boot Block Code Protection. //
#pragma config CPD = OFF // Data EEPROM Code Protection. //
#pragma config WRT0 = OFF // Write Protection Block 0. //
#pragma config WRT1 = OFF // Write Protection Block 1. //
#pragma config WRT2 = OFF // Write Protection Block 2. //
#pragma config WRT3 = OFF // Write Protection Block 3. //
#pragma config WRTB = OFF // Boot Block Write Protection. //
#pragma config WRTC = OFF // Config Register Write Protection. //
#pragma config WRTD = OFF // Data EEPROM Write Protection. //
#pragma config EBTR0 = OFF // Table Read Protection Block 0. //
#pragma config EBTR1 = OFF // Table Read Protection Block 1. //
#pragma config EBTR2 = OFF // Table Read Protection Block 2. //
#pragma config EBTR3 = OFF // Table Read Protection Block 3. //
#pragma config EBTRB = OFF // Boot Block Table Read Protection. //
//=======================================================================//

//============================ Global constants. ========================//
#define TICKS_PER_SECOND 5 // Number of interrupts in 1 second. //
#define STATUS_LED PORTDbits.RD2 // Green LED on pin RD2. //
#define ERROR_LED PORTDbits.RD3 // Red LED on pin RD2. //
//=======================================================================//

//============================ Global variables. ========================//
int tick_counter = 0; // Create and zero a global counter. //
//=======================================================================//

//============================ Low-priority interupt setup. =============//
void timer0_handler (void); // Declare an empty function. //
#pragma code low_vector = 0x18 // Go to low_vector’s memory section.//
void timer0_vector (void) // Declare the setup function. //
{ //
_asm GOTO timer0_handler _endasm// Execute timer0_interupt function. //
} //
#pragma code // Return to original memory section.//
#pragma interruptlow timer0_handler // Redeclare the timer function as a //
// low priority interupt. //
//=======================================================================//

//============================ Main code. ===============================//
void main (void) //
{ //
OpenTimer0 (TIMER_INT_ON // Timer interupt enabled. //
& T0_SOURCE_INT // Lets timer0 trigger low interupts.//
& T0_16BIT // 16-bit mode. //
& T0_PS_1_32); // 1:32 post scalar. //
INTCONbits.GIE = 1; // Global interupts enabled. //
RCONbits.IPEN = 1; // Enable priority levels. //
TRISD = 0; // Set port D for output. //
while(1) // Infinite loop keeps micro running.//
{ //
// Interuptable processes goes here. //
} //
} //
//=======================================================================//

//============================ Low-priority interupt. ===================//
void timer0_handler (void) //
{ //
INTCONbits.TMR0IF = 0; // Reset timer0 interupt flag. //
TMR0H = 0x3D; // Reset the timer period. //
TMR0L = 0x09; // Reset the timer period. //
tick_counter++; // Count how many interupts occured. //
//
//
//
//================== Blink an LED really fast. =================// //
STATUS_LED = ~STATUS_LED; // Toggle the LED on and off. // //
//==============================================================// //
//
//
//
//================== Blink an LED more slowly. =================// //
if (tick_counter > TICKS_PER_SECOND) // //
// This is true every second. // //
{ // //
tick_counter = 0; // //
ERROR_LED = ~ERROR_LED; // Toggle the LED on and off. // //
} // //
//==============================================================// //
//
//
//
} //
//=======================================================================//
[/code]

Because everything divided in evenly, the one-second interval LED is accurate enough to set my clocks by.
:stuck_out_tongue:

Now, I can finally load the USART program that I’ve been working on and test it with HyperTerm.
::crosses fingers::

I have used the ExpressPCB software but all my boards have been created in Eagle Cad and then I used Spark Fun’s Batch PCB service. I have never used ExpressPCB to make the fabs. I know Pete Has used ExpressPCB.

Ahh, my bad.
:slight_smile:

I went with Express simply because Dan showed me how easy it was to use.
I don’t doubt that Eagle is just as easy, so I’ll go check the prices there and give it a try before I get set on ExpressPCB.

Still, I won’t be ready to SMT the board until I’ve gotten the prototype working, which is a long way into the future.
:stuck_out_tongue:

Here’s the new design that I’ve come up with for my biped’s control.

f10.putfile.com/thumb/7/19515043186.jpg

I had been toying with the idea of locating multiple PICs in currently unused, small locations on my bot.
Originally, I had planned on using the 40-pin that I’m prototyping as a organizer/brain, and network the menial tasks to more conveniently located PICs.
However, that would require bitbanging, since I’ve only got one UART on the 40-pin.

With this daisey-chaining method, I only need one UART per micro.
One con of daisey chaining is that if I were to send the entire position data through the SMiRF, it’d have to be resent 3 more times before it even got to the SSC-32, which is just plain slow.
Another con is that some amount of data must be the address of the micro sending the info, which means even more slowness.

I’m combatting this in the following ways:

First, I’m going to impliment a single-byte communication system.
For instance, the keyboard will send a “j” to the first micro through the Bluetooth.
The RX interupt will trigger and imediately send that “j” to the next micro.
And so on, until the last micro gets it.
That micro looks at “j” and reads the corresponding servo positions in the I2C EEPROM (not actually connected in the picture; I’ll be looking at the data sheet next to figure out how that fits in, next).
Then it sends that string to the SSC-32.

Since I’ll be sending characters a-z from my computer (01100001 - 01111010), with each micro I can figure out that this character is coming from the computer because the first two bits are always “01”.
Thus, the first two bits are the address.

Following this pattern, I determined that I needed four addresses (one for each micro and one for the computer).
If I know the address, I’ll know which servos need to be corrected.
The last micro will do that correcting addition.

I figured that a minimal change of 25 pulse value is more than enough precision for balancing.
2250 - 750 (full pulse range values) = 1500 total different values / 25 minimal pulse change = 60 necessary different values.
Thus the last 6 bits (64 different values) covers the 60 necessary.
Therefore, I can use the first two bits of each byte sent as the address, which provides the four different values that I need.

How’s that sound?

Hi Nick,

I think your plan will work, but you might want to look into using I2C to link the PICs together, instead of the serial daisy-chain. The I2C protocol has addressing built-in - you basically would just connect the SDA and SCL lines from each device together, and then designate one PIC as the ‘master’ (the one that talks to the BlueSmirf). Ordinary I2C is rated for 100,000 bps - plenty fast enough. Another big advantage of going I2C is that it will be bi-directional. With the serial daisy-chain, you won’t be able to get data from your sensors (the 2nd PIC) back to the first PIC. I2C is intended for exactly the type of thing you’re doing. And your EEPROM will need I2C anyway.

The downside of using I2C is that it’s more SW. But, folks like Andy and I already have working code that you can use. I’m sure there’s a lot more on the web.

Using I2C would also free up the serial ports on the 2nd and 3rd PICs, so that (for example) you could go bi-directional to your SSC-32 and Smirf, and perhaps use the 2nd PICs port to connect to another device.

Here’s a good link for I2C info, including an official spec. Don’t get hung up on the gory details - the basics are really pretty easy.
semiconductors.philips.com/p … index.html

Pete

Ooooh…
So that’s what I2C is for…
I feel stupid.
:stuck_out_tongue:

That would indeed allow for a lot more flexibility.
I had been thinking it a shame that I couldn’t use the RX of the Bluetooth as a debugging tool.
This seems to solve everything.

Thanks!

I don’t think SW will be too much of a trouble.

Once I get it right by following the multiple examples that the web offers, I’ll be able to reuse it for all 3 of the micros, which will save time.

I’ve been taking the time to make working templates for such things as UARTs, timers, interupts, etc, which is starting to save me a lot of time in the long-run.
I’ll just struggle for a couple days making an I2C template and then have a working base to go from for all my future projects.

Thanks again!