Showing posts with label PIC. Show all posts
Showing posts with label PIC. Show all posts

Saturday, July 9, 2011

Microcontroller based Pump Controller

Updates:-
  1. 28 Jun 11: I cant help but thank the kind guys at Texas Instruments. I cant believe my eyes, they have shipped me a sample of their instrumentation amplifier. Thats would help me simplify my input block. Thanks u guys… You rock.
  2. 01 Jul 11: Received Sample. Waiting for Farnell guys to ship my pressure sensors…
  3. 07 Jul 11 :  Received Pressure sensors.
 
 
This project will describe building of a Pump control system. The requirement primarily arose to satiate the requirements of my parents, who have to manually switch on the pump every day morning and switch it off and continuously monitor the tank for overflow. So I have taken up the challenge onto myself...
However I would be ungrateful, I do not acknowledge the inputs I received after reading Kayne Richens blog post.
 
This blog is progressive ; hence will get updated as things progress.....

Lets me see how do things unfold...


Basic Design Objectives:-
  1. Should be cheap and affordable.
  2. Should be as automated as possible requiring minimal user supervision.
  3. Should have a user-friendly MMI.
  4. Prevent water and electricity wastage.
Design Challenges:-
  1. Erratic water supply timings.
  2. Non scheduled Electrical Load shedding .
  3. High head of water tank.
  4. Intelligent control system.
Preliminary System Design:-

image


System Blocks Functions:-
Input Block:-
Input Description  Sensor Type  Micro-controller Input  
Sense Tank Capacity
Differential Pressure Sensor
Analog
Sense Electricity Availability Optocoupler Digital/Interrupt
Sense Time RTC Digital
Sense Input Water Supply Availability Differential Pressure Sensor Analog

Output Block:-
Output Description  Transducer Type  Micro-controller Output  
Motor On/Off
Solid State Relay
Digital
Valve Solenoid On/Off Relay Digital
Alarm Buzzer Analog

 
 
Mathematics for Selecting Differential Pressure Sensor:-
 
Why Differential Pressure Sensor?
 
A differential pressure sensor will eliminate variation in pressure due to changes in atmospheric pressure.
 
Mathematics
 
Capacity of Water Tank = 500 Lt
Water Tank Head = 30 Ft = 9.144 Mt = 914.4 Cm
Average Ambient Temperature = 25 deg Celcius
Specific Gravity of Tap water=0.997gm per cubic cm = 997Kg per cubic meter
Dia of Discharge Pipe=1/2 in = 1.27 Cm=0.0127 M

Pressure exerted at Base of Building by a column of Water at height
 
P = h * rho * g
where
P = Pressure
h = height of liquid column (2000 mm = 2m)
rho = Density of water (1000 kg/m^3)
g = Acceleration due to gravity (9.81 m/s^2)
 
P=9.14 x 997x 9.81 = 89394.4098 Pascals = 89.39kPa = 89.4 kPa (approx)
Similarly Pressure at Rooftop at the base of tank itself
P=1.5 x 997x 9.81 =14670.855 Pascals =14.67kPa = 14.7 kPa (approx)
 
Selected Sensor  :  Freescale Differential Pressure Sensor MPX2100DP  0-100 kPa


Selection  of MCU:-

Family : Microchip PIC
Why : Because I have necessary experience and required development tools.

Max No of ADC Channels Required = 3 (2xpressure Sensor + 1 spare)
No of Interrupts : 02 (Electrical Supply Available & Float Valve)
Digital I/O = 8
Operating Voltage= 5V
SPI Required = Yes (For Interfacing RTC)
MCU Selected  = 16F876A  or 16F877A Why? Because I already have!

Design of Pressure Sensor Amplifier:-
Design Guide/Reference : -
  1. Op Amps for Everyone Design Guide.

Amplifier Design Objective : The output span of the transducer must be matched to the input span of the ADC to achieve optimum performance.

Mathematics for Amplifier Design

Span and Offset Characteristics at 10v,15v & 5V Excitation Voltage. As sensor is ratio-metric the the values are scaled for.

MPX2100DP

Excitation Voltage Min Span 
(mV)
Max Span 
(mV)  
Min. Offset 
(mV)  
Max Offset 
(mV)  
10V
38.5
40
-1
1
15V (scaled)
57.75 60 -1.5 1.5
5V (scaled)
19.25
20 -0.5 0.5
9V(scaled) 34.65 3.6 -0.9 0.9
 
 
MPX2010DP
 

Excitation Voltage Min Span 
(mV)
Max Span 
(mV)  
Min. Offset 
(mV)  
Max Offset 
(mV)  
10V
24
26
-1
1
15V (scaled)
36 39 -1.5 1.5
5V (scaled)
12
13 -0.5 0.5
9V(scaled) 21.6 23.4 -0.9 0.9
 
 

Desired Amplified Span and Offset


Desired Offset= 0.5V
Desired Span = 5V

Gain Range & Offset Calculation
Maximum Gain      =Desired Span (V)
                           Sensor’s Minimum Span
Desired Span = 5V

Excitation Voltage

Maximum Gain (MPX2100DP)

Maximum Gain (MPX2010DP)

10V =5/38.5 = 129.8 = 130

208

15V =5/57.75 = 86.58 = 87

139

5V =5/19.25 = 259.75 = 260

417

9V =5/34.65=144.300=144

231

 
Since Texas Instruments was kind to ship me samples of their instrumentation amplifiers, I would be basing my calculations on same. There is no rocket science involved since the datasheet is fairly self explanatory and the instrumentation amplifier itself requires only one external component for gain adjustment.
Texas Instruments was generous in mailing following samples to me
INA126, INA128,INA122,INA2126
 
I would be using INA126 amplifier for testing purpose
 
Brief description about INA126 ..”The INA126 and INA2126 are precision instrumentation amplifiers for accurate, low noise differential signal acquisition. Theirtwo-op-amp design provides excellent performance with very low quiescent current (175µA/channel). This, combined with awide operating voltage range of ±1.35V to ±18V, makes them ideal for portable instrumentation and data acquisition systems. Gain can be set from 5V/V to 10000V/V with a single external resistor. Laser trimmed input circuitry provides low offset voltage (250µV max), low offset voltage drift (3µV/°C max) and excellent common-mode rejection.”
 
Gain calculation formulae
 

Instr Amplifier

Gain Formula

INA 122 G=5+200kΩ 
         RG
INA 126 G=5+80kΩ 
         RG
INA 128 G=1+50kΩ 
         RG
 
RG (IN OHMS)values at Max Gain. Values in (brackets) indicate nearest standard resistor values.
 
MPX2100DP
 

Instr. Amplifier

10V

15V

5V

9V

INA 122

   1602 Ω (1.6KΩ)

2452Ω(2.4KΩ)

785Ω (750Ω)

1439Ω(1.5K)
INA 126

641Ω (620Ω)

981Ω (1kΩ)

584Ω (560Ω)

576Ω(560Ω)
INA 128

388Ω (390Ω)

548Ω (560Ω)

193Ω (180Ω)

347Ω(360Ω)
 
MPX2010DP
 

Instr. Amplifier

10V

15V

5V

9V

INA 122

   984 Ω (1KΩ)

1494Ω(1.5KΩ)

486Ω (470Ω)

885Ω(820Ω)

INA 126

393Ω (390Ω)

598Ω (560kΩ)

194Ω (200Ω)

356Ω(360Ω)

INA 128

241Ω (240Ω)

363Ω (360Ω)

120Ω (120Ω)

214Ω(200Ω)

 
Amplifier Interface Design
 
\includegraphics[scale=0.500000]{ckt8.1.1.ps}
 
In the MPX sensor, each of the resistors in the bridge is an active strain gage, so this design illustration is applicable for the amplifier design.
 
image
 
Test Schematic
 
image
 
3D PCB Render (Using Diptrace)
 
image
 




 

Saturday, June 11, 2011

Decoding A Ultrasonic Parking Sensor

This post I am going to explain how I went about decoding / hacking a COTS Ultrasonic Car Parking Sensor. This project idea primarily stemmed out of sheer curiosity after reading a similar post at MP3Car.com. The the original hack was done by one of the forum members at MP3car and he had explained his hack in great detail, surprisingly the author has withheld the firm ware for the micro controller and is available on sale only.

Being a electronics enthusiast with decent programming skills, I decided to venture in recreating this hack and most importantly release the code in open source.

I sourced the a parking sensor from ebay.in. And as the luck would have had it, I got the same parking system as the original author had.

Devel Board: 

Home made PIC 18f4550 devel board with a 20MHz crystal.
From Reverse Biased

Theory of operation:

The parking sensor communicates with the display console over an rf link. In my case I screwed up my RF receiver in the display console due to hurry and 'bad engineering practises'. So the only option left was  hard wiring to my micro-controller dev. board.

Decoding the Communication Protocol

The system uses PWM (Pulse Width Modulation) to communicate. The shorter pulse in logic 0 and the longer pulse is logic 1. 
Since I have no high end development tools at my home to estimate pulse width, I used my devel. board to estimate the pulse width. I used a slightly modified EX_CCPMP.C example available in CCS compiler library to estimate the pulse width. Following is the code
1:  #include <18F4550.H>   
2:  #fuses HSPLL, PLL5, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP   
3:  #use delay(clock=48000000)   
4:  #use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)  
5:  long rise,fall,pulse_width;  
6:  #int_ccp2  
7:  void isr()  
8:  {  
9:    rise = CCP_1;  
10:    fall = CCP_2;  
11:    pulse_width = fall - rise;     
12:  }                   
13:  //short Pin 17 and 16 on microcontroller to use CCP1 and CCP2  
14:  void main()  
15:  {  
16:    printf("\n\rHigh time\n\r");  
17:    setup_ccp1(CCP_CAPTURE_RE);  // Configure CCP1 to capture rise  
18:    setup_ccp2(CCP_CAPTURE_FE);  // Configure CCP2 to capture fall  
19:    setup_timer_1(T1_INTERNAL);  // Start timer 1  
20:    enable_interrupts(INT_CCP2);  // Setup interrupt on falling edge  
21:    enable_interrupts(GLOBAL);  
22:    while(TRUE) {  
23:     printf("\n\r%lu us ", pulse_width);  
24:    }  
25:  }  

Using this I realised that the pulse widths were
3599 us  -> Logic Zero
7198 us -> Logic One.
They might be wrong due to wrong setup of CCP module (due to my ignorance). But it doesn't matter till the time you get two distinct pulse widths.
Once this step was over the next step was to make a bit stream out of this pulse width outputs. I slightly modified the above code to dump the bit stream on a serial console

1:  #include <18F4550.H>   
2:  #fuses HSPLL, PLL5, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP   
3:  #use delay(clock=48000000)   
4:  #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)   
5:  int bit_val;short flag;   
6:  long rise,fall,pulse_width;   
7:  #int_ccp2   
8:  void isr()   
9:  {   
10:   rise = CCP_1;   
11:    fall = CCP_2;   
12:    pulse_width = fall - rise;   
13:    bit_val=3;   
14:  if (pulse_width <=3600 && pulse_width >=3598) {   
15:    bit_val=0;   
16:    }   
17:  if (pulse_width <=7200 && pulse_width >=7197) {   
18:    bit_val=1;   
19:    }   
20:  }   
21:  void main()   
22:  {   
23:    printf("\n\rPulse Width:\n\r");   
24:    setup_ccp1(CCP_CAPTURE_RE);  // Configure CCP1 to capture rise   
25:    setup_ccp2(CCP_CAPTURE_FE);  // Configure CCP2 to capture fall   
26:    setup_timer_1(T1_INTERNAL);  // Start timer 1   
27:    enable_interrupts(INT_CCP2);  // Setup interrupt on falling edge   
28:    enable_interrupts(GLOBAL);   
29:    while(TRUE) {   
30:     if (bit_val<=1){   
31:     //printf("\n\r%lu us ", pulse_width );   
32:     printf("%u", bit_val);   
33:       bit_val=4;   
34:     }   
35:    }   
36:  }   

This was the dump I got on the serial port

 Pulse Width:  
 1101001011101111000100001101001011101111000100001110000111101111000100001110000100000
00011111111110000111110111100010000110000110010011111011000111100001110111100010000111
10000001010011101011011010010111011110001000011010010000000001111111111100001000000001
11111111110000100000000111111111100001100100111110110001100001100100111110110001111000
00010100111010110111100000010100111010110110100100000000011111111110100100000000011111
11111100001000000001111111111100001000000001111111111000011001001111101100011000011001
00111110110001111000000101001110101101111000000101001110101101101001000000000111111111
10100100000000011111111111000010000000011111111111000010000000011111111110000110010011
11101100011000011001001111101100011110000001010011101011011110000001010011101011011010
01000000000111111111101001000000000111111111110000100000000111111111110000100000000111
11111110000110010011111011000110000110010011111011000111100000010100111010110111100000
01010011101011011010010000000001111111111010010000000001111111111100001000000001111111
11110000100000000111111111100001100100111110110001100001100100111110110001111000000101
00111010110111100000010100111010110110100100000000011111111110100100000000011111111111
00001000000001111111111100001000000001111111111000011001001111101100011000011001010001
10101111111000000101001110101101111000000101001110101101101001000000000111111111101001
00000000011111111111000010000000011111111111000010000000011111111110000110010100011010
11111000011001001111101100011110000001010011101011011110000001010011101011011010010000
00000111111111101001000000000111111111110000100000000111111111110000100000000111111111
10000110010011111011000110000110010011111011000111100000010100111010110111100000010100

Bit Structure
Total data packet of each sensor consists of 24 bits (3bytes x8) 
The first byte is the sensor address and consists of 2 nibbles which are complementary of each other (1111 0000).
The second byte is the complement of third byte. and third byte contains the distance data (in centimeters)



Sensors are numbered as 0,1,2,3 so in the binary representation along with the nibble part they become:-
A=11110000  (1111 0000)
B=11010010 (1101  0010)
C=11100001 (1110  0001)
D=11000011 (1100  0011)


Another hidden thing (which the original author did not mention). Each data frame is transmitted twice and the readings are not repeated. So the bit stream is like AABBCCDDAABBCCDD........


Once we are done till here... the last step is only to write the code to search the bit stream for those golden characters mentioned above.
The logic is as follows

  1. Read the bits and load them in a buffer using left shift.
  2. Continuously read the buffer till you encounter sensor address.. i.e value of buffer = sensor address.
  3. Empty the buffer and read next 8 bits (distance nibblebits)
  4. Distance in centimeters is complement of the 2nd bit.
  5. Reset all flags and variables to zero
  6. Implement above in a code.
Here is the final code... needs much improvement
1:  /*  
2:  <Automotive Ultrasonic Car Parking Sensor Protocol Decoder>  
3:    Copyright (C) <2011> <Ishan Anant Karve>  
4:    This program is free software: you can redistribute it and/or modify  
5:    it under the terms of the GNU General Public License as published by  
6:    the Free Software Foundation, either version 3 of the License, or  
7:    (at your option) any later version.  
8:    This program is distributed in the hope that it will be useful,  
9:    but WITHOUT ANY WARRANTY; without even the implied warranty of  
10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
11:    GNU General Public License for more details.  
12:    Visit <http://www.gnu.org/licenses/> for terms and conditions.  
13:  /*  
14:  #include <18F4550.H>   
15:  #fuses HSPLL, PLL5, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP   
16:  #use delay(clock=48000000)   
17:  #use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)  
18:  #define SEN_A 0b11110000  
19:  #define SEN_B 0b11010010   
20:  #define SEN_C 0b11100001  
21:  #define SEN_D 0b11000011  
22:  int bit_val;int count;  
23:  short sensor_ready,nibble_byte_ready, dist_byte_ready; //flags for correspond to 03 bytes of each sensor data  
24:  int sensor, nibble_byte; byte dist_byte;  
25:  long rise,fall,pulse_width;int16 temp;  
26:  #int_ccp2  
27:  void isr()  
28:  {  
29:   rise = CCP_1;  
30:    fall = CCP_2;  
31:    pulse_width = fall - rise;  
32:  bit_val=2;  
33:  if (pulse_width <=3600 && pulse_width >=3598) {  
34:   bit_val=0; count++;shift_left(&temp,1,bit_val);  
35:   }   
36:  if (pulse_width <=7200 && pulse_width >=7197) {  
37:   bit_val=1; count++;shift_left(&temp,1,bit_val);  
38:   }  
39:   if (temp==SEN_A){sensor=1;sensor_ready=1;count=0;nibble_byte_ready=0; dist_byte_ready=0;nibble_byte=0;dist_byte=0;temp=0;}  
40:   if (temp==SEN_B){sensor=2;sensor_ready=1;count=0;nibble_byte_ready=0; dist_byte_ready=0;nibble_byte=0;dist_byte=0;temp=0;}  
41:   if (temp==SEN_C){sensor=3;sensor_ready=1;count=0;nibble_byte_ready=0; dist_byte_ready=0;nibble_byte=0;dist_byte=0;temp=0;}  
42:   if (temp==SEN_D){sensor=4;sensor_ready=1;count=0;nibble_byte_ready=0; dist_byte_ready=0;nibble_byte=0;dist_byte=0;temp=0;}  
43:  }  
44:  void main()  
45:  {   count=0;temp=0;bit_val=2;  
46:   //init all flags  
47:    sensor_ready=0;nibble_byte_ready=0; dist_byte_ready=0;  
48:   //init all vars  
49:   sensor=0;nibble_byte=0;dist_byte=0;  
50:   printf("\n\rPulse Width:\n\r");  
51:     setup_ccp1(CCP_CAPTURE_RE);  // Configure CCP1 to capture rise  
52:     setup_ccp2(CCP_CAPTURE_FE);  // Configure CCP2 to capture fall  
53:     setup_timer_1(T1_INTERNAL);  // Start timer 1  
54:     enable_interrupts(INT_CCP2);  // Setup interrupt on falling edge  
55:     enable_interrupts(GLOBAL);  
56:     while(TRUE) {  
57:     if (sensor_ready && count==16){  
58:     nibble_byte=make8(temp,0); dist_byte=~nibble_byte; //there is some problem in reading the dist_byte .. so the dirty solution  
59:     printf("%u-> %u, %u, %Lu  ", sensor,nibble_byte,dist_byte,temp);  
60:     if (sensor==4){printf("\r");}  
61:     sensor=0;sensor_ready=0;count=0;nibble_byte_ready=0; dist_byte_ready=0;nibble_byte=0;dist_byte=0;temp=0;  
62:    }  
63:    }  
64:  }  

Ok guys this is the code to be compiled and flashed in your microcontroller. 
 /*  
 Copyright 2011 Ishan Anant Karve, India. All rights reserved.  
 Redistribution and use in source and binary forms, with or without modification, are  
 permitted provided that the following conditions are met:  
   1. Redistributions of source code must retain the above copyright notice, this list of  
    conditions and the following disclaimer.  
   2. Redistributions in binary form must reproduce the above copyright notice, this list  
    of conditions and the following disclaimer in the documentation and/or other materials  
    provided with the distribution.  
 THIS SOFTWARE IS PROVIDED BY ISHAN ANANT KARVE ``AS IS'' AND ANY EXPRESS OR IMPLIED  
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR  
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON  
 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING  
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 The views and conclusions contained in the software and documentation are those of the  
 authors and should not be interpreted as representing official policies, either expressed  
 */  
 #include <18F4550.h>  
 #fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN  
 #use delay(clock=48000000)  
 #use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)  
 #DEFINE USB_HID_DEVICE TRUE  
 #define USB_EP1_TX_ENABLE USB_ENABLE_INTERRUPT  //turn on EP1 for IN bulk/interrupt transfers  
 #define USB_EP1_TX_SIZE  8 //allocate 8 bytes in the hardware for transmission  
 #define USB_EP1_RX_ENABLE USB_ENABLE_INTERRUPT  //turn on EP1 for OUT bulk/interrupt transfers  
 #define USB_EP1_RX_SIZE  8 //allocate 8 bytes in the hardware for reception  
 #define RAND_MAX 200   
 #define SEN_A     0b11110000 //SENSOR A Address  
 #define SEN_B     0b11010010     //SENSOR B Address  
 #define SEN_C     0b11100001     //SENSOR C Address  
 #define SEN_D     0b11000011     //SENSOR D Address  
 //change USB descriptors for custom use  
 #include <stdlib.h>           //required for rand() function  
 #include <pic18_usb.h>  //Microchip 18Fxx5x hardware layer for usb.c  
 #include <usb_desc_hid.h>     //USB Configuration and Device descriptors for this UBS device  
 #include <usb.c>    //handles usb setup tokens and get descriptor reports  
 short tx_flag;  
 int bit_val;int count;  
 short sensor_ready; //flags for correspond to 03 bytes of each sensor data  
 int sensor,Dist_A,Dist_B,Dist_C,Dist_D, nibble_byte,dist_byte;  
 short BUZZER;  
 long rise,fall,pulse_width;int16 temp;  
 #int_ccp2  
 void isr()  
 {  
  rise = CCP_1;  
   fall = CCP_2;  
   pulse_width = fall - rise;  
 bit_val=2;  
 if (pulse_width <=3600 && pulse_width >=3598) {  
      bit_val=0; count++;shift_left(&temp,1,bit_val);  
      }   
 if (pulse_width <=7200 && pulse_width >=7197) {  
      bit_val=1; count++;shift_left(&temp,1,bit_val);  
      }  
      if (temp==SEN_A){sensor=1;sensor_ready=1;count=0;nibble_byte=0;dist_byte=0;temp=0;} //distance DIST_A purposely not set to zero  
      if (temp==SEN_B){sensor=2;sensor_ready=1;count=0;nibble_byte=0;dist_byte=0;temp=0;}  
      if (temp==SEN_C){sensor=3;sensor_ready=1;count=0;nibble_byte=0;dist_byte=0;temp=0;}  
      if (temp==SEN_D){sensor=4;sensor_ready=1;count=0;nibble_byte=0;dist_byte=0;temp=0;}  
 }  
 void main() {  
 int8 out_data[20];  
 int8 in_data[2];  
 int8 send_timer=0;  
 count=0;temp=0;bit_val=2;tx_flag=0;  
 sensor=0;sensor_ready=0;count=0;nibble_byte=0;dist_byte=0;Dist_A=0;Dist_B=0;Dist_C=0;Dist_D=0;  
 //SETUP INTERRUPTS  
 setup_ccp1(CCP_CAPTURE_RE);  // Configure CCP1 to capture rise  
 setup_ccp2(CCP_CAPTURE_FE);  // Configure CCP2 to capture fall  
 setup_timer_1(T1_INTERNAL);  // Start timer 1  
 enable_interrupts(INT_CCP2);  // Setup interrupt on falling edge  
 enable_interrupts(GLOBAL);  
 delay_ms(1000);  
 printf("\r\n\nParking Sensor");  
 usb_init_cs();  
      while (TRUE) {  
   usb_task();  
           if (sensor_ready && count==16){  
                nibble_byte=make8(temp,0); dist_byte=~nibble_byte;  
                switch (sensor) {  
                  case 1:Dist_A=dist_byte; //Set data for Sensor A  
                break;  
                  case 2:Dist_B=dist_byte; //Set data for Sensor B  
                break;  
                  case 3:Dist_C=dist_byte; //Set data for Sensor C  
                break;  
                  case 4:Dist_D=dist_byte; //Set data for Sensor D  
                break;  
              }  
                //printf("%u --> %u\n\r"sensor,dist_byte); //for debug purposes  
                //reset all variables  
                sensor=0;sensor_ready=0;count=0;nibble_byte=0;dist_byte=0;temp=0;  
           }        
    if (usb_enumerated()) {  
      if (!send_timer) {  
       send_timer=250;  
       out_data[0]=Dist_A;  
       out_data[1]=Dist_B;  
       out_data[2]=Dist_C;  
       out_data[3]=Dist_D;  
       out_data[4]=0;  
            if (tx_flag){tx_flag=0;  
                 if (usb_put_packet(1, out_data,5, USB_DTS_TOGGLE)){  
                   //printf("\r\n<-- Sending 2 bytes: 0x%X 0x%X 0x%X 0x%X 0x%X", out_data[0], out_data[1], out_data[2], out_data[3], out_data[4]);  
                          //printf("\r\n<-- Sending 2 bytes: %u %u %u %u %u", out_data[0], out_data[1], out_data[2], out_data[3], out_data[4]);// for debug purposes  
                          }  
                }            
                }  
      if (usb_kbhit(1)) {  
       usb_get_packet(1, in_data, 2);  
       {  
                //printf("\r\n--> Received data: 0x%X 0x%X",in_data[0],in_data[1]);//for debug purposes  
                }  
       if (in_data[0]==0x20) {tx_flag=1;}   
     }  
      send_timer--;  
      delay_ms(1);  
    }  
   }  
 }  
Thats all....... Will post the circuit schematic shortly... Thanks for reading.

Friday, April 15, 2011

How to read a rotary encoder using a PIC 18F45K20 using CCS Compiler

This is  short blog on reading a Rotary Encoder using a PIC microcontroller and CCS compiler

Hardware :

  1. Rotary Encoder
  2. PICkit™ 3 Debug Express PIC18F45K20
  3. USB -TTL board for RS232 connectivity 

Connections:
Rotary encoder  - MCU

  1. Pin A and Pin C of rotary encoder connected to RB4 and RB5 of MCU respectively
  2. Pin B (Common ) of rotary encoder connected to VCC.
  3. Both RB4 and RB 5 pulled to ground using a resistance of 47K

USB-TTL board <-> MCU

  1. RC6 (Tx) of MCU connected to USB-TTL board Recv.
  2. Vss of MCU connected to USB_TTL board Gnd.



Coding Platform:

  1. PICKIT 3 (Programmer/Debugger)
  2. CCS Compiler
  3. MPLAB IDE
  4. Putty/Hyperterminal for results



Code:
 #include <18F45K20.h>   
 #fuses HS,NOWDT,NOPROTECT,NOLVP,BROWNOUT,PUT,NOPBADEN,DEBUG   
 #use delay(internal=4Mhz)  
 #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)   
 /////////////////////////////Working Vars//////////////////////////////////////   
 int d0=0;int d1=0;int d2=0;int d3=0;int16 a=0;int b=0;   
 int1 preva=0;int1 prevb=0;   
 int16 counter=0;int pata=0b00000000;int patb=0b00000000;   
 int y=0;   
 int1 ina=0;int1 inb=0;   
 int1 temp=0;int dir=0;   
 //INTERRUPT ISR   
 #INT_RB   
 void rb_isr(void)   
 {  ina=input(pin_b4);   
   inb=input(pin_b5);   
   pata=pata<<1;   
   bit_clear(pata,4);   
   if(ina==1)   
   {  bit_set(pata,0);   
   }   
   else   
   {  bit_clear(pata,0);   
   }    
   patb=patb<<1;   
   bit_clear(patb,4);   
   if(inb==1)   
   {  bit_set(patb,0);   
   }   
   else   
   {  bit_clear(patb,0);   
   }   
   if(pata==6&&patb==12)   
   {  counter--;   
 printf("Encoder = %03Ld \n\n\r",counter);   
   }   
   else if(pata==12&&patb==6)   
   {  counter++;   
 printf("Encoder = %03Ld \n\n\r",counter);   
   }   
 }      
 //////////////////////////////////////////////////////////////////////////////////  
 #byte IOCB = 0xF7D   
 #byte ANSEL = 0xF7E   
 #byte ANSELH = 0xF7F   
 void main(void)   
 {   
   setup_adc_ports(NO_ANALOGS);   
    enable_interrupts(INT_RB);   
 setup_comparator(NC_NC_NC_NC);   
 IOCB = 0xF0;   
 ANSEL = 0;   
 ANSELH = 0;   
  EXT_INT_EDGE(L_to_H);  
   enable_interrupts(GLOBAL);   
   printf("\n\n\rRotary Encoder Test\n\n\r");   
   while (true)   
   {   
 //put ur menu code here  
   }   // end of while loop   
 }    // end of main   









Many thanks to http://www.ccsinfo.com/forum/viewtopic.php?t=44491 ; http://www.ccsinfo.com/forum/viewtopic.php?p=127421