Tuesday, December 21, 2010

Electronic Combination Lock Using PIC16F628A

This electronic combination lock can be use with an outdoor gate. The functionality is implemented in software. It turns on a relay (usually to open a door) for a few seconds if someone enters the valid code. The relay can operate a power to open type electric strike with a shorting contact or a power-to-hold type electromagnetic lock with a breaking contact (we need the relay because these locks usually work with AC, not DC). The code can be changed any time after entering the current code.

Thursday, December 16, 2010

Water Level Controller and motor Protector v2

This is the v2 by using PIC16F877A with minimum components. The most left circuitry is the same as in mains monitor; used to check to variation in ac voltage (operating range is between 200v ac - 240v ac). Five pull-up resistor circuitry is used to measure the water level in the desired water tank. Note that the push buttons are used here is only for illustration purpose, basically they are representing the probes (6 probes made of 28 gauge wire; one is of ground (reference) level). The left most probe indicates 20% of water in tank, next indicates 40% and so on till 100% or full level.

Saturday, December 11, 2010

Stepper Motor Programming

Full Step Sequence:
I am using PIC16F628A with uln2003 to drive unipolar stepper motor. Adjusting the delay will increase or decrease the speed of the motor. Here just for demonstration i have taken some delay, you can change it as you want. If you want to change the direction of stepper motor, just reverse the step sequence (means 9,3,6, and C etc). 

Friday, December 10, 2010

Unipolar Stepper Motor Drivers

There are actually many ways you can interface a stepper motor to your controller, out of them the most used interfaces are:

  • Interface using L293D - H-Bridge Motor Drive
  • Interface using ULN2003/2004 - Darlington Arrays

Thursday, December 9, 2010

Stepper Motor Stepping Modes

Stepper Motor Connections:
Unipolar motor should have five or six connections depending on the model. If the motor has six connections like the one pictured above, you have to join pins 1 and 2 (red) together and connect them to a (+) 12-24V voltage supply. The remaining pins; a1 (yellow), b1 (black), a2 (orange), b2 (brown) should be connected to a driver (ULN2003 etc).

Wednesday, December 8, 2010

Stepper Motor Introduction

Introduction:
This section of tutorial will explain you everything that you need to know about stepper motors. Stepper motors can be used in various areas of your microcontroller projects such as making robots, robotic arm, automatic door lock system etc. This tutorial will explain you construction of stepper motors (unipolar and bipolar stepper motors ), basic pricipal, different controlling types (Half step and Full step), Interfacing Techniques (using ULN2003) and programming your microcontroller in C to control stepper motor. 

Sunday, December 5, 2010

Mains Monitor

Mains Monitor or Manager is the circuit; i used to measure or check the ac voltage and frequency. Its accuracy is about 90-97% and quite handy for hobbyist. The ac voltage limit is 500v ac and 99Hz for frequency. There are two different ideas combine, to achieve this goal. 

Saturday, December 4, 2010

Glow Plug Controller

In diesel engines, the air in the cylinders is not hot enough to ignite the fuel under cold conditions. Therefore each cylinder of these engines is fitted with an electric heater known as ‘glow plug.’ A control circuit is necessary to optimise the functioning of glow plugs. It raises the air temperature inside the engine cylinder for quick and reliable starting, extended battery life and reduced diesel consumption.

Wednesday, December 1, 2010

Mini UPS System

This circuit provides an un-interrupted power supply (UPS) to operate 12V, 9V and 5V DC-powered instruments at up to 1A current. The backup battery takes up the load without spikes or delay when the mains power gets interrupted. It can also be used as a workbench power supply that provides 12V, 9V and 5V operating voltages. The circuit immediately disconnects the load when the battery voltage reduces to 10.5V to prevent deep discharge of the battery. LED1 indication is provided to show the full charge voltage level of the battery. miniature white LEDs (LED2 and LED3) are used as emergency lamps during power failure at night.

Tuesday, November 30, 2010

High Intensity Energy Efficient LED Light

Here is a rechargeable LED lamp that gives you bright light for a long duration of time as it consumes little power. The circuit presented here is compact, automatic, reliable, low-cost and easy to assemble.

The circuit comprises power supply, battery charging and switching sections. The power supply section takes power from 230V AC mains supply without using a transformer. Capacitor C1 is used as an AC voltage dropper, a well-known transformerless solution. This helps to make the circuit compact without generating heat, as capacitor C1 dissipates negligible power. Capacitor C1 also protects against fluctuations in mains.

Monday, November 29, 2010

Cellphone Operated Land Rover

Conventionally, wireless-controlled robots use RF circuits, which have the drawbacks of limited working range, limited frequency range and limited control. Use of a mobile phone for robotic control can overcome these limitations. It provides the advantages of robust control, working range as large as the coverage area of the service provider,no interference with other controllers and up to twelve controls.

Thursday, November 25, 2010

Remote Controlled 6-Camera CCTV Switcher

Closed-circuit television (CCTV) uses video cameras to transmit signals to specific monitors. It differs from broadcast television in that the signal is not openly transmitted, though it may employ point-to-point wireless links. CCTV is often used for surveillance in areas that need security,such as banks, casinos, shops, departmental stores and airports or military installations. 
Here is a remote-controlled CCTV switcher circuit to monitor six cameras on a single or dual monitor/TV. 

Tuesday, November 23, 2010

Smart Voltage Stabilizer Using PIC16F877A

Voltage stabilizers are used for many appliances in homes, offices and industries. The mains supply suffers from large voltage drops due to losses on the distribution lines en route. A voltage stabilizer maintains the voltage to the appliance at the nominal value of around 220 volts even if the input mains fluctuates over a wide range.

Monday, November 22, 2010

Water Level Controller and motor Protector

Many a time we forget to switch off the motor pushing water into the overhead tank (OHT) in our households. As a result, water keeps overflowing until we notice the overflow and switch the pump off. As the OHT is usually kept on the topmost floor, it is cumbersome to go up frequently to check the water level in the OHT.

Sunday, November 21, 2010

Over/Under Voltage Cut-off with On-Time Delay

Here is an inexpensive auto cutoff circuit, which is fabricated using transistors and other discrete components. It can be used to protect loads such as refrigerator, TV, and VCR from undesirable over and under line voltages, as well as surges caused due to sudden failure/resumption of mains power supply. This circuit can be used directly as a standalone circuit between the mains supply and the load, or it may be inserted between an existing automatic/manual stabilizer and the load. 

Saturday, November 20, 2010

Parallel Port Logic Analyzer

When you build a digital electronic project and have trouble with it you need a device to debug it. To analyze logic output from your project you need a Logic Analyzer. 
If you don’t have it you can try to build by yourself cheap logic analyzer device using parallel port. The device only use few resistors and IC 74HC245 as data buffer. To display the graphical output from logic analyzer device you can use Fabulous Logic Analyzer software, here.


Schematic:
Parallel Port logic analyzer


Component Required:
IC1,               74HC245
R1-R8,         10K ohm
R9-R16,       100 ohm
R17,              2K ohm
LED
DB25 Male, Parallel Port Connector

Telephone Operated Remote Control v2 Using PIC16F876A

This is a newer version of previous device. This one can have up to 6 relays and 6 sensor-state inputs.
The task was to build a device that connects to the phone line and has a relay as an output switch. It should also sense if the connected «consumer» is turned-on or off and report to the administrator at the other end of the phone line. The administrator would then call-in the device, log in with the password, and check the state of «consumer», turn it on or off, change password or some other settings.


DownloadSchematic, Program files And Documentation


Schematic:


Full Schematic


Telephone operated remote control

Telephone Operated Remote Control Using PIC16F84A

This design controls up to 8 devices using a PIC microcontroller (PIC16F84A) connected to the phone line. The unique feature here is that unlike other telephone line based remote control, this device does not need the call to be answered at the remote end so the call will not be charged. This device depends on number of rings given on the telephone line to activate/deactivate devices.

Friday, October 1, 2010

PIC16F887/877 programming in C Tutorial 10 (ADC)


Analog to Digital Converter (ADC):
In this tutorial i will show how to convert analog values into digital, by using 887 (little bit differ with 877), then display these digital value on LCD.

The Analog-to-Digital Converter (ADC) allows conversion of an analog input signal to a 10-bit binary representation of that signal. This device uses analog inputs, which are multiplexed into a single sample and hold circuit. The output of the sample and hold is connected to the input of the converter. The converter generates a 10-bit binary result via successive approximation and stores the conversion result into the ADC result registers (ADRESL and ADRESH).

The ADC voltage reference is software selectable to be either internally generated or externally supplied.

ADC Configuration:
When configuring and using the ADC the following functions must be considered:
• Port configuration
• Channel selection
• ADC voltage reference selection
• ADC conversion clock source
• Interrupt control
• Results formatting

Port configuration:
The ADC can be used to convert both analog and digital signals. When converting analog signals, the I/O pin should be configured for analog by setting the associated TRIS and ANSEL bits.

Channel selection:
The CHS bits of the ADCON0 register determine which channel is connected to the sample and hold circuit. When changing channels, a delay is required before starting the next conversion.
ADC voltage reference selection:
The VCFG bits of the ADCON0 register provide independent control of the positive and negative voltage references. The positive voltage reference can be either VDD or an external voltage source. Likewise, the negative voltage reference can be either VSS or an external voltage source. 

ADC conversion clock source: 
The source of the conversion clock is software selectable via the ADCS bits of the ADCON0 register. There are four possible clock options:
• FOSC/2
• FOSC/8
• FOSC/32
• FRC (dedicated internal oscillator)
The time to complete one bit conversion is defined as TAD. One full 10-bit conversion requires 11 TAD periods as shown in Figure.


Interrupt control:
The ADC module allows for the ability to generate an interrupt upon completion of an Analog-to-Digital conversion. The ADC interrupt flag is the ADIF bit in the PIR1 register. The ADC interrupt enable is the ADIE bit in the PIE1 register. The ADIF bit must be cleared in
software. 

Results formatting: 
The 10-bit A/D conversion result can be supplied in two formats, left justified or right justified. The ADFM bit of the ADCON0 register controls the output format. 


ADC Operation:
STARTING A CONVERSION:To enable the ADC module, the ADON bit of the ADCON0 register must be set to a ‘1’. Setting the GO/DONE bit of the ADCON0 register to a ‘1’ will start the Analog-to-Digital conversion. 


COMPLETION OF A CONVERSION:When the conversion is complete, the ADC module will:
• Clear the GO/DONE bit
• Set the ADIF flag bit
• Update the ADRESH:ADRESL registers with new conversion result


A/D CONVERSION PROCEDURE:
This is an example procedure for using the ADC to perform an Analog-to-Digital conversion:
1. Configure Port:
• Disable pin output driver (See TRIS register)
• Configure pin as analog
2. Configure the ADC module:
• Select ADC conversion clock
• Configure voltage reference
• Select ADC input channel
• Select result format
• Turn on ADC module
3. Configure ADC interrupt (optional):
• Clear ADC interrupt flag
• Enable ADC interrupt
• Enable peripheral interrupt
• Enable global interrupt(1)
4. Wait the required acquisition time(2).
5. Start conversion by setting the GO/DONE bit.
6. Wait for ADC conversion to complete by one of the following:
• Polling the GO/DONE bit
• Waiting for the ADC interrupt (interrupts enabled)
7. Read ADC Result
8. Clear the ADC interrupt flag (required if interrupt is enabled).


ADC REGISTER DEFINITIONS:
The following registers are used to control the operation of the ADC.




Code:
Lets make it easy by using adc library of mikroc. The following code will convert the analog input, at pin RA2, into digital and display it on lcd. As the conversion is of 10-bit, so the range is from 0-1023.

unsigned int temp_res;

// 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

char txt1[] = "ADC Example";
char txt[7];
void main() {
/////////// comment for 877/////////////////////////////////////
  ansel=4;                     // Configure AN2 pin as analog
  anselh=0;
  c1on_bit=0;
  c2on_bit=0;
 ////////////////////////////////////////////////////////////////
  TRISA  = 0xFF;              // PORTA is input
  Lcd_Init();
  Lcd_Cmd(_LCD_CLEAR);               // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);          // Cursor off
  Lcd_Out(1,1,txt1);
  adc_init();
  do {

    temp_res = ADC_read(2);   // Get 10-bit results of AD conversion
    IntToStr(temp_res, txt);    //int to string conversion
    Lcd_Out(2,1,txt);
  } while(1);
}

adc_init(); This routine initializes PIC’s internal ADC module to work with RC clock. Clock determines the time period necessary for performing AD conversion.

ADC_read(2); 10 or 12-bit unsigned value read from the specified channel (MCU dependent).Parameter channel represents the channel from which the analog value is to be acquired.In this case it is 2.

IntToStr(temp_res, txt); Converts input signed integer number to a string. The output string has fixed width of 7 characters including null character at the end (string termination). The output string is right justified and the remaining positions on the left (if any) are filled with blanks.

Schematic:

Wednesday, September 29, 2010

PIC16F887/877 programming in C Tutorial 9 (Timers Interrupts)

Timers Interrupt:
Now lets see the interrupt of timers. As we know Timer0 will generate an interrupt when the TMR0 register overflows from FFh to 00h. The T0IF interrupt flag bit of the INTCON register is set every time the TMR0 register overflows, regardless of whether or not the Timer0 interrupt is enabled. The T0IF bit must be cleared in software. The Timer0 interrupt enable is the T0IE bit of the INTCON register. However we will use TMR0IF bit for interrupt programming.

The Timer1 register pair (TMR1H:TMR1L) increments to FFFFh and rolls over to 0000h. When Timer1 rolls over, the Timer1 interrupt flag bit of the PIR1 register is set. To enable the interrupt on rollover, you must set these bits:
• Timer1 interrupt enable bit of the PIE1 register
• PEIE bit of the INTCON register
• GIE bit of the INTCON register
The interrupt is cleared by clearing the TMR1IF bit in the Interrupt Service Routine.

For interrupt programming we have to create ISR (interrupt service routine); so that when an interrupt will occur ISR will take care of it. So, to use timers interrupt; first we have to enable the global interrupt by setting the GIE bit of intcon register, then the interrupts of the respective timer.

Code:  
unsigned cnt, cnt1, cnt2;

void interrupt() {
  if (TMR2IF_bit) {
    cnt2++;                    // increment counter
    TMR2IF_bit = 0;           // clear TMR2IF
    TMR2 = 0;
    if (cnt2 >= 122) {
      PORTc = ~PORTc;         // Toggle PORTc LEDs
      cnt2 = 0;                // Reset cnt
    }
   
  }
  if (TMR0IF_bit) {
    cnt++;                 // increment counter
    TMR0IF_bit = 0;        // clear TMR0IF
    TMR0   = 0;
    if (cnt >= 122) {         //1 sec delay
      PORTd = ~PORTd;      // Toggle PORTd LEDs
      cnt = 0;             // Reset cnt
    }
   
  }
  if(tmr1if_bit){
      tmr1if_bit=0;
      cnt1++;
      tmr1h=128;
      tmr1l=0;
      if(cnt1>=36){
           porta=!porta;
           cnt1=0;
        }
    }
 
 
}

void main() {
  OPTION_REG = 0x84;       // Assign prescaler to TMR0 32
 ////////////// commect for 877///////////////
  ansel=0;
  anselh=0;
  c1on_bit=0;
  c2on_bit=0;
///////////////////////////////////////
  TRISc = 0;               // PORTc is output
  PORTc = 0xFF;            // Initialize PORTc
  TRISd = 0;               // PORTd is output
  PORTd = 0xFF;            // Initialize PORTd
  TRISa = 0;               // PORTa is output
  PORTa = 1;            // Initialize PORTa
  TMR0  = 0;              // Timer0 initial value
  INTCON = 0xA0;           // Enable TMRO interrupt
  cnt = 0;                 // Initialize cnt

  t1con=1;
  tmr1if_bit=0;
  tmr1h=128;
  tmr1l=0;
  tmr1ie_bit=1;
  cnt1=0;
  intcon=192;
 
  cnt2 = 0;                    // initialize cnt
  PORTc = 0xFF;               // Initialize PORTc
  TRISc =   0;                // PORTc is output
  T2CON = 7;               // Timer2 settings
  TMR2  =   0;                // Initialize Timer2 register
  TMR2IE_bit = 1;             // enable interupt
  INTCON = 0xC0;              // Set GIE, PEIE

}

This code toggle the bits of port a, b and d when the interrupts of timer 1, 0, and 2 respectively. The time duration is about 0.5 sec, 1 sec, and 2 sec.

void interrupt() is the isr taking care of interrupts; handling interrupts and take decision according to them.

Schematic:

Wednesday, September 15, 2010

PIC16F887/877 programming in C Tutorial 8 (PWM)

PWM:
The PWM mode generates a Pulse-Width Modulated signal on the CCPx pin. The duty cycle, period and resolution are determined by the following registers:
• PR2
• T2CON
• CCPRxL
• CCPxCON
In Pulse-Width Modulation (PWM) mode, the CCP module produces up to a 10-bit resolution PWM output on the CCPx pin. Since the CCPx pin is multiplexed with the PORT data latch, the TRIS for that pin must be cleared to enable the CCPx pin output driver.

PWM Period:
The PWM period is specified by the PR2 register of Timer2. The PWM period can be calculated using the formula
                             PWM Period = [(PR2) + 1] • 4 • TOSC • (TMR2 Prescale Value)
                             Note: TOSC = 1/FOSC

When TMR2 is equal to PR2, the following three events occur on the next increment cycle:
• TMR2 is cleared
• The CCPx pin is set. (Exception: If the PWM duty cycle = 0%, the pin will not be set.)
• The PWM duty cycle is latched from CCPRxL into CCPRxH.

PWM Duty Cycle:
The PWM duty cycle is specified by writing a 10-bit value to multiple registers: CCPRxL register and DCxB<1:0> bits of the CCPxCON register. The CCPRxL contains the eight MSbs and the DCxB<1:0> bits of the CCPxCON register contain the two LSbs. CCPRxL and DCxB<1:0> bits of the CCPxCON register can be written to at any time. The duty cycle
value is not latched into CCPRxH until after the period completes (i.e., a match between PR2 and TMR2 registers occurs). While using the PWM, the CCPRxH register is read-only.

         Pulse Width = (CCPRxL:CCPxCON<5:4>) • TOSC • (TMR2 Prescale Value)

                  Duty Cycle Ratio (CCPRxL:CCPxCON<5:4>) / 4(PR2 + 1)

PWM Resolution:
The resolution determines the number of available duty cycles for a given period. For example, a 10-bit resolution will result in 1024 discrete duty cycles, whereas an 8-bit
resolution will result in 256 discrete duty cycles. The maximum PWM resolution is 10 bits when PR2 is 255.
                                     Resolution = log[4(PR2 + 1)] / log(2)  bits

Setup for PWM Operation:
The following steps should be taken when configuring the CCP module for PWM operation:
1. Disable the PWM pin (CCPx) output drivers as an input by setting the associated TRIS bit.
2. Set the PWM period by loading the PR2 register.
3. Configure the CCP module for the PWM mode by loading the CCPxCON register with the appropriate values.
4. Set the PWM duty cycle by loading the CCPRxL register and DCxB<1:0> bits of the CCPxCON register.
5. Configure and start Timer2:
• Clear the TMR2IF interrupt flag bit of the PIR1 register.
• Set the Timer2 prescale value by loading the T2CKPS bits of the T2CON register.
• Enable Timer2 by setting the TMR2ON bit of the T2CON register.
6. Enable PWM output after a new PWM cycle has started:
• Wait until Timer2 overflows (TMR2IF bit of the PIR1 register is set).
• Enable the CCPx pin output driver by clearing the associated TRIS bit.

Note: This is only for 887. For Enhanced PWM Mode please refer to pic16F887 datasheet.

Lets do all this things in easy way by using in-build mikroc library for pwm.
Code:
Lets write the code to generate PWM on pins RC1 & RC2. And switches RA0-RA3 to increase/decrease PWM duty cycle.

unsigned short current_duty, current_duty1;

void InitMain() {
//using 887 and 8MHz xtal//////////////
  ANSEL  = 0;                         // Configure AN pins as digital
  ANSELH = 0;
  C1ON_bit = 0;                       // Disable comparators
  C2ON_bit = 0;

  PORTA = 255;
  TRISA = 255;                        // configure PORTA pins as input
  PORTC = 0;                          // set PORTC to 0
  TRISC = 0;                          // designate PORTC pins as output
  PWM1_Init(1000);                    // Initialize PWM1 module at 1KHz
  PWM2_Init(2000);                    // Initialize PWM2 module at 2KHz
}

void main() {
  InitMain();
  current_duty  = 16;                 // initial value for current_duty
  current_duty1 = 16;                 // initial value for current_duty1

  PWM1_Start();                       // start PWM1
  PWM2_Start();                       // start PWM2
  PWM1_Set_Duty(current_duty);        // Set current duty for PWM1
  PWM2_Set_Duty(current_duty1);       // Set current duty for PWM2

  while (1) {                         // endless loop
    if (RA0_bit) {                    // button on RA0 pressed
      Delay_ms(40);
      current_duty++;                 // increment current_duty
      PWM1_Set_Duty(current_duty);
     }

    if (RA1_bit) {                    // button on RA1 pressed
      Delay_ms(40);
      current_duty--;                 // decrement current_duty
      PWM1_Set_Duty(current_duty);
     }

    if (RA2_bit) {                    // button on RA2 pressed
      Delay_ms(40);
      current_duty1++;                // increment current_duty1
      PWM2_Set_Duty(current_duty1);
     }

    if (RA3_bit) {                    // button on RA3 pressed
      Delay_ms(40);
      current_duty1--;                // decrement current_duty1
      PWM2_Set_Duty(current_duty1);
     }

    Delay_ms(5);                      // slow down change pace a little
  }
}

PWM1_Init();Initializes the PWM module with duty ratio 0. Parameter freq is a desired PWM frequency in Hz.
PWM1_Set_Duty(); Sets PWM duty ratio. Parameter duty takes values from 0 to 255, where 0 is 0%, 127 is 50%, and 255 is 100% duty ratio. Other specific values for duty ratio can be calculated as (Percent*255)/100.
PWM1_Start(); Starts PWM.


Schematic:

Thursday, September 9, 2010

PIC16F887/877 programming in C Tutorial 7 (LCD Moving Display n Custom Characters)

LCD; Moving Display & Custom Character:
You can display your custom characters by using mikroc custom character tool. Go to tools>>customer character then make the character you want to display. After this click on 'generate code'. It will generate a customchar function just copy and paste above the main function. customchar has two parameters; row and position in that row. Just pass these parameters where you want to see your custom character on LCD.
You can also move the text, left and right, on LCD screen; by using the LCD commands. _LCD_SHIFT_LEFT and   _LCD_SHIFT_RIGHT are the commands. There are various other commands in mikroc, i forget to tell you in lcd tutorial, these are:
LCD Commands
Now lets write a code to display and move the custom character, back and forth, (of your choice) on LCD screen.

Code:

// 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

char txt[] = "MOVING TEXT";
char txt1[] = "EEW";
char i;                              // Loop variable
const char character[] = {0,31,4,10,17,17,14,0};

void CustomChar(char pos_row, char pos_char) {
  char i;
    Lcd_Cmd(64);
    for (i = 0; i<=7; i++) Lcd_Chr_CP(character[i]);
    Lcd_Cmd(_LCD_RETURN_HOME);
    Lcd_Chr(pos_row, pos_char, 0);
}

void main(){
///////// comment for 877////////////////////////////////////////
  ANSEL  = 0;                        // Configure AN pins as digital I/O
  ANSELH = 0;
  C1ON_bit = 0;                      // Disable comparators
  C2ON_bit = 0;
////////////////////////////////////////////////////////////////
  Lcd_Init();                        // Initialize LCD

  Lcd_Cmd(_LCD_CLEAR);               // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);          // Cursor off
  Lcd_Out(1,8,txt);                 // Write text in first row
  Lcd_Out(2,11,txt1);                 // Write text in second row
  CustomChar(2,14);
  CustomChar(2,10);

  // Moving text
  for(i=0; i<8; i++) {               // Move text to the right 4 times
    Lcd_Cmd(_LCD_SHIFT_RIGHT);
    Delay_ms(200);
  }

  while(1) {                         // Endless loop
    for(i=0; i<8; i++) {             // Move text to the left 7 times
      Lcd_Cmd(_LCD_SHIFT_LEFT);
      Delay_ms(200);
    }

    for(i=0; i<8; i++) {             // Move text to the right 7 times
      Lcd_Cmd(_LCD_SHIFT_RIGHT);
      Delay_ms(200);
    }
  }
}

After you specify the LCD connections paste the code of your custom character you wanna display. Then initialize the LCD, display text (if you want), and display your custom char by passing the positions parameter.  

Now to move text just use for loop and LCD command LEFT/RIGHT, where you want to move. Number of iterations depends on you. Once you have done this, use a endless loop and apply the for loop to move text in back forth. That is it!!.

Schematic:
moving text

PIC16F887/877 programming in C Tutorial 6 (Keypad Interfacing)

Keypad Interfacing:
This tutorial is about the interfacing of 4x3(4 rows & 3 columns) keypad with micro-controller using library routine of mikroc. Using these functions it is much easy to program. The basic technique is,  make the coloums as i/p and drive the rows making them o/p, this whole procedure of reading the keyboard is called scanning.

In order to detect which key is pressed from the matrix, we make row lines low one by one and read the coloums. Lets say we first make Row1 low, then read the columns. If any of the key in row1 is pressed will make the corrosponding column as low i.e if second key is pressed in Row1, then column2 will give low. So we come to know that key 2 of Row1 is pressed. This is how scanning is done.

So to scan the keypad completely, we need to make rows low one by one and read the columns. If any of the button is pressed in a row, it will take the corrosponding column to a low state which tells us that a key is pressed in that row. If button 1 of a row is pressed then Column 1 will become low, if button 2 then column2 and so on...

The above whole algorithm is in Keypad_Key_Click() function, we are going to use, ones we have key just compare it the ASCII value to get the right key.  

Code:
Lets write a program that display the pressed key and quantity (how many times the key is pressed), on LCD using mickroc routines.  

unsigned short kp, cnt, oldstate = 0;
char txt[4];

// 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() {
  cnt = 0;                                 // Reset counter
  Keypad_Init();                           // Initialize Keypad
 ///////////// comment for 877/////////////////////////////////////
  ANSEL  = 0;                              // Configure AN pins as digital I/O
  ANSELH = 0;
  c1on_bit=0;
  c2on_bit=0;
/////////////////////////////////////////////////////////////////
  Lcd_Init();                              // Initialize LCD
  Lcd_Cmd(_LCD_CLEAR);                     // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);                // Cursor off

  Lcd_Out(1, 1, "Key Pressed :");                 // Write message text on LCD
  Lcd_Out(2, 1, "Times: ");

  do {
    kp = 0;                                // Reset key code variable

    // Wait for key to be pressed and released
    do
            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  1: kp = 49; break; // 1
      case  2: kp = 50; break; // 2
      case  3: kp = 51; break; // 3
      case  4:                              //  kp = 65; break; // A for 4x4 pad
      case  5: kp = 52; break; // 4
      case  6: kp = 53; break; // 5
      case  7: kp = 54; break; // 6
      case  8:                              //kp = 66; break; // B for 4x4 pad
      case  9: kp = 55; break; // 7
      case 10: kp = 56; break; // 8
      case 11: kp = 57; break; // 9
      case 12:                             //kp = 67; break; // C for 4x4 pad
      case 13: kp = 42; break; // *
      case 14: kp = 48; break; // 0
      case 15: kp = 35; break; // #
      //case 16: kp = 67; break; // D for 4x4 pad
    }

    if (kp != oldstate) {                  // Pressed key differs from previous
      cnt = 1;
      oldstate = kp;
      }
    else {                                 // Pressed key is same as previous
      cnt++;
      }

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


    byteToStr(cnt, txt);                   // Transform counter value to string
    Lcd_Out(2, 12, txt);                   // Display counter value on LCD
  } while (1);
}

First specify the keypad connections; same thing we did in last tutorial, and LCD connections. Then initialize the keypad routine by using Keypad_Init() function, initialize the lcd and display the appropriate messages. Now once the key is pressed and the value is store in kp, by using Keypad_Key_Click() function, we have to compare the key number to its ASCII code to get the right key. Switch(kp) is used for this purpose.

Once we get the right key we compare it with oldstate; if Pressed key differs from previous, assign the cnt with one and update the oldstate. And if the Pressed key is same as previous, cnt is incremented (to count the number of times this key is pressed).

After this we want to display the pressed key and number of times on LCD. To display ASCII value, kp, we use 'Lcd_Chr' function. On the other hand cnt is a short to display it we have to convert it into a string; 'byteToStr' function is do the job. It converts input byte to a string. The output string has fixed width of 4 characters including null character at the end. txt[4] is declared for this purpose. For the next key the whole steps are repeated. 

Schematic:
keypad connection diagram

Wednesday, September 8, 2010

PIC16F887/877 programming in C Tutorial 5 (LCD Interfacing)

LCD Interfacing:
In this tutorial i will show you how to interface 16x2 LCD with micro-controller. 16x2 means there are two rows and each row contain maximum 16 characters. 
For more detail refer to the LCD datasheet, which you are using.
Basic Connection:
Applies 5v to pin 2 and gnd to pins 1 & 5. Use variable resistor at pin 3 to set contrast. Pins 7 to 14 are the data pins,, used to send/rec data. Pin 6 is of enable; every time when you write to lcd you should have to give high to low, to this pin. pin 4 is register select pin use to give commands like clear, home etc.  

In this tutorial i will interface lcd in 4-bit instead of 8-bit, so we only required four data pins.

Code:
Lets write a code that will display the motor status and its direction; it will be fun!!!!

Requirements:
Design a motor controller circuit using l298 and display its status on lcd. LCD is connected to portb and motor controller circuit is at portd. Required two switches to change motor direction; if both are open/close the motor should remain off. Also the switches are connected to portd.

// 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
char txt3[] = "Motor Direction";
char txt2[] = "Clock Wise ";
char txt1[] = "Counter C.W";
char txt[]  = "Motor Off  ";

void main() {
/////// comment for 877//////////////////
     ansel=0;
     anselh=0;
    
     c1on_bit=0;
     c2on_bit=0;
 ///////////////////////////////////////
     trisd0_bit=0;
     trisd1_bit=0;
     trisd2_bit=0;
    
     trisd3_bit=1;                 // CW dir
     trisd4_bit=1;                  //CCW dir

     Lcd_Init();                    // lcd ini
     Lcd_Cmd(_LCD_CLEAR);           //lcd clear
     Lcd_Cmd(_LCD_CURSOR_OFF);
     while(1){

      Lcd_Out(1,1,txt3);             //1row 1col
      delay_ms(500);
      if(rd3_bit){
        Lcd_Out(2,1,txt2);
        rd1_bit=0;
        rd0_bit=1;
      }
       
      if(rd4_bit){
        Lcd_Out(2,1,txt1);
        rd0_bit=0;
        rd1_bit=1;
      }
       
      if(rd3_bit & rd4_bit){             //invalid selction
        lcd_out(2,1,txt);
        rd0_bit=0;                       //to stop motor
        rd1_bit=0;
      }
       
      if(!rd3_bit & !rd4_bit){           //inv sec
        lcd_out(2,1,txt);
        rd0_bit=0;
        rd1_bit=0;
      }
      }

}


This is the simple code according to out requirement. To interface the LCD you must have to specify the port (port i/o), as well as the sfr of that port,  you are using 'sbit LCD_RS at RB4_bit' and 'sbit LCD_RS_Direction at TRISB4_bit' doing this job. As we are using LCD in four bit so, just specify the four data pins (pins 11 to 14 of LCD), E and RS pins.

txt1 to txt3 are the character array containing the message you want to display. Pins 0, 1, and 2 of portD is configure as o/p whereas pins 3, and 4 as i/p. L298 is connected to the pins0-2 and switches are at pins 3 and 4.

After setting the pins for LCD we used Lcd_Init(); a mikroc lcd library function, to initialize the LCD. Lcd_Cmd(char) is used to send commands to LCD like clear screen, curs0r off etc.
Lcd_Out(char row, char column, char *text); Prints text on Lcd starting from specified position; 1, 1 means first row and first column. Then a simple logic off switches and their functions.

L298 Connections:
Important thing is the connection of l298, as we are using out1 & out2 so we have to use in1 & in2, also have to enable ena pin for these selections. Use a 10 ohm resistor to connect between sensa pin and ground. Apply 9/12v to VCC, pin 9, depending on your motor voltage and 5v at pin 4, VC. To change to direction just change the bit value of in1 and in2; or in other words swap these values. If the both have same value, 0 or 1, motor will not rotate; as potential is same, current can't flow!!.

Schematic:
motor controller

Tuesday, September 7, 2010

PIC16F887/877 programming in C Tutorial 4 (Counter)

Counter:
Timer 0 and Timer 1 can be used as counter, as well. The only difference is Timer0 can count till 256 where as Timer1 till 65536; as Timer0 is 8-bit and Timer1 is 16-bit.

To use Timer 1 in counter just set the TMRCS (Timer1 Clock Source Select) bit, of T1CON reg. It will count when the signal is applied at T1CK1 pin, RC0. 
Where as, if you want to use Timer0; then set the T0CS (TMR0 Clock Source Select) bit of option reg. It will count when the signal is applied at T0CK1 pin, RA4. You can also select the edge, rising or falling, to trigger your counter by T0SE bit.

Code: 
Now lets write a code that will count till 65536 and display its count on LEDs attached to portD & portB;

void main() {
     //using 4MHz ext xtal
     trisd=0;
     portd=0;
     trisb=0;
     portb=0;

//////////////////////comment for 877 //////////////////////////
     ansel=0;
     anselh=0;
     c1on_bit=0;
     c2on_bit=0;
/////////////////////////////////////////////////////////////

     tmr1l=0;
     tmr1h=0;
     t1con=3;
     while(1){
          if(!tmr1if_bit) {             
              portd=tmr1l;
              portb=tmr1h;
          }
          tmr1if_bit=0;

     }
  }

Schematic:

Monday, September 6, 2010

PIC16F887/877 programming in C Tutorial 3-3 (Timer 2)

Timer 2:
Timer2 is an 8-bit timer with a prescaler and a postscaler. It can be used as the PWM time base for the PWM mode of the CCP module(s). The TMR2 register is readable and writable and is cleared on any device Reset.

The input clock (FOSC/4) has a prescale option of 1:1, 1:4 or 1:16, selected by control bits T2CKPS1:T2CKPS0 (T2CON<1:0>). 

The Timer2 module has an 8-bit period register, PR2.
Timer2 increments from 00h until it matches PR2 and then resets to 00h on the next increment cycle. PR2 is a readable and writable register. The PR2 register is initialized to FFh upon Reset. 

The match output of TMR2 goes through a 4-bit postscaler (which gives a 1:1 to 1:16 scaling inclusive) to generate a TMR2 interrupt (latched in flag bit, TMR2IF (PIR1<1>)).
Timer2 can be shut-off by clearing control bit, TMR2ON (T2CON<2>), to minimize power consumption.

Prescaler and Postscaler - Timer2 is an 8-bit timer with a prescaler and a postscaler. Each allows to make additional division of the frequency clock source.
Prescaler divides the frequency clock source BEFORE the counting take place at the register TMR2, thus the counting inside the TMR2 register is performed based on the divided frequency clock source by the Prescaler.
Postscaler divides the frequency that comes out of the Comparator.
T2CON Register:

How to calculate the required values of the TIMER2: TIMER2 FORMULA
Fout – The output frequency after the division.
Tout – The Cycle Time after the division.
4 - The division of the original clock by 4, when using internal crystal as clock (and not external oscillator).
Count - A numeric value to be placed to obtain the desired output frequency - fout.
(PR2 – TMR2) - The number of times the counter will count.

Code
Lets write the code to toggle the bits of portc after 2 sec;

void main() {
     // using 4MHz ext xtal
     int count=0;
     trisc=0;
     portc=255;
/////////////////// comment this block if you are using 877///////////
     ansel=0;
     anselh=0;
     c1on_bit=0;
     c2on_bit=0;
////////////////////////////////////////////
    
     t2con=124;         //prescaler is 16
     pr2=255;            //final value to count
     tmr2=0;              //initial value

     while(1){
        while(!tmr2if_bit);        //tmr2 flag bit
        tmr2if_bit=0;
        cnt++;


     if(cnt==488){                //for 2 sec(16*256u*488=2sec)
         portc=~portc;
         cnt=0;
         }

  }   
}


Schematic:
Timer 0 schematic can be used (tutorial 3 part 1).