15
ermicroblog Microcontrollers and Electronics Project Blog Home About Copyright and Disclaimer Contact Us Blog Entry PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project December 9, 2009 by rwb, under Microcontroller. Equipped with sophisticated Enhanced Capture/Compare/PWM (ECCP) peripheral the Microchip PIC18F14K50 microcontroller could produce up to four PWM channels output. The enhanced PWM (Pulse Width Modulation) mode in ECCP peripheral is capable to drive the full bridge DC Motor circuit directly both in forward or reverse direction. It also could generate single PWM output on the selectable PIC18F14K50 pins when it configured in pulse steering mode. In this tutorial we will take advantage of PIC18F14K50 pulse steering mode to drive the DC Motor and at the same time we will build the RPM (Rotation per Minute) counter to observe the PWM effect on the DC Motor speed and display it on the 2×16 LCD. The PWM and RPM Counter Project On this project we will use the HITEC C PRO PIC18 MCU Family Version 9.63PL3 and Microchip MPLAB IDE version 8.40 as our development tools platform. This project also serves as the learning tools of how to use many of the Microchip PIC18 advanced peripherals simultaneously to accomplish the project goal. You could see the complete project demonstrated on the video at the end of this tutorial; Ok now let’s list down all the project interesting features: Using Advanced 8-bit Microchip PIC18F14K50 microcontroller with PICJazz 20PIN development board Driving the HD44780U 2×16 LCD in 4-bit data mode Use DC Motor taken from discarded dual shock PS2 Playstation joystick and the Tamiya racing car Search This Site Future Post The 16-bit class microcontroller currently is become a choice to more advanced embedded system application. On the next post we will step into the 16-bit microcontroller world and explore some of its features. Therefore don't miss it, stay tune on this blog ! Recent Posts Building your own Simple Laser Projector using the Microchip PIC12F683 Microcontroller Working with the Comparator Circuit Build Your Own Simple and Easy Search Custom Search Ads by Google PWM Circuit Pic PWM Pic Tutorial PWM 8051 AC DC Motor Micro Analog Joystick Extended Temp, Ultra Low Power Reliable Performance For Portables. Digi - Key 한국 Distributor of Quality Electronic Products. 페이지 1 / 15 PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob... 2010-06-14 http://www.ermicro.com/blog/?p=1461

Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

Embed Size (px)

Citation preview

Page 1: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

ermicroblog Microcontrollers and Electronics Project Blog

Home About Copyright and Disclaimer Contact Us

Blog Entry

PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project December 9, 2009 by rwb, under Microcontroller.

Equipped with sophisticated Enhanced Capture/Compare/PWM (ECCP) peripheral the Microchip PIC18F14K50

microcontroller could produce up to four PWM channels output. The enhanced PWM (Pulse Width Modulation)

mode in ECCP peripheral is capable to drive the full bridge DC Motor circuit directly both in forward or

reverse direction. It also could generate single PWM output on the selectable PIC18F14K50 pins when it

configured in pulse steering mode. In this tutorial we will take advantage of PIC18F14K50 pulse steering

mode to drive the DC Motor and at the same time we will build the RPM (Rotation per Minute) counter to

observe the PWM effect on the DC Motor speed and display it on the 2×16 LCD.

The PWM and RPM Counter Project

On this project we will use the HITEC C PRO PIC18 MCU Family Version 9.63PL3 and Microchip MPLAB IDE

version 8.40 as our development tools platform. This project also serves as the learning tools of how to use

many of the Microchip PIC18 advanced peripherals simultaneously to accomplish the project goal. You could

see the complete project demonstrated on the video at the end of this tutorial; Ok now let’s list down all the

project interesting features:

Using Advanced 8-bit Microchip PIC18F14K50 microcontroller with PICJazz 20PIN development board

Driving the HD44780U 2×16 LCD in 4-bit data mode

Use DC Motor taken from discarded dual shock PS2 Playstation joystick and the Tamiya racing car

Search This Site

Future Post

The 16-bit class microcontroller currently is become a choice to more advanced embedded system application. On the next post we will step into the 16-bit microcontroller world and explore some of its features.

Therefore don't miss it, stay tune on

this blog !

Recent Posts

Building your own Simple Laser

Projector using the Microchip

PIC12F683 Microcontroller

Working with the Comparator

Circuit

Build Your Own Simple and Easy

Search

Custom Search Ads by Google PWM Circuit Pic PWM Pic Tutorial PWM 8051 AC DC Motor

Micro Analog Joystick Extended Temp, Ultra Low Power Reliable Performance For Portables. Digi-Key 한국 Distributor of Quality Electronic Products.

페이지 1 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 2: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

tire for measuring the DC Motor RPM

Simple and easy to build RPM sensor with the infra red reflective object sensor

Use the ADC peripheral to read the trimport value for adjusting the DC Motor Speed and display the

PWM duty cycle on the LCD

Use the PIC18F14K50 external interrupt and 16-bit TIMER0 counter to measure the RPM and display

it on the LCD.

The following is the C code that makes this thing happens:

/* *************************************************************************** ** File Name : pwmrpm.c ** Version : 1.0 ** Description : PIC18 Pulse Width Modulation with RPM Counter ** Author : RWB ** Target : PICJazz 20PIN Board: PIC18F14K50 ** Compiler : HI-TECH C PRO PIC18 MCU Family(Lite) Version 9.63PL3 ** IDE : Microchip MPLAB IDE v8.40 ** Programmer : PICKit2 ** Last Updated : 28 Nov 2009 ** ***************************************************************************/ #include <pic18.h>

/* ** PIC18F14K50 Configuration Bit: ** ** FCMDIS - Fail-Safe Clock Monitor disabled ** CPUDIV_0 - No CPU System Clock divide ** RCIO - Internal RC Oscillator ** PLLDIS - PLL is under software control ** ---------------------------------------------------------------------- ** BORDIS - Brown-out Reset disabled in hardware and software ** WDTDIS - WDT is controlled by SWDTEN bit of the WDTCON register ** ---------------------------------------------------------------------- ** MCLREN - MCLR pin enabled, RE3 input pin disabled ** ----------------------------------------------------------------------

PICAXE Microcontroller Based

Photovore Robot

Make your own Microcontroller

Printed Circuit Board (PCB) using

the Toner Transfer Method

The 2009 Year End Notes

PIC18 Pulse Width Modulation

(PWM) DC Motor Speed Controller

with the RPM Counter Project

PIC18 Microcontroller Analog to

Digital Converter with Microchip

C18 Compiler

Introduction to the Embedded

System with PICAXE

Microcontroller

Transforming your AVR

Microcontroller to the I2C or TWI

Slave I/O Expander Project

Build Your Own Microcontroller

Based PID Control Line Follower

Robot (LFR) – Second Part

Some Cool Electronics Stuff from

Your Discarded DVD Player

Build Your Own Transistor Based

Mobile Line Follower Robot (LFR) –

First Part

Simple and Easy Light Emitting

Diode (LED) Tester

Using Serial Peripheral Interface

(SPI) Master and Slave with Atmel

AVR Microcontroller

Single In Line (SIL) LED Display

for your Microcontroller Based

Project

Subscribe

Posts | Comments

Recommended Books

Teach Yourself Electricity and Elect...

Stan Gibilisco Best Price $18.35

or Buy New $23.07

Privacy Information

페이지 2 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 3: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

** XINSTDIS - Disable extended instruction set (Legacy mode) ** LVPDIS - Single-Supply ICSP disabled */

__CONFIG(1, FCMDIS & CPUDIV_0 & RCIO & PLLDIS); __CONFIG(2, BORDIS & WDTDIS); __CONFIG(3, MCLREN); __CONFIG(4, XINSTDIS & LVPDIS); __CONFIG(5, 0xFFFF); __CONFIG(6, 0xFFFF); __CONFIG(7, 0xFFFF);

// LCD Definition #define LCD_HOME 0x02 #define LCD_NEXT_LINE 0xC0 #define LCD_CLEAR 0x01 #define LCD_1CYCLE 0 #define LCD_2CYCLE 1

// RPM Counter Variable volatile unsigned int rpm_value; char sdigit[6]={'0','0','0','0','0','\0'};

/* Delay Function */ #define FOSC 16000000UL // Using Internal Clock of 16 MHz #define delay_us(x) { unsigned char _dcnt; \ _dcnt = (x)/(24000000UL/FOSC)|1; \ while(--_dcnt != 0) continue; }

void delay_ms(unsigned int cnt) { unsigned char i; do { i = 5; do { delay_us(164); } while(--i); } while(--cnt); }

// PIC18 High-priority Interrupt Service void interrupt high_isr(void){ static unsigned char pulse_state=0; unsigned int rpm_timer;

if (TMR0IF) { // Check for TIMER0 Overflow Interrupt rpm_value = 0; // Reset the RPM Value TMR0IF=0; // Clear TIMER0 interrupt flag }

if (INT0IF){ // Check for External INT0 Interrupt switch(pulse_state) { case 0: // First Low to High Pulse TMR0H = 0; // Zero the high byte in TMR0H Buffer TMR0L = 0; // Clear 16-bit TIMER0 Counter pulse_state=1; break; case 1: // Second Low to High Pulse rpm_timer=TMR0L; // Get the first 8-bit TIMER0 Counter rpm_timer+=(TMR0H << 8); // Get the last 8-bit TIMER0 Counter

// Calculate RPM = 60 x (1/Period) // RPM Value = 60000 (1 / (0.032 ms x rpm_timer)) rpm_value = (int) (60000.0 / (0.032 * rpm_timer)); pulse_state=0; } INT0IF = 0; // Clear INT0 interrupt flag } }

/* ** LCD Routine ** LCD Data RB7,RB6,RB5,RB4 ** LCD Control: RC7 -> E-Enable, RC6 -> RS-Register Select, R/W-Always 0 */ void LCD_putcmd(unsigned char data,unsigned char cmdtype) { // Put the Upper 4 bits data PORTB = data & 0xF0; RC6=0; // RS = 0 RC7=1; // E = 1

// E=0; write data RC7=0; delay_us(1); // Delay 1us for 16 MHz Internal Clock // cmdtype = 0; One cycle write, cmdtype = 1; Two cycle writes if (cmdtype) { // Put the Lower 4 bits data PORTB = (data & 0x0F) << 4; RC6=0; // RS = 0 RC7=1; // E = 1 // E=0; write data RC7=0; delay_us(1); // Delay 1us for 16 MHz Internal Clock }

Feature Product

PICJazz 20PIN Board

Categories

Blognote

Development Board News

Electronics

Microcontroller

Robotics

Yet Another Tips

Blogroll

ermicro shop

ermicroblog Amazon Store

ermicroblog on YouTube

ermicroblog video on Metacafe

Archives

April 2010

March 2010

February 2010

January 2010

December 2009

November 2009

October 2009

September 2009

August 2009

July 2009

June 2009

May 2009

April 2009

March 2009

Embedded C Programming and the

Atmel... Richard H. Barnett...

Best Price $73.76 or Buy New $111.59

Privacy Information

The PIC Microcontrolle John Morton

Best Price $19.56 or Buy New $19.65

Privacy Information

페이지 3 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 4: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

delay_ms(5); // Wait for busy flag (BF) }

void LCD_putch(unsigned char data) { // Put the Upper 4 bits data PORTB = data & 0xF0; RC6=1; // RS = 1 RC7=1; // E = 1

// E=0; write data RC7=0; delay_us(1); // Delay 1us for 16 MHz Internal Clock // Put the Lower 4 bits data PORTB = (data & 0x0F) << 4; RC6=1; // RS = 1 RC7=1; // E = 1 // E=0; write data RC7=0; delay_ms(5); // Wait for busy flag (BF) }

void LCD_init(void) { // Wait for more than 15 ms after VCC rises to 4.5 V delay_ms(30);

// Send Command 0x30 LCD_putcmd(0x30,LCD_1CYCLE);

// Wait for more than 4.1 ms delay_ms(8);

// Send Command 0x30 LCD_putcmd(0x30,LCD_1CYCLE);

// Wait for more than 100 us delay_us(200); // Delay 250us for 16 MHz Internal Clock ;

// Send Command 0x30 LCD_putcmd(0x30,LCD_1CYCLE);

// Function set: Set interface to be 4 bits long (only 1 cycle write). LCD_putcmd(0x20,LCD_1CYCLE);

// Function set: DL=0;Interface is 4 bits, N=1; 2 Lines, F=0; 5x8 dots font) LCD_putcmd(0x28,LCD_2CYCLE);

// Display Off: D=0; Display off, C=0; Cursor Off, B=0; Blinking Off LCD_putcmd(0x08,LCD_2CYCLE);

// Display Clear LCD_putcmd(0x01,LCD_2CYCLE);

// Entry Mode Set: I/D=1; Increament, S=0; No shift LCD_putcmd(0x06,LCD_2CYCLE);

// Display On, Cursor Off LCD_putcmd(0x0C,LCD_2CYCLE); }

void LCD_puts(const char *s) { while(*s != 0) { // While not Null if (*s == '\n') LCD_putcmd(LCD_NEXT_LINE,LCD_2CYCLE); // Goto Second Line else LCD_putch(*s); s++; } }

// Implementing integer value from 0 to 65530 char *num2str(unsigned int number,unsigned char start_digit) { unsigned char digit;

if (number > 65530) number = 0; digit = '0'; // Start with ASCII '0' while(number >= 10000) // Keep Looping for larger than 10000 { digit++; // Increase ASCII character number -= 10000; // Subtract number with 10000 } sdigit[0]='0'; // Default first Digit to '0' if (digit != '0') sdigit[0]=digit; // Put the first digit

digit = '0'; // Start with ASCII '0' while(number >= 1000) // Keep Looping for larger than 1000

February 2009

January 2009

December 2008

November 2008

Ads by Google 8051 Microcontroller DC Motor Control PWM Motor Driver Microcontroller LCD AVR Microcontroller

페이지 4 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 5: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

{ digit++; // Increase ASCII character number -= 1000; // Subtract number with 1000 }

sdigit[1]='0'; // Default Second Digit to '0' if (digit != '0') sdigit[1]=digit; // Put the Second digit

digit = '0'; // Start with ASCII '0' while(number >= 100) // Keep Looping for larger than 100 { digit++; // Increase ASCII character number -= 100; // Subtract number with 100 }

sdigit[2]='0'; // Default Second Digit to '0' if (digit != '0') sdigit[2]=digit; // Put the Second digit

digit = '0'; // Start with ASCII '0' while(number >= 10) // Keep Looping for larger than 10 { digit++; // Increase ASCII character number -= 10; // Subtract number with 10 }

sdigit[3]='0'; // Default Second Digit to '0' if (digit != '0') sdigit[3]=digit; // Put the Second digit

sdigit[4]='0' + number; return(sdigit + start_digit); }

void main(void) { unsigned char motor_stat,duty_cycle;

OSCCON=0x70; /* Select 8 MHz internal clock */

// Initial PORT TRISA = 0x30; // Input for RA4 and RA5 TRISC = 0x01; // Set RC0 as Input, RC<7:1> on PORTC as Output PORTC = 0x00; // Initial Port C TRISB = 0x00; // Set PORTB as Output PORTB = 0x00; // Initial Port B TRISB = 0x00; // Set All on PORTB as Output ANSEL = 0x08; // Set PORT AN3 to analog input ANSELH = 0x00; // Set PORT AN8 to AN11 as Digital I/O

// Initial LCD using 4 bits data interface LCD_init(); LCD_puts("PICJazz 20-PIN\n");

// Init ADC ADCON0=0b00001101; // ADC port channel 3 (AN3), Enable ADC ADCON1=0b00000000; // Use Internal Voltage Reference (Vdd and Vss) ADCON2=0b00101011; // Left justify result, 12 TAD, Select the FRC for 16 MHz // Init TIMER0: Period: 4 x Tosc x Prescale for each counter // Tosc = 1/16 Mhz = 0.0000000625 // TIMER0 Period: 4 x 0.0000000625 x 128 = 0.000032 Second = 0.032 ms T0CON = 0b10000110; // TIMER0 Enable, use 16-bit timer and prescale 1:128 TMR0H = 0; // Zero the high byte in TMR0H Buffer TMR0L = 0; // Clear 16-bit TIMER0 Counter TMR0IE = 1; // Enable TIMER0 Overflow Interrupt

// Set the External Interrupt on INT0 (RC0) Port INT0IE = 1; // Enables the INT0 external interrupt INTEDG0 = 1; // Interrupt on rising edge // Init PWM for Single Output CCP1CON=0b00001100; // Single PWM mode; P1A, P1C active-high; P1B, P1D active-high CCPR1L=0; // Start with zero Duty Cycle PSTRCON=0b00000100; // Enable PIC Pulse Steering PWM on RC3 Port

// PWM Period = 4 x Tosc x (PR2 + 1) x TMR2 Prescale Value // Tosc = 1/16 Mhz = 0.0000000625 // PWM Period = 4 x 0.0000000625 x 201 x 4 = 0.000201 // PWM Frequency = 1/PWM Period = 1/0.000201 = 4.975 kHz T2CON=0b00000101; // Postscale: 1:1, Timer2=On, Prescale = 1:4 PR2=200; // Frequency: 4.975 kHz TMR2=0; // Start with zero Counter // Initial Variable used rpmvalue=0; motor_stat=0; // Motor Off Condition duty_cycle=0; // 0 Duty Cycle

// Now Enable the Interrupt IPEN = 1; // Enable High Priority Interrupt GIEH = 1; // Global Interrupt Enable (High Priority)

for(;;) { if (RA5 == 0) { // Read Switch delay_ms(1); if (RA5 == 0) { // Read again for Simple Debounce

페이지 5 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 6: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

motor_stat ^= 0x01; } } if (motor_stat) { GODONE=1; while (GODONE) continue; // Wait conversion done duty_cycle=ADRESH; // Get the High byte ADC 8-bit result } else { duty_cycle=0; } // Assign duty cycle to the PWM CCPR1L register CCPR1L = duty_cycle;

// Display the Information on the LCD LCD_putcmd(LCD_HOME,LCD_2CYCLE); // LCD Home LCD_puts("Duty Cycle: "); LCD_puts(num2str((int)((duty_cycle/255.0) * 100.0),3)); LCD_puts(" %"); LCD_putcmd(LCD_NEXT_LINE,LCD_2CYCLE); // Goto Second Line LCD_puts("RPM: "); LCD_puts(num2str(rpm_value,1)); // Put the delay here delay_ms(10); } }

/* EOF: pwmrpm.c */

The PIC18 Pulse Steering PWM mode

The heart of the PIC18F14K50 pulse steering PWM mode is rely on the TIMER2 peripheral, where it used as

the basic counter generator for the PWM signal. The TIMER2 counter clock (TMR2) is supplied by selectable

prescale clock, this prescale circuit will divide the system clock by 1, 4 or 16 respectively. The prescale could

be selected by assigning the T2CKPS1 and T2CKPS0 bits in the T2CON register.

페이지 6 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 7: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

The TMR2 register value is continuously compared to the PR2 register which determine the TOP value of

the TMR2 counter register. When the TMR2 register value reach the PR2 value, then the TMR2 counter

register value will be reset to 0.

At the same time the value of TMR2 counter register is also being compared to the CCPR1L register value

(actually with the CCPR1H register value, since the CCPR1H equal to CCPR1L than we could say CCPR1L),

when the TMR2 reach the CCPR1L value than the PWM peripheral circuit will reset the CCP1 output (logical

“0“) and when the TMR2 counter register equal to the PR2 register value than it will set the CCP1 output

(logical “1“). Therefore by changing the PR2 value we could change the PWM period and this mean changing

the PWM frequency as well. The PWM period could be calculated using this following formula:

PWM period = 4 x Tosc x ( PR2 + 1) x (TMR2 prescale value) second

Where Tosc is the system clock period in second

PWM frequency = 1 / PWM Period Hz

By assigning the PR2 register with 200 and select the prescale to 4; and applying all these values to the

formula above, we could determine the PWM frequency for our DC Motor base on the internal system

oscillator of 16 MHz as follow:

PWM period = 4 x (1 / 16.000.000) x 201 x 4 = 0.000201 second

Therefore the PWM frequency is:

PWM frequency = 1 / 0.000201 = 4.975 kHz

The T2CON (TIMER2 Control) register is used select the postscale (T2OUTPS<3:0>), activate the TIMER2

peripheral (TMR2ON) and set the prescale clock used by the TMR2 counter register. BY setting the

T2CKPS1=0 and T2CKPS0=1 in the T2CON register we select the 1:4 prescale; and by setting the

TMR2ON to logical “1” we activate the TIMER2 peripheral.

페이지 7 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 8: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

The following is the C code to initialize the TIMER2 peripheral:

// PWM Period = 4 x Tosc x (PR2 + 1) x TMR2 Prescale Value // Tosc = 1/16 Mhz = 0.0000000625 // PWM Period = 4 x 0.0000000625 x 201 x 4 = 0.000201 // PWM Frequency = 1/PWM Period = 1/0.000201 = 4.975 kHz T2CON=0b00000101; // Postscale: 1:1, Timer2=On, Prescale = 1:4 PR2=200; // Frequency: 4.975 kHz TMR2=0; // Start with zero Counter

By setting P1M1=0 and P1M0=0 bits in the CCP1CON register we select the single output PWM; setting

the CCP1M3=1, CCP1M2=1, CCP1M1=0 and CCP1M0=0 in the CCP1CON register we select the PWM

mode with P1A, P1C active-high; P1B, P1D active-high.

On this tutorial we just set the additional 2 LSB extended bits (DC1B1 and DC1B0) to all zero (logical “0“)

for the CCPR1L register (10-bit wide). We start by setting the CCPR1L to zero mean we start with zero

duty cycle (no PWM output yet). In single PWM mode we could select the PWM output to PIC18F14K50 RC3

output port by setting the STRC bit on PSTRCON (Pulse Steer Control) register to the logical “1” while other

bits is set to logical “0“. The following is the C code:

// Init PWM for Single Output CCP1CON=0b00001100; // Single PWM mode; P1A, P1C active-high; P1B, P1D active-high CCPR1L=0; // Start with zero Duty Cycle PSTRCON=0b00000100; // Enable PIC Pulse Steering PWM on RC3 Port

By applying the analog value read from the 10K trimport connected to the PIC18F14K50 RA4 pins, we could

easily varying the PWM duty cycle by changing the voltage divider output formed by the 10K trimport. The

following C code shows how we use the PIC18F14K50 microcontroller ADC peripheral to change the PWM

duty cycle; for more information about using the ADC peripheral on PIC18 families you could read my

previous posted blog PIC18 Microcontroller Analog to Digital Converter with Microchip C18 Compiler:

// Init ADC ADCON0=0b00001101; // ADC port channel 3 (AN3), Enable ADC ADCON1=0b00000000; // Use Internal Voltage Reference (Vdd and Vss) ADCON2=0b00101011; // Left justify result, 12 TAD, Select the FRC for 16 MHz ... ...

if (motor_stat) { GODONE=1; while (GODONE) continue; // Wait conversion done duty_cycle=ADRESH; // Get the High byte ADC 8-bit result } else { duty_cycle=0; } // Assign duty cycle to the PWM CCPR1L register CCPR1L = duty_cycle;

The enhanced PWM feature on the PIC18 families actually is almost identical to the PIC16 families series,

therefore you could read more about the enhanced PWM feature if you want to drive the H-bridge DC motor

circuit from my previous posted blog H-Bridge Microchip PIC Microcontroller PWM motor Controller.

The RPM Sensor

To count the DC motor rotation per minute (RPM), I decided to use the infra red reflective object sensor

Junye JY209-01 or you could replace it with Fairchild QRE00034; as this type of sensor will make sensing the

DC motor rotation become easier.

페이지 8 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 9: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

The infra red reflective object sensor work by simply emitting the infra red beam and when it encounter the

white object surface than the infra red beam will be reflected back to the phototransistor; next the

phototransistor and the 2N3904 transistor which formed the Darlington pair will start to conduct and will

generate enough voltage across the 470 Ohm resistor to be considered by the PIC18F14K50 microcontroller

build in Schmitt trigger RC0 input port as the logical “1“. When the infra red beam encounters the black tire

surface than both of the phototransistor and 2N3904 transistor will turn off; and the voltage across 470 Ohm

resistor will drop to zero volt (logical “0“).

Therefore by timing the generated pulse period by the infra red reflective object sensor we could easily

calculate the RPM using this following formula:

Frequency = 1/T Hz; T is the generated pulse period in second.

RPM (Rotation per Minute) = Frequency x 60

The following pictures show in detail of how I put the PS2 Playstation dual shock DC motor, the Tamiya

racing car tire with the white sticker and the infra red reflective object sensor for this project.

페이지 9 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicrob...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 10: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

The PIC18 External Interrupt

As I mention before that in order to calculate the DC motor RPM, we could simply calculate the period of the

pulse generated by the RPM sensor shown above. One of the methods to measure the pulse period is to use

the PIC18F14K50 microcontroller ECCP (Enhanced Capture/Compare/PWM) peripheral in the capture mode

to calculate the period; in the capture mode we could easily use the 16-bit TIMER1 or TIMER3 to count the

pulse period by feeding the pulse directly to the CCP1 pins (RC5). The capture interrupt will be generated

every rising edge of the pulse (or falling edge), therefore by knowing the exact TIMER1 or TIMER3 counter

clock time period and get the timer 16-bit counted value between the two rising edge pulse we could

calculate the RPM.

Unfortunately we could not use the Microchip PIC18F14K50 microcontroller ECCP peripheral as this

peripheral has already being used to generate the PWM signal for the DC motor in our project, but using the

same principal we could make use of the PIC18F14K50 external interrupt peripheral on pin INT0 (RC0) or

INT1 (RC1). This external interrupt peripheral will generate interrupt on every rising edge (or falling edge)

of the pulse; therefore by combining it with the 16-bit TIMER0 counter mode now we could calculate the

RPM as shown on the following diagram.

As shown on the above picture, first we have to activate the PIC18F14K50 microcontroller external interrupt

and configure it to detect the pulse rising edge; next we configure the TIMER0 peripheral for the RPM period

counter.

페이지 10 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicr...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 11: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

By setting the TMR0E and INT0IE bits to logical “1” on the PIC18F14K50 microcontroller interrupt control

register (INTCON) and TMT0ON bits to logical “1” on the TIMER0 control register (T0CON), we activate

both the TIMER0 and External peripherals. Selecting the 1:256 prescale value we could calculate the time

required to increase the TIMER0 16-bit counter.

TIMER0 Clock period = 4 x Tosc x TMR2 prescale value second

TIMER0 Clock period = 4 x (1/16.000.000) x 128 = 0.000032 second = 0.032 ms

This mean the TIMER0 counter required 0.032 ms to increase the TMR0L and TMR0H registers counter

value by one. The following C code shows the PIC18F14K50 microcontroller external interrupt and TIMER0

peripherals initialization:

// Init TIMER0: Period: 4 x Tosc x Prescale for each counter // Tosc = 1/16 Mhz = 0.0000000625 // TIMER0 Period: 4 x 0.0000000625 x 128 = 0.000032 Second = 0.032 ms T0CON = 0b10000110; // TIMER0 Enable, use 16-bit timer and prescale 1:128 TMR0H = 0; // Zero the high byte in TMR0H Buffer TMR0L = 0; // Clear 16-bit TIMER0 Counter TMR0IE = 1; // Enable TIMER0 Overflow Interrupt

// Set the External Interrupt on INT0 (RC0) Port INT0IE = 1; // Enables the INT0 external interrupt INTEDG0 = 1; // Interrupt on rising edge

By setting the INTEDG0 to logical “1” on INTCON2 (interrupt Control 2) register we choose the Rising

Edge detection. The RPM value is being calculated inside the interrupt service routine as shown on this

following C code:

// PIC18 High-priority Interrupt Service void interrupt high_isr(void){ static unsigned char pulse_state=0; unsigned int rpm_timer;

if (TMR0IF) { // Check for TIMER0 Overflow Interrupt rpm_value = 0; // Reset the RPM Value TMR0IF=0; // Clear TIMER0 interrupt flag }

if (INT0IF){ // Check for External INT0 Interrupt switch(pulse_state) { case 0: // First Low to High Pulse TMR0H = 0; // Zero the high byte in TMR0H Buffer TMR0L = 0; // Clear 16-bit TIMER0 Counter pulse_state=1; break; case 1: // Second Low to High Pulse rpm_timer=TMR0L; // Get the first 8-bit TIMER0 Counter rpm_timer+=(TMR0H << 8); // Get the last 8-bit TIMER0 Counter

// Calculate RPM = 60 x (1/Period) // RPM Value = 60000 (1 / (0.032 ms x rpm_timer)) rpm_value = (int) (60000.0 / (0.032 * rpm_timer)); pulse_state=0; } INT0IF = 0; // Clear INT0 interrupt flag } }

By resetting the TIMER0 counter on the first rising edge external interrupt and reading back the TIMER0

counter on the second rising edge external interrupt we could easily calculate the pulse period

페이지 11 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicr...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 12: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

Pulse Period = 0.032 x TIMER0 Counter (TMR0H:TMR0L) millisecond

The RPM value is the frequency of rotation measured in minute (60 second), therefore the DC motor RPM

value could be calculated as the following formula:

rpm_value = (1 / Pulse Period) in second x 60 = 60000.0 / 0.032 x rpm_timer

The rpm_timer variable contains the 16-bit TIMER0 counter value, while the global rpm_value contain the

RPM value of the DC motor.

The PICKit2 Logic Analyzer

To check the RPM counter accuracy I simply use one of the useful feature of the Microchip PICKit2

programmer, where we could use it as the powerful Logic Analyzer tools to debug serial communication

buses such as UART, SPI and I2C. This time we will use it to analyze the RPM pulse produce by the infra red

reflective object sensor circuit above and connected the output directly to the PIC18F14K50 microcontroller

RC0 input port and the PICKit2 channel 3 inputs to measure the RPM pulse period.

The PICKit2 Logic Analyzer tool could be used by running the PICKit2 programmer Version v2.61 and

selecting the Logic Tools from the Tools menu; set the Rising Edge trigger on the channel 3 and 100 ms

Sample Rate; next press the RUN button. After the pulse appears check the Cursor checkbox to activate the

X and Y horizontal bar to measure the pulse period.

As shown on the above picture, the channel 3 on the PICKit2 logic analyzer tool show that the measured

pulse frequency is about 77.52 Hz; this mean the RPM is about 4651 (77.52 x 60) which is close enough to

the RPM calculated value 4641 displayed on the LCD at 72% PWM duty cycle.

The 2×16 LCD Display

To display both of the PWM duty cycle and RPM value, I used the Hitachi HD44780U or the equivalent

microcontroller 2×16 LCD with back light LED in 4-bit data mode. Most of the LCD function C routine I use in

this project is taken from my previous posted blog AVR LCD Thermometer Using ADC and PWM Poject;

where you could read more information about the principal of how to drive this kind of display. The following

is the list of C function for driving the LCD:

LCD_putch() function is used to display single character on the LCD

LCD_putcmd() function is used to send LCD command (e.g. clear the LCD, move to second row, etc)

LCD_init() function is used to initialized the 2×16 LCD; this function will initialized the 2×16 LCD into

4-bit data mode

LCD_puts() function is used to display a string on the LCD

num2str() function is used to convert a numeric value to a string, we use this function to display

numeric value on the LCD.

Inside the C Code

The C program begins by selecting the 16 MHz internal clock and setting all the I/O ports used on this

project. After doing the LCD, ADC, TIMER0, External Interrupt and PWM/TIMER2 peripherals setup. After

페이지 12 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicr...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 13: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

enabling the high priority interrupt and activating the global interrupt the code enter the for(;;) endless

loop. Inside this loop; first we read the user’s switch, this switch is attached to the PIC18F14K50

microcontroller input port RA5 and work as the toggle switch to run or stop the DC motor:

if (RA5 == 0) { // Read Switch delay_ms(1); if (RA5 == 0) { // Read again for Simple Debounce motor_stat ^= 0x01; } }

The PIC18F14K50 microcontroller ADC peripheral than read the analog input on channel 3 (RA4) port and

assigned the value to the CCPR1L register where it used to control the PWM duty cycle.

if (motor_stat) { GODONE=1; while (GODONE) continue; // Wait conversion done duty_cycle=ADRESH; // Get the High byte ADC 8-bit result } else { duty_cycle=0; }

// Assign duty cycle to the PWM CCPR1L register CCPR1L = duty_cycle; Then next we display the duty cycle and the RPM value on the 2x16 LCD:

// Display the Information on the LCD LCD_putcmd(LCD_HOME,LCD_2CYCLE); // LCD Home LCD_puts("Duty Cycle: "); LCD_puts(num2str((int)((duty_cycle/255.0) * 100.0),3)); LCD_puts(" %"); LCD_putcmd(LCD_NEXT_LINE,LCD_2CYCLE); // Goto Second Line LCD_puts("RPM: "); LCD_puts(num2str(rpm_value,1));

Downloading and Running the Code

After compiling and simulating your code hook up your PICKit2 programmer to the PICJazz 20PIN

development and learning board ICSP port turn power on. From the MPLAB IDE menu select Programmer -

> Select Programmer -> Pickit2 it will automatically configure the connection and display it on the

PICkit2 tab Output windows; now you are ready to down load the code from MPLAB IDE menu select

Programmer -> Program; this will down load the HEX code into the PICJazz 20PIN board with the

Microchip PIC18F14K50 microcontroller on it.

Now its time to run your PWM and RPM counter code, where you could enjoy this following video showing all

of the process that we’ve been going through.

The Final Though

Obviously the Microchip PIC18 PWM peripheral feature is almost identical to its 8-bit PIC16 little brother

families, therefore upgrading from the PIC16 to PIC18 could be done almost without changing the code. In

this project we also take advantage of the infra red reflective object sensor to measure the RPM, where we

don’t have to make special modification on the wheel in order to make this sensor to sense the rotation; all

we need is just a piece of white sticker attached to the wheel.

This project also shows us an example of how we use many of the advanced PIC18F14K50 microcontroller

peripherals at the same time, which will help to shape our understanding of how we could utilize all of these

페이지 13 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicr...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 14: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

peripherals in the future project.

Bookmarks and Share

Related Posts

The 2009 Year End Notes

Using Maxim DS1307 Real Time Clock with Atmel AVR Microcontroller

Basic Servo Motor Controlling with Microchip PIC Microcontroller

H-Bridge Microchip PIC Microcontroller PWM Motor Controller

AVR Twinkle Twinkle Using PWM Project

6 Responses to “PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project”

Comment by lawrence.

Hi I would appreciate it if you could send the code in assembly

(*.asm ) as i am not familiar c or if there is a method to change

the code then i would appreciate it and i am using the pic

16f887A mplab v8.1 using a bootloader connected via rs232.

please help me out

29.03.10 #1

Comment by rwb.

For this project I program it only on C language not assembler,

but if you familiar with the PIC assembler you could use similar

principle to manipulate the PIC microcontroller registers as

described on this blog. As I also use direct register manipulation

to achieve this project purpose (i.e. PWM and ADC).

29.03.10 #2

Comment by lawrence.

well i have tried to change tmr0 as it is 16-bit on the 18f but 8-

bit on the 16f etc so do you mind if you can post a C code but

this using the famous outdated 16f877a please help me out as I

am struggling to get it right using the pic 16f877 believe me i

have manipulated the timer and ADC to 10 bit and did the

justification but still struggling.

31.03.10 #3

Comment by rwb.

My suggestion is to try the microcontroller peripherals once at

the time start with the ADC then continue with the PWM,

External Interrupt and TIMER0.

31.03.10 #4

Comment by embed84.

Hi i am a student embedded systems, and i’m working on my

first microchip project cool, i wonder if i can use the void interrupt high_isr(void); function on a pic18f4550 to read

01.06.10 #5

Netbooks NetBooks Core Smart Book Processors www.Freescale.com/i.mx

페이지 14 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicr...

2010-06-14http://www.ermicro.com/blog/?p=1461

Page 15: Pic18 Pulse Width Modulation (Pwm) Dc Motor Speed Controller With the Rpm Counter Project Ermicroblog

Leave a Comment

You must be logged in to post a comment.

the rotation of my robot wheels. i’m using two QSE113

transistors. the pulses will be used to make a rotation of 45

degrees. is it possible?

Comment by rwb.

Although its possible to do that but for controlling DC motor for

fix 45 degree rotation will be quite hard as you need to apply

special circuit and logic for the DC motor break system. For

precision position its better to use the DC stepper motor.

01.06.10 #6

Copyright © 2008-2010 By ermicro. Powered by Word Press.

페이지 15 / 15PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project | ermicr...

2010-06-14http://www.ermicro.com/blog/?p=1461