You are on page 1of 18

ĐO TỐC ĐỘ VÀ ĐIỀU KHIỂN ĐỘNG CƠ

ENCODER
I. Nguyên lý:
Ta sử dụng L298 để đảo chiều quay cho động cơ. ADC sẽ dùng
để điều chỉnh độ rộng xung cho PWM. Dùng ngắt để đếm xung
đo được từ động cơ encoder . Còn timer1 để tạo thời gian trích
mẫu tính toán để ra được tốc độ của động cơ, sau đó truyền
thông tốc độ của động cơ lên máy tính.

II. Các linh kiện


1. Động cơ encoder
- tín hiệu từ encoder tạo ra các dạng xung vuông có tần số
thay đổi phụ thuộc vào tốc độ động cơ. Do đó các xung
vuông này được đưa vào bộ vi xử lý để đếm số xung trong
khoảng thời gian cho phép từ đó ta có thể tính được giá trị
vận tốc của động cơ.
- Động cơ encoder có một đĩa tròn xoay quay quanh trục.
Trên đĩa có các lỗ (rãnh). Người ta dùng một đèn led để
chiếu lên mặt đĩa. Khi đĩa quay, chỗ không có lỗ (rãnh),
đèn led không chiếu xuyên qua được, chỗ có lỗ (rãnh), đèn
led sẽ chiếu xuyên qua. Khi đó, phía mặt bên kia của đĩa,
người ta đặt một con mắt thu. Với các tín hiệu có, hoặc
không có ánh sáng chiếu qua, người ta ghi nhận được đèn
led có chiếu qua lỗ hay không.Số xung đếm được và tăng
lên nó tính bằng số lần ánh sáng bị cắt!
2. IC L298
- là 1 IC tích hợp nguyên khối gồm 2 mạch cầu H bên trong.
Với điện áp làm tăng công suất đầu ra từ 5V – 47 V, dòng
lên đến 4A. L298 rất thích hợp trong những ứng dụng
công suất nhỏ như động cơ DC loại vừa . L298 có thể điều
khiển 2 động cơ DC hoặc 1 động cơ bước.
- Thông số kỹ thuật L298:
+ Driver: L298N tích hợp hai mạch cầu H
+ Điện áp điều khiển : +5V ~ +12 V
+ Dòng tối đa cho mỗi cầu H là :2A
+ Điện áp của tín hiệu điều khiển : +5 V ~ +7 V
+ Dòng của tín hiệu điều khiển : 0 ~ 36mA
+ Công suất hao phí : 20W (khi nhiệt độ T = 75 °C)
+ Nhiệt độ bảo quản : -25°C ~ +130
- Các chân chức năng của L298:
+ 4 chân INPUT: IN1, IN2, IN3, IN4 được nối lần lượt với
các chân 5, 7, 10, 12 của L298. Đây là các chân nhận tín
hiệu điều khiển.
+ 4 chân OUTUT: OUT1, OUT2, OUT3, OUT4 (tương
ứng với các chân INPUT) được nối với các chân 2,
3,13,14 của L298. Các chân này sẽ được nối với động cơ.
+ Hai chân ENA và ENB dùng để điều khiển mạch cầu H
trong L298. Nếu ở mức logic “1” (nối với nguồn 5V) cho
phép mạch cầu H hoạt động, nếu ở mức logic “0” thì mạch
cầu H không hoạt động
- Cách điều khiển chiều quay động cơ:
+ Khi ENA = 0: Động cơ không quay với mọi đầu vào.
+ Khi ENA = 1:
 INT1 = 1; INT2 = 0: Động cơ quay thuận.
 INT1 = 0; INT2 = 1: Động cơ quay nghịch.
 INT1 = INT2: Động cơ dùng ngay tức thì.
+ Với ENB cũng tương tự với INT3, INT4.
3. LCD
- LCD 16x2 là một thiết bị hiển thị cơ bản thường được
dùng để giao tiếp với người dùng thông qua việc hiển thị.
LCD 16×2 gồm 2 dòng, mỗi dòng có thể hiển thị được 16
ký tự, ngoài ra còn có nhiều loại LCD khác nhau như
16x1, 16x4… với LCD này mỗi ký tự được hiển thị bởi
một ma trận điểm 5x8 hoặc 5x10.
- Các chân của LCD 16x2
+ Chân GND và VCC chính là chân đất và chân nguồn
dương cấp cho LCD.
+ Chân thứ 3 – VEE dùng để điều chỉnh độ sáng cho LCD,
thông thường chân này được nối với một biến trở để cho
phép điều chỉnh độ sáng của LCD.
+ Vi điều khiển cần truyền dữ liệu cho LCD để LCD có
thể hiển thị, dữ liệu truyền xuống gồm 2 phần:
 Data: là mã ASCII của ký tự cần hiển thị lên màn
hình LCD
 Command: Lệnh yêu cầu LCD thực thi, ví dụ như
xóa màn hình, dịch màn hình, vị trí hiển thị…

III. Công thức tính toán


* tính tốc độ động cơ dựa vào số xung đo được trong khoảng
thời gian trích mẫu:
+ Ta có :
V = n/N (vòng/giây)
Trong đó:
V: Tốc độ động cơ.
n: Số xung Encoder đếm được trong 1 giây.
N: Độ phân giải của Encoder. Trong 1 giây lấy mẫu này nó sẽ là
quá lớn dẫn đến việc sai số trong đếm xung và làm cho thời gian
hiệu chỉnh tốc độ không được liên tục vậy thời gian lấy mẫu rất
quan trọng, không được quá lớn hay quá bé.

Vậy ta chọn lại thời gian lấy mẫu.


Ta có công thức:
V = (nS*1000)/(N*TS) (vòng/giây)

Trong đó:
TS: Thời gian lấy mẫu (ms)
nS: Số xung Encoder xuất ra trong thời gian TS

 Vậy tốc độ tính theo vòng/phút thì ta sẽ có:

V = (nS*1000*60)/(N*TS) (vòng/phút)

IV. Code
 Thư viện ADC

void ADC_Init()
{
ADCON0 = 0x81; //kenh0, tan so 32, kich hoat
ADC
ADCON1 = 0x80; //kieu ghi du lieu vao thanh
ghi(du lieu 16bit theo thu tu 10bit)
}
unsigned int ADC_Read(unsigned char channel)
{
if(channel > 7)
return 0;
ADCON0 &= 0xC5;
ADCON0 |= channel << 3;
__delay_ms(2);
GO_nDONE = 1;
while(GO_nDONE);
return((ADRESH<<8) + ADRESL);
}
 Thư viện LCD

#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
void Lcd_Port(char a)
{
if(a & 1)
D4 = 1;
else
D4 = 0;
if(a & 2)
D5 = 1;
else
D5 = 0;
if(a & 4)
D6 = 1;
else
D6 = 0;
if(a & 8)
D7 = 1;
else
D7 = 0;
}
//////////////////
void Lcd_Cmd(char a)
{
RS = 0; // => RS = 0
Lcd_Port(a);
EN = 1; // => E = 1
__delay_ms(4);
EN = 0; // => E = 0
}
/////////////////
void Lcd_Init()
{
Lcd_Port(0x00);
__delay_ms(20);
Lcd_Cmd(0x03);
__delay_ms(5);
Lcd_Cmd(0x03);
__delay_ms(11);
Lcd_Cmd(0x03);
/////////////////////////////////////////////////////
Lcd_Cmd(0x02);
Lcd_Cmd(0x02);
Lcd_Cmd(0x08);
Lcd_Cmd(0x00);
Lcd_Cmd(0x0C);
Lcd_Cmd(0x00);
Lcd_Cmd(0x06);
}
//////////////
Lcd_Clear()
{
Lcd_Cmd(0);
Lcd_Cmd(1);
}
//////////////////
void Lcd_Set_Cursor(char a, char b)
{
char temp,z,y;
if(a == 1)
{
temp = 0x80 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
else if(a == 2)
{
temp = 0xC0 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
}
////////////
void Lcd_Write_Char(char a)
{
char temp,y;
temp = a&0x0F;
y = a&0xF0;
RS = 1; // => RS = 1
Lcd_Port(y>>4); //Data transfer
EN = 1;
__delay_us(40);
EN = 0;
Lcd_Port(temp);
EN = 1;
__delay_us(40);
EN = 0;
}

void Lcd_Write_String(char *a)


{
int i;
for(i=0;a[i]!='\0';i++)
Lcd_Write_Char(a[i]);
}
////////////
void Lcd_Shift_Right()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
}
///////////////////////////////////////////////////////
void Lcd_Shift_Left()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x08);
}
 Thư viện PWM

#ifndef XC_HEADER_TEMPLATE_H
#defineXC_HEADER_TEMPLATE_H
#include <xc.h> // include processor files - each
processor file is guarded.
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

// TODO If C++ is being used, regular C code


needs function names to have C
// linkage so the functions can be used by the c
code.

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* XC_HEADER_TEMPLATE_H */

#include <xc.h>

long freq;
#define TMR2PRESCALE 4
//#define _XTAL_FREQ 20000000
int PWM_Max_Duty()
{
return
(_XTAL_FREQ/(freq*TMR2PRESCALE));
}

//chuog trinh con cai dat tan so bam xung


PWM1_Init(long fre)
{
PR2 =
(_XTAL_FREQ/(fre*4*TMR2PRESCALE))-1;
//tinh PR2 theo CT chu ki xung
freq = fre;
}

PWM2_Init(long fre)
{
PR2 =
(_XTAL_FREQ/(fre*4*TMR2PRESCALE))-1;
freq = fre;
}

//cai dat ham pwm


PWM1_Start()
{
CCP1CONbits.CCP1M3 = 1;
CCP1CONbits.CCP1M2 = 1;

#if TMR2PRESCALAR == 1
T2CKPS0 = 0
T2CKPS1 = 0
#elif TMR2PRESCALAR == 4
T2CKPS0 = 1;
T2CKPS1 = 0;
#elif TMR2PRESCALAR == 16
T2CKPS0 = 1;
T2CKPS1 = 1;
#endif
TMR2ON = 1; // kích ho?t timer2
TRISC2 = 0; //cho phép ccp1 ho?t ??ng
}
//////
PWM2_Start()
{
CCP2CONbits.CCP2M3 = 1;
CCP2CONbits.CCP2M2 = 1;
#if TMR2PRESCALE == 1
T2CKPS0 = 0;
T2CKPS1 = 0;
#elif TMR2PRESCALE == 4
T2CKPS0 = 1;
T2CKPS1 = 0;
#elif TMR2PRESCALE == 16
T2CKPS0 = 1;
T2CKPS1 = 1;
#endif
TMR2ON = 1;
TRISC1 = 0;
}
/////
//cai dat va chon do rong xung
void duty_cycle(unsigned char ccp, unsigned int
duty)
{
switch (ccp) {
case 1:
{
if (duty < 1024) {
duty = ((float) duty / 1023) * PWM_Max_Duty();
CCP1X = duty & 2;
CCP1Y = duty & 1;
CCPR1L = duty >> 2;
}
}
break;
case 2:
{
if (duty < 1024) {
duty = ((float) duty / 1023) * PWM_Max_Duty();
CCP2X = duty & 2;
CCP2Y = duty & 1;
CCPR2L = duty >> 2;
}
}
break;
}
}
 Main chính

#include <xc.h>
#include <pic.h>
#include <pic16f877a.h>
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 20000000

// CONFIG
#pragma config FOSC = HS // Oscillator
Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog
Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up
Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out
Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage
(Single-Supply) In-Circuit Serial Programming
Enable bit (RB3 is digital I/O, HV on MCLR must
be used for programming)
#pragma config CPD = OFF // Data EEPROM
Memory Code Protection bit (Data EEPROM code
protection off)
#pragma config WRT = OFF // Flash Program
Memory Write Enable bits (Write protection off; all
program memory may be written to by EECON
control)
#pragma config CP = OFF // Flash Program
Memory Code Protection bit (Code protection off)

#include "ADC.h"
#include "LCD.h"
#include "PWM.h"
#define timerstart 3035
unsigned int xungdem, xungdo, chieu, aaa;
char s[20], c[20];

//ham khoi tao timer1 de tao thoi gian trich mau


void Timer1_Init()
{
T1CONbits.TMR1CS=0; // Dùng xung noi
//chon bo chia 1:8
T1CONbits.T1CKPS1=1;
T1CONbits.T1CKPS0=1;
TMR1H=34286>>8; //Tách ra 8 bit cao.
TMR1L=34286&0X00FF; // L?y giá tri 8 bit
th?p
T1CONbits.TMR1ON=1; // Bat imer1
PIR1bits.TMR1IF = 0; //Xóa co tran
PIE1bits.TMR1IE = 1; //Cho phép ngat timer1
INTCONbits.PEIE = 1; //Cho phép ngat ngoai
vi
INTCONbits.GIE = 1; //Cho phép ngat toan cuc
}
///////////
//ham ngat ngoai dem xung dong co Encoder
void Int_Init()
{
OPTION_REGbits.INTEDG = 0; //Ng?t c?nh xu?
ng
INTCONbits.INTE = 1; //Cho Cho phép ng?t ngoài
INTCONbits.GIE = 1; //Cho phép ng?t toàn c?c
}

void main(void) {
unsigned int toc_do;
TRISD = 0x00;
TRISC = 0x00;
TRISBbits.TRISB0 = 1;
TRISAbits.TRISA0=1;
TRISBbits.TRISB1=1;
PWM2_Init(10000);
Lcd_Init();
Timer1_Init();
ADC_Init();
INTCONbits.GIE = 1 ; // ngat toan cuc
INTCONbits.INTE = 1; // ngat cuc bo
OPTION_REGbits.INTEDG = 1; //ngat
canh len
while(1)
{
if(chieu==1)
{
sprintf(s,"(Thuan) duty:%d",aaa/10-2);
Lcd_Set_Cursor(2,1);
Lcd_Write_String(s);
}
if(chieu==0)
{
sprintf(s,"(Nguoc) duty:%d",aaa/10-2);
Lcd_Set_Cursor(2,1);
Lcd_Write_String(s);
}
Lcd_Write_Char(37);
Lcd_Write_Char(" ");
toc_do =(xungdo*600)/334;
Lcd_Set_Cursor(1,1);
sprintf(c,"Toc Do: %d v/p ",toc_do);
Lcd_Write_String(c);
aaa=ADC_Read(0);
duty_cycle(2, aaa);
PWM2_Start();
}

void __interrupt() ISR()


{
if(INTCONbits.INTF==1) //khi có
co bao ngat
{
{
xungdem++;
if(RB1==1)
chieu=0;
if(RB1==0)
chieu=1;
INTCONbits.INTF=0; //
Xóa co bao ngat
}
}
if(PIR1bits.TMR1IF ==1)
{
xungdo=xungdem;
xungdem=0;
TMR1H=timerstart>>8;
//Nap lai gia tri cho timer1
TMR1L=timerstart&0X00FF;
PIR1bits.TMR1IF = 0;
}
}
V. Mô phỏng

You might also like