You are on page 1of 28

http://www.blitzlogic.com/led.

htm

1.Example to drive 8 LEDS

/************************************************
* *
* COPYRIGHT (c) Blitzlogic Sdn. Bhd. *
* Author : Abraham Wong 21/1/2000 *
* *
* example of using WHILE loop construct *
* to drive 8 LEDS connected to port B *
* *
************************************************/
#include <16c84.h>
#USE DELAY( CLOCK=4000000 ) /* Using a 4 Mhz clock */
#FUSES XT,NOWDT,NOPROTECT,NOPUT
/* Use XT mode, No Watch Dog, No Code Protect, No Power-up Timer */
#byte port_b=6 /* define the location of register port_b */
main(){
byte cnt; value;
set_tris_b(0); /* set port_b to be outputs */
port_b = 0; /* initialize All port_b outp/uts to be zero */
value = 0x01;
while( TRUE )
{ /* forever loop using WHILE construct */
cnt = 0;
while ( cnt<8 )
{
port_b = value;
DELAY_MS(1000);
value = value; /* shift left will put 0x01, 0x02, 0x04,
0x08, 0x10 */
cnt++; /* 0x2<< 10, 0x40, 0x80 to port_b */
}
}
}

EXERCISES

Modify the above program to display


the following sequence : -
LED1 and LED8 turn on, 1 sec delay;
LED2 and LED7 turn on, 1 sec delay;
LED3 and LED6 turn on, 1 sec delay;
LED4 and LED5 turn on, 1 sec delay;

Loop back & Repeat again forever.

2.TWO 7 SEGMENT LED & 2 SWITCHES

Since we can source a maximum of 20mA per pin for PORTB and total maximum
source current of PORTB is 100mA, hence we can use PORTB to drive LED
display directly. As shown in the circuit, 2 common cathode 7-segment LEDs are
connected to PORTB with 120 Ohms current limit- ing resistor. Each segment of
two LED are tied in parallel to P1. Q1 and Q2 are activated by logic high of PA0
and PA1 which switch on ground to the respective common cathode pins. PA2
and PA3 pin are use to read the inputs S1 or S2 switches.

The following code, 7-SEG.C demonstrate how to drive two 7-segment LEDs. The
program first display digits on the Left LEDs and counts from 0 to 9 with a delay
of 1 second between each digit. Then it switches to the Right LED and repeats
the same tasks and then the whole sequence is repeated all over again from the
beginning.

Example to drive two 7-Segment LEDs


/****************************************
*
* COPYRIGHT (c) Blitzlogic Sdn. Bhd.
* Author : Abraham Wong 21/1/2000
*
* example of using FOR loop to drive
* two 7-Segment LEDs

****************************************/
#include <16c84.h>
#USE DELAY( CLOCK=4000000 ) /* Using a 4 Mhz clock */
#FUSES XT,NOWDT,NOPROTECT,NOPUT
/* Use XT mode, No Watch Dog, No Code Protect, No Power-up Timer */
#byte port_b=6 /* define the location of register port_b */
#byte port_a=5 /* define the location of register port_b */
byte CONST LED_MAP[10] =
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
main(){
byte cnt, right,num ;
set_tris_b(0); /* set port_b as outputs */
set_tris_a(0); /* set port_a as output */
port_b = 0; /* ZERO port_a & port_b */
port_a = 0;
for( ;; ){
for (right=1;right<3;right++){
port_a = right;
for (cnt=0;cnt<10;cnt++){
port_b = LED_MAP[cnt];
DELAY_MS(1000); /* one second delay */
}
}
}
}

EXERCISES

Assignment 1 :
The two 7-segment LED now is made to display 00 simultaneously and starting
counting up automatically by incrementingby one with a one second delay
between each increment. When count reach 99, it should reset itself to 00 and
repeat all over again

Assignment 2 :
This is a modification to Asignment 1 where the increment by one is executed
only when S1 switch is pressed. When the switch is released, the increment
stops. When S2 switch is pressed, it initiate a decrement by one. When count is
99, and S1 is pressed, it becomes 00. When the count is 00, and S1 is pressed,
it will becomes 99.
3.Interface Led matrix 5X7
Since we can source a maximum of 20mA per pin for PORTB and total maximum
source current of PORTB is 100mA, hence we can use PORTB to drive LED
display directly. As shown circuit below, One Common Cathode 5 x 7 Matrix LEDs
are connected to Port B with 120 Ohms current limiting resistor. The Columns
are activated by Q1, Q2, Q3, Q4 and Q5 respectively by logic high of PA0, PA1,
PA2, PA3, PA4 which switch on gnd to the respective common cathode pins.

The following code, matrix_cdemonstrate how to drive a 5 x 7- Matrix LED. The


program first display one 5 x 7 pattern on the LEDs and then redisplay this
pattern over and over again.

Example to drive 5 x 7 Matrix LED

/************************************************
* *
* COPYRIGHT (c) Blitzlogic Sdn. Bhd. *
* Author : Abraham Wong 21/1/2000 *
* example of driving 5 x 7 Matrix LEDs *
* *
************************************************/
#include <16c84.h>
#USE DELAY( CLOCK=4000000 ) /* Using a 4 Mhz clock */
#FUSES XT,NOWDT,NOPROTECT,NOPUT
/* Use XT mode, No Watch Dog, No Code Protect, No Power-up Timer
*/
#byte port_b=6 /* define the location of register port_b */
#byte port_a=5 /* define the location of register port_b */
char const pat[5]={0x3f,0x02,0x04,0x02,0x3f};
main(){
char cnt, col;

set_tris_b(0); /* set port_b as outputs */


set_tris_a(0); /* set port_a as output */
port_b = 0; /* ZERO port_a & port_b */
port_a = 0;
for( ;; )
{
col = 1;
for(cnt = 0;cnt < 5;cnt++)
{
port_b = pat[cnt];
port_a = col;
delay_ms(1);
col<<=1;
}
}
}

EXERCISES

Assignment 1 : Modify the above program to display your name on the display,
flashing each Alphabet for one second and then flashing the next alhabet until all
the alphabet in your name has been shown and repeat this sequence all over
again

4.interfacing to 16 x 1 LCD

This program uses both the KBD.C and LCD.C drivers to allow keypad entry and
LCD display. All keys are echoed except that will clear the display. Either the
kbd_getc or lcd_putc may be replaced with getc or putc to use just one device
with the RS-232.
The following code, ex_lcdkb.c together with lcd.c and kbd.c demonstrate how to
implement key pressed on the 4 x 3 keypad to be display on the 16 x 1 LCD
Module and echoed on the RS-232 channel.

EXAMPLE to use KBD.C and LCD.C drivers


//// EX_LCDKB.C
//// This program uses both the KBD.C and LCD.C drivers to allow
//// keypad entry and LCD display. All keys are echoed except *
//// that will clear the display. Either the kbd_getc or lcd_putc
//// may be replaced with getc or putc to use just one device with
//// the RS-232.
//// (C) Copyright 1996,1997 Custom Computer Services
////////////////////////////////////////////////////////////////////
/////
#include <16F84.H>
#fuses XT,NOPROTECT,NOWDT
#use delay(clock=4000000)
#include
#include

main() {
char k;
lcd_init();
kbd_init();
lcd_putc("\fReady...\n");

while (TRUE) {
k=kbd_getc();
if(k!=0)
if(k=='*')
lcd_putc('\f');
else
lcd_putc(k);
}
}

Driver for common LCD modules


//// LCD.C
//// Driver for common LCD modules
//// lcd_init() Must be called before any other function.
//// lcd_putc(c) Will display c on the next position of the LCD.
//// The following have special meaning:
//// \f Clear display
//// \n Go to start of second line
//// \b Move back one position
//// lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//// lcd_getc(x,y) Returns character at position x,y on LCD
//// (C) Copyright 1996,1997 Custom Computer Services
// As defined in the following structure the pin connection is as
follows:
// B0 enable
// B1 rs
// B2 rw
// B4 D4
// B5 D5
// B6 D6
// B7 D7
// LCD pins D0-D3 are not used and PIC B3 is not used.

struct lcd_pin_map { // This structure is overlayed


boolean enable; // on to an I/O port to gain
boolean rs; // access to the LCD pins.
boolean rw; // The bits are allocated from
boolean unused; // low order up. ENABLE will
int data : 4; // be pin B0.
} lcd;

#byte lcd = 6 // This puts the entire structure


#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line

byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};


// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
STRUCT lcd_pin_map const LCD_WRITE = {0,0,0,0,0};
// For write mode all pins are out
STRUCT lcd_pin_map const LCD_READ = {0,0,0,0,15};
// For read mode data pins are in
byte lcd_read_byte() {
byte low,high;
set_tris_b(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
high = lcd.data;
lcd.enable = 0;
delay_cycles(1);
lcd.enable = 1;
delay_us(1);
low = lcd.data;
lcd.enable = 0;
set_tris_b(LCD_WRITE);
return( (high<<4) | low);
}

void lcd_send_nibble( byte n ) {


lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}

void lcd_send_byte( byte address, byte n ) {

lcd.rs = 0;
while ( bit_test(lcd_read_byte(),7) ) ;
lcd.rs = address;
delay_cycles(1);
lcd.rw = 0;
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}

void lcd_init() {
byte i;
set_tris_b(LCD_WRITE);
lcd.rs = 0;
lcd.rw = 0;
lcd.enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}

void lcd_gotoxy( byte x, byte y) {


byte address;

if(y!=1)
address=lcd_line_two;
else
address=0;
address+=x-1;
lcd_send_byte(0,0x80|address);
}

void lcd_putc( char c) {


switch (c) {
case '\f' : lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n' : lcd_gotoxy(1,2); break;
case '\b' : lcd_send_byte(0,0x10); break;
default : lcd_send_byte(1,c); break;
}
}

char lcd_getc( byte x, byte y) {


char value;
lcd_gotoxy(x,y);
lcd.rs=1;
value = lcd_read_byte();
lcd.rs=0;
return(value);
}
Generic keypad scan driver
////////////////////////////////////////////////////////////////////
//// KBD.C ////
//// Generic keypad scan driver
//// kbd_init() Must be called before any other function.
////c = kbd_getc(c) Will return a key value if pressed or /0 if not
//// This function should be called frequently so as
/// not to miss a key press.
////// The following defines the keypad layout on port B
#byte kbd = 6 // Keypad is connected to port B (address 6)
//Keypad connection: (for example column 0 is B2)
// Bx:

#ifdef blue_keypad /////////////////////////// For the blue keypad


#define COL0 (1 << 2)
#define COL1 (1 << 3)
#define COL2 (1 << 6)
#define ROW0 (1 << 4)
#define ROW1 (1 << 7)
#define ROW2 (1 << 1)
#define ROW3 (1 << 5)

#else //////////////////////////////////////////////For my keypad


#define COL0 (1 << 6)
#define COL1 (1 << 2)
#define COL2 (1 << 3)
#define ROW0 (1 << 4)
#define ROW1 (1 << 5)
#define ROW2 (1 << 1)
#define ROW3 (1 << 7)
#endif
#define ALL_ROWS (ROW0|ROW1|ROW2|ROW3)
#define ALL_PINS (ALL_ROWS|COL0|COL1|COL2)
// Keypad layout:
char const KEYS[4][3] = {{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}};

#define KBD_DEBOUNCE_FACTOR 33 //Set this number to apx n/333where


// n is the number of times you expect
// to call kbd_getc each second
void kbd_init() {
#ifdef __PCM__
port_b_pullups(true);// If not PCM be sure to use external pullups
#endif
}
char kbd_getc( ) {
static byte kbd_call_count;
static short int kbd_down;
static char last_key;
static byte col;
byte kchar;
byte row;
kchar='\0';
if(++kbd_call_count>KBD_DEBOUNCE_FACTOR) {
switch (col) {
case 0 : set_tris_b(ALL_PINS&~COL0);
kbd=~COL0&ALL_PINS;
break;
case 1 : set_tris_b(ALL_PINS&~COL1);
kbd=~COL1&ALL_PINS;
break;
case 2 : set_tris_b(ALL_PINS&~COL2);
kbd=~COL2&ALL_PINS;
break;
}

if(kbd_down) {
if((kbd & (ALL_ROWS))==(ALL_ROWS)) {
kbd_down=false;
kchar=last_key;
last_key='\0';
}
} else {
if((kbd & (ALL_ROWS))!=(ALL_ROWS)) {
if((kbd & ROW0)==0)
row=0;
else if((kbd & ROW1)==0)
row=1;
else if((kbd & ROW2)==0)
row=2;
else if((kbd & ROW3)==0)
row=3;
last_key =KEYS[row][col];
kbd_down = true;
} else {
++col;
if(col==3)
col=0;
}
}
kbd_call_count=0;
}
set_tris_b(ALL_PINS);
return(kchar);
}

5.interfacing to LTC1298 Serial A/D Convertor


this program will read both A/D channels and display the results as both a
voltage and raw hex number over the RS-232. A reading is taken every second.
The following code, ex_ad12.c and ltc1298.c demonstrate how to implement the
above program which reads both A/D Channels, namely AN0 and AN1
respectively and display out the results over an RS-232 terminal program
running on a PC.
Example to read two A/D Channels of LTC1298
//// EX_AD12.C
//// This program will read both A/D channels and display the
//// results as both a voltage and raw hex number over the RS-232.
//// A reading is taken every second.
#include <16F84.H>
#fuses HS,NOPROTECT,NOWDT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)
#include

void display_data( long int data ) {


char volt_string[6];
convert_to_volts( data, volt_string );
printf(volt_string);
printf(" (%4lX)",data);
}

main() {
long int value;
adc_init();
printf("Sampling:\r\n");
do {
delay_ms(1000);
value = read_analog(0);
printf("\n\rCh0: ");
display_data( value );
value = read_analog(1);
printf(" Ch1: ");
display_data( value );
} while (TRUE);
}
Driver for LTC1298 A/D Converter

/******************************************************************
Driver for LTC1298 A/D Converter
*adc_init() Call after power up
* value = read_analog( channel ) Read a analog channel,channel is 0
or 1
*convert_to_volts( value, string ) Fills in string with
the true voltage in
the form 0.000
*********/
#ifndef ADC_CS
#define ADC_CLK PIN_B0
#define ADC_DOUT PIN_B1
#define ADC_DIN PIN_B2
#define ADC_CS PIN_B3
#endif

void adc_init() {
output_high(ADC_CS);
}
void write_adc_byte(byte data_byte, byte number_of_bits) {
byte i;
delay_us(2);
for(i=0; i>1;
output_high(ADC_CLK);
delay_us(50);
output_low(ADC_CLK);
delay_us(50);
}
}
byte read_adc_byte(byte number_of_bits) {
byte i,data;
data=0;
for(i=0;i<<8)|l);
}
void convert_to_volts( long int data, char volts[6]) {
byte i, d, div_h, div_l;
long int temp,div;
div=0x3330;
for(i=0;i<=4;i++) {
temp=data/div;
volts[i]=(byte)temp+'0';
if(i==0) {
volts[1]='.';
i++;
}
temp=div*(byte)temp;
data=data-temp;
div=div/10;
}
volts[i]='\0';
}
6.Interfacing to I2C serial EEPROM 24C02

The circuit below shows how to interface a Serial I2C EEPROM, namely the 2402
to a PIC16F84 via a simple 2 wire interface ! In addition, the circuit has a
MAX232 IC for the Voltage level shifting so that it can be connected to a serial
COMport(RS-232C) of a PC.

Thefollowing code, ex_extee.c and 2402.c demonstrate how to uses the 2402
external EEPROM to read and write to an external serial EEPROM and then
display out the results via an RS-232 terminal program running on a PC.

I2C EEPROM 24LC02 EXAMPLE

//// EX_EXTEE.C
//// This program uses the 24xx or 93xx external EEPROM drivers to
//// read and write to an external serial EEPROM.
//// Change the #include <9356.C> to any of the other drivers to
//// test other parts. Note each driver defines EEPROM_ADDRESS
//// indicate 8 or 16 bit addresses.
#include <16F84.H>
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)
#include
#include <2402.C>

main() {
byte value,cmd;
EEPROM_ADDRESS address;
init_ext_eeprom();
do {
do {
printf("\r\nRead or Write: ");
cmd=getc();
cmd=toupper(cmd);
putc(cmd);
} while ( (cmd!='R') && (cmd!='W') );
printf("\n\rLocation: ");
#if sizeof(EEPROM_ADDRESS)==1
address = gethex();
#else
#if EEPROM_SIZE>0xfff
address = gethex();
#else
address = gethex1();
#endif
address = (address<<8)+gethex();
#endif
if(cmd=='R')
printf("\r\nValue: %X\r\n",READ_EXT_EEPROM( address ) );
if(cmd=='W') {
printf("\r\nNew value: ");
value = gethex();
printf("\n\r");
WRITE_EXT_EEPROM( address, value );
}
} while (TRUE);
}

I2C Library Sub-Routines for 24LC02

//// Library for a MicroChip 24LC02B configured for a x8 org


//// init_ext_eeprom(); Call before the other functions are used
//// write_ext_eeprom(a, d); Write the byte d to the address a
//// d = read_ext_eeprom(a); Read the byte d from the address a
//// The main program may define eeprom_sda
//// and eeprom_scl to override the defaults below.
#ifndef EEPROM_SDA
#define EEPROM_SDA PIN_B7
#define EEPROM_SCL PIN_B6
#endif
#use i2c(master,sda=EEPROM_SDA, scl=EEPROM_SCL)
#define EEPROM_ADDRESS byte
#define EEPROM_SIZE 256

void init_ext_eeprom() {
output_low(eeprom_scl);
output_high(eeprom_sda);
}

void write_ext_eeprom(byte address, byte data) {


i2c_start();
i2c_write(0xa0);
i2c_write(address);
i2c_write(data);
i2c_stop();
delay_ms(11);
}
byte read_ext_eeprom(byte address) {
byte data;
i2c_start();
i2c_write(0xa0);
i2c_write(address);
i2c_start();
i2c_write(0xa1);
data=i2c_read(0);
i2c_stop();
return(data);
}

7.STOP Watch Timer via RTCC

This program uses the RTCC (timer0) and interrupts to keep a real time seconds
counter. A simple stop watch function is then implemented.The following
code, ex_stwt.c demonstrate how to implement the above program which sets
up the PIC's RTCC & interrupts to keep track of a real time seconds counter.

Stop Watch function via RTCC & interrupts


//// EX_STWT.C
//// This program uses the RTCC (timer0) and interrupts to keep a
//// real time seconds counter. A simple stop watch function is
//// then implemented.
#include <16F84.H>
#fuses XT,NOWDT,NOPROTECT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)
#define INTS_PER_SECOND 76 // (20000000/(4*256*256))
byte seconds; // A running seconds counter
byte int_count;
//Number of interrupts left before a second has elapsed

#int_rtcc // This function is called every time


clock_isr() { // the RTCC (timer0) overflows (255->0).
// For this program this is apx 76 times
if(--int_count==0) { // per second.
++seconds;
int_count=INTS_PER_SECOND;
}
}
main() {
byte start;
int_count=INTS_PER_SECOND;
set_rtcc(0);
setup_counters( RTCC_INTERNAL, RTCC_DIV_256);
enable_interrupts(RTCC_ZERO);
enable_interrupts(GLOBAL);
do {
printf("Press any key to begin.\n\r");
getc();
start=seconds;
printf("Press any key to stop.\n\r");
getc();
printf("%u seconds.\n\r",seconds-start);
} while (TRUE);
}

8.Measure input Pulse time via RTCC

This program uses the RTCC (timer0) to time a single pulse to the PIC input.The
following code, ex_pulse_c demonstrate how to measure a pulse input by using
the PIC's RTCC timer0 to time a single pulse input.

Example to create a pulse via RTCC( timer0 )


//// EX_PULSE.C
//// This program uses the RTCC (timer0) to time a single pulse
//// input to the PIC.
#include <16F84.H>
#fuses XT,NOPROTECT,NOWDT
#include
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)
char get_scale() {
char scale;
do {
printf("\n\rPress S for short or L for long: ");
scale = getc();
scale = toupper(scale);
} while ( (scale!='S') && (scale!='L') );
return(scale);
}

void wait_for_low_to_high() {
while(input(PIN_B1)) ; /* if it's high, wait for a low */
delay_us(3); /* account for fall time */
while(!input(PIN_B1)); /* wait for signal to go high */
}

void wait_for_low() {
delay_us(3); /* account for rise time */
while(input(PIN_B1)); /* wait for signal to go high */
}

main() {
char scale;
byte time;
do {
scale = get_scale();
if(scale=='S')
setup_counters( RTCC_INTERNAL, RTCC_DIV_64 );
else
setup_counters( RTCC_INTERNAL, RTCC_DIV_256 );

printf("\n\rWaiting...\n\r");
wait_for_low_to_high();
set_rtcc(0);
wait_for_low();
time = get_rtcc();
printf("Counter value: %2X\n\n\r", time);
} while (TRUE);
}

9.Measure Temperature using DS1621 chip

This program will Reads the temperature using the DS1621 chip from
DallasSemiconductor and sends the results to be dispalyed over a RS232
terminal.The following code, ex_temp_c and ds1621_c demonstrate how to
implement the above program which reads the temperature using the DS1621
chip and display out the results over an RS-232 terminal program running on a
PC.
Example to Read temperature using the DS1621
//// EX_TEMP.C
//// Reads temperature using the DS1621 and sends it over the RS232
#include <16F84.H>
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)
#include
main() {
byte value;
init_temp();
do {
value = read_temp();
printf("%u\r\n",value);
delay_ms(1000);
}while (TRUE);
}

Library for Dallas 1621 Temperature chip


//// Library for a Dallas 1621 Temperature chip
//// init_temp(); Call before the other functions are used
/// d = read_temp(); Read the temerature in degrees (0-255)
#use i2c(master,sda=PIN_B7, scl=PIN_B6)

void temp_config(byte data) {


i2c_start();
i2c_write(0x90);
i2c_write(0xac);
i2c_write(data);
i2c_stop();
delay_ms(11);
}

void init_temp() {
output_high(PIN_B7);
output_high(PIN_B6);
i2c_start();
i2c_write(0x90);
i2c_write(0xee);
i2c_stop();
temp_config(8);
}

byte read_temp() { ////// Returns degrees F (0-255)


byte datah,datal;
long data;
i2c_start();
i2c_write(0x90);
i2c_write(0xaa);
i2c_start();
i2c_write(0x91);
datah=i2c_read();
datal=i2c_read(0);
i2c_stop();
data=datah;
data=data*9;
if((datal&0x80)!=0)
data=data+4;
data=(data/5)+32;
datal=data;
return(datal);
}

10.Expanding no. of I/O Lines using 74165/74595

It is ussually a common situation when we have used up all our I/O on our
microcontroller but we still need to use additional I/O and what shall we do ?
The following is one solution to this problem by expanding the number of I/O
using shift register I.C like 74165 and 74595.The following code, exp_io_c shows
how to use the 74165.Cand 74595.C libraries for extended input and output.
When button S1 is pushed, LED 1 will toggle green. Button S2 will toggle LED 2.
However, when both buttons are pushed, LED 3 will toggle green.

Example to expand number of I/O using 74165 & 74595


//// EX_EXPIO.C
//// This program shows how to use the 74165.C and 74595.C
//// libraries for extended input and output.
//// When button S1 is pushed, LED 1 will toggle green. Button
//// S2 will toggle LED 2. However, when both buttons are pushed,
//// LED 3 will toggle green.

#ifdef __PCB__
#include <16C56.H>
#else
#include <16C74.H>
#endif
#include <74595.C>
#include <74165.C>

main() {
byte data;
do {
read_expanded_inputs (&data);
data |= 0xF8; //Force the unused input bits on
//Turn on bit 2 it both inputs are toggled
data -= (!(data&0x01)&!(data&0x02))<<2;
write_expanded_outputs (&data);
} while (TRUE);
}

74165 Library Routine to expand no. of input lines


//// Library for a 74165 Expanded Input Chip
//// Any number of these chips may be connected in series to get
//// 8 additional inputs per chip. The cost is 3 I/O pins for
//// any number of chips.
//// read_expanded_inputs(ei); Reads the array ei from the chips
//// This source code may only be used by licensed users of the CCS
//// compiler. This source code may only be distributed to other
//// licensed users of the CCS C compiler.No other use, reproduction
//// or distribution is permitted without written permission.
//// Derivative programs created using this software in object code
//// form are not restricted in any way.
#IFNDEF EXP_IN_ENABLE
#define EXP_IN_ENABLE PIN_B3
#define EXP_IN_CLOCK PIN_B4
#define EXP_IN_DI PIN_B5
#define NUMBER_OF_74165 1
#ENDIF

void read_expanded_inputs(byte *ei) {


byte i;
output_high(EXP_IN_CLOCK);
output_low(EXP_IN_ENABLE); // Latch all inputs
output_high(EXP_IN_ENABLE);
// Clock in bits to the ei structure
for(i=1;i<=NUMBER_OF_74165*8;++i) {
shift_left(ei,NUMBER_OF_74165,input(EXP_IN_DI));
output_low(EXP_IN_CLOCK);
output_high(EXP_IN_CLOCK);
}
output_low(EXP_IN_ENABLE);
}

74595 Library Routine to expand no. of output lines

///////////////////////////////////////////////////////////////////////////
//// Library for a 74595 Expanded Output Chip ////
//// ////
//// Any number of these chips may be connected in serise to get ////
//// 8 additional outputs per chip. The cost is 3 I/O pins for ////
//// any number of chips. ////
//// write_expanded_outputs(eo); Writes the array eo to the chips ////
//// ////
#IFNDEF EXP_OUT_ENABLE
#define EXP_OUT_ENABLE PIN_B0
#define EXP_OUT_CLOCK PIN_B1
#define EXP_OUT_DO PIN_B2
#define NUMBER_OF_74595 1
#ENDIF

void write_expanded_outputs(byte* eo) {


byte i;
output_low(EXP_OUT_CLOCK);
output_low(EXP_OUT_ENABLE);

for(i=1;i<=NUMBER_OF_74595*8;++i) { // Clock out bits from the eo array


if((*(eo+(NUMBER_OF_74595-1))&0x80)==0)
output_low(EXP_OUT_DO);
else
output_high(EXP_OUT_DO);
shift_left(eo,NUMBER_OF_74595,0);
output_high(EXP_OUT_CLOCK);
output_low(EXP_OUT_CLOCK);
}
output_high(EXP_OUT_ENABLE);
}

11.Floating Point Number Example

The circuit below shows how to input, output and standard operations with
floating point numbers. I/O is RS232.The following
code, ex_float.c and input.c demonstrate how to input and output floating point
numbers over a serial RS232 I/O channel.

Floating Point Number example


//// EX_FLOAT.C
//// This program shows input, output and standard operations with
//// floating piont numbers. I/O is RS232.

#include < 16F628.H >


#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2 )
#include < input.c >
#include < stdlib.h >

float get_float() {
char s[20];
float f;
get_string(s,20);
f=atof(s);
return(f);
}
void main() {
long int l;
float a, b;
while(true) {
printf("\r\nEnter first number: ");
a=get_float();
printf("\r\nEnter second number: ");
b=get_float();
printf("\r\n\nA= %E\r\n", a);
printf("B= %E\r\n", b);
printf("\r\na + b = %E", a + b);
printf("\r\na - b = %E", a - b);
printf("\r\na * b = %E", a * b);
printf("\r\na / b = %E\r\n", a / b);
if(a <= b)
printf("a<=b, ");
else
printf("a>b, ");
if(a < b)
printf("a

Sub-Routines for standard inputs


//// Routines for standard inputs
#include < CTYPE.H >
byte gethex1() {
char digit;
digit = getch();
putchar(digit);
if(digit<='9')
return(digit-'0');
else
return((toupper(digit)-'A')+10);
}
byte gethex() {
int lo,hi;
hi = gethex1();
lo = gethex1();
if(lo==0xdd)
return(hi);
else
return( hi*16+lo );
}

void get_string(char * s,int max) {


int len;
char c;
max--;
len=0;
do {
c=getc();
if(c==8) { // Backspace
if(len>0) {
len--;
putc(c);
putc(' ');
putc(c);
}
} else if ((c>=' ')&&(c<='~'))
if( len < max ) {
s[len++]=c;
putc(c);
}
} while(c!=13);
s[len]=0;
}

#ifdef _stdlib_
signed int get_int() {
char s[5];
signed int i;
get_string(s, 5);
i=atoi(s);
return(i);
}

signed long get_long() {


char s[7];
signed long l;
get_string(s, 7);
l=atol(s);
return(l);
}
#endif

12.Interfacing X10 TW523 to RS232

The circuit below shows how to interface to an X10 TW523 Module to a RS-232
Serial communications so that X10 commands can be send using the serial RS-
232 channel.The following code, ex_x10.c , x10.c and input.c demonstrate how
to interfaces to a X10 TW523 unit to RS-232. This program will accept and send
three character codes of the form xyy where x is A-P and yy is 00-1F. Key codes
00-0F are translated to the key number.
X10 TO RS232 INTERFACE EXAMPLE
//// EX_X10.C
//// This program interfaces a X10 TW523 unit to RS-232. This
//// program will accept and send three character codes of the
//// form xyy where x is A-P and yy is 00-1F.
//// Key codes 00-0F are translated to the key number.
//// A * is sent to indicate transmition was aborted due to
//// a collision. A > is sent when reception begins to reduce
//// the chance of attempting to transmit during reception.
//// Connect B0 to TW523 pin 1
//// B1 3
//// B2 4
//// GND 2
//// For a 40 pin part such as the 16C74 add jumpers from
//// 8 to 11, 7 to 12, and change the #USE RS232 to:
//// #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#include <16F84.H>
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)
#fuses XT,NOPROTECT,NOWDT
#include < x10.c >
#include < input.c >

main() {
char house_code;
byte key_code;
printf("Online\n\r");
while (TRUE) {
if(kbhit()) {
house_code = getc();
if((house_code>='A') && (house_code<='P')) {
putc(house_code);
key_code=gethex();
x10_write(house_code,key_code);
x10_write(house_code,key_code);
}
}
if(x10_data_ready()) {
putc('>');
x10_read(&house_code,&key_code);
printf("%c%2X",house_code,key_code);
}
}
}

TW523 X10 Driver


//// TW523 X10 Driver
//// x10_write(house_code,key_code) Send a data burst, house_code
/// must be 'A' to 'P' and
//// key_code is 0-1F
//// x10_read( house_code, key_code) Waits for and reads the next
//// data burst.
//// is starting. Be sure to call
//// faster than 1khz in order not
//// to miss any data.
//// Connect B0 to TW523 pin 1
//// B1 3
//// B2 4
//// GND 2

#ifndef X10_ZERO_CROSS
#define X10_ZERO_CROSS PIN_B0
#define X10_TO_PIC PIN_B1
#define X10_FROM_PIC PIN_B2
#endif

char const X10_HOUSE_CODES[16] =


{'M','N','O','P','C','D','A','B','E',
'F','G','H','K','L','I','J'};
byte const X10_KEY_CODES[16] =
{13,14,15,16,3,4,1,2,5,6,7,8,11,12,9,10};

void wait_for_zero_cross() {
if(input(X10_ZERO_CROSS))
while(input(X10_ZERO_CROSS)) ;
else
while(!input(X10_ZERO_CROSS)) ;
}

void x10_write_bits(byte data, byte n, byte start) {


byte i;
boolean the_bit;
for(i=1;i<=n;++i) {
wait_for_zero_cross();
the_bit=shift_right(&data,1,0);
output_bit(X10_FROM_PIC, the_bit);
delay_ms(1);
output_low(X10_FROM_PIC);
if(start==0) {
wait_for_zero_cross();
output_bit(X10_FROM_PIC, !the_bit);
delay_ms(1);
output_low(X10_FROM_PIC);
}
}
}

void x10_write(byte house_code, byte key_code) {


byte i;
i=0;
while (X10_HOUSE_CODES[i]!=house_code)
i++;
house_code=i;
if(key_code<16) {
i=0;
while (X10_KEY_CODES[i]!=key_code)
i++;
key_code=i;
}
x10_write_bits(7,4,1);
x10_write_bits(house_code,4,0);
x10_write_bits(key_code,5,0);
x10_write_bits(0,6,1);
}

byte x10_data_ready() {
port_b_pullups(TRUE);
return(!input(X10_TO_PIC));
}

byte x10_read_bits(byte n) {
byte data,i;
for(i=1;i<=n;++i) {
wait_for_zero_cross();
delay_us(300);
shift_right(&data,1,input(X10_TO_PIC));
wait_for_zero_cross();
delay_us(300);
}
data>>=8-n;
return(data);
}

void x10_read(byte *house_code,byte *key_code) {

port_b_pullups(TRUE);
x10_read_bits(2);
*house_code=x10_read_bits(4);
*house_code=X10_HOUSE_CODES[*house_code];
*key_code=x10_read_bits(5);
if(*key_code<16)
*key_code=X10_KEY_CODES[*key_code];
}
Sub-Routines for standard inputs
//// Routines for standard inputs
#include < CTYPE.H >
byte gethex1() {
char digit;
digit = getch();
putchar(digit);
if(digit<='9')
return(digit-'0');
else
return((toupper(digit)-'A')+10);
}
byte gethex() {
int lo,hi;
hi = gethex1();
lo = gethex1();
if(lo==0xdd)
return(hi);
else
return( hi*16+lo );
}
void get_string(char * s,int max) {
int len;
char c;
max--;
len=0;
do {
c=getc();
if(c==8) { // Backspace
if(len>0) {
len--;
putc(c);
putc(' ');
putc(c);
}
} else if ((c>=' ')&&(c<='~'))
if( len < max ) {
s[len++]=c;
putc(c);
}
} while(c!=13);
s[len]=0;
}

#ifdef _stdlib_
signed int get_int() {
char s[5];
signed int i;
get_string(s, 5);
i=atoi(s);
return(i);
}
signed long get_long() {
char s[7];
signed long l;
get_string(s, 7);
l=atol(s);
return(l);
}
#endif

You might also like