Embedded C Programming PDF
Embedded C Programming PDF
University of Portsmouth
Faculty of Technology
Department of Electronic and Computer Engineering
Content
Module:
Module Code:
Module Topic:
Lecturer:
Principles of DigitalSystems
B122L
Microcontroller Applications
Branislav Vuksanovic
Lecture Notes:
Basics of C Programming
for
Embedded Systems
Ease of implementation
Maintainability
Readability
Bit manipulation
Another example:
c=getch();
at
at
at
at
at
at
BYTE Registers
0x80 sfr P0
;
0x90 sfr P1
;
0xA0 sfr P2
;
0xB0 sfr P3
;
0xD0 sfr PSW ;
0xE0 sfr ACC ;
0xF0 sfr B
;
0x81 sfr SP
;
0x82 sfr DPL ;
0x83 sfr DPH ;
0x87 sfr PCON ;
0x88
0x89
0x8A
0x8B
0x8C
0x8D
sfr
sfr
sfr
sfr
sfr
sfr
TCON
TMOD
TL0
TL1
TH0
TH1
;
;
;
;
;
;
*/
-
the next line in the template declares the beginning of the body of
the main part of the program
the main part of the program is treated as any other function in C
program
every C program should have a main function
functions are like procedures and subroutines in other languages
C function may be written in one of the following formats:
void main(void)
therefore, indicates that the main function requires no parameters and
that it does not return any value.
-
what the function must perform will be placed within the curly
brackets following function declaration (your C code)
#define ON 0xFF
-
C Directives
-
the first form (with the angle brackets) will search for the include file
in certain locations known to the compiler and it is used to include
standard system header files (such are stdlib.h and stdio.h in
standard C)
the second form (with the double quotes) will search for the file in
the same directory as the source file and this is used for header files
specific to the program and usually written by the programmer
all directives are preceded with a # symbol
another useful directive is a #define directive
Example 1
P1 = ON;
Indefinite Loops
-
Once the loop counter reaches the value of 255 program will exit the
loop and continue execution with the first statement following the loop
section
-
for a longer delays we can use a nested loop structure, i.e. loop
within the loop:
for(i=0; i<=255; i=i+1)
{
for(j=0; j<=255; j=j+1)
{
;
}
}
Note that with this structure the program counts to 255 x 255.
Variables in Embedded C
-
Type
Size
Range
unsigned char
1 byte
0 to 255
(signed) char
1 byte
-128 - +127
unsigned int
2 bytes
0 - 65535
(signed) int
2 bytes
-32768 - +32767
bit
1 bit
0 or 1
(RAM bit-addressable part of
memory only)
sbit
1 bit
0 or 1
(SFR bit-addressable part of
memory only)
sfr
8 bit
Example 2
Used delay routine is not very accurate so the delay should only
approximately be 1 s.
Note that the first line immediately after the beginning of the main
function is used to declare two variables in the program, I and j:
#include <reg66x.h>
void main(void)
{
unsigned char i,j;
for(;;)
{
P1 = 0xFF; /* Turn All LEDs ON */
for(i=0; i<=255; i=i+1)
{
for(j=0; j<=255; j=j+1)
{
;
}
}
P1 = 0x00; /* Turn All LEDs OFF */
for(i=0; i<=255; i=i+1)
{
for(j=0; j<=255; j=j+1)
{
;
}
}
}
}
Note that this program contains two identical time delay routines first
one keeps ON state on LEDs for app. 1 second and the second one
keeps OFF state on LEDs for the same amount of time. Without those
two delays LEDs would switch ON and OFF so rapidly that the whole
set would constantly appear as not fully turned ON set of LEDs.
C Functions
-
a function is defined in the same way as the main function (an open
curly bracket marks the beginning of the function, variables used
within the function are then declared in the next line before the body
of the function is implemented, the function ends with a closed curly
bracket)
the name of a function must follow the rules for the name of a
variable - the function name may not have spaces, or any
punctuation
a use of functions is advisable as functions make programs shorter
and readable, a shorter program also requires less space in the
memory and therefore better efficiency
function is called in the main program using function name and
appropriate parameters (if any)
Example 3
In this example program from Example 2, to indefinitely flash all LEDs
on port 1 at a rate of 1 second is rewritten using function to generate
time delay.
#include <reg66x.h>
void DELAY(void);
void main(void)
{
for(;;)
{
P1 = 0xFF;
DELAY();
P1 = 0x00;
DELAY();
}
}
void DELAY(void)
{
unsigned char i, j;
for(i=0; i<=255; i=i+1)
{
for(j=0; j<=255; j=j+1)
{
;
}
}
}
Other Loops in C
Example 4
Two other loops exist in C language - <dowhile> and <while>.
Instructions to generate single loop delay using those two loop
techniques are given below.
i=0;
do
{
i=i+1;
} while(i<=255);
i=0;
while(i<=255)
{
i=i+1;
}
void DELAY(void)
{
unsigned char i,j;
for(i=0; i<=255; i=i+1)
{
for(j=0; j<=255; j=j+1)
{
;
}
}
}
10
? Operator
Yes
False
Condition
?
Action B
B>C
?
No
True
A=X
A=Y
Action A
A = (B > C) ? X : Y;
-
In other words if B is greater than C then let A=X otherwise let A=Y.
if(condition)
{
Perform Action A
}
else
{
Perform Action B
}
11
Example 5
Program to operate the LEDs attached to port 1 as a BCD (Binary
Coded Decimal) up counter. A BCD up counter is one, which counts in
binary from 0 to 9 and then repeats from 0 again.
#include <reg66x.h>
void DELAY(void);
void main(void)
{
unsigned char N=0;
for(;;)
{
P1 = N;
/* Turn All LEDs ON */
DELAY();
/* Wait for a while */
N=N+1;
if(N>9)
{
N=0;
}
}
}
void DELAY(void)
{
unsigned char i,j;
for(i=0; i<=255; i=i+1)
{
for(j=0; j<=255; j=j+1)
{
;
}
}
}
Short hand
A++
A-A+=B
A-=B
A*=B
A/=B
Explanation
Increment A
Decrement A
Let A=A+B
Let A=A-B
A=A*B
A=A/B
In Assembly
CPL A
ANL A,#DATA
ORL A,#DATA
XRL A,#DATA
RRA
RLA
In C
~
&
^
>>
<<
Example in C
A=~A;
A= A & DATA
A= A DATA
A= A ^ DATA
A=A>>n
A=A<<n
The bit-wise AND may be used to perform a bit mask operation. This
operation may be used to isolate part of a string of bits, or to determine
whether a particular bit is 1 or 0. For example, to determine whether the
third bit in the 4 bit patter is 1, a bitwise AND is applied to it along with
another bit pattern containing 1 in the third bit, and 0 in all other bits,
Given a bit pattern 0101 we can bit-wise AND it with 0010. Result is 0.
We therefore know that the third bit in the original pattern was 0. Using
bit-wise AND in this manner is called bit masking. The 0 values in the
mask pattern 0010 mask the bits that are not of concern, in this case.
12
Arrays
-
Example 6
Two versions of the program that reads the state of the switches on port
0 and operates the LEDs on port 1 accordingly. For example if switch
S0 is pressed, program will turn LED0 ON, if S2 and S3 are pressed,
then LED 2 and 3 must turn ON and so on.
// version 1
#include <reg66x.h>
void main(void)
{
for(;;)
{
P1=P0;
}
}
// version 2
#include <reg66x.h>
#define SWITCHES P0
#define LEDS P1
void main(void)
{
for(;;)
{
LEDS = SWITCHES;
}
}
13
void DELAY(void)
{
unsigned char i,j;
for(i=0; i<=255; i=i+1)
{
for(j=0; j<=255; j=j+1)
{
;
}
}
}
Example 7
This program monitors switch S0 attached to the pin 0 of port 0. When
this switch is pressed, it flashes the single LED attached to pin 0 of port
1 ten times. Previously discussed bit masking technique is used to test
the value of switch S0.
#include <reg66x.h>
#define ON 0x01
#define OFF 0x00
#define mask 0x01
// 00000001
void DELAY(void);
void main(void)
{
unsigned char S0;
unsigned char N;
Another way to access a single pin on any port of 8051 is to make use
of special sbit data type. This data type provides access to bitaddressable SFRs and bit-addressable memory space within the
processor.
Line:
for(;;)
{
S0=P0&mask; // masking bits
while(S0)
// wait for key press
{
for(N=0;N<10;N++)
{
P1=ON;
DELAY();
P1=OFF;
DELAY();
}
S0=P0&mask;
}
}
sbit S0=P0^0;
creates an sbit type variable S0 that points to pin 0 of port 0.
14
for(;;)
{
while(S0)
{
for(N=0;N<10;N++)
{
P1=ON;
DELAY();
P1=OFF;
DELAY();
}
}
}
}
15
University of Portsmouth
Faculty of Technology
Department of Electronic and Computer Engineering
Content
Module:
Module Code:
Module Topic:
Lecturer:
Lecture Notes:
The purpose of this handout is to explain how to use the internal 8051
timers to generate time delays.
11.0592 106
= 1843200
6
This means that if the timer has counted from 0 to 100000 a 0.05425
seconds or 54.25 milliseconds have passed since:
100000
= 0.05425
1843200
0.02 1843200=36864
It is therefore necessary to have exactly 36864 timer increments to
achieve a time period of 20 milliseconds. This is actually a way to
measure time using timers on the microcontroller by counting the
number of timer increments during the measured time period. All that is
now needed is to learn how to control and initialise timers to provide the
needed information. This is done through the proper setting of a
number of SFRs related to timer functions and explained in following
sections of this document.
Timer Registers
Two 8051 timers are called Timer0 and Timer1 and they share two
SFRs (TMOD and TCON) which control the timers, and each timer also
has two SFRs dedicated solely to itself (TH0/TL0 and TH1/TL1).
Timer registers names; brief descriptions and addresses are given in
the table below.
Timer 0 has two SFRs dedicated exclusively to itself: TH0 and TL0.
Those are high and low bytes of the timer. When Timer 0 has a value of
0, both TH0 and TL0 will contain 0. When Timer 0 has the value of for
example 1000, TH0 will hold the high byte of the value (3 decimal) and
TL0 will contain the low byte of the value (232 decimal). The final value
of timer register is obtained by multiplying the high byte value by 256
and adding the low byte value to this value:
SFR Name
Description
SFR Address
TH0
8Ch
TL0
8Ah
TH1
8Dh
Bit
Name
GATE 1
C/T1
T1M1
T1M0
GATE 0
C/T0
T0M1
The TMOD SFR is used to control the mode of operation of both timers.
Each bit of the SFR gives the microcontroller specific information
concerning how to run a timer. The high four bits (bits 4 through 7)
relate to Timer 1 whereas the low four bits (bits 0 through 3) perform
the same functions, but for timer 0.
The individual bits of TMOD and their functions are detailed in the table
below.
T0M0
TL1
8Bh
TCON
Timer Control
88h
TMOD
Timer Mode
89h
TMOD SFR
Explanation of Function
The modes of operation determined with four bits from the TMOD
register are:
TxM1
TxM0
Timer Mode
Mode Description
13-bit Timer
16-bit Timer
8-bit auto-reload
Timer mode "2" is an 8-bit auto-reload mode. In this mode THx holds
the "reload value" and TLx is the timer itself. Thus, TLx starts counting
up. When TLx reaches 255 and is subsequently incremented, instead
of resetting to 0 (as in the case of modes 0 and 1), it will be reset to the
value stored in THx.
In mode 2 THx is always set to a known value and TLx is the SFR that
is constantly incremented.
In this mode microcontroller hardware takes care of checking for the
timer overfow and reloading of the timer, thus saving some of the
processing time.
The auto-reload mode is very commonly used for establishing a baud
rate necessary for the serial communications.
TCON SFR
Bit
Name
Bit Address
Explanation of Function
TF1
8Fh
TR1
8Eh
Timer 1 Run
TF0
8Dh
TR0
8Ch
Timer 0 Run
Overflow flags TF1 and TF0 are set by the corresponding timers when
they overflow. Timer Run bits are used by the program to turn the timer
on (when this bit is set to 1) or off (when the bit is cleared).
The benefit of bit-addressability of this register is now clear. This has
the advantage of setting the high bit of TCON without changing the
value of any of the other bits of the SFR. To start or stop a timer no
modification of any other value in TCON is necessary.
Once the modes of the operation of the timers are clear and functions
of the individual bits of timer initialising registers are known, writing
programs to use timers is an easy task.
Example 1
Example 2
Delay Value
20 10 3
6
11.0592 10 6
Procedure is:
Delay:
MOV
TMOD,#01H
; initialise
MOV
MOV
SETB
TL0,#47H
TL0,#FFH
TR0
; initialise TL0
; initialise TH0
; start timer
JNB
CLR
CLR
RET
TF0,Wait
TR0
TF0
TMOD
Timer Reload Value
Wait:
Delay Value
100 10 3
= 184
6
11.0592 10 6
TL0 = 0xFF;
Example 3
while(1)
// keep repeating the following section
{
pin7 = on;
// pin 7 to 5 volts, i.e. logic 1
pin7 = off;
// pin 7 to 0 v0lts, i.e. logic 0
Example 4
7
main()
{
TMOD = 0x01;
// timer 0 mode 1,
Example 6
Example 5
Load the timer 0 in order to produce 1 kHz square wave (i.e. cycle time
of 1000 s and delay time 500 s). Oscillator frequency is 11.0592
MHz.
Delay Value =
500 10 6
= 922
6
11.0592 10 6
ON
OFF
4 x delay
delay
Alternatively if we use:
TH0 = ~(922/256);
TL0 = -(922%256)
will negate reminder of division 922/256 and store the result in TL0
i.e.
922%256 = 154
-(922%256) = 256-154 = 102 = 0x66
main()
{
TMOD = 0x01;
// initialise TMOD for Timer 0 in mode 1
while(1)
// repeat this
{
pwm = on;
// output
delay_on();
// 800 us
pwm = off;
// output
delay_off(); // 200 us
}
pin high
delay
pin low
delay
}
// 800 us delay function
void delay_on()
{
// loading Timer 0 for longer delay
TH0 = ~(1475/256);
TL0 = -(1475%256);
TR0 = on;
// turn the Timer 0 ON
while(!TF0); // wait for timer overflow
TR0 = off;
// switch the Timer 0 off
TF0 = off;
// clear the overflow flag
}
// 200 us delay function
void delay_off()
{
// loading Timer 0 for shorter delay
TH0 = ~(369/256);
TL0 = -(369%256);
TR0 = on;
while(!TF0);
TR0 = off;
TF0 = off;
}
10
University of Portsmouth
Faculty of Technology
Department of Electronic and Computer Engineering
Content
Module:
Module Code:
Module Topic:
Lecturer:
Lecture Notes:
Interrupts .............................................................................. 2
Interrupt Events .................................................................... 2
Enabling Interrupts ............................................................... 3
Interrupt Priorities ................................................................. 3
Interrupt Handling ................................................................ 4
Timer Interrupts .................................................................... 5
External Interrupts ................................................................ 5
Serial Interrupts .................................................................... 5
Example 1 Timer Interrupt................................................. 6
Example 2 External Interrupt............................................. 6
Interrupts on 8051
Interrupts
As the name implies, an interrupt is some event which interrupts
normal program execution.
Program flow is always sequential, being altered only by those
instructions which cause program flow to deviate in some way.
However, interrupts provide a mechanism to "put on hold" the normal
program flow, execute a subroutine (interrupt service routine or interrupt
handler), and then resume normal program flow. ISR (interrupt service
routine) is only executed when a certain event (interrupt) occurs. The
event may be one of the timers "overflowing," receiving a character via
the serial port, transmitting a character via the serial port, or one of two
"external events." The 8051 may be configured so that when any of
these events occur the main program is temporarily suspended and
control passed to a special section of code which would execute some
function related to the event that occurred. Once complete, control
would be returned to the original program so that the main program
never even knows it was interrupted.
The ability to interrupt normal program execution when certain events
occur makes it much easier and much more efficient to handle certain
conditions. Without interrupts a manual check in the main program
would have to be performed to establish whether the timers had
overflown, whether another character has been received via the serial
port, or if some external event had occurred. Besides making the main
program longer and more complicated to read and understand, more
importantly, such a situation would make program inefficient since
"instruction cycles" would be spent checking for events that usually
dont happen or happen very infrequently during the program execution.
It was shown in the previous handout how timer flag needs to be
checked to detect timer overflow when generating accurate delay in the
program. This isnt necessary. Interrupts let us forget about checking for
the condition. The microcontroller itself will check for the condition
automatically and when the condition is met will jump to a subroutine
(called an interrupt handler), execute the code, then return.
Interrupt Events
The 8051 family of microcontrollers can be configured to respond to
interrupts caused by the following events:
Timer 0 Overflow
Timer 1 Overflow
Reception/Transmission of Serial Character
External Event 0
External Event 1
Name
ISR Address
External 0
IE0
0003h
Timer 0
TF0
000Bh
External 1
IE1
0013h
Timer 1
TF1
001Bh
Serial
RI/TI
0023h
From the above IVT it can be seen that whenever Timer 0 overflows
(i.e., the TF0 bit is set), the main program will be temporarily suspended
and control will jump to 000BH. It is of course necessary to have a code
at address 000BH that handles the situation of Timer 0 overflowing.
Enabling Interrupts
By default at power up, all interrupts are disabled. Therefore even if, for
example, the TF0 bit is set, the 8051 will not execute the interrupt. User
program must specifically tell the 8051 that it wishes to enable
interrupts and specifically which interrupts it wishes to enable.
Enabling and disabling of the interrupts is done by modifying the IE
SFR (Interrupt Enable) (A8h):
Bit
Name
Bit Address
Explanation of Function
EA
AFh
AEh
Undefined
ADh
Undefined
ES
ACh
ET1
ABh
EX1
AAh
ET0
A9h
EX0
A8h
Each of the 8051s interrupts has its own bit in the IE SFR. To enable a
given interrupt a corresponding bit needs to be set. To enable Timer 1
IE = 0x08;
or
ET1 = 1;
Once Timer 1 Interrupt is enabled, whenever the TF1 bit is set, the
8051 will automatically put "on hold" the main program and execute the
Timer 1 Interrupt Handler at address 001Bh.
However, before Timer 1 Interrupt (or any other interrupt) is truly
enabled, bit 7 of IE must also be set. Bit 7, the Global Interrupt
Enable/Disable, enables or disables all interrupts simultaneously. If bit 7
is cleared then no interrupts will occur, even if all the other bits of IE are
set. Setting bit 7 will enable all the interrupts that have been selected by
setting other bits in IE. This is useful in program executing time-critical
code where it might be needed to execute code from start to finish
without any interrupt getting in the way. To accomplish this bit 7 of IE
can simply be cleared (EA = 0;) and then set after the time-critical code
is done. So to fully enable the Timer 1 Interrupt the most common
approach is to execute the following two instructions:
ET1 = 1;
EA = 1;
Alternatively, instruction:
IE = 0x88;
will have the same effect.
Thereafter, the Timer 1 Interrupt Handler at 01Bh will automatically be
called whenever the TF1 bit is set (upon Timer 1 overflow).
Interrupt Priorities
When checking for interrupt conditions, 8051 always checks according
to predetermined sequence:
1.
2.
3.
4.
5.
External 0 Interrupt
Timer 0 Interrupt
External 1 Interrupt
Timer 1 Interrupt
Serial Interrupt
This also means that if a Serial Interrupt occurs at the exact same
instant that an External 0 Interrupt occurs, the External 0 Interrupt will
be serviced first and the Serial Interrupt will be serviced once the
External 0 Interrupt has completed.
This priority order in servicing the interrupts on 8051 can be altered.
Custom defined priority order offers two levels of interrupt priority: high
and low.
If Timer 1 and Serial Interrupt are enabled in the program Timer 1
Interrupt will have a higher priority than the Serial Interrupt, i.e. if two
interrupts occur at the same time Timer 1 Interrupt will be serviced first.
To change this high priority can be assigned to a Serial Interrupt and
low priority to a Timer 1 Interrupt. In this interrupt priority scheme, even
if Timer 1 Interrupt is already executing the serial interrupt itself can
interrupt the Timer 1 Interrupt. When the serial interrupt ISR is
complete, control passes back to Timer 1 Interrupt and finally back to
the main program.
Interrupt priorities are controlled by the IP SFR (B8h).
Bit
Name
Bit Address
Explanation of Function
Undefined
Undefined
Undefined
PS
BCh
PT1
BBh
PX1
BAh
PT0
B9h
PX0
B8h
Interrupt Handling
When an interrupt is triggered, the following actions are taken
automatically by the microcontroller:
An interrupt ends when your program executes the RETI (Return from
Interrupt) instruction. When the RETI instruction is executed the
following actions are taken by the microcontroller:
two bytes are popped off the stack into the Program
Counter to restore normal program execution.
Timer Interrupts
Timer interrupts occur as a result of Timer 0 or Timer 1 overflow. This
sets the corresponding timer flag in TCON register. Flag is cleared
automatically by the hardware, so there is no need for the flag clearing
instruction in the ISR.
Last two unexplained bits of TCON SFR are interrupt flags IE1 and IE0.
Similarly to timer flags those two flags are set when corresponding
external interrupt occurs. They are cleared by hardware when the CPU
vectors to the ISR if the interrupt is transition-activated. If the interrupt is
level activated, then IEx flag has to be cleared by the user software
Serial Interrupts
Serial Interrupts are slightly different than the rest of the interrupts. This
is due to the fact that there are two interrupt flags: RI and TI (bits 0 and
1 from SCON register). If either flag is set, a serial interrupt is triggered.
RI bit is set when a byte is received by the serial port and the TI bit is
set when a byte has been sent. This means that when serial interrupt
occurs, it may have been triggered because the RI flag was set or
because the TI flag was set-or because both flags were set. Thus,
interrupt routine must check the status of these flags to determine what
action is appropriate. Also, since the 8051 does not automatically clear
the RI and TI flags ISR must clear these bits.
External Interrupts
There is one not so obvious detail, which requires an additional
explanation, and it concerns the external interrupts. Namely, if bits IT0
and IT1 (in register TCON) are set, program will be interrupted on
change of logic on interrupt pins (P3.2 for External Interrupt 0 and P3.3
for External Interrupt 1) from 1 to 0, i.e. on falling edge of the impulse. If
these two bits are cleared, same signal will trigger an interrupt, but in
this case it will be continually executed as long as the state on interrupt
pins is low.
#include <reg66x.h>
#include <reg66x.h>
in mode 2
EA = 1;
EX1 = 1;
IT1 = 1;
reload value
start timer 0
global INT enable
timer 0 INT enable
wait for INT
//
//
//
//
while(1)
{
unsigned int j;
for(j = 1; j <=10; j++)
pin6 = ~pin6;
}
}
University of Portsmouth
Faculty of Technology
Department of Electronic and Computer Engineering
Content
Module:
Module Code:
Module Topic:
Lecturer:
Lecture Notes:
Bit
Name
Explanation of Function
SM0
SM1
SM2
REN
TB8
RB8
TI
RI
SM1
Serial Mode
Explanation
Baud Rate
Oscillator / 12
8-bit UART
9-bit UART
Oscillator / 32 (*)
9-bit UART
Note: The baud rate indicated in this table is doubled if PCON.7 (SMOD) is set.
Bits SM0 and SM1 set the serial mode to a value between 0 and 3,
inclusive. The four modes are defined in the chart immediately above.
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.
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 our applications it is safe to say that
this bit needs to be cleared so that the flag is set upon reception of any
character.
The next bit, REN, is "Receiver Enable." This bit is very straightforward:
To receive data via the serial port, this bit needs to be set.
The last four bits (bits 0 through 3) are operational bits. They are used
when actually sending and receiving data, i.e. 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.
Crystall
TH 1 = 256 192
Baud
110590
= 256 192
19200
57699
= 256
19200
= 256 3
= 253
Crystall
TH 1 = 256 384
Baud
If PCON.7 is set then the baud rate is effectively doubled, thus the
equation becomes:
Crystall
TH 1 = 256 192
Baud
Since, timer register TH1 can only be loaded with integer number, if it is
set to 254 achieved baud rate is 14,400 and if it is set to 255 achieved
baud is 28,800. To achieve exactly 19,200 baud PCON.7 (SMOD) bit
needs to be set. This will double the baud rate and utilize the second
equation mentioned above:
character has been transmitted and the next character can be send as
well. Consider the following code segment:
SBUF = A; // write char to SBUF
while(!TI); // wait until done
TI = 0;
// clear interrupt flag
The above three instructions will successfully transmit a character and
wait for the TI bit to be set before continuing. The program will pause on
the while(!TI) instruction until the TI bit is set by the 8051 upon
successful transmission of the character.
Example
Following two programs can be used to establish serial communication
between two 8051 microcontrollers. First program sends the message,
6 characters long to another 8051 while second program, to be run on
another 8051 can receive message of the same length.
/* program to send a message, 6 characters
long, to another 8051 via serial channel */
#include <reg66x.h>
char message[6] = {'H','e','l','p',' ','!'};
int letter;
main()
{
/* initialise serial channel 0 */
S0CON = 0x40;
/* UART mode 1 */
TMOD = 0x20;
/* timer mode 2 */
TCON = 0x40;
/* start the timer */
TH1
= 0xE6;
/* 1200 baud @ 12 MHz */
/* transmit routine */
for (letter=0;letter<6;letter++)
{
S0BUF = message[letter];
while (!TI0);
TI0 = 0;
}
/* afterwards wait in endless loop */
while(1);
}