Thursday, March 31, 2016

RC5 remote control protocol decoder using PIC16F877A and CCS PIC C

PIC16F877A RC-5 decoder
The RC-5 protocol was developed by Philips in the late 1980s as a semi-proprietary consumer IR (infrared) remote control communication protocol for consumer electronics.
The RC5 has 14 bits per 1 code transmission, the 14 bits can be divided into 4 parts:

The first 2 bits are start bits and they are always logic 1.
The third bit called toggle bit, it can be logic 1 or logic 0.
The next 5 bits are address bits, each device type has its address number for example TV address number is 0, CD player address = 20 ............
And the last 6 bits are command bits, each button has its command number.
For the same device for example TV all the remote control buttons has the same address but each button has its command.
The toggle bit changes whenever a button is pressed.
The RC5 protocol uses Manchester coding, logic 1 and logic 0 are coded as shown in the following drawing where toggle bit is 1, address = 0 and command is 2: 
RC5 IR remote control protocol coding 
This link from Wikipedia has more details about Philips RC5 protocol.
RC5 IR remote control protocol decoder using PIC16F877A microcontroller: This topic shows how to decode and get RC5 data of a TV remote control uses RC5 protocol with PIC16F877A microcontroller and CCS PIC C compiler.
The project circuit schematic is shown below.
 PIC16F877A RC5 IR remote control decoder circuit CCS PIC C
The IR receiver is used to receive the IR signals transmitted from the remote control and convert this signals to a digital data (logic 0, logic 1). The microcontroller PIC16F877A reads digital data from the IR receiver, this data is decoded and the results displayed on 1602 LCD display. The LED which is connected to RB1 pin blinks when RC5 protocol is received.
The following drawing shows how the IR receiver receive and transmit data to the microcontroller:
IR receiver circuit 
RC5 IR remote control protocol decoder using PIC16F877A CCS PIC C code:
The code is written and compiled with CCS C compiler.
I made the code simple as I can, no Timer module and no interrupt are used.
The microcontroller waits until the IR receiver receives IR data which means it waits until RB0 pin goes from high to low.
The 2 start bits are used to check if the received IR signal uses RC5 protocol. Each bit is 1778us long. The fist start bit is 1 which means it is 0 for 889us and 1 for 889us, the first 889us is not detected because RB0 not triggered yet and the second 889us is detected using the following code:
while((input(PIN_B0) == 0) && (count < 20)){
  count++;
  delay_us(50);}
  if( (count > 20) || (count < 14))

    goto ret;
The signal is checked every 50us and a variable (count) is used to count number of 50s, for example if count = 5 so the total time before RB0 goes high is 250us.
If count >= 20 it means time out and the received signal is high for more than 889us.
If count < 14 it means signal high time is lower than 889us.
The second start bit is checked using the following code:
// Check first 889us
while((input(PIN_B0)) && (count < 20)){
   count++;
    delay_us(50);}
    if( (count > 20) || (count < 14))            

      goto ret;
// Check 2nd 889us
      count = 0;
while((input(PIN_B0) == 0) && (count < 40)){
  count++;
  delay_us(50);}
  if( (count > 40) || (count < 14))      // Signal doesn't use RC5 protocol
    goto ret;                           
  if(count > 30)
    delay_us(400);
  else          
    delay_us(1200);

Second bit checking is the same as the first bit checking except that low both 889us are checked.
After the 2nd start bit there is toggle bit which is 1 or 0, and if toggle bit is 0 time required for RB0 pin is 1778us which means to start reading bits we have to add a delay about 400us, and if the toggle bit is 1 we have to wait 1200us.
The following drawing shows the 2 start bit with toggle bit when it's 0 and when it's 1:
RC-5 IR remote control code
And the following drawing shows when the microcontroller reads the RC5 bits:
RC5 IR remote control decoding
The complete RC5 decoder CCS C code is as the following below.
// RC5 remote control protocol decoder using PIC16F877A
// http://ccspicc.blogspot.com/
// electronnote@gmail.com

//LCD module connections
#define LCD_RS_PIN PIN_C0
#define LCD_RW_PIN PIN_C1
#define LCD_ENABLE_PIN PIN_C2
#define LCD_DATA4 PIN_C3
#define LCD_DATA5 PIN_C4
#define LCD_DATA6 PIN_C5
#define LCD_DATA7 PIN_C6
//End LCD module connections

#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock = 8000000)
#include <lcd.c>
#use fast_io(B)

int1 toggle;
unsigned int8 count, i, address, command;
void main(){
  port_b_pullups(TRUE);                  // Enable PORTB pull-ups
  output_b(0);                           // PORTB initial state
  set_tris_b(1);
  lcd_init();                            // Initialize LCD module
  lcd_putc('\f');                        // LCD clear
  lcd_gotoxy(3, 1);                      // Go to column 3 row 1
  lcd_putc("RC5 protocol");
  lcd_gotoxy(5, 2);                      // Go to column 5 row 2
  lcd_putc("decoder");
  while(TRUE){
    ret:
    count = 0;
    output_low(PIN_B1);
    while(input(PIN_B0));                // Wait until RB0 pin falls
    // Check if the received signal uses RC5 protocol
    while((input(PIN_B0) == 0) && (count < 20)){
      count++;
      delay_us(50);}
    if( (count > 20) || (count < 14))      // Signal doesn't use RC5 protocol
      goto ret;                            // Return
    count = 0;
    while((input(PIN_B0)) && (count < 20)){
      count++;
      delay_us(50);}
    if( (count > 20) || (count < 14))      // Signal doesn't use RC5 protocol
      goto ret;                            // Return
    count = 0;
    while((input(PIN_B0) == 0) && (count < 40)){
      count++;
      delay_us(50);}
    if( (count > 40) || (count < 14))      // Signal doesn't use RC5 protocol
      goto ret;                            // Return
    // End check (The received signal uses RC5 protocol)
    if(count > 30)
      delay_us(400);
    else
      delay_us(1200);
    output_high(PIN_B1);                        // Toggle RB1 LED
    for(i = 0; i < 12; i++){
      if(i == 0){
        if(input(PIN_B0) == 1)   toggle = 0;
        else                     toggle = 1;
        }
      else {
        if(i < 6){                                //Read address bits
          if(input(PIN_B0) == 1)
            bit_clear(address, (5 - i));          //Clear bit (5-i)
          else
            bit_set(address, (5 - i));           //Set bit (5-i)
          }
        else {                                 //Read command bits
          if(input(PIN_B0) == 1)
            bit_clear(command, (11 - i));        //Clear bit (11-i)
          else
            bit_set(command, (11 - i));          //Set bit (11-i)
          }
        }
      delay_us(1778);
      }
                     // Display results
    address &= 0x1F;
    command &= 0x3F;
    lcd_putc('\f');
    lcd_gotoxy(2, 1);
    lcd_putc("Toggle bit:");
    lcd_gotoxy(1, 2);
    lcd_putc("Adds:");
    lcd_gotoxy(9, 2);
    lcd_putc("Cmd:");
    lcd_gotoxy(14, 1);
    printf(lcd_putc,"%1u",toggle);
    lcd_gotoxy(6, 2);
    printf(lcd_putc,"%2u",address);
    lcd_gotoxy(14, 2);
    printf(lcd_putc,"%2u",command);
    }
}

RC5 IR remote control protocol decoder using PIC16F877A video:
The following video shows the project using hardware circuit with some details.

Tuesday, March 29, 2016

DC motor speed and direction control with PIC18F4550 microcontroller

DC motor control with PIC18F4550 and H-Bridge
The microcontroller PIC18F4550 has two CCP modules CCP1 and CCP2, the CCP1 module is implemented as a standard CCP module with Enhanced PWM capabilities. These include the provision for 2 or 4 output channels, user-selectable polarity, dead-band control and automatic shutdown and restart.
The Enhanced PWM mode provides additional PWM output options for a broader range of control applications. The module is a backward compatible version of the standard CCP module and offers up to four outputs, designated P1A through P1D.
This topic shows how to use the enhanced PWM as a Full-Bridge Mode to control DC motor speed and direction.
In Full-Bridge Output mode, four pins are used as outputs; however, only two outputs are active at a time. In the Forward mode, pin P1A is continuously active and pin P1D is modulated. In the Reverse mode, pin P1C is continuously active and pin P1B is modulated.
P1A, P1B, P1C and P1D outputs are multiplexed with the PORTC<2>, PORTD<5>, PORTD<6> and PORTD<7> data latches. The TRISC<2>, TRISD<5>, TRISD<6> and TRISD<7> bits must be cleared to make the P1A, P1B, P1C and P1D pins outputs.
The motor speed is controlled when the PWM duty cycle changes.
An H-Bridge circuit is used to reverse motor terminals which gives us the ability to change rotation direction.
Related topics:
DC motor speed control with PIC18F4550 and CCS PIC C
PIC18F4550 ADC example with CCS PIC C compiler
PIC18F4550 PWM example using CCS PIC C

DC motor control with PIC18F4550 microcontroller circuit:
The following circuit schematic shows project circuit.
PIC18F4550 DC motor speed and direction control circuit CCS PIC C
PORTB internal weak pull-ups are enabled.
There are 3 pushbuttons in the circuit 2 of them to choose rotation direction and the other one stops the motor. The two LEDs indicate rotation direction, if Direction 1 button is pressed the motor moves in the first direction and LED 1 on and the same thing for Direction 2 button and LED 2. The motor speed is controlled from potentiometer connected to RA0 (analog channel 0). The microcontroller PIC18F4550 reads analog data from channel 0 and use the digital value to set the PWM duty cycle.
The PWM frequency is 500Hz.
The basic elements of the H-bridge are the four MOSFETs (2 N-type and 2 P-type).
PIC18F4550 microcontroller internal oscillator is used and set to 8MHz.
DC motor control with PIC18F4550 CCS PIC C code:
PIC18F4550 Timer2 is configured to generate a PWM frequency of 500Hz and the microcontroller runs with its internal oscillator at 8MHz.
The microcontroller PIC18F4550 reads RA0 analog value and stores the digital value on variable (i), this variable is used to set the PWM duty cycle.
// Dc motor control with PIC18F4550 CCS PIC C code
// http://ccspicc.blogspot.com/
// electronnote@gmail.com

#include <18F4550.h>
#device ADC = 10
#fuses NOMCLR INTRC_IO
#use delay(clock = 8000000)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)

unsigned int16 i ;
void main(){
  setup_oscillator(OSC_8MHZ);            // Set internal oscillator to 8MHz
  port_b_pullups(TRUE);                  // Enable PORTB pull-ups
  output_b(0);                           // PORTB initial state
  set_tris_b(7);                         // Configure RB0, RB1 & RB2 as inputs
  output_c(0);                           // PORTC initial state
  set_tris_c(0);                         // Configure PORTC pins as outputs
  output_d(0);                           // PORTD initial state
  set_tris_d(0);                         // Configure PORTD pins as outputs
  setup_adc(ADC_CLOCK_DIV_8);            // Set ADC conversion time to 8Tosc
  setup_adc_ports(AN0);                  // Configure AN0 as analog input
  set_adc_channel(0);                    // Select channel AN0
  setup_timer_2(T2_DIV_BY_16, 250, 1);   // Set PWM frequency to 500Hz
  delay_ms(100);                         // Wait 100ms
  while(TRUE){
    i = read_adc();                      // Read from AN0 and store in i
    set_pwm1_duty(i);                    // Set pwm1 duty cycle
    delay_ms(10);                        // Wait 10ms
    if(input(PIN_B0) == 0){              // If RB0 button pressed
      if(input(PIN_B3) == 0){            // If direction 1 not already selected
        output_b(0);                     // Both LEDs OFF
        setup_ccp1(CCP_OFF);             // CCP1 OFF
        output_c(0);                     // PORTC pins low
        output_d(0);                     // PORTD pins low
        delay_ms(100);                   // Wait 100ms
        setup_ccp1(CCP_PWM | CCP_PWM_FULL_BRIDGE);
                                         // Configure CCP1 as a PWM output forward
        output_high(PIN_B3);             // RB3 LED ON
        }}
    if(input(PIN_B1) == 0){              // If RB1 button pressed
      if(input(PIN_B4) == 0){            // If direction 2 not already selected
        output_b(0);                     // Both LEDs OFF
        setup_ccp1(CCP_OFF);             // CCP1 OFF
        output_c(0);                     // PORTC pins low
        output_d(0);                     // PORTD pins low
        delay_ms(100);                   // Wait 100ms
        setup_ccp1(CCP_PWM | CCP_PWM_FULL_BRIDGE_REV);
                                         // Configure CCP1 as a PWM output reverse
        output_high(PIN_B4);             // RB4 LED ON
        }}
    if(input(PIN_B2) == 0){              // If RB2 button pressed
      setup_ccp1(CCP_OFF);               // CCP1 OFF
      output_b(0);                       // Both LEDs OFF
      output_c(0);                       // PORTC pins low
      output_d(0);                       // PORTD pins low
      }
   }
}

DC motor control with PIC18F4550 video:
The following video shows more about this project with hardware circuit.
Reference:
Microchip PIC18F4550 datasheet.

DC motor speed and direction control with PIC16F877A and H-bridge

DC motor control with PIC16F877A and CCS PIC C
The microcontroller PIC16F877A has two CCP modules CCP1 and CCP2, these modules could be used as PWM yo generate two PWM signals. In this topic we are going to see how to use the two modules to control a DC motor speed and direction.
We can control the speed of DC motor using PWM technique as shown in the following topic:
DC Motor speed control with PIC16F877A and CCS PIC C compiler
And the direction of the DC motor can be controlled using H-Bridge circuit which allows us to reverse terminals polarity of the motor.
Related topics:
PIC16F877A ADC example with CCS PIC C compiler
PIC16F877A PWM example with CCS PIC C compiler
DC motor control with PIC16F877A circuit:

The following circuit schematic shows the full circuit of the project.
PIC16F877A DC motor speed and direction control with H bridge circuit CCS PIC C
PORTB internal weak pull-ups are enabled.
There are 3 pushbuttons in the circuit 2 of them to choose rotation direction and the other one stops the motor. The two LEDs indicate rotation direction, if Direction 1 button is pressed the motor moves in the first direction and LED 1 on and the same thing for Direction 2 button and LED 2. The motor speed is controlled from potentiometer connected to RA0 (analog channel 0). The microcontroller PIC16F877A reads analog data from channel 0 and use the digital value to set the PWM duty cycle. If direction 1 button is pressed the microcontroller starts PWM1 (RC2 pin) and stops PWM2 (RC1 pin) and if direction 2 button is pressed the microcontroller stops PWM1 (RC2 pin) and starts PWM2 (RC1 pin), when the stop button is pressed the microcontroller stops PWM1 and PWM2 signals and the motor will stop.
The PWM (PWM1 & 2) frequency is 500Hz.
The basic elements of the H-bridge are the four MOSFETs (2 N-type and 2 P-type).
DC motor control with PIC16F877A CCS PIC C code:
PIC16F877A Timer2 is configured to generate a PWM frequency of 500Hz and the microcontroller runs with 8MHz crystal oscillator.
The microcontroller PIC16F877A reads RA0 analog value and stores the digital value on variable (i), this variable is used to set duty cycle of the active PWM (PWM1 or PWM2).
// DC motor control using PIC16F877A CCS C code
// http://ccspicc.blogspot.com/
// electronnote@gmail.com

#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device ADC = 10
#use delay(clock = 8000000)
#use fast_io(B)
#use fast_io(C)

unsigned int16 i ;
void main(){
  port_b_pullups(TRUE);                  // Enable PORTB pull-ups
  output_b(0);                           // PORTB initial state
  set_tris_b(7);                         // Configure RB0, RB1 & RB2 as inputs
  output_c(0);                           // PORTC initial state
  set_tris_c(0);                         // Configure PORTC pins as outputs
  setup_adc(ADC_CLOCK_DIV_32);           // Set ADC conversion time to 32Tosc
  setup_adc_ports(AN0);                  // Configure AN0 as analog
  set_adc_channel(0);                    // Select channel AN0
  setup_timer_2(T2_DIV_BY_16, 250, 1);   // Set PWM frequency to 500Hz
  delay_ms(100);                         // Wait 100ms
  while(TRUE){
    i = read_adc();                      // Read from AN0 and store in i
    if(input(PIN_B3) == 1)               // If direction 1 is selected
      set_pwm1_duty(i);                  // Set pwm1 duty cycle
    if(input(PIN_B4) == 1)               // If direction 2 is selected
      set_pwm2_duty(i);                  // Set pwm2 duty cycle
    delay_ms(10);                        // Wait 10ms
    if(input(PIN_B0) == 0){              // If RB0 button pressed
      if(input(PIN_B3) == 0){            // If direction 1 not already selected
        output_b(0);                     // Both LEDs OFF
        setup_ccp1(CCP_OFF);             // CCP1 OFF
        setup_ccp2(CCP_OFF);             // CCP2 OFF
        output_c(0);                     // PORTC pins low
        delay_ms(100);                   // Wait 100ms
        setup_ccp1(CCP_PWM);             // Configure CCP1 as a PWM
        output_high(PIN_B3);             // RB3 LED ON
        }}
    if(input(PIN_B1) == 0){              // If RB1 button pressed
      if(input(PIN_B4) == 0){            // If direction 2 not already selected
        output_b(0);                     // Both LEDs OFF
        setup_ccp1(CCP_OFF);             // CCP1 OFF
        setup_ccp2(CCP_OFF);             // CCP2 OFF
        output_c(0);                     // PORTC pins low
        delay_ms(100);                   // Wait 100ms
        setup_ccp2(CCP_PWM);             // Configure CCP2 as a PWM
        output_high(PIN_B4);             // RB4 LED ON
        }}
    if(input(PIN_B2) == 0){              // If RB2 button pressed
      setup_ccp1(CCP_OFF);               // CCP1 OFF
      setup_ccp2(CCP_OFF);               // CCP2 OFF
      output_c(0);                       // PORTC pins low
      output_b(0);}                      // Both LEDs OFF
   }
}

DC motor control with PIC16F877A video:
The following video shows more about this project with hardware circuit.

Sunday, March 27, 2016

DC Motor speed and direction control with PIC16F84A using H-bridge

Interfacing DC motor with PIC16F84A using H-bridge
We can control DC motor speed and direction using H-bridge circuit, the H-bridge circuit allows us to reverse power supply polarity and with PWM technique we can easily control the speed of the motor. This topic shows how to control the speed and direction of 12V DC motor using PIC16F84A microcontroller and H-bridge circuit.
I want to see how to control DC motor speed using PIC16F84A visit the following topic:
DC motor speed control using PIC16F84A and CCS PIC C

DC Motor speed and direction control with PIC16F84A circuit:
The following circuit schematic shows the full circuit of the project with the H-bridge circuit.
DC motor speed and direction control using PIC16F84A circuit CCS PIC C
The basic elements of the H-bridge are the four MOSFETs (2 N-type and 2 P-type).
In the circuit there are 5 buttons, the first button which is connected to RB0 pin is used to speed up the motor, and speed down button to decrease motor speed. Third and fourth buttons are used to choose direction rotation of the motor (direction 1 or direction 2). The last button stops the motor no matter what speed or direction.
There are 3 LEDs, LED1 and LED2 are used to indicate motor direction rotation, and the other LED indicates maximum speed which means when it is on the motor runs at maximum speed.
When speed up button is pressed the PWM duty cycle increases which causes the motor to increase its speed and when the duty cycle = 100 LED 3 turned on. In the other hand if speed down button is pressed the duty cycle decreases and the motor speed also decreases.
If the stop button pressed the motor stops and the 3 LEDs turned off.
Software PWM is used wih frequency of 500Hz.
DC Motor speed and direction control with PIC16F84A CCS C code:
The full C code is shown below. Official software PWM library which comes with CCS PIC C compiler is used, this library uses Timer0 to generate the PWM signal.
// DC motor speed control using PIC16F84A CCS C code
// http://ccspicc.blogspot.com/
// electronnote@gmail.com

#include <16F84A.h>
#fuses HS,NOWDT,PUT,NOPROTECT
#use delay(clock = 8000000)
#use fast_io(B)
#use fast_io(A)
#use pwm(output = pin_a0, output = pin_a1, timer = 0, frequency= 500Hz, duty = 0)

unsigned int8 i = 1;
void main() {
  port_b_pullups(TRUE);                // Enable PORTB pull-ups
  output_a(0);                         // PORTA initial state
  set_tris_a(0);                       // All PORTA pins are configured as outputs
  output_b(0);                         // PORTB initial state
  set_tris_b(0x1F);                    // Configure RB0 to RB4 as inputs
  pwm_off();                           // Turn off all pwm outputs
  while(TRUE) {
    if(input(PIN_B0) == 0){            // If RB0 button pressed
      i++;                             // Increment i by 1 (i = i + 1)
      if(i > 99){
        i = 100;
        output_high(PIN_B7);}          // RB7 LED ON
      pwm_set_duty_percent(i * 10UL);  // Duty cycle change in tenths %
      delay_ms(100);      }            // Wait 100ms
    if(input(PIN_B1) == 0){            // If RB1 button pressed
      output_low(PIN_B7);              // RB7 LED OFF
      i--;                             // Decrement i by 1 (i = i - 1)
      if(i < 1)
        i = 1;
      pwm_set_duty_percent(i * 10UL);  // Duty cycle change in tenths %
      delay_ms(100);      }            // Wait 100ms
    if(input(PIN_B2) == 0){            // If RB2 button pressed
      if(input(PIN_B5) == 0){
        output_low(PIN_B6);            // RB6 LED OFF
        pwm_off();                     // Turn off pwm for both outputs
        output_a(0);                   // PORTA pins low
        delay_ms(100);                 // Wait 100ms
        pwm_on(PIN_A0);                // Turn pwm on at RA0
        output_high(PIN_B5);           // RB5 LED ON
        if(i > 99)
          output_high(PIN_B7);}}
    if(input(PIN_B3) == 0){            // If RB3 button pressed
      if(input(PIN_B6) == 0){
        output_low(PIN_B5);            // RB5 LED OFF
        pwm_off();                     // Turn off pwm for both outputs
        output_a(0);                   // PORTA pins low
        delay_ms(100);                 // Wait 100ms
        pwm_on(PIN_A1);                // Turn PWM on at RA1
        output_high(PIN_B6);
        if(i > 99)
          output_high(PIN_B7);}}
    if(input(PIN_B4) == 0){            // If RB4 button pressed
      pwm_off();                       // Turn off pwm for both outputs
      output_a(0);                     // PORTA pins low
      output_b(0);}                    // PORTB pins low
    }
}

DC Motor speed and direction control with PIC16F84A video:
The following video shows more about this project with hardware circuit.