PWM, as the name suggests, is simply a pulse width modulation. We take a pulse and then we modulate its width and make it small or big. Another term important while studying PWM is named duty cycle. The duty cycle shows the duration for which the PWM pulse remains HIGH. Now if the pulse remains high for 50% and LOW for 50% then we say that PWM pulse has a duty cycle of 50%. Similarly, if the pulse is HIGH for 70% and Low for 30% then it has a duty cycle of 70%.
Most of the microcontrollers have special pins assigned for PWM as in Arduino UNO it has 6 PWM pins on it. Similarly, PIC Microcontrollers also have PWM pins but unfortunately, the 8051 Microcontroller doesn't have this luxury means there are no special PWM pins available in 8051 Microcontroller. But PWM is necessary so we are going to manually generate the PWM pulse using Timer0 interrupt. So, before reading this tutorial you must first read How to use Timer Interrupt in 8051 Microcontroller so that you understand the functioning of Timer Interrupt. Anyways, let's get started with the generation of PWM in the 8051 Microcontroller.
| Where To Buy? | ||||
|---|---|---|---|---|
| No. | Components | Distributor | Link To Buy | |
| 1 | 8051 Microcontroller | Amazon | Buy Now | |
#include<reg51.h>
// PWM_Pin
sbit PWM_Pin = P2^0; // Pin P2.0 is named as PWM_Pin
// Function declarations
void cct_init(void);
void InitTimer0(void);
void InitPWM(void);
// Global variables
unsigned char PWM = 0; // It can have a value from 0 (0% duty cycle) to 255 (100% duty cycle)
unsigned int temp = 0; // Used inside Timer0 ISR
// PWM frequency selector
/* PWM_Freq_Num can have values in between 1 to 257 only
* When PWM_Freq_Num is equal to 1, then it means highest PWM frequency
* which is approximately 1000000/(1*255) = 3.9kHz
* When PWM_Freq_Num is equal to 257, then it means lowest PWM frequency
* which is approximately 1000000/(257*255) = 15Hz
*
* So, in general you can calculate PWM frequency by using the formula
* PWM Frequency = 1000000/(PWM_Freq_Num*255)
*/
#define PWM_Freq_Num 1 // Highest possible PWM Frequency
// Main Function
int main(void)
{
cct_init(); // Make all ports zero
InitPWM(); // Start PWM
PWM = 127; // Make 50% duty cycle of PWM
while(1) // Rest is done in Timer0 interrupt
{}
}
// Init CCT function
void cct_init(void)
{
P0 = 0x00;
P1 = 0x00;
P2 = 0x00;
P3 = 0x00;
}
// Timer0 initialize
void InitTimer0(void)
{
TMOD &= 0xF0; // Clear 4bit field for timer0
TMOD |= 0x01; // Set timer0 in mode 1 = 16bit mode
TH0 = 0x00; // First time value
TL0 = 0x00; // Set arbitrarily zero
ET0 = 1; // Enable Timer0 interrupts
EA = 1; // Global interrupt enable
TR0 = 1; // Start Timer 0
}
// PWM initialize
void InitPWM(void)
{
PWM = 0; // Initialize with 0% duty cycle
InitTimer0(); // Initialize timer0 to start generating interrupts
// PWM generation code is written inside the Timer0 ISR
}
// Timer0 ISR
void Timer0_ISR (void) interrupt 1
{
TR0 = 0; // Stop Timer 0
if(PWM_Pin) // if PWM_Pin is high
{
PWM_Pin = 0;
temp = (255-PWM)*PWM_Freq_Num;
TH0 = 0xFF - (temp>>8)&0xFF;
TL0 = 0xFF - temp&0xFF;
}
else // if PWM_Pin is low
{
PWM_Pin = 1;
temp = PWM*PWM_Freq_Num;
TH0 = 0xFF - (temp>>8)&0xFF;
TL0 = 0xFF - temp&0xFF;
}
TF0 = 0; // Clear the interrupt flag
TR0 = 1; // Start Timer 0
}
After reading this post, you will also get the skilled hand on timer interrupt and can understand them more easily. In today's post, I am gonna design a digital clock which will increment after every one second and we will calculate this one second increment using timer interrupt. This clock will be displayed on LCD so if you are not familiar with LCD then must read Interfacing of LCD with 8051 Microcontroller. You can also implement this digital clock with any other microcontroller like Arduino or PIC Microcontroller but today we are gonna implement it on 8051 Microcontroller. The complete simulation along with code is given at the end of this post but my suggestion is to design it on your own so that you get most of it. Use our code and simulation as a guide. So, let's get started with Interrupt based Digital clock with 8051 Microcontroller. :)
#include<reg51.h>
//Function declarations
void cct_init(void);
void delay(int);
void lcdinit(void);
void WriteCommandToLCD(int);
void WriteDataToLCD(char);
void ClearLCDScreen(void);
void InitTimer0(void);
void UpdateTimeCounters(void);
void DisplayTimeToLCD(unsigned int,unsigned int,unsigned int);
void WebsiteLogo();
void writecmd(int);
void writedata(char);
//*******************
//Pin description
/*
P2.4 to P2.7 is data bus
P1.0 is RS
P1.1 is E
*/
//********************
// Defines Pins
sbit RS = P1^0;
sbit E = P1^1;
// Define Clock variables
unsigned int usecCounter = 0;
unsigned int msCounter = 0;
unsigned int secCounter = 0;
unsigned int minCounter = 0;
unsigned int hrCounter = 0;
// ***********************************************************
// Main program
//
void main(void)
{
cct_init(); // Make all ports zero
lcdinit(); // Initilize LCD
InitTimer0(); // Start Timer0
// WebsiteLogo();
while(1)
{
if( msCounter == 0 ) // msCounter becomes zero after exact one sec
{
DisplayTimeToLCD(hrCounter, minCounter, secCounter); // Displays time in HH:MM:SS format
}
UpdateTimeCounters(); // Update sec, min, hours counters
}
}
void writecmd(int z)
{
RS = 0; // This is command
P2 = z; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void writedata(char t)
{
RS = 1; // This is data
P2 = t; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void cct_init(void)
{
P0 = 0x00; //not used
P1 = 0x00; //not used
P2 = 0x00; //used as data port
P3 = 0x00; //used for generating E and RS
}
void InitTimer0(void)
{
TMOD &= 0xF0; // Clear 4bit field for timer0
TMOD |= 0x02; // Set timer0 in mode 2
TH0 = 0x05; // 250 usec reloading time
TL0 = 0x05; // First time value
ET0 = 1; // Enable Timer0 interrupts
EA = 1; // Global interrupt enable
TR0 = 1; // Start Timer 0
}
void Timer0_ISR (void) interrupt 1 // It is called after every 250usec
{
usecCounter = usecCounter + 250; // Count 250 usec
if(usecCounter==1000) // 1000 usec means 1msec
{
msCounter++;
usecCounter = 0;
}
TF0 = 0; // Clear the interrupt flag
}
void WebsiteLogo()
{
writecmd(0x95);
writedata('w'); //write
writedata('w'); //write
writedata('w'); //write
writedata('.'); //write
writedata('T'); //write
writedata('h'); //write
writedata('e'); //write
writedata('E'); //write
writedata('n'); //write
writedata('g'); //write
writedata('i'); //write
writedata('n'); //write
writedata('e'); //write
writedata('e'); //write
writedata('r'); //write
writedata('i'); //write
writedata('n'); //write
writedata('g'); //write
writecmd(0xd8);
writedata('P'); //write
writedata('r'); //write
writedata('o'); //write
writedata('j'); //write
writedata('e'); //write
writedata('c'); //write
writedata('t'); //write
writedata('s'); //write
writedata('.'); //write
writedata('c'); //write
writedata('o'); //write
writedata('m'); //write
writecmd(0x80);
}
void UpdateTimeCounters(void)
{
if (msCounter==1000)
{
secCounter++;
msCounter=0;
}
if(secCounter==60)
{
minCounter++;
secCounter=0;
}
if(minCounter==60)
{
hrCounter++;
minCounter=0;
}
if(hrCounter==24)
{
hrCounter = 0;
}
}
void DisplayTimeToLCD( unsigned int h, unsigned int m, unsigned int s ) // Displays time in HH:MM:SS format
{
ClearLCDScreen(); // Move cursor to zero location and clear screen
// Display Hour
WriteDataToLCD( (h/10)+0x30 );
WriteDataToLCD( (h%10)+0x30 );
//Display ':'
WriteDataToLCD(':');
//Display Minutes
WriteDataToLCD( (m/10)+0x30 );
WriteDataToLCD( (m%10)+0x30 );
//Display ':'
WriteDataToLCD(':');
//Display Seconds
WriteDataToLCD( (s/10)+0x30 );
WriteDataToLCD( (s%10)+0x30 );
}
void delay(int a)
{
int i;
for(i=0;i<a;i++); //null statement
}
void WriteDataToLCD(char t)
{
RS = 1; // This is data
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= (t&0xF0); // Write Upper nibble of data
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= ((t<<4)&0xF0);// Write Lower nibble of data
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void WriteCommandToLCD(int z)
{
RS = 0; // This is command
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= (z&0xF0); // Write Upper nibble of data
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= ((z<<4)&0xF0);// Write Lower nibble of data
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void lcdinit(void)
{
///////////// Reset process from datasheet /////////
delay(15000);
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= (0x30&0xF0); // Write 0x3
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
delay(4500);
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= (0x30&0xF0); // Write 0x3
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
delay(300);
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= (0x30&0xF0); // Write 0x3
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
delay(650);
P2 &= 0x0F; // Make P2.4 to P2.7 zero
P2 |= (0x20&0xF0); // Write 0x2
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
delay(650);
/////////////////////////////////////////////////////
WriteCommandToLCD(0x28); //function set
WriteCommandToLCD(0x0c); //display on,cursor off,blink off
WriteCommandToLCD(0x01); //clear display
WriteCommandToLCD(0x06); //entry mode, set increment
}
void ClearLCDScreen(void)
{
WriteCommandToLCD(0x01); // Clear screen command
delay(1000);
}
Now coming towards interrupt, interrupt is interrupt :P Yeah really, we call it interrupt because its an interrupt. In programming codes there are many things which needs to run in background and appear when its time for them to appear. Here where interrupt comes handy. Interrupt is kind of a background code which keeps on running in the background while the main code keeps on running in front but when the interrupt condition is fullfilled then it interrupts the main program and executes the functions defined in it. For Timer interrupts, suppose I wanna blink my LED after every 2 seconds then what will I do is I will start a timer for 2 seconds and when this timer completes I will generate an interrupt. So, in this way after every two seconds the led will blink. So, let's start with timers interrupt in 8051 Microcontroller and see how we are gonna do this.
As I explained earlier, we are gonna use Timer interrupt in 8051 Microcontroller. so, now before gong into the details, let me first throw some light on how we are gonna implement this. Timers count from 0 to 255 in 8 bit mode as in 8 bit 255 is the maximum value and when timer hits the 255 number then we say that our timer is overflowed. Now when timer overflows, then it sends us a indication using which we generate our intterupt. In timers, there are few registers in which they store their value. If we are talking about Timer0 then timer0 stores its value in TL0 register. Now suppose I want my timer to start counting from 10 instead 0 then I will store 10 in my TL0 register and it will count from 10 instead 0 and when it reaches 255 it will overflow. Now when Timer0 will overflow then it will make TF0 bit HIGH. TF0 is another register value, if its 1 then it means that our timer is full and if its 0 then it means our timer is still counting. So, that's how we count from our timer and check the pin TF0. Now first of all, I am gonna use Timer0 and then we will have a quick look at Timer1.
#include<reg51.h>
// Out Pin
sbit Out = P2^0; // Pin P2.0 is named as Out
//Function declarations
void cct_init(void);
void InitTimer0(void);
int main(void)
{
cct_init(); // Make all ports zero
InitTimer0(); // Start Timer0
while(1) // Rest is done in Timer0 interrupt
{
}
}
void cct_init(void)
{
P0 = 0x00;
P1 = 0x00;
P2 = 0x00;
P3 = 0x00;
}
void InitTimer0(void)
{
TMOD &= 0xF0; // Clear 4bit field for timer0
TMOD |= 0x02; // Set timer0 in mode 2
TH0 = 0x05; // 250 usec reloading time
TL0 = 0x05; // First time value
ET0 = 1; // Enable Timer0 interrupts
EA = 1; // Global interrupt enable
TR0 = 1; // Start Timer 0
}
void Timer0_ISR (void) interrupt 1 // It is called after every 250usec
{
Out = ~Out; // Toggle Out pin
TF0 = 0; // Clear the interrupt flag
}
Download Timer0 Code and Simulation
#include<reg51.h>
// Out Pin
sbit Out = P2^0; // Pin P2.0 is named as Out
//Function declarations
void cct_init(void);
void InitTimer1(void);
int main(void)
{
cct_init(); // Make all ports zero
InitTimer1(); // Start Timer1
while(1) // Rest is done in Timer1 interrupt
{
}
}
void cct_init(void)
{
P0 = 0x00;
P1 = 0x00;
P2 = 0x00;
P3 = 0x00;
}
void InitTimer1(void)
{
TMOD &= 0x0F; // Clear 4bit field for timer1
TMOD |= 0x20; // Set timer1 in mode 2
TH1 = 0x05; // 250 usec reloading time
TL1 = 0x05; // First time value
ET1 = 1; // Enable Timer1 interrupts
EA = 1; // Global interrupt enable
TR1 = 1; // Start Timer 1
}
void Timer1_ISR (void) interrupt 3 // It is called after every 250usec
{
Out = ~Out; // Toggle Out pin
TF1 = 0; // Clear the interrupt flag
}
Download Timer1 Code and Simulation
That's all for today, I hope you guys have got something out of today's post and gonna like this one. In the coming post, I am gonna design some simple project on 8051 Microcontroller in which I will use these Timers, then you will get know more about them. So, stay tuned and subscribe us by email. Take care !!! :)
8051 Microcontroller, as we all know, is another Microcontroller series just like PIC Microcontroller or Arduino etc. The benefit of 8051 Microcontrollers is that they are quite cheap and easily available so if you are going to design some product then its better to use 8051 Microcontroller instead of PIC Microcontroller or Arduino etc. As they are cheap so they also come with a disadvantage which is that they are not much rich with features. Few of 8051 Microcontrollers doesn't even support Serial Communication. So, before choosing it for your project, must check their datasheet to confirm that they are suitable for your projects.
In most of these below projects, I have designed the complete simulation in Proteus and the code is also given but my suggestions is don't simply download the simulation and run it. Instead design the simulation from scratch and then design your code and run the simulation on your own. Consider my codes and simulations as a guide but dont get dependent on them as then you are not gonna get anything. Anyways let's get started with 8051 Microcontroller Projects.
Below are mentioned all the 8051 Microcontrollers Projects, which I have shared on this blog. You can check these projects and can also download their simulations designed in Proteus. I have given codes for most of these projects but few are paid, which you can buy from our shop at a quite minimal rate.
These are basic projects and are best for beginner level programmers. If you are new to 8051 Microcontroller then first read these projects. These all projects contain complete codes as well as the Proteus simulation so you can quite easily test them in Proteus software and can edit the codes and learn from it.
These are Intermediate level 8051 Microcontroller Projects. If you wanna do these projects then you must first learn or atleast have a look at basic 8051 Microcontroller projects as they are using same components as we interfaced in basic level. If you feel any problem then ask in comments.
That's all for today, but I am gonna add more projects in it and will keep on updating the list. Subscribe us and get these exciting tutorials straight to your mail box.As 8051 Microcontroller is concerned, we all know that Its a Microcontroller in which we program our code and make it work. The 8051 microcontroller, I have used in this post is AT89C51. I have also designed this project on hardware and have tested code and it works fine. The crystal oscillator I have used in this project is of 16MHz. You can also download the Proteus Simulation along with programming code and hex file designed in keil uvision 3, at the end of this post. So, now let's get started with it. You may also wanna read the below projects on 8051 Microcontroller:
#include<reg51.h>
void cct_init(void);
void delay(int);
void DisplayOn7Segment(char);
int main(void)
{
char ch = '0'; // Character to be displayed on 7seg
cct_init(); // Make all ports zero
while(1)
{
DisplayOn7Segment(ch); // Display ch on 7seg
delay(30000); // About 1 sec delay
switch(ch) // Update ch with new value to be displayed
{
case '0': ch = '1'; break;
case '1': ch = '2'; break;
case '2': ch = '3'; break;
case '3': ch = '4'; break;
case '4': ch = '5'; break;
case '5': ch = '6'; break;
case '6': ch = '7'; break;
case '7': ch = '8'; break;
case '8': ch = '9'; break;
case '9': ch = '0'; break;
default: ch = '0'; break;
}
}
}
void cct_init(void)
{
P0 = 0x00;
P1 = 0x00;
P2 = 0x00;
P3 = 0x00;
}
void delay(int a)
{
int i;
for(i=0;i<a;i++); //null statement
}
void DisplayOn7Segment(char ch) // ch can have a value from '0' to 'F' only
{
switch(ch)
{
case '0': P2 = 0x3F; break;
case '1': P2 = 0x06; break;
case '2': P2 = 0x5B; break;
case '3': P2 = 0x4F; break;
case '4': P2 = 0x66; break;
case '5': P2 = 0x6D; break;
case '6': P2 = 0x7D; break;
case '7': P2 = 0x07; break;
case '8': P2 = 0x7F; break;
case '9': P2 = 0x6F; break;
default: P2 = 0x3F; break;
}
}
That's all for today, I hope now you can quite easily interface this seven segment display with 8051 Microcontroller. In the next post, we will have a look at some new project with 8051 Microcontroller. So, till then take care and have fun !!! :)
Actually we have already understood the working of both keypad and LCD so I thought to share this small project as it will give you the practical application of both keypad and LCD. And if you are new to 8051 Microcontroller then its always better to first design a small project and then move to pro one. The Simulation file along with hex file and complete code is given at the end for download. But my suggestion is to design it by yourself as it will help you in learning. You will do mistakes but obviously it will help you in learning so make mistakes and learn with it. So, let's get started with it.
while(1)
{
//get numb1
key = get_key();
writecmd(0x01); //clear display
writedata(key); //Echo the key pressed to LCD
num1 = get_num(key); //Get int number from char value, it checks for wrong input as well
if(num1!=Error) //if correct input then proceed, num1==Error means wrong input
{
//get function
key = get_key();
writedata(key); //Echo the key pressed to LCD
func = get_func(key); //it checks for wrong func
if(func!='e') //if correct input then proceed, func=='e' means wrong input
{
//get numb2
key = get_key();
writedata(key); //Echo the key pressed to LCD
num2 = get_num(key); //Get int number from char value, it checks for wrong input as well
if(num2!=Error) //if correct input then proceed, num2==Error means wrong input
{
//get equal sign
key = get_key();
writedata(key); //Echo the key pressed to LCD
if(key == '=') //if = is pressed then proceed
{
switch(func) //switch on function
{
case '+': disp_num(num1+num2); break;
case '-': disp_num(num1-num2); break;
case 'x': disp_num(num1*num2); break;
case '/': disp_num(num1/num2); break;
}
}
else //key other then = here means error wrong input
{
if(key == 'C') //if clear screen is pressed then clear screen and reset
writecmd(0x01); //Clear Screen
else
DispError(0); //Display wrong input error
}
}
}
}
}
#include<reg51.h>
#include<string.h>
//Define Macros
#define Error 13 // Any value other than 0 to 9 is good here
//Function declarations
void cct_init(void);
void delay(int);
void lcdinit(void);
void writecmd(int);
void writedata(char);
void writeline(char[]);
void ReturnHome(void);
char READ_SWITCHES(void);
char get_key(void);
int get_num(char);
char get_func(char);
void DispError(int);
void disp_num(int);
void WebsiteLogo();
//*******************
//Pin description
/*
P2 is data bus
P3.7 is RS
P3.6 is E
P1.0 to P1.3 are keypad row outputs
P1.4 to P1.7 are keypad column inputs
*/
//********************
// Define Pins
//********************
sbit RowA = P1^0; //RowA
sbit RowB = P1^1; //RowB
sbit RowC = P1^2; //RowC
sbit RowD = P1^3; //RowD
sbit C1 = P1^4; //Column1
sbit C2 = P1^5; //Column2
sbit C3 = P1^6; //Column3
sbit C4 = P1^7; //Column4
sbit E = P3^6; //E pin for LCD
sbit RS = P3^7; //RS pin for LCD
// ***********************************************************
// Main program
//
int main(void)
{
char key; //key char for keeping record of pressed key
int num1 = 0; //First number
char func = '+'; //Function to be performed among two numbers
int num2 = 0; //Second number
cct_init(); //Make input and output pins as required
lcdinit(); //Initilize LCD
WebsiteLogo();
while(1)
{
WebsiteLogo();
//get numb1
key = get_key();
writecmd(0x01); //clear display
WebsiteLogo();
writedata(key); //Echo the key pressed to LCD
num1 = get_num(key); //Get int number from char value, it checks for wrong input as well
if(num1!=Error) //if correct input then proceed, num1==Error means wrong input
{
//get function
key = get_key();
writedata(key); //Echo the key pressed to LCD
func = get_func(key); //it checks for wrong func
if(func!='e') //if correct input then proceed, func=='e' means wrong input
{
//get numb2
key = get_key();
writedata(key); //Echo the key pressed to LCD
num2 = get_num(key); //Get int number from char value, it checks for wrong input as well
if(num2!=Error) //if correct input then proceed, num2==Error means wrong input
{
//get equal sign
key = get_key();
writedata(key); //Echo the key pressed to LCD
if(key == '=') //if = is pressed then proceed
{
switch(func) //switch on function
{
case '+': disp_num(num1+num2); break;
case '-': disp_num(num1-num2); break;
case 'x': disp_num(num1*num2); break;
case '/': disp_num(num1/num2); break;
}
}
else //key other then = here means error wrong input
{
if(key == 'C') //if clear screen is pressed then clear screen and reset
{
writecmd(0x01); //Clear Screen
WebsiteLogo();
}
else
{
DispError(0); //Display wrong input error
WebsiteLogo();
}
}
}
}
}
}
}
void WebsiteLogo()
{
writecmd(0x95);
writedata('w'); //write
writedata('w'); //write
writedata('w'); //write
writedata('.'); //write
writedata('T'); //write
writedata('h'); //write
writedata('e'); //write
writedata('E'); //write
writedata('n'); //write
writedata('g'); //write
writedata('i'); //write
writedata('n'); //write
writedata('e'); //write
writedata('e'); //write
writedata('r'); //write
writedata('i'); //write
writedata('n'); //write
writedata('g'); //write
writecmd(0xd8);
writedata('P'); //write
writedata('r'); //write
writedata('o'); //write
writedata('j'); //write
writedata('e'); //write
writedata('c'); //write
writedata('t'); //write
writedata('s'); //write
writedata('.'); //write
writedata('c'); //write
writedata('o'); //write
writedata('m'); //write
writecmd(0x80);
}
void cct_init(void)
{
P0 = 0x00; //not used
P1 = 0xf0; //used for generating outputs and taking inputs from Keypad
P2 = 0x00; //used as data port for LCD
P3 = 0x00; //used for RS and E
}
void delay(int a)
{
int i;
for(i=0;i<a;i++); //null statement
}
void writedata(char t)
{
RS = 1; // This is data
P2 = t; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void writecmd(int z)
{
RS = 0; // This is command
P2 = z; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void lcdinit(void)
{
///////////// Reset process from datasheet /////////
delay(15000);
writecmd(0x30);
delay(4500);
writecmd(0x30);
delay(300);
writecmd(0x30);
delay(650);
/////////////////////////////////////////////////////
writecmd(0x38); //function set
writecmd(0x0c); //display on,cursor off,blink off
writecmd(0x01); //clear display
writecmd(0x06); //entry mode, set increment
}
void ReturnHome(void) /* Return to 0 cursor location */
{
writecmd(0x02);
delay(1500);
WebsiteLogo();
}
void writeline(char Line[])
{
int i;
for(i=0;i<strlen(Line);i++)
{
writedata(Line[i]); /* Write Character */
}
ReturnHome(); /* Return to 0 cursor position */
}
char READ_SWITCHES(void)
{
RowA = 0; RowB = 1; RowC = 1; RowD = 1; //Test Row A
if (C1 == 0) { delay(10000); while (C1==0); return '7'; }
if (C2 == 0) { delay(10000); while (C2==0); return '8'; }
if (C3 == 0) { delay(10000); while (C3==0); return '9'; }
if (C4 == 0) { delay(10000); while (C4==0); return '/'; }
RowA = 1; RowB = 0; RowC = 1; RowD = 1; //Test Row B
if (C1 == 0) { delay(10000); while (C1==0); return '4'; }
if (C2 == 0) { delay(10000); while (C2==0); return '5'; }
if (C3 == 0) { delay(10000); while (C3==0); return '6'; }
if (C4 == 0) { delay(10000); while (C4==0); return 'x'; }
RowA = 1; RowB = 1; RowC = 0; RowD = 1; //Test Row C
if (C1 == 0) { delay(10000); while (C1==0); return '1'; }
if (C2 == 0) { delay(10000); while (C2==0); return '2'; }
if (C3 == 0) { delay(10000); while (C3==0); return '3'; }
if (C4 == 0) { delay(10000); while (C4==0); return '-'; }
RowA = 1; RowB = 1; RowC = 1; RowD = 0; //Test Row D
if (C1 == 0) { delay(10000); while (C1==0); return 'C'; }
if (C2 == 0) { delay(10000); while (C2==0); return '0'; }
if (C3 == 0) { delay(10000); while (C3==0); return '='; }
if (C4 == 0) { delay(10000); while (C4==0); return '+'; }
return 'n'; // Means no key has been pressed
}
char get_key(void) //get key from user
{
char key = 'n'; //assume no key pressed
while(key=='n') //wait untill a key is pressed
key = READ_SWITCHES(); //scan the keys again and again
return key; //when key pressed then return its value
}
int get_num(char ch) //convert char into int
{
switch(ch)
{
case '0': return 0; break;
case '1': return 1; break;
case '2': return 2; break;
case '3': return 3; break;
case '4': return 4; break;
case '5': return 5; break;
case '6': return 6; break;
case '7': return 7; break;
case '8': return 8; break;
case '9': return 9; break;
case 'C': writecmd(0x01); return Error; break; //this is used as a clear screen and then reset by setting error
default: DispError(0); return Error; break; //it means wrong input
}
}
char get_func(char chf) //detects the errors in inputted function
{
if(chf=='C') //if clear screen then clear the LCD and reset
{
writecmd(0x01); //clear display
WebsiteLogo();
return 'e';
}
if( chf!='+' && chf!='-' && chf!='x' && chf!='/' ) //if input is not from allowed funtions then show error
{
DispError(1);
WebsiteLogo();
return 'e';
}
return chf; //function is correct so return the correct function
}
void DispError(int numb) //displays differet error messages
{
writecmd(0x01); //clear display
WebsiteLogo();
switch(numb)
{
case 0: writeline("Wrong Input"); break;
case 1: writeline("Wrong Function"); break;
default: writeline("Wrong Input"); break;
}
}
void disp_num(int numb) //displays number on LCD
{
unsigned char UnitDigit = 0; //It will contain unit digit of numb
unsigned char TenthDigit = 0; //It will contain 10th position digit of numb
if(numb<0)
{
numb = -1*numb; // Make number positive
writedata('-'); // Display a negative sign on LCD
}
TenthDigit = (numb/10); // Findout Tenth Digit
if( TenthDigit != 0) // If it is zero, then don't display
writedata(TenthDigit+0x30); // Make Char of TenthDigit and then display it on LCD
UnitDigit = numb - TenthDigit*10;
writedata(UnitDigit+0x30); // Make Char of UnitDigit and then display it on LCD
}
Anyways, let's come back to keypad, if you wanna read the keypad details then you should read Interfacing of keypad with Arduino in Proteus ISIS as I have mentioned all the basic details about keypad in that tutorial and I am not gonna repeat it. But as a simple recall, keypad works on matrix system like it has 4 columns and 4 rows so we will have total 8 pins through which we are gonna control these 16 buttons. So, let's get started with it.
char READ_SWITCHES(void)
{
RowA = 0; RowB = 1; RowC = 1; RowD = 1; //Test Row A
if (C1 == 0) { delay(10000); while (C1==0); return '7'; }
if (C2 == 0) { delay(10000); while (C2==0); return '8'; }
if (C3 == 0) { delay(10000); while (C3==0); return '9'; }
if (C4 == 0) { delay(10000); while (C4==0); return '/'; }
RowA = 1; RowB = 0; RowC = 1; RowD = 1; //Test Row B
if (C1 == 0) { delay(10000); while (C1==0); return '4'; }
if (C2 == 0) { delay(10000); while (C2==0); return '5'; }
if (C3 == 0) { delay(10000); while (C3==0); return '6'; }
if (C4 == 0) { delay(10000); while (C4==0); return 'x'; }
RowA = 1; RowB = 1; RowC = 0; RowD = 1; //Test Row C
if (C1 == 0) { delay(10000); while (C1==0); return '1'; }
if (C2 == 0) { delay(10000); while (C2==0); return '2'; }
if (C3 == 0) { delay(10000); while (C3==0); return '3'; }
if (C4 == 0) { delay(10000); while (C4==0); return '-'; }
RowA = 1; RowB = 1; RowC = 1; RowD = 0; //Test Row D
if (C1 == 0) { delay(10000); while (C1==0); return 'C'; }
if (C2 == 0) { delay(10000); while (C2==0); return '0'; }
if (C3 == 0) { delay(10000); while (C3==0); return '='; }
if (C4 == 0) { delay(10000); while (C4==0); return '+'; }
return 'n'; // Means no key has been pressed
}
#include<reg51.h>
//Function declarations
void cct_init(void);
void delay(int);
void lcdinit(void);
void writecmd(int);
void writedata(char);
void Return(void);
char READ_SWITCHES(void);
char get_key(void);
//*******************
//Pin description
/*
P2 is data bus
P3.7 is RS
P3.6 is E
P1.0 to P1.3 are keypad row outputs
P1.4 to P1.7 are keypad column inputs
*/
//********************
// Define Pins
//********************
sbit RowA = P1^0; //RowA
sbit RowB = P1^1; //RowB
sbit RowC = P1^2; //RowC
sbit RowD = P1^3; //RowD
sbit C1 = P1^4; //Column1
sbit C2 = P1^5; //Column2
sbit C3 = P1^6; //Column3
sbit C4 = P1^7; //Column4
sbit E = P3^6; //E pin for LCD
sbit RS = P3^7; //RS pin for LCD
// ***********************************************************
// Main program
//
int main(void)
{
char key; // key char for keeping record of pressed key
cct_init(); // Make input and output pins as required
lcdinit(); // Initilize LCD
writecmd(0x95);
writedata('w'); //write
writedata('w'); //write
writedata('w'); //write
writedata('.'); //write
writedata('T'); //write
writedata('h'); //write
writedata('e'); //write
writedata('E'); //write
writedata('n'); //write
writedata('g'); //write
writedata('i'); //write
writedata('n'); //write
writedata('e'); //write
writedata('e'); //write
writedata('r'); //write
writedata('i'); //write
writedata('n'); //write
writedata('g'); //write
writecmd(0xd8);
writedata('P'); //write
writedata('r'); //write
writedata('o'); //write
writedata('j'); //write
writedata('e'); //write
writedata('c'); //write
writedata('t'); //write
writedata('s'); //write
writedata('.'); //write
writedata('c'); //write
writedata('o'); //write
writedata('m'); //write
writecmd(0x80);
while(1)
{
key = get_key(); // Get pressed key
//writecmd(0x01); // Clear screen
writedata(key); // Echo the key pressed to LCD
}
}
void cct_init(void)
{
P0 = 0x00; //not used
P1 = 0xf0; //used for generating outputs and taking inputs from Keypad
P2 = 0x00; //used as data port for LCD
P3 = 0x00; //used for RS and E
}
void delay(int a)
{
int i;
for(i=0;i<a;i++); //null statement
}
void writedata(char t)
{
RS = 1; // This is data
P2 = t; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void writecmd(int z)
{
RS = 0; // This is command
P2 = z; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void lcdinit(void)
{
///////////// Reset process from datasheet /////////
delay(15000);
writecmd(0x30);
delay(4500);
writecmd(0x30);
delay(300);
writecmd(0x30);
delay(650);
/////////////////////////////////////////////////////
writecmd(0x38); //function set
writecmd(0x0c); //display on,cursor off,blink off
writecmd(0x01); //clear display
writecmd(0x06); //entry mode, set increment
}
void Return(void) //Return to 0 location on LCD
{
writecmd(0x02);
delay(1500);
}
char READ_SWITCHES(void)
{
RowA = 0; RowB = 1; RowC = 1; RowD = 1; //Test Row A
if (C1 == 0) { delay(10000); while (C1==0); return '7'; }
if (C2 == 0) { delay(10000); while (C2==0); return '8'; }
if (C3 == 0) { delay(10000); while (C3==0); return '9'; }
if (C4 == 0) { delay(10000); while (C4==0); return '/'; }
RowA = 1; RowB = 0; RowC = 1; RowD = 1; //Test Row B
if (C1 == 0) { delay(10000); while (C1==0); return '4'; }
if (C2 == 0) { delay(10000); while (C2==0); return '5'; }
if (C3 == 0) { delay(10000); while (C3==0); return '6'; }
if (C4 == 0) { delay(10000); while (C4==0); return 'x'; }
RowA = 1; RowB = 1; RowC = 0; RowD = 1; //Test Row C
if (C1 == 0) { delay(10000); while (C1==0); return '1'; }
if (C2 == 0) { delay(10000); while (C2==0); return '2'; }
if (C3 == 0) { delay(10000); while (C3==0); return '3'; }
if (C4 == 0) { delay(10000); while (C4==0); return '-'; }
RowA = 1; RowB = 1; RowC = 1; RowD = 0; //Test Row D
if (C1 == 0) { delay(10000); while (C1==0); return 'C'; }
if (C2 == 0) { delay(10000); while (C2==0); return '0'; }
if (C3 == 0) { delay(10000); while (C3==0); return '='; }
if (C4 == 0) { delay(10000); while (C4==0); return '+'; }
return 'n'; // Means no key has been pressed
}
char get_key(void) //get key from user
{
char key = 'n'; //assume no key pressed
while(key=='n') //wait untill a key is pressed
key = READ_SWITCHES(); //scan the keys again and again
return key; //when key pressed then return its value
}
LCD is also used almost in every Engineering Project for displaying different values. For example, if you have used the ATM machine, which you must have, then you have seen an LCD there displaying the options to select. Obviously that's quite a big LCD but still LCD. Similarly, all mobile phones are also equipped with LCDs. The LCD we are gonna use in this project is quite small and basic. It is normally known as the 16x2 LCD as it has rows and 2 columns for writing purposes. So, we are gonna interface that LCD with 8051 Microcontroller. The proteus Simulation along with hex file and the programming code in keil uvision 3 is given at the end of this post for download. If you are working with Arduino, then you should have a look at Interfacing of LCD with Arduino. The next level from LCD is Graphical LCD also known as GLCD, so if you wanna know more about that then you should read Interfacing of Arduino with GLCD. So, let's get started with it.
void lcdinit(void)
{
delay(15000);
writecmd(0x30);
delay(4500);
writecmd(0x30);
delay(300);
writecmd(0x30);
delay(650);
writecmd(0x38); //function set
writecmd(0x0c); //display on,cursor off,blink off
writecmd(0x01); //clear display
writecmd(0x06); //entry mode, set increment
}
void writecmd(int z)
{
RS = 0; // => RS = 0
P2 = z; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void writedata(char t)
{
RS = 1; // => RS = 1
P2 = t; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
#include<reg51.h>
//Function declarations
void cct_init(void);
void delay(int);
void lcdinit(void);
void writecmd(int);
void writedata(char);
void ReturnHome(void);
//*******************
//Pin description
/*
P2 is data bus
P1.0 is RS
P1.1 is E
*/
//********************
// Defines Pins
sbit RS = P1^0;
sbit E = P1^1;
// ***********************************************************
// Main program
//
void main(void)
{
cct_init(); //Make all ports zero
lcdinit(); //Initilize LCD
writecmd(0x81);
writedata('w'); //write
writedata('w'); //write
writedata('w'); //write
writedata('.'); //write
writedata('T'); //write
writedata('h'); //write
writedata('e'); //write
writedata('E'); //write
writedata('n'); //write
writedata('g'); //write
writedata('i'); //write
writedata('n'); //write
writedata('e'); //write
writedata('e'); //write
writedata('r'); //write
writedata('i'); //write
writedata('n'); //write
writedata('g'); //write
writecmd(0xc4);
writedata('P'); //write
writedata('r'); //write
writedata('o'); //write
writedata('j'); //write
writedata('e'); //write
writedata('c'); //write
writedata('t'); //write
writedata('s'); //write
writedata('.'); //write
writedata('c'); //write
writedata('o'); //write
writedata('m'); //write
ReturnHome(); //Return to 0 position
while(1)
{
}
}
void cct_init(void)
{
P0 = 0x00; //not used
P1 = 0x00; //not used
P2 = 0x00; //used as data port
P3 = 0x00; //used for generating E and RS
}
void delay(int a)
{
int i;
for(i=0;i<a;i++); //null statement
}
void writedata(char t)
{
RS = 1; // => RS = 1
P2 = t; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void writecmd(int z)
{
RS = 0; // => RS = 0
P2 = z; //Data transfer
E = 1; // => E = 1
delay(150);
E = 0; // => E = 0
delay(150);
}
void lcdinit(void)
{
delay(15000);
writecmd(0x30);
delay(4500);
writecmd(0x30);
delay(300);
writecmd(0x30);
delay(650);
writecmd(0x38); //function set
writecmd(0x0c); //display on,cursor off,blink off
writecmd(0x01); //clear display
writecmd(0x06); //entry mode, set increment
}
void ReturnHome(void) //Return to 0 location
{
writecmd(0x02);
delay(1500);
}
Download Proteus Simulation & Code
That's all for today, in the next post I am gonna share how to display custom characters on LCD with 8051 Microcontroller, because till now you can just display the simple characters like alphabets and numbers on it but can't display the custom characters like arrowhead etc. You should have a look at LCD Interfacing with Microcontrollers, where I have combined all tutorials related to LCD. So stay tuned and have fun.Now, today we are gonna go a little further and will have a look at Serial Communication with 8051 Microcontroller and we will also design the simulation of this project in Proteus ISIS software. 8051 Microcontroller also supports Serial port similar to Arduino and PIC Microcontroller. And the communication protocol is exactly the same as its a Serial Port. But obviously the syntax is bit different as we are not working in Arduino software or MPLAB. So let's get started with it.
#include <reg52.h>
#define Baud_rate 0xFD // BAUD RATE 9600
void SerialInitialize(void);
void SendByteSerially(unsigned char);
void cct_init(void);
sbit Appliance1 = P1^0;
sbit Appliance2 = P1^1;
sbit Appliance3 = P1^2;
sbit Appliance4 = P1^3;
sbit Appliance5 = P1^4;
sbit Appliance6 = P1^5;
sbit Appliance7 = P1^6;
sbit Appliance8 = P1^7;
void main()
{
cct_init();
SerialInitialize();
EA = 1;
ES = 1;
while(1) {;}
}
void cct_init(void) //initialize cct
{
P0 = 0x00; //not used
P1 = 0x00; //Used for Appliances
P2 = 0x00; //not used
P3 = 0x03; //used for serial
}
void SerialInitialize(void) // INITIALIZE SERIAL PORT
{
TMOD = 0x20; // Timer 1 IN MODE 2 -AUTO RELOAD TO GENERATE BAUD RATE
SCON = 0x50; // SERIAL MODE 1, 8-DATA BIT 1-START BIT, 1-STOP BIT, REN ENABLED
TH1 = Baud_rate; // LOAD BAUDRATE TO TIMER REGISTER
TR1 = 1; // START TIMER
}
void SendByteSerially(unsigned char serialdata)
{
SBUF = serialdata; // LOAD DATA TO SERIAL BUFFER REGISTER
while(TI == 0); // WAIT UNTIL TRANSMISSION TO COMPLETE
TI = 0; // CLEAR TRANSMISSION INTERRUPT FLAG
}
void serial_ISR (void) interrupt 4
{
//receive character
char chr;
if(RI==1)
{
chr = SBUF;
RI = 0;
}
P0 = ~P0; //Show the data has been updated
switch(chr)
{
case '1': Appliance1 = 1; SendByteSerially('k'); break;
case '2': Appliance2 = 1; SendByteSerially('k'); break;
case '3': Appliance3 = 1; SendByteSerially('k'); break;
case '4': Appliance4 = 1; SendByteSerially('k'); break;
case '5': Appliance5 = 1; SendByteSerially('k'); break;
case '6': Appliance6 = 1; SendByteSerially('k'); break;
case '7': Appliance7 = 1; SendByteSerially('k'); break;
case '8': Appliance8 = 1; SendByteSerially('k'); break;
case 'a': Appliance1 = 0; SendByteSerially('k'); break;
case 'b': Appliance2 = 0; SendByteSerially('k'); break;
case 'c': Appliance3 = 0; SendByteSerially('k'); break;
case 'd': Appliance4 = 0; SendByteSerially('k'); break;
case 'e': Appliance5 = 0; SendByteSerially('k'); break;
case 'f': Appliance6 = 0; SendByteSerially('k'); break;
case 'g': Appliance7 = 0; SendByteSerially('k'); break;
case 'h': Appliance8 = 0; SendByteSerially('k'); break;
default: ; break; //do nothing
}
RI = 0;
}