Monday, April 4, 2011

##### SERIAL COMMUNICATION BETWEEN LAPTOP AND PIC16F877A ######


Hi friends,

I am new to blogging.Here is my first blog. I would like to have your comments !!

Serial communication is of two types Synchronous and Asynchronous. Most of the PC communications are asynchronous. I am showing here the communication of laptop with a PIC 16F877A microcontroller.

What i am doing here is ,sending some characters using my laptop keypad(Through Hyperterminal) and displaying a LCD Display interfaced with my PIC controller.Hyperterminal is a very good door for the serial communication. In laptops there wont be a COM Port(RS232 port) so we need a USB to Serial converter.Lets talk about it later..

First let us collect the components....

PIC16F877A (40 pin DIP)
LCD Module(2 line Dotmatix)
MAX232
RS232 jack (Female and male according to need)
USB to serial converter
4MHz Crystal Oscillator
Ceramic Capacitor [22pf X 2
0.1uf X 5(104AEC)]
Resistance pot and Resistance(1k each)


We need to start with the Powering up of PIC. It just the process of giving basic connections and make the controller ready for working.

we need to use 7 pins of the PIC16f877a to power up. They are
VDD (2), VSS (2), MCLR, OSC1, OSC2. It is shown in the Powering up diagram(Fig 2).

Next thing we need to do is the interfacing of LCD
This particular LCD Module have 16 pins(Pin details are in the figure)
In some modules the Backlight can be enabled by using the 15th (+5volt) and 16th(GND) pins.

In this project i used data 4,5,6,7 as inputs to the LCD.3rd pin should connect with a 1 k pot(main terminal) and the side terminals, one should given +5volt and other to Ground.

I used PORTD to connect the LCD
PORTD,0 LCDdata1
PORTD,1 LCDdata2
PORTD,2 LCDdata3
PORTD,3 LCDdata4
PORTD,6 RS
PORTD,7 Enable

We will discuss about the coding later...

MAX232 is a chip used to interface the RS232 cable and the microcontroller. Microcontroller and PC can understand only binary value....even though their ranges are different. That means logic zero for the microcontroller is zero voltage but for PC it is some negative values (-25 or something). MAX232 is a voltage converter. it is also called as line drivers. It converts the +25 to -25 volts in to 0 to 5 volts. The connections to the chip are shown in the figure. It is possible to use the MAX233 chip also, but it is much expensive and need a little space to place. It is because MAX233 doesn’t need any capacitors.

The connections will be in this order

Laptop USB port --> USB to Serial converter --> RS232 cable --> MAX232 chip --> Microcontroller


Here is the USB to serial connector i am using. Most of the converters will not work properly. But this one is working perfectly. It is manufactured by Li2 innovations,Bangalore.

My USB to Serial converter have a RS232 female pin output. I use a cable as extension. So again I will get the female pin at the output again. So I use a male pin at the MAX232 side. We use only 6 pins in the RS232 socket.in that only two of them come into MAX232. The capacitors used are 0.1uF (104 AEC) ceramic type.

12th pin from MAX232 (RX) should be connected with RC7 (26th pin). Similarly 11th pin (TX) to the RC6 (25th pin).It need a direct connection, don’t use any resistors or capacitors in this path.

I used PORTD for the LCD display.

The full coding for this project is given in the last....

Let me explain it

I configured the controller with disabled watchdog timer mode. If you need, u can enable it. but you have to use “clrwdt” command repeatedly and also at the start of the subroutine.

You can see that I defined some pins in the PORTC as LCDA,LCDB…. These are for simplicity in usage in the program. Next is the MACROs…they are the simple program which can be executed in the main program while typing the macro name (For example while using “LCDSTROBE” the following set of programs will be executed. No need to call them, this is for frequently using functions)

CBLOCK H’20’ this is the space where we store the variables. While compiling, each variables will allocate a byte of memory. I use so many variables which are needed for my delay programs and LCD subroutines etc.

When the microcontroller is powered up, it usually starts with the zeroth memory location. But the thing is the 4th memory location which is reserved for interrupt routines. When an interrupt occurs, microcontroller jump into the 4th memory location. So on the zeroth location I put “goto main” which will jump over all the interrupt routine. Since there is no interrupts in this project, we can start at anywhere from the memory but it should be sequential. “ORG” command is used to choose the memory location.

I defined my subroutines in the ORG 4 memory (you can use what ever you want).

Let us start with the init sub routine

It initializes the ports, serial transmissions etc. This you can use it in the main program itself. Since I told the PORTD is used for LCD module. So I have to make all the pin of PORTD as output. To make this, we need to enter the value ‘0’ in the TRISD SFR(special function register).In the program you can use the ‘TRISB’ to represent it if you include “pic16f877a.inc”.This include file contains all SFR’s and their address defined. You can simply open the file from the microchip MPLAB files using notepad.

So the instructions will be

movlw B’00000000’

movwf TRISD

but there is a problem that TRISD is located in the Bank1 of memory. Default bank will be bank 0. So we have to switch it to Bank 1. There is a bit in the STATUS register which help here- RP0.

So a small modification

bsf STATUS, RP0

movlw B'00000000'

movwf TRISD

bcf STATUS, RP0

In the init subroutine we need to configure the serial register also.

A delay program also there which works on a 4MHz crystal. Delay will be changed if you change the crystal frequency.

The main concept of this program is

When a character is send from the keyboard, it received by controller. How it is receiving? How the controller came to know whether the data is received?...all the answer is in the PIR1 SFR.

There is a bit called RCIF, when a data is received completely, the flag sets. So we continyesly monitor this flag and when it sets, the value from the RCREG is moved into the LCD temporary bits which is displayed using LCD subroutines.

There are two sub programs like hello & hello1 they are used to display data in line1 and line2 of LCD respectively.

I am attaching a video of the project

Hope you enjoyed it..


**************SERIAL COMMUNICATION***************



LIST P=16F877A
INCLUDE "p16f877a.inc"

__CONFIG H'3F3D'

#define LCDA PORTD, 0 ; Pin 19 LCD DATA - D0
#define LCDB PORTD, 1 ; Pin 20 LCD DATA - D1
#define LCDC PORTD, 2 ; Pin 21 LCD DATA - D2
#define LCDD PORTD, 3 ; Pin 22 LCD DATA - D3
#define LCDRS PORTD, 6 ; Pin 29 LCD Register Instruction/Data select
#define LCDE PORTD, 7 ; Pin 30 LCD Module Enable 1=ENABLE, 0=DISABLE


LCDSTROBE MACRO
bcf LCDE
nop
bsf LCDE
clrwdt
bcf LCDE
ENDM

BITSCLR MACRO
clrwdt
bcf LCDA
bcf LCDB
bcf LCDC
bcf LCDD
ENDM

LEDSTROBE MACRO
bcf STROBE
nop
bsf STROBE
clrwdt
bcf STROBE
ENDM
LEDCLOCK MACRO
bcf CLOCK
nop
bsf CLOCK
clrwdt
bcf CLOCK
ENDM


CBLOCK H'20'

delay1
delay2

lcd_templa
lcd_temp ; Used LCD routine
lcd_templ ; Used LCD routine
lcd_temph ; Used LCD routine

lcd_la0 ; LCD Line - 1 Address 0 Data
lcd_la1 ; LCD Line - 1 Address 1 Data
lcd_la2 ; LCD Line - 1 Address 2 Data
lcd_la3 ; LCD Line - 1 Address 3 Data
lcd_la4 ; LCD Line - 1 Address 4 Data
lcd_la5 ; LCD Line - 1 Address 5 Data
lcd_la6 ; LCD Line - 1 Address 6 Data
lcd_la7 ; LCD Line - 1 Address 7 Data
lcd_la8 ; LCD Line - 1 Address 8 Data
lcd_la9 ; LCD Line - 1 Address 9 Data
lcd_laa ; LCD Line - 1 Address A Data
lcd_lab ; LCD Line - 1 Address B Data
lcd_lac ; LCD Line - 1 Address C Data
lcd_lad ; LCD Line - 1 Address D Data
lcd_lae ; LCD Line - 1 Address E Data
lcd_laf ; LCD Line - 1 Address F Data



ENDC

ORG 0
goto main

ORG 4

init:
clrwdt
bsf STATUS, RP0

movlw B'10010001'
movwf TRISC

movlw B'00110000'
movwf TRISD

movlw D'25'
movwf SPBRG


bcf STATUS, RP0

movlw B'10010000'
movwf RCSTA



clrlcd:
clrwdt
clrf lcd_temp ; (CLEAR) LCD_TEMP (Used LCD routine)
clrf lcd_templ ; (CLEAR) LCD_TEMPl (Used LCD routine)
clrf lcd_temph ; (CLEAR) LCD_TEMPh (Used LCD routine)
clrf lcd_la0 ; (CLEAR) LCD Line - 1 Address 0 Data
clrf lcd_la1 ; (CLEAR) LCD Line - 1 Address 1 Data
clrf lcd_la2 ; (CLEAR) LCD Line - 1 Address 2 Data
clrf lcd_la3 ; (CLEAR) LCD Line - 1 Address 3 Data
clrf lcd_la4 ; (CLEAR) LCD Line - 1 Address 4 Data
clrf lcd_la5 ; (CLEAR) LCD Line - 1 Address 5 Data
clrf lcd_la6 ; (CLEAR) LCD Line - 1 Address 6 Data
clrf lcd_la7 ; (CLEAR) LCD Line - 1 Address 7 Data
clrf lcd_la8 ; (CLEAR) LCD Line - 1 Address 8 Data
clrf lcd_la9 ; (CLEAR) LCD Line - 1 Address 9 Data
clrf lcd_laa ; (CLEAR) LCD Line - 1 Address A Data
clrf lcd_lab ; (CLEAR) LCD Line - 1 Address B Data
clrf lcd_lac ; (CLEAR) LCD Line - 1 Address C Data
clrf lcd_lad ; (CLEAR) LCD Line - 1 Address D Data
clrf lcd_lae ; (CLEAR) LCD Line - 1 Address E Data
clrf lcd_laf ; (CLEAR) LCD Line - 1 Address F Data
return



nsec_a:
movlw D'100'
movwf delay1
nsecloop_a:
nop
nop
nop
nop
nop
nop
nop
nop
nop
clrwdt
decfsz delay1
goto nsecloop_a
return

nsec1a:
call nsec_a
decfsz delay2
goto nsec1a
return

nmsec:
movlw D'1'
movwf delay2
goto nsec1a

msec40a:
movlw D'40'
movwf delay2
goto nsec1a

msec50a:
movlw D'50'
movwf delay2
goto nsec1a


msec250a:
movlw D'250'
movwf delay2
goto nsec1a


receive:
zz: clrwdt
btfss PIR1,RCIF
goto zz
movf RCREG,W
return

main:
clrwdt
call init
call lcdinitx
hello:
clrwdt
call blank
call dis
call receive
movwf lcd_la0
call dis
call receive
movwf lcd_la1
call dis
call receive
movwf lcd_la2
call dis
call receive
movwf lcd_la3
call dis
call receive
movwf lcd_la4
call dis
call receive
movwf lcd_la5
call dis
call receive
movwf lcd_la6
call dis
call receive
movwf lcd_la7
call dis
call receive
movwf lcd_la8
call dis
call receive
movwf lcd_la9
call dis
call receive
movwf lcd_laa
call dis
call receive
movwf lcd_lab
call dis
call receive
movwf lcd_lac
call dis
call receive
movwf lcd_lad
call dis
call receive
movwf lcd_lae
call dis
call receive
movwf lcd_laf
call dis
goto hello1

hello1: ;for the 2nd line display
clrwdt
call blank
call dis1
call receive
movwf lcd_la0
call dis1
call receive
movwf lcd_la1
call dis1
call receive
movwf lcd_la2
call dis1
call receive
movwf lcd_la3
call dis1
call receive
movwf lcd_la4
call dis1
call receive
movwf lcd_la5
call dis1
call receive
movwf lcd_la6
call dis1
call receive
movwf lcd_la7
call dis1
call receive
movwf lcd_la8
call dis1
call receive
movwf lcd_la9
call dis1
call receive
movwf lcd_laa
call dis1
call receive
movwf lcd_lab
call dis1
call receive
movwf lcd_lac
call dis1
call receive
movwf lcd_lad
call dis1
call receive
movwf lcd_lae
call dis1
call receive
movwf lcd_laf
call dis1
goto hello

dis:
clrwdt
movlw H'80'
call lcdinstrx
call lcdl1x
call msec50a
return
dis1:
clrwdt
movlw H'C0'
call lcdinstrx
call lcdl1x
call msec50a
return


lcdinitx:
clrwdt
call msec250a
bcf LCDRS
bsf LCDA
bsf LCDB
bcf LCDC
bcf LCDD
LCDSTROBE
call msec40a
LCDSTROBE
call msec40a
LCDSTROBE
call msec40a
bcf LCDRS
bcf LCDA
LCDSTROBE
call msec40a
movlw H'28'
call lcdinstrx
call msec40a
movlw H'0C'
call lcdinstrx
call msec40a
movlw H'01'
call lcdinstrx
call msec40a
movlw H'06'
call lcdinstrx
call msec40a
movlw H'80'
call lcdinstrx
call msec40a
return


;............................................................................................................................................................................;
; LCD INSTRUCTION ;
; Lcd Instruction to be placed in W Register ;
;............................................................................................................................................................................;
lcdinstrx:
clrwdt
bcf INTCON, GIE ; Disabled INT System
clrf lcd_temp
clrf lcd_templ ; (CLEAR) LCD_TEMP (Used LCD routine)
clrf lcd_temph ; (CLEAR) LCD_TEMP (Used LCD routine)
movwf lcd_temp
andlw H'0F'
movwf lcd_templ
movf lcd_temp, W
andlw H'F0'
movwf lcd_temph
swapf lcd_temph, W
movwf lcd_temph
bcf lcd_temph, 5
bcf lcd_temph, 6
movwf PORTD
bcf LCDRS
LCDSTROBE
call nmsec
movf lcd_templ, W
bcf lcd_templ, 5
bcf lcd_templ, 6
movwf PORTD
bcf LCDRS
LCDSTROBE
call nmsec
return

blank:
clrwdt
movlw H'20'
movwf lcd_la0
movwf lcd_la1
movwf lcd_la2
movwf lcd_la3
movwf lcd_la4
movwf lcd_la5
movwf lcd_la6
movwf lcd_la7
movwf lcd_la8
movwf lcd_la9
movwf lcd_laa
movwf lcd_lab
movwf lcd_lac
movwf lcd_lad
movwf lcd_lae
movwf lcd_laf
return

;............................................................................................................................................................................;
; LCD DISPLAY DATA ;
; Lcd Display Data to be placed in W Register ;
;............................................................................................................................................................................;

lcddisx:
clrwdt
clrf lcd_temp
clrf lcd_templ ; (CLEAR) LCD_TEMP (Used LCD routine)
clrf lcd_temph ; (CLEAR) LCD_TEMP (Used LCD routine)
movwf lcd_temp
andlw H'0F'
movwf lcd_templ
movf lcd_temp, W
andlw H'F0'
movwf lcd_temph
swapf lcd_temph, W
movwf lcd_temph
bcf lcd_temph, 5
bcf lcd_temph, 6
movwf PORTD
bsf LCDRS
LCDSTROBE
call nmsec
movf lcd_templ, W
bcf lcd_templ, 5
bcf lcd_templ, 6
movwf PORTD
bsf LCDRS
LCDSTROBE
call nmsec
return

;----------------------------------------------------------------------------------------------------------------------------------------------------;
; Display Top Line on LCD ;
;----------------------------------------------------------------------------------------------------------------------------------------------------;
lcdl1x:
clrwdt
movf lcd_la0, W
call lcddisx
movf lcd_la1, W
call lcddisx
movf lcd_la2, W
call lcddisx
movf lcd_la3, W
call lcddisx
movf lcd_la4, W
call lcddisx
movf lcd_la5, W
call lcddisx
movf lcd_la6, W
call lcddisx
movf lcd_la7, W
call lcddisx
movf lcd_la8, W
call lcddisx
movf lcd_la9, W
call lcddisx
movf lcd_laa, W
call lcddisx
movf lcd_lab, W
call lcddisx
movf lcd_lac, W
call lcddisx
movf lcd_lad, W
call lcddisx
movf lcd_lae, W
call lcddisx
movf lcd_laf, W
call lcddisx
return

end

*****************THANK YOU**************************





I love to hear from you.... sankar.m8@gmail.com