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; }