Wednesday, 17 October 2007

Traffic Lights Using Pic 16f84

Here is a way of making a set of traffic lights using a 16f84 microchip mcu. It is fairly simple, all you have to do is wire up the mcu with a pair of red, green and yellow leds. Note the addresses of all leds connected to the pic chip. From now on I'll refer to the red lights as R1 and R2, green lights as G1 and so on.


I connected my leds in this configuration:
R1: B0
Y1: B1
G1: B2
R2: B3
Y2: B4
G2: B5
After this, map out the sequence you want. Mine was the standard sequence for a simple two way traffic light system in the UK. Here it is (format:R1Y1G1R2Y2G2):
100001;
010001;
001001;
001011;
001100;
001010;
001001;
011001;

Just literally translate this line for line into embedded C for the main routine but remember to place delays between each line for however long you want the lights to stay in that state before changing.

Here is my final code:
//Glen Lashley
//Traffic Lights
void InitialisePorts(void)
{
TRISA=0; //Make all ports outputs
TRISB=0;
}
void Routine(void)
{
PORTB = 0b00100001;
Delay_ms(100);
PORTB = 0b00010001;
Delay_ms(100);
PORTB = 0b00001001;
Delay_ms(100);
PORTB = 0b00001011;
Delay_ms(100);
PORTB = 0b00001100;
Delay_ms(100);
PORTB = 0b00001010;
Delay_ms(100);
PORTB = 0b00001001;
Delay_ms(100);
PORTB = 0b00011001;
Delay_ms(100);
}
MAIN(void)
{
InitialisePorts();
while(1)
{
Routine();
}
}

Feel free to question or comment guys! :)

Monday, 15 October 2007

Simple H-Bridge concept

Ever had the need to change the polarity of a power source and had no idea where to start? Well this simple h-bridge will give you a starting stone to work with. This can be used for motor direction control, bi colour LED's or anything involving the direction in which current flows.



The concept is simple. Use an array of transistors for switching and re-routing the direction in which the current flows.

A picture of this concept is shown below:



Keep in mind that this is a concept and in order for it to work resistors and/or any protection circuits have to be added. Remember that motors give emf and can cause the transistors to burn up. Some people use darlington pairs and relays to trigger a higher voltage (for the motor in this case).

Hope this entry has been of use!

Bootloaders for 16F87X

A bootloader is a simple solution to avoid waiting hours and avoid plugging the pic out of the circuit just to program it. You can update the code on a pic in seconds.

After initially preparing the pic, just one click of the mouse can update your pic. There is no need to modify your circuit if you want a simple implementation.

It is supported on Linux, Windows and even DOS. Its free to use and distribute without any agreements.

Thanks to http://microchipc.com/PIC16bootload/ , they have made it available for download and many tips, tricks and hints are located there.

Sunday, 14 October 2007

Timer using 16F84A (with internal interrupts), Seven Segment Display and Multiplexing

Have you ever needed a PIC based timer? This simple template can be used to count any where between 0 and 60 using a common cathode seven segment display. It can be easily modified to include a pause switch and a reset switch, even if you want to integrate an alarm it can be easily done. For now though, all I'll do is demonstrate how to get a simple 0-60 timer.

Step 1.
Create a new project in MikroC using PIC 16f84a. Make the processor speed equal to 4Mhz.

Step 2 - Start Coding!
First we will declare all functions and variables, in MikroC type:

void PortSetup(void); // function that configures MCU's inputs and outputs
void TimerSetup(void); // function to set up timer to interrupt
void interrupt (void); // interrupt service routine
void Convert(void); // function to decode numbers for seven segment display

// global variables
int Huns,Seconds,Segment,Tens,Units;


Now we'll write the main program. Type the following:

void main(void)
{
PortSetup();
TimerSetup();
PORTA = 0b00001; // initialise display
while(1) //endless loop
{
Convert();
}
}

Step 3 - Start coding functions.

First we'll set up the ports on the MCU. For now, we know that all we will be having is outputs to the seven segment, its up to you if you want to include any input buttons at a later time. Type the following in MikroC:

void PortSetup(void)
{
PORTA=0; //clear internal buffers
PORTB=0;
TRISA=0b00000; // program I/O (0==output, 1==input)
TRISB=0b00000000;
Huns = 0;
Seconds = 0;
TMR0 = 100;
}

Next we'll code the time function to interrupt the "while(1)" loop. We want it to be as accurate to a second as possible so we'll make it interrupt every 10 milliseconds. We'll do the math for working out the seconds further on. Type the following in MikroC:

void TimerSetup(void)
{

// function to set up timer to interrupt
// program every 10 Ms
OPTION_REG.PSA = 0; //assigns prescalar to Timer not Watch dog
OPTION_REG.PS0 = 1; //PS2-PS0 assign the prescaler ratio
OPTION_REG.PS1 = 0; // 64
OPTION_REG.PS2 = 1; //
INTCON.GIE = 1; // switch on interrupts
INTCON.T0IE = 1; // enable timer interrupt
INTCON.T0IF = 0; // set interrupt flag
OPTION_REG.T0CS = 0; // start timer
}

The OPTION_REG and INTCON registers were configured using the 16F84a datasheet. If its hard to understand, refer to my values and comments to try and figure it out. Otherwise, just send me an email!

Next is the hardest part! We'll setup the interrupt service routine to deal with the math and multiplexing of the seven segment displays. Multiplexing in this application saves a whole lot of port space. For every seven segment display, eight pins are required; seven for each segment and one common cathode pin (or "on" switch). Instead of using 16 pins (which is impossible), we'll use seven for both displays' data and one extra pin for each common cathode. In short, the total pins used to power two seven segment displays is 9, to power three displays, we need 10 pins and so on. The concept is simple, if we turn on one cathode then we'll send the data on the seven pins that correspond to that display. So if we want to display "32" on both displays, we'll turn on the cathode for for the first display and send the seven seg equivalent of "3" on the seven ports. Then we'll turn of that cathode and turn on the other cathode while sending the seven seg equivalent of "2" on the seven pins. If we do this fast enough, it will appear that "32" is being displayed when in actual fact they are changing so fast our brains cannot keep up!

Type the following code and refer to comments to see what each line does:

void interrupt(void) // ISR
{

/*Work out math for seconds (dividing a number into its 'tens' and 'ones' so each value can be displayed independently)*/
OPTION_REG.T0CS=1; // stop counter
TMR0=100; // reload timer 256-156=100
asm{nop}; // pad out with 'nops'
asm{nop}; // for ten milli-seconds
OPTION_REG.T0CS=0; // start counter
Huns++;
if (Huns > 99) // if one hundred interrupts!
{
Seconds++;
Huns = 0;
}
if(Seconds > 59)
{
Seconds = 0;
}
Tens = Seconds/10;
Units = Seconds - (Tens * 10);

//Code for multiplexing and displaying values
if ( PORTA.F0 == 1 )
{
PORTA = 0B00010; // Tens on Units off
Segment = Units;
}
else if(PORTA.F1 == 1)
{
PORTA = 0B00001;
Segment = Tens;
}
INTCON.T0IF=0; // reset interrupt flag
}

Finally we'll set up the decoding function to translate a numeric value into its seven segment binary equivalent. Type the folling code into MikroC:

void Convert(void) //Seven Segment decoder
{
switch (Segment)
{
case 0 : PORTB = 0B01111110;
break;
case 1 : PORTB = 0B00001100;
break;
case 2 : PORTB = 0B10110110;
break;
case 3 : PORTB = 0B10011110;
break;
case 4 : PORTB = 0B11001100;
break;
case 5 : PORTB = 0B11011010;
break;
case 6 : PORTB = 0B11111010;
break;
case 7 : PORTB = 0B00001110;
break;
case 8 : PORTB = 0B11111110;
break;
case 9 : PORTB = 0B11001110;
}
}

And thats it! All we need to do now is compile it!

The schematic for isis (for simulation), .asm, .ppc and .c files can be downloaded here: http://factm8.com/glen/blogfiles/60Seccounter.rar