Showing posts with label 89C51 Tutorials. Show all posts
Showing posts with label 89C51 Tutorials. Show all posts

Wednesday, April 13, 2016

Stepper Motor Interface using 89C51

Introduction
Stepper motors are commonly used in accurate motion control. They allow to control any motion with high precision by counting the number of steps applied to the motor.Most of systems controlling stepper motors are embedded systems such as printer, scanner or floppy disk drive. This application note describes how to drive a unipolar stepper motor with the Programmable Counter Array of an Atmel 89C51microcontroller.

Connection Diagram:
Stepper Motor Interface with 89C51

Identification of Stepper Motor:

There are several types of stepper motors, these cannot be driven in the same way. In this application note, we have chosen to drive a unipolar stepper motor (see Figure 2). For more information you will find schemes to identify the other types of stepper motors.

Figure 2. Unipolar Stepper Motors Coils
Unipolar Stepper Motor Unipolar stepper motors are characterised by their center-tapped windings.


Figure 3. Bipolar Stepper Motor Coils
Bipolar Stepper Motor Bipolar stepper motors are designed with separate coils.


Driving Unipolar Stepper Motors
There are three ways to drive uni polar stepper motors (one phase on, two phase on or half step), each one has some advantages and disadvantages.





In one phase mode, each successive coil is energized in turn. One phase mode produces smooth rotations and the lowest power comsumption of the three modes. Steps are applied in order from one to four. After step four, the sequence is repeated from step one. Applying steps from one to four makes the motor run clockwise, reversing the order of step from four to one will make the motor run counter-clockwise.


In two phase mode, successive pairs of adjacent coils are energised in turn, motion is not as smooth as in one phase mode, power comsumption is more important but it produces greater torque. As in one phase mode, applying the steps in order makes the stepper motor run clockwise and reversing order makes it turn 
counter-clockwise.


Programming Stepper Motor:


INCLUDE 89C51.MC
;-----------------------STEPPER MOTOR--------------------------
;Motor connections to microcontroller
C1  EQU P0.0  ; coil 1
C2   EQU P0.1  ; coil 2
C3  EQU  P0.2  ; coil 3
C4  EQU P0.3  ; coil 4
DATA  EQU P0
;----------------------------------------------------------
(0000H):
 JMP on_reset
;----------------------------------------------------------
(00FFH):
on_reset: 
  CLR C1
  CLR C2
  CLR C3
  CLR C4
  MOV A,#88H
ENDLESS: 
  RR A
  MOV DATA,A
  CALL delay
  JMP ENDLESS 
;----------------------------------------------------------
delay:
  MOV R7,#FFH
again: NOP
  DJNZ R7, again
RET

89C51 Serial interface in Assembly language

One of the 8051s many powerful features is its integrated UART, otherwise known as a serial port. The fact that the 8051 has an integrated serial port means that you may very easily read and write values to the serial port. If it were not for the integrated serial port, writing a byte to a serial line would be a rather tedious process requring turning on and off one of the I/O lines in rapid succession to properly "clock out" each individual bit, including start bits, stop bits, and parity bits.

However, we do not have to do this. Instead, we simply need to configure the serial ports operation mode and baud rate. Once configured, all we have to do is write to an SFR to write a value to the serial port or read the same SFR to read a value from the serial port. The 8051 will automatically let us know when it has finished sending the character we wrote and will also let us know whenever it has received a byte so that we can process it. We do not have to worry about transmission at the bit level--which saves us quite a bit of coding and processing time.

Setting the Serial Port Mode:

The first thing we must do when using the 8051s integrated serial port is, obviously, configure it. This lets us tell the 8051 how many data bits we want, the baud rate we will be using, and how the baud rate will be determined.

First, lets present the "Serial Control" (SCON) SFR and define what each bit of the SFR represents:
Bit
Name
Bit Addres
Explanation of Function
7
SM0
9Fh
Serial port mode bit 0
6
SM1
9Eh
Serial port mode bit 1.
5
SM2
9Dh
Mutliprocessor Communications Enable (explained later)
4
REN
9Ch
Receiver Enable. This bit must be set in order to receive characters.
3
TB8
9Bh
Transmit bit 8. The 9th bit to transmit in mode 2 and 3.
2
RB8
9Ah
Receive bit 8. The 9th bit received in mode 2 and 3.
1
TI
99h
Transmit Flag. Set when a byte has been completely transmitted.
0
RI
98h
Receive Flag. Set when a byte has been completely received.

Additionally, it is necessary to define the function of SM0 and SM1 by an additional table:
SM0
SM1
Serial Mode
Explanation
Baud Rate
0
0
0
8-bit Shift Register
Oscillator / 12
0
1
1
8-bit UART
Set by Timer 1 (*)
1
0
2
9-bit UART
Oscillator / 64 (*)
1
1
3
9-bit UART
Set by Timer 1 (*)
(*) Note: The baud rate indicated in this table is doubled if PCON.7 (SMOD) is set.

The SCON SFR allows us to configure the Serial Port. Thus, well go through each bit and review its function.
The first four bits (bits 4 through 7) are configuration bits. Bits SM0 and SM1 let us set the serial mode to a value between 0 and 3, inclusive. The four modes are defined in the chart immediately above. As you can see, selecting the Serial Mode selects the mode of operation (8-bit/9-bit, UART or Shift Register) and also determines how the baud rate will be calculated. In modes 0 and 2 the baud rate is fixed based on the oscillators frequency. In modes 1 and 3 the baud rate is variable based on how often Timer 1 overflows. Well talk more about the various Serial Modes in a moment.

The next bit, SM2, is a flag for "Multiprocessor communication." Generally, whenever a byte has been received the 8051 will set the "RI" (Receive Interrupt) flag. This lets the program know that a byte has been received and that it needs to be processed. However, when SM2 is set the "RI" flag will only be triggered if the 9th bit received was a "1". That is to say, if SM2 is set and a byte is received whose 9th bit is clear, the RI flag will never be set. This can be useful in certain advanced serial applications. For now it is safe to say that you will almost always want to clear this bit so that the flag is set upon reception of any character.

The next bit, REN, is "Receiver Enable." This bit is very straightforward: If you want to receive data via the serial port, set this bit. You will almost always want to set this bit.
The last four bits (bits 0 through 3) are operational bits. They are used when actually sending and receiving data--they are not used to configure the serial port.

The TB8 bit is used in modes 2 and 3. In modes 2 and 3, a total of nine data bits are transmitted. The first 8 data bits are the 8 bits of the main value, and the ninth bit is taken from TB8. If TB8 is set and a value is written to the serial port, the datas bits will be written to the serial line followed by a "set" ninth bit. If TB8 is clear the ninth bit will be "clear."

The RB8 also operates in modes 2 and 3 and functions essentially the same way as TB8, but on the reception side. When a byte is received in modes 2 or 3, a total of nine bits are received. In this case, the first eight bits received are the data of the serial byte received and the value of the ninth bit received will be placed in RB8.

TI means "Transmit Interrupt." When a program writes a value to the serial port, a certain amount of time will pass before the individual bits of the byte are "clocked out" the serial port. If the program were to write another byte to the serial port before the first byte was completely output, the data being sent would be garbled. Thus, the 8051 lets the program know that it has "clocked out" the last byte by setting the TI bit. When the TI bit is set, the program may assume that the serial port is "free" and ready to send the next byte.

Finally, the RI bit means "Receive Interrupt." It funcions similarly to the "TI" bit, but it indicates that a byte has been received. That is to say, whenever the 8051 has received a complete byte it will trigger the RI bit to let the program know that it needs to read the value quickly, before another byte is read.

Setting the Serial Port Baud Rate:
Once the Serial Port Mode has been configured, as explained above, the program must configure the serial ports baud rate. This only applies to Serial Port modes 1 and 3. The Baud Rate is determined based on the oscillators frequency when in mode 0 and 2. In mode 0, the baud rate is always the oscillator frequency divided by 12. This means if youre crystal is 11.059Mhz, mode 0 baud rate will always be 921,583 baud. In mode 2 the baud rate is always the oscillator frequency divided by 64, so a 11.059Mhz crystal speed will yield a baud rate of 172,797.

In modes 1 and 3, the baud rate is determined by how frequently timer 1 overflows. The more frequently timer 1 overflows, the higher the baud rate. There are many ways one can cause timer 1 to overflow at a rate that determines a baud rate, but the most common method is to put timer 1 in 8-bit auto-reload mode (timer mode 2) and set a reload value (TH1) that causes Timer 1 to overflow at a frequency appropriate to generate a baud rate.

To determine the value that must be placed in TH1 to generate a given baud rate, we may use the following equation (assuming PCON.7 is clear).

TH1 = 256 - ((Crystal / 384) / Baud)

If PCON.7 is set then the baud rate is effectively doubled, thus the equation becomes:
TH1 = 256 - ((Crystal / 192) / Baud)

For example, if we have an 11.059Mhz crystal and we want to configure the serial port to 19,200 baud we try plugging it in the first equation:
TH1 = 256 - ((Crystal / 384) / Baud)

TH1 = 256 - ((11059000 / 384) / 19200 )

TH1 = 256 - ((28,799) / 19200)

TH1 = 256 - 1.5 = 254.5

As you can see, to obtain 19,200 baud on a 11.059Mhz crystal wed have to set TH1 to 254.5. If we set it to 254 we will have achieved 14,400 baud and if we set it to 255 we will have achieved 28,800 baud. Thus were stuck...

But not quite... to achieve 19,200 baud we simply need to set PCON.7 (SMOD). When we do this we double the baud rate and utilize the second equation mentioned above. Thus we have:
TH1 = 256 - ((Crystal / 192) / Baud)

TH1 = 256 - ((11059000 / 192) / 19200)

TH1 = 256 - ((57699) / 19200)

TH1 = 256 - 3 = 253

Here we are able to calculate a nice, even TH1 value. Therefore, to obtain 19,200 baud with an 11.059MHz crystal we must:
1. Configure Serial Port mode 1 or 3.

2. Configure Timer 1 to timer mode 2 (8-bit auto-reload).

3. Set TH1 to 253 to reflect the correct frequency for 19,200 baud.

4. Set PCON.7 (SMOD) to double the baud rate.

Writing to the Serial Port:
Once the Serial Port has been propertly configured as explained above, the serial port is ready to be used to send data and receive data. If you thought that configuring the serial port was simple, using the serial port will be a breeze.

To write a byte to the serial port one must simply write the value to the SBUF (99h) SFR. For example, if you wanted to send the letter "A" to the serial port, it could be accomplished as easily as:
MOV SBUF,#A
Upon execution of the above instruction the 8051 will begin transmitting the character via the serial port. Obviously transmission is not instantaneous--it takes a measureable amount of time to transmit. And since the 8051 does not have a serial output buffer we need to be sure that a character is completely transmitted before we try to transmit the next character.
The 8051 lets us know when it is done transmitting a character by setting the TI bit in SCON. When this bit is set we know that the last character has been transmitted and that we may send the next character, if any. 

Consider the following code segment:
CLR TI ;Be sure the bit is initially clear

MOV SBUF,#A ;Send the letter A to the serial port

JNB TI,$ ;Pause until the TI bit is set.


The above three instructions will successfully transmit a character and wait for the TI bit to be set before continuing. The last instruction says "Jump if the TI bit is not set to $"--$, in most assemblers, means "the same address of the current instruction." Thus the 8051 will pause on the JNB instruction until the TI bit is set by the 8051 upon successful transmission of the character.


Reading the Serial Port:
Reading data received by the serial port is equally easy. To read a byte from the serial port one just needs to read the value stored in the SBUF (99h) SFR after the 8051 has automatically set the RI flag in SCON.
            
For example, if your program wants to wait for a character to be received and subsequently read it into the Accumulator, the following code segment may be used:

JNB RI,$ ;Wait for the 8051 to set the RI flag

MOV A,SBUF ;Read the character from the serial port


The first line of the above code segment waits for the 8051 to set the RI flag; again, the 8051 sets the RI flag automatically when it receives a character via the serial port. So as long as the bit is not set the program repeats the "JNB" instruction continuously.


Once the RI bit is set upon character reception the above condition automatically fails and program flow falls through to the "MOV" instruction which reads the value.


Assembly Language Program for Serial Communication using 89C15:


INCLUDE 89C51.MC
;---------------------MAX232-------------------------------
; Register definitions.

rBUFFER EQU 00h  ; read data register
wBUFFER EQU 01h  ; send data register
;----------------------------------------------------------
(0000H):
 JMP on_reset
;-----------------------Serial Interrupt-------------------
(0023H): 
 JNB RI,ser_down  
 MOV rBUFFER,SBUF  ; read data
 CLR RI
 JMP int_end
ser_down:
 MOV SBUF,wBUFFER  ; send data
 CLR TI
int_end: 
RETI
;----------------------------------------------------------
(00FFH):
on_reset:
;Initialize Timer
;Baud rate table

;Fosc = 11.0592 MHz
;Baud rate TH1 TH1(hex) SMOD(PCON.7)
;300  160 A0   0
;1200  232 E8   0
;2400  244 F4   0
;4800  250 FA   0
;9600  253 FD   0
;19200 253 FD   1
;28800 255 FF   0


  MOV TH1,#FDH ; baud rate 9600
  MOV TMOD,#20H ; timer-1 in 8-bit auto reload
  MOV SCON,#50H ; receive enable
  CLR PCON.7  ; SMOD = 0

;  MOV IE,#90H  ; Serial Interrupt 10010000b
ENDLESS:
  
  CALL get_byte
  MOV A,rBUFFER
  MOV wBUFFER,A
  CALL send_byte

  JMP ENDLESS 
;----------------------------------------------------------
;Without interrupt
;----------------------------------------------------------
send_byte:
  MOV SBUF,wBUFFER  ; send data
  SETB TR1
RS232BACK:  JNB SCON.1,RS232BACK ; wait for TI
  CLR TF1
  CLR SCON.1
RET
;---------------------------------------------------------- 
get_byte:
  SETB TR1
RS232B:   JNB SCON.0,RS232B  ; wait for RI
  MOV rBUFFER,SBUF  ; get data
  CLR TF1
  CLR SCON.0
RET
;-----------------------------------------------------------

16x2 LCD Interface with 89C51

This tutorial describes the software and hardware needed to interface 16x2 LCD an Hitachi HD44780 LCD controller to a AT89C51 microcontroller. The HD44780 is one of the most common controllers used for character displays from one up to four lines. It is also available from several different manufacturers. This tutorial demonstrates how to interface and program a four lines of 16 characters display. The hardware is simple.

Figure 1 shows the hardware schematic

16x2 LCD Interface with 89C51

Sample Assembly Code for 4-bit mode 16x2 LCD Interface:
For C code of 4-Bit LCD interface Click Here LCD Interface in 4-Bit Mode requires only 6 IO Lines.
INCLUDE 89C51.MC
;-----------------------LCD 4-bit--------------------------
;LCD Connections to microcontroller
E  EQU P0.4  ; PIN 6 enable
RS   EQU P0.5  ; /register select

DATA  EQU P0  ; data lines P0-P3
;----------------------------------------------------------
(0000H):
 JMP on_reset
;----------------------------------------------------------
(00FFH):
on_reset: 
  MOV DPTR,#init_data
  CALL disp_init
  
  MOV DPTR,#message1
  CALL disp_string
  
  CALL disp_line2
  
  MOV DPTR,#message2
  CALL disp_string

ENDLESS:
  JMP ENDLESS 
;----------------------------------------------------------
; display char in A
; used reg R2
disp_char:
  SETB RS   ; desable register select
  
  MOV R2,A
  ANL A,#F0H   ; send high nybble first
  RR A
  RR A
  RR A
  RR A
  ANL DATA,#F0H
  ORL DATA,A
  
  SETB E   ; give E pulse
  CALL delay_data
  CLR E
  CALL delay_data
  
  MOV A,R2
  ANL A,#0FH   ; send lower nybble
  ANL DATA,#F0H
  ORL DATA,A
  
  SETB E   ; give E pulse
  CALL delay_data
  CLR E
  CALL delay_data
  
  
RET
;----------------------------------------------------------
; used registers A,R1,R7
disp_string:
  MOV A,#00H
  MOV R1,#00h
next_char:
  INC R1   
  MOVC A,@A+DPTR
   MOV DATA,A
   CALL disp_char
   MOV A,R0
  CJNE R1,#0Fh,next_char   
RET
;----------------------------------------------------------
; used registers A,R1,R7,R2
disp_init:
  CLR RS   ; enable /register select
  MOV A,#00H
  MOV R1,#00h
next_chari:
  INC R1   
  MOVC A,@A+DPTR
  MOV R2,A   ; take backup
  
  ANL A,#F0H   ; send high nybble first
  RR A
  RR A
  RR A
  RR A
  ANL DATA,#F0H
  ORL DATA,A
  
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init
  
  MOV A,R2
  ANL A,#0FH   ; send lower nybble
  ANL DATA,#F0H
  ORL DATA,A
  
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init

  MOV A,R0
  CJNE R1,#02h,next_chari 
  

RET
;----------------------------------------------------------
disp_line1:
  CLR RS   ; register select
  ANL DATA,#F0H
  ORL DATA,#08H  ; first line address
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init
  
  ANL DATA,#F0H  ; second nybble
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init

RET
;----------------------------------------------------------
disp_line2:
  CLR RS   ; register select 
  ANL DATA,#F0H  ; next line address
  ORL DATA,#0AH
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init
  
  ANL DATA,#F0H  ; next line address
  ORL DATA,#08H
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init

RET
;----------------------------------------------------------
;2 msec delay
delay_data:
  MOV R7,#FFH
del:  NOP
  NOP
  DJNZ R7, del 
RET
;----------------------------------------------------------
;20 msec delay
delay_init:
  MOV R7,#FFH
del1:  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  DJNZ R7, del1 

RET
;----------------------------------------------------------
message1:
DB "Testing 123.... "
message2:
DB "It's working    "
init_data:
DB 0FH ; Display On, Cursor On,Cursor Blink On(1)/Off(0)
DB 01H ; Clear Display
DB 38H ; Set Interface Length

Sample Assembly Code for 8-bit mode 16x2 LCD Interface:
For C code Click here

8-Bit mode is simple to interface but it takes 10-IO lines. I will recommend go for 4-bit mode interface


INCLUDE 89C51.MC
;-----------------------LCD 8-bit--------------------------
;LCD Connections to microcontroller
E  EQU P2.0  ; PIN 6 enable
RS   EQU P2.1  ; /register select

DATA  EQU P0  ; data lines
;----------------------------------------------------------
(0000H):
 JMP on_reset
;----------------------------------------------------------
(00FFH):
on_reset: 
  MOV DPTR,#init_data
  CALL disp_init
  
  MOV DPTR,#message1
  CALL disp_string
  
  CALL disp_line2
  
  MOV DPTR,#message2
  CALL disp_string

ENDLESS:
  JMP ENDLESS 
;----------------------------------------------------------
; display char in A
disp_char:
  SETB RS   ; desable register select
  MOV DATA,A
  SETB E   ; give E pulse
  CALL delay_data
  CLR E
  CALL delay_data
RET
;----------------------------------------------------------
; used registers A,R1,R7
disp_string:
  MOV A,#00H
  MOV R1,#00h
next_char:
  INC R1   
  MOVC A,@A+DPTR
   MOV DATA,A
   CALL disp_char
   MOV A,R0
  CJNE R1,#0Fh,next_char   
RET
;----------------------------------------------------------
; used registers A,R1,R7
disp_init:
  CLR RS   ; enable /register select
  MOV A,#00H
  MOV R1,#00h
next_chari:
  INC R1   
  MOVC A,@A+DPTR
   MOV DATA,A
   SETB E  ; give E pulse
   CALL delay_init
   CLR E
   CALL delay_init
   MOV A,R0
  CJNE R1,#02h,next_chari 
  

RET
;----------------------------------------------------------
disp_line1:
  CLR RS   ; register select
  MOV DATA,#80H  ; first line address
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init
RET
;----------------------------------------------------------
disp_line2:
  CLR RS   ; register select 
  MOV DATA,#A8H  ; next line address
  SETB E   ; give E pulse
  CALL delay_init
  CLR E
  CALL delay_init
RET
;----------------------------------------------------------
;2 msec delay
delay_data:
  MOV R7,#FFH
del:  NOP
  NOP
  DJNZ R7, del 
RET
;----------------------------------------------------------
;20 msec delay
delay_init:
  MOV R7,#FFH
del1:  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  DJNZ R7, del1 

RET
;----------------------------------------------------------
message1:
DB "Testing 123.... "
message2:
DB "It's working    "
init_data:
DB 0FH ; Display On, Cursor On,Cursor Blink On(1)/Off(0)
DB 01H ; Clear Display
DB 38H ; Set Interface Length


For C code of 4-Bit LCD interface Click Here

Microcontroller interface
The HD44780 controller can be set up to communicate with 4–bit or 8–bit microcontrollers. The fastest way to communicate is to set up the interface for 8–bit communication and then interface the display as a memory mapped device. The drawbacks of this solution are located in the “glue” logic needed to interface the display and in the fact that wait states need to be programmed to avoid timing violations when interfaced to a 89C51.

This application note shows how to interface the controller using the 4–bit interface mode. When the controller is set up for 4–bit communication, the following signals are used:

  •  DB4, DB5, DB6, DB7 Multiplexed data bus signals (four bits are sent twice to form a byte)  
  •  RS Register select
  • R/W Read / Write signal
  • E Enable

Contrast control
The recommended way to adjust the LCD contrast is to connect the Vo input of the display to a 10 kΩ variable resistor as shown in Figure 2. Adjustment in then done during factory setup. 


Timing
Execution times: Clear display 1.64 ms; Home cursor 40 μs; all others 40μs, except read busy flag which is complete in a single enable cycle (or two cycles in 4–bit mode), and character generator ram reads and writes which should be separated by 120μs delays. These execution times mean that after an operation, the CPU must perform Busy Flag checks until the BF (bit 7) is 0, or, when the connection to the module from the CPU is write–only, wait more than the execution time before the next operation. These times are usually strict, LCDs used in a write–only configuration should provide the specified delays.