Tuesday, 23 August 2016

Lesson 11 Interrupt with PIC Microcontroller - Mikroc

Interrupt is a very important concept in microcontroller. It notifies the microcontroller of an external/internal event or that a device needs its service.
There are 2 ways that a device can notify the microcontroller for its service;

  •    Polling.
  •    Interrupt.
In polling the microcontroller keeps monitoring the status of a particular device, when the condition is met, it services the given device. After that it moves to next device until all the devices are serviced.
This method is not efficient as it wastes much of the microcontroller time polling devices that do not need service.
In interrupt, when a device needs service,
  • The device will send an interrupt signal to the microcontroller to notify it of its service.
  • The microcontroller interrupts whatever it is doing to serve the device on receiving of the interrupt signal.


*** Every interrupt request have an interrupt handler otherwise called Interrupt Service Routine (ISR). The microcontroller runs the ISR on every interrupt request.

*** For every interrupt, there is a fixed location in memory that holds the ADDRESS of its ISR. These group of memory location is called INTERRUPT VECTOR TABLE.
Interrupts can occur either ASYNCHRONUOSLY (External Events) or SYNCHRONUOSLY (usually Timer Interrupt).

STEPS INVOLVED IN EXECUTING AN INTERRUPT
When an interrupt request is made, the microcontroller goes through the following steps:
  • It finishes the instruction it is executing and saves the address of the next instruction (program counter) on the stack.
  • It jumps to Interrupt Vector Table (IVT), the IVT directs the microcontroller to the address of the ISR.
  •  The microcontroller gets the address of the ISR from IVT and jumps to it. It starts to execute the ISR until it reaches the last instruction which is Return from Interrupt Exist.
  • Upon executing the Return from Interrupt Exist instruction, the microcontroller returns to the place where it was interrupted and resumes its normal flow of execution.


There are several sources of interrupt for PIC 16/18 microcontrollers. Most commonly used are the:
  •  Timer Interrupt.
  •  External Interrupt
  •  PORTB change Interrupt etc.


We’ll consider the timer interrupt in this tutorial. The registers associated with Timer interrupt in PIC microcontrollers include:
  • OPTION REG
  • INTCON Register

All interrupts in PIC microcontrollers are enabled/disabled with GIE Bit (Global Interrupt Enable Bit) of INTCON Register. Look up in the device datasheet for more information on INTCON REG
Each interrupt source has 2 bits to control it;
  • One Enables it
  • The other detects when an interrupt occurs


OPTION REG is an 8 bits wide register. Bits 0 – 2 of OPTION REG is used to set Prescaler Value and bit 3 is used to assign the Prescaler to watchdog timer or timer 0. Prescaler divides down the clock signals used for timing giving reduced overflow rate. Refer to device datasheet for more information
Some of PIC 16 timer interrupts are :
  • Timer 0
  • Timer 1
  • Timer 2


This timer interrupt occurs when the timer overflows. For any Overflow time (time for interrupt to occur) you have to load a value to the Timer register. Let’s consider timer 0 (TMR0) in 16F877A, which is an 8 bit register. It will count up to 255 and then overflow occurs and continue counting from 0. When an overflow occurs (when it changes from 255 to 0), it generates an interrupt if TMR0 interrupt and the GIE bit were ENABLED in the INTCON register. That is; T0IE = 1 (Timer 0 Interrupt Enable), GIE = 1

*** For the same interrupt to re-occur, the completion status has to be cleared that is; T0IF=0 (Timer 0 Interrupt Flag) and the Timer Value reloaded into the timer register.

Note: By loading TMR0 Register we can control the count until an overflow occurs (interrupt takes place)

How to Calculate Value to be loaded into the Timer 0 Register
TMRO value = 256 - t / (T * prescaler value)

t = Overflow Time or Time Interrupt Occurs (in microseconds)  

T (Oscillator Period in Microseconds) =  1 / (Internal Oscillator Frequency)

Internal Oscillator Frequency =  Crystal clock / 4

*** In PIC microcontroller instruction takes 4 clock cycles, that’s why you see crystal clock being divided by 4.

Assuming we have PIC 16F877A microcontroller using an external clock of 8 MHz and we are required to generate 200 microseconds interrupt with a Prescaler value of 2. The TMRO Value will be 56 using the above formula.
Internal Oscillator Frequency = 8MHz / 4  = 2MHz

T (Oscillator Period in Microseconds) =  1 / 2MHz = 0.5microseconds

t = Overflow Time or Time Interrupt Occurs (in microseconds) = 200microseconds  

TMRO value = 256 - 200microsec / (0.5microsec * 2)  = 256-200 = 56

There is a handy tool you can use when working with Timer Interrupt. In fact I can’t recall the last time I went through all this mathematics. Timer Calculator does the magic. It is made by Mikroelektronika http://www.libstock.com/projects/view/398/timer-calculator. It one of my best software from Mikroelektronika. You need just 4 easy steps:

  •    Select your device from the device drop down
  •    Choose your clock frequency
  •    Select the timer interrupt you want
  •    Select Interrupt time
After this 4 steps, you click the calculate button and you are home and done. You can copy the generated code to your Main program.

Lets write a program to blink PORTD and PORTB LEDs. PORTD LED will blink every 200ms, PORTB every 1sec using TIMER 0 Interrupt

Mikroc code:


 /**********************************
Project Name :
    Interrupt with PIC Microcontroller
Author : Promise
Description :
    this program demontrates the use of timer0 interrupt
    Interrupt is generated every ms
   the program blinks a led attached to PORTD every 200ms. it also blinks another led at PORTB every second
Test configuration:
   MCU:  PIC 18F45K22
   Oscillator: XT 8.0000 MHz, 8.0000 MHz Crystal
   Dev Board : Easy Pic v7
***********************************/

 volatile  unsigned int count1 = 0 ;
 volatile unsigned int count2= 0 ;

 void Interrupt(){
  if (TMR0IF_bit){
    TMR0IF_bit = 0;
    TMR0L         = 0x06;
    ++count1 ;        // timer configured to generate 1ms periodic ticks
    ++count2 ;
  }
}


void InitTimer0(){

  T0CON         = 0xC2;
  TMR0L         = 0x06;
  GIE_bit         = 1;
  TMR0IE_bit         = 1;
}

void task_1 (){
   if (count1 ==200)    //blinks led every 200ms
      {
       count1 = 0;
       LATD = ~ LATD;
       }
}

void task_2 () {
      if (count2 == 1000)     // blinks every second
      {
         count2 = 0;
         LATB = ~ LATB;
      }

}

void main() {

  TRISD = 0x00;
  TRISB = 0x00;
  // clear output bit
  LATD = 0x00;
  LATB = 0x00;
  
  InitTimer0();

           while (1)  {
              task_1 ();  //blinks every 200ms
              task_2 ();  // blinks every 1 sec

           }
}









Monday, 8 August 2016

Lesson 10 Multiplexing of Seven Segment Display with PIC Microcontroller - MikroC

In the previous tutorial we showed how to interface Seven Segment Display(SSD) with PIC microcontroller. For most applications like in digital clocks, meters, etc, it usually require more SSD units.
One SSD takes up 7 i/o ports of the microcontroller, that means 2 SSD will consume 14 i/o ports and 3 will take up 21 i/o ports excluding the decimal connection. This is not reasonable, being that the SSD unit can be just a part of a big project you intend to build.

There's a technique that can be used to serve up i/o ports of the microcontroller. This is called multiplexing.
Multiplexing uses Persistence of Vision of human eyes. Human eyes cannot detect visual changes at a rate of 25 frames/sec. This means any transition effect in which the time difference is less than 1/25 sec, the human eye will not notice it.

This concept is used in Multiplexing of SSD. Only one out the  4 SSD units  used in this project comes ON at a time, but they change their ON/OFF condition very fast creating the impression that all the digits are ON at the same time. The Proteus Schematic is shown below

Proteus Schematic

In the Proteus Schematic above, SSD is connected to PORT B and the transistors (which act like a switch) are connected to PORT A.
The 1st byte which represent Unit digit is sent to the SSD via PORT B and the 1st transistor is activated at the same time, after a short time it is turned OFF.
The tens digit is sent to the SSD, and the corresponding transistor is activated at the same time, after a short time, it is turned OFF. This same is repeated for the hundred and thousand byte.
The whole process is continuously repeated at high speed for all digit and their corresponding transistors.

*** Please note on Easy PIC V7, the SSD unit is connected to PORT D. In our Proteus design we used PORTB. Also the code below is for 18F45K22 which is the chip that comes with Easy PIC V7. To use with 16F877A comment out ANSELA and ANSELD

MikroC Code:

/**********************************
Project Name :
   Multiplexing of 7 segment display with PIC 18F45K22
Author : Promise
Description :
   This project demonstrate multiplexing of 4 7 segment display. it counts from 0000 - 9999
Test configuration:
   MCU:  PIC 18F45K22
   Oscillator: XT 8.0000 MHz
   Dev Board : Easy Pic v7
 turn on switches SW4.0, SW4.1, SW4.2, SW4.3
***********************************/


unsigned int unit,tens,hundreds,thousand ;
unsigned int counter = 0;
unsigned int digit = 0;


 unsigned int display(unsigned int digit1) {

   unsigned int my_digit;
   unsigned int array[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; // array holding common cathode 7 segment look up table for 0-9
   my_digit = array[digit1];
   return (my_digit) ;
     
     }
 

 void short_delay(){    // delay function to control how digit is incremented

     if(counter<100){
      counter++  ;
      if(counter==100){
      digit++ ;
      counter = 0;  }
      if(digit==9999){
      digit = 0;
      }
  }
           }

void main() {

 ANSELA = 0;
 ANSELD = 0;
  TRISD = 0x00;    // set PORTD as output
  TRISA = 0x00;

  TRISA.F0 = 0;    // set PORTA bit 0-3 as output
  TRISA.F1 = 0;
  TRISA.F2 = 0;
  TRISA.F3 = 0;

   PortA.F0 = 0;  //turn off PORTA bit 0-3
   PortA.F1 = 0;
   PortA.F2 = 0;
   PortA.F3 = 0;

 while(1) {
   
  short_delay();                    // call delay function

   unit = digit % 10 ;               //extract unit from digit
   PORTD = display(unit);            // send  unit value to PORTD
   PortA.F0 = 1;                     // turn ON 1st 7 segment (LSD 7 Segment display)
   PortA.F1 = 0;
   PortA.F2 = 0;
   PortA.F3 = 0;
   delay_ms(1);
   PortA.F0 = 0;

   tens =  (digit / 10) % 10 ;        //extract tens from digit
   PORTD = display(tens);              // send tens value to PORTD
   PortA.F0 = 0;
   PortA.F1 = 1;                       // turn ON 2nd 7 segment
   PortA.F2 = 0;
   PortA.F3 = 0;
   delay_ms(1);
   PortA.F1 = 0;

   hundreds =  (digit / 100) % 10;    //extract hundreds from digit
  PORTD = display(hundreds);          // send hundreds value to PORTD
   PortA.F0 = 0;
   PortA.F1 = 0;
   PortA.F2 = 1;                      // turn ON 3rd 7 segment
   PortA.F3 = 0;
   delay_ms(1);
   PortA.F2 = 0;

    thousand =  digit / 1000 ;        //extract thousand from digit
  PORTD = display(thousand);           // send  thousand value to PORTD
   PortA.F0 = 0;
   PortA.F1 = 0;
   PortA.F2 = 0;
   PortA.F3 = 1;                       // turn ON 4th 7 segment
   delay_ms(1);
   PortA.F3 = 0;
   }
}

Thursday, 4 August 2016

Lesson 9 Interfacing Keypad with PIC Microcontroller - MikroC

Keypad finds its application where there is need for the user to enter alpha-numeric inputs. In this tutorial, we'll consider how a matrix keypad is interfaced with a PIC microcontroller. Keypads comes in various sizes 3x3, 4x3 ,4x4. we're making use of a 4x4 matrix keypad, which is a basically a combination of push buttons in a matrix form. these arrangements allows for less i/o ports of the microcontroller to be used by the keypad.
A 4x4 keypad will require 8 i/o lines. the keypad is connected to the microcontroller (PIC18F45K22) as shown below in the Proteus Schematic:
Proteus Schematic
column pins is connected to D0-D3
Row pins is connected to D4-D7

Keypad scanning is done to determine which key is pressed. 
A high signal is sent to one of the column lines: for instance, a logic high is given to col. 1 which is connected to PORT D0, the microcontroller reads the state of the row pins PORT D4 - D7, if the D-Row (PORT D7) is high, then the  asterisk (*) button is pressed. A logic high signal is also applied to other columns through the microcontroller port and the rows are read again.

 Assuming col 2 is high, the microcontroller reads the state of the row pins PORT D4 - D7, if Row C (PORT D6) is high, then 8 button is pressed.

This procedure is repeated for all the columns continuously.
MikroC has library functions for keypad inputs, go to the MikroC help files and search for Keypad. The library routines are:
  • keypad_Init()
  • keypad_Key_Press()
  • keypad_Key_Click()
Remember to check the help files to see how to use them.

MikroC Code:

/**********************************
Project Name :
   Interfacing keypad with PIC 18F45k22
Author : Promise
Description :
   This project demonstrate how to interface A MATRIX keypad with PIC 18F45K22. The keypad is connected to PORTD, and the LCD PORTB
Test configuration:
     MCU:             PIC18F45K22
                    http://ww1.microchip.com/downloads/en/DeviceDoc/41412D.pdf
     Dev.Board:       EasyPIC7
                      http://www.mikroe.com/easypic/
     Oscillator:      16.00000 MHz
     SW:              mikroC PRO for PIC
                      http://www.mikroe.com/mikroc/pic/
 * NOTES:
     - Pull-down PORTD (PortD three-state switch).
     - Turn on LCD backlight SW4.6 (board specific)
***********************************/


unsigned short kp, count, oldstate = 0;
char txt[6];

// Keypad module connections
char  keypadPort at PORTD;
// End Keypad module connections

// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections

void main() {
  count = 0;                                 // Reset counter
  Keypad_Init();                           // Initialize Keypad
  ANSELB = 0;                              // Configure AN pins as digital I/O
  ANSELD = 0;
  Lcd_Init();                              // Initialize LCD
  Lcd_Cmd(_LCD_CLEAR);                     // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);                // Cursor off

  Lcd_Out(1, 1, "Press any Key");                 // Write message text on LCD
  Lcd_Out(2, 1, "After 2 secs");
  delay_ms(2000);
  Lcd_Cmd(_LCD_CLEAR);                     // Clear display
  
  do {
    kp = 0;                                // Reset key code variable

    // Wait for key to be pressed and released
    do
      // kp = Keypad_Key_Press();          // Store key code in kp variable
      kp = Keypad_Key_Click();             // Store key code in kp variable
    while (!kp);
   // Prepare value for output, transform key to it's ASCII value
    switch (kp) {
      //case 10: kp = 42; break;  // '*'   // Uncomment this block for keypad4x3
      //case 11: kp = 48; break;  // '0'
      //case 12: kp = 35; break;  // '#'
      //default: kp += 48;

      case  1: kp = 49; break; // 1        // Uncomment this block for keypad4x4
      case  2: kp = 50; break; // 2
      case  3: kp = 51; break; // 3
      case  4: kp = 65; break; // A
      case  5: kp = 52; break; // 4
      case  6: kp = 53; break; // 5
      case  7: kp = 54; break; // 6
      case  8: kp = 66; break; // B
      case  9: kp = 55; break; // 7
      case 10: kp = 56; break; // 8
      case 11: kp = 57; break; // 9
      case 12: kp = 67; break; // C
      case 13: kp = 42; break; // *
      case 14: kp = 48; break; // 0
      case 15: kp = 35; break; // #
      case 16: kp = 68; break; // D

    }

    Lcd_Chr(1,++count, kp);                    // Print key ASCII value on LCD

    if (count == 16) {                               // If counter variable overflow
      Lcd_Out(2, 1, "Wait for 2 secs");
      delay_ms(2000);
      count = 0;                                                 //Reset counter
      Lcd_Cmd(_LCD_CLEAR);                     // Clear display
      }

    } while (1);
}


Sunday, 28 February 2016

Lesson 8 Interfacing 7 Segment Display With PIC 16F877A (MikroC)

Seven Segment Display (SSD) is commonly used in counters, electronic meters, digital clocks, etc.
It is composed of 8 LEDs, 7 of the LEDs are arranged  in rectangular form to display numbers from 0-9 and also characters A-F. The 8th LED is for decimal point display.
There two types of SSD:
  • Common Cathode.
  • Common Anode.
In Common Cathode, all the cathode of the diodes are connected to a common pin. while in Common Anode, all the anode are connected to a common pin.
Segments are marked with a-g                                            
                                                 
    Each diode is treated separately, that is : when connecting it to a microcontroller, each diode must have its own limiting resistor. For you to display numbers or characters on SSD, the binary format of each digit must be replaced with different combination of bits (masking). For instance to display 2, which is 0000 0010 in binary it is replaced with 0110 1101. 

Here is a look up table for displaying 0 - F on a common cathode SSD.
                        
                       


By sending this numbers one after the other to the PORT where the SSD is connected, you have a counter from 0 - F . 
MikroC has SSD Editor which you can use to get this numbers for both common Cathode and Common Anode. On the Tool Bar click on  the 7 symbol and it will pop up.

       

MikroC Code:

/**********************************
Project Name :
   Interfacing of 7 segment display with PIC 16F877A
Author : Promise
Description :
   This project demonstrate how to interface 7 segment display with PIC 16F877A. it counts from 0 - F
Test configuration:
   MCU:  PIC 16F877A
   Oscillator: XT 8.0000 MHz, 8.0000 MHz Crystal
   Dev Board : Easy Pic v7
 turn on switches SW4.0, SW4.1, SW4.2, SW4.3
 For common Cathode 7 segment display, Uncomment count1[16]
***********************************/


unsigned int i;

//unsigned int count1[16] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};  //array for common cathode display (0-15)

unsigned int count[16] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};  //array for common anode display (0-15)

void main() {

  TRISB  = 0x00;           //Configure PORTB as Outputs
  
  while(1) {
  
   for(i=0;i<16;i++){       // loop through array element
   PORTB = count[i];       // send arrray elemnts to PORTB
   delay_ms(500);
   }
   }
 }

Proteus Schematic for Common Anode:


Proteus Schematic for Common Cathode:




Saturday, 27 February 2016

Lesson 7 Interfacing Servomotor with PIC 16F877A - MikroC


Servos are used in cars, boats, helicopters, robots etc. They are geared DC motors with positional feedback control that allows for the rotor to be accurately positioned. The gear drives the output shaft and also control an internal potentiometer. The potentiometer feeds back the output shaft position to the internal control devices that control the DC motor. Servos can be rotated through 180 degrees (+ or - 90 degrees) though its internals can be modified to give full 360 degree rotation.

It has 3 wires: power (5v), ground, and the control wire. By sending pulse width signals to the control wire, the shaft can be rotated. The pulse can be varied from 1 - 2 miliseconds.
1 ms will rotatae the shaft counter clockwise (-90 degrees).
1.5 ms will rotate the shaft to its neutral axis (0 degrees)  
2 ms will rotate the shaft in clockwise direction (+90 degrees).
Any pulse width in between moves  the shaft between these positions (+ or - 90 degrees)






        MikroC Code:
     
/**********************************
Project Name :
   Interfacing Servomotor with PIC 16F877A
Author : Promise
Description :
   This project demonstrate how to interface a servomotor with PIC 16F877A. It rotates back and forth (CW and CCW) continuously

Test configuration:
   MCU:  PIC 16F877A
   Oscillator: XT 8.0000 MHz, 8.0000 MHz Crystal
***********************************/

unsigned i ;

void main() {

TRISB.B0 = 0;             // set PORTB bit zero to output

while(1){

for(i=0;i<100;i++){        // rotate to neutral axis (0 degree)
PORTB.B0 = 1;
delay_us(1500);             // generate 1.5ms pulse
PORTB.B0 = 0;
  delay_ms(20);            // 50Hz frequency for servo to react
}

for(i=100;i<200;i++){     // rotate CounterClock wise CCW (-90 degree)
PORTB.B0 = 1;
delay_ms(1);              // generate 1ms pulse
PORTB.B0 = 0;
  delay_ms(20);           // 50Hz frequency for servo to react
}

for(;i>100;i--){         // rotate ClockWise CW (+90 degree)
PORTB.B0 = 1;
delay_ms(2);             // generate 2ms pulse
PORTB.B0 = 0;
 delay_ms(20);           // 50Hz frequency for servo to react
}
}
}

Proteus Schematic:

   
      

Thursday, 23 July 2015

Flowcode Lesson 5 LCD Interfacing With PIC 16F877A

Liquid Crystal Display(LCD) is used for displaying messages. In this tutorial we are using 2x20  LCD. It has 2 lines and 40 characters per line. Only the first 20 characters of each line are visible. The LCD  has 14 pins plus 2 additional pins for its backlight.
You can watch or download the video here

Flowcode Lesson 4 Forward and Backward blinking of LED array

In this tutorial we are going to show you how you can use flowcode to make an array of LED to blink Forward and Backward.
You can watch or download the video here.