gia thiet bi ve sinh chinh hang, doc truyen truyện tranh cười Việt Nam doc truyen ma kinh di truyen tinh yeu lãng mạn, tin tuc onlinethiet bi nha ve sinh Việt Nam - Voi hoa sen

kiem tien online
Hiển thị các bài đăng có nhãn Vi xu ly PIC. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Vi xu ly PIC. Hiển thị tất cả bài đăng

Hướng dẫn làm mạch nạp pickit2 student edition

Được đăng bởi NetVN Thứ Ba, 1 tháng 5, 2012 0 nhận xét
Hướng dẫn làm mạch nạp pickit 2 student edition
Ưu điểm:
-rẻ tiền (130k + 2 tiếng ngồi hàn)
-chạy hoàn toàn ổn định như mạch mua bên ngoài
-chức năng giống hoàn toàn mạch pickit 2 thí nghiệm
-thêm chức năng nạp chip 3v3 bán tự động như mạch pk2fun của RP
http://products.rpc.vn/tools/pk2fun/
Nhược điểm:
-to hơn do mạch 1 lớp (5x10 cm)
-xấu hơn do hàn dở


mạch nguyên lý


mạch in


sơ đồ cắm linh kiện (sau khi ngâm mạch và quét nhựa thông, in file "PICKIT 2 SE TOP LAYOUT.pdf" ủi lên mặt lưng của mạch cho đẹp và dễ hàn)

-firmware cho 18F2550 là file hex nằm ở đường dẫn C:\Program Files\Microchip\PICkit 2 v2. Ráp mạch xong dùng 1 mạch nạp khác nạp vào 6 chân ICSP nằm cạnh con pic
-cuộn cảm 680uH có thể thay = 330uH
-diod 5818 ko tìm dc có thể thay = 5819

-Ferrite Bead (cuộn xeo hoặc xeo than) có thể chạy ra nhật tảo mua 1k/cái hoặc câu sợi dây đồng qua cũng OK, tác dụng của nó là lọc nhiễu của nguồn USB nhưng laptop xài pin nên chắc ko nhiễu đâu

-các linh kiện còn lại qua đối diện trường mua có hết. con pic mua lẻ là 105k, bo đồng mua loại 10x20cm rửa dc vừa đủ 4 mạch, in đề can 4,5k/tờ, thuốc ngâm 2,5k/bịch số còn lại mua hết tầm 25k nhưng ko bán lẻ. điện trở 10 con 500d nên 2 đứa mua chung là mua rẻ dc 4k rồi và mua chung nhiều đứa thì cảng rẻ

danh sách linh kiện:
-Pic 18F2550 nạp sẵn firmware + socket 28 chân
-Transistor: C1815 x3, A1015 x1
-1 hàng jump đực + 1 cái jumper
-2 LED 1 xanh 1 đỏ
-1 nút reset 2 chân
-Diode: 4148 x1, 5819 x1
-L: 330uH
-1 cái lỗ USB loại B cái
-Thạch anh 20 MHz x1
-Ferrite Bead x1
-Tụ: 104 x1, 22p x2, 47uF x1, 0.47 x1, 100uF x1
-R: 1k x1, 100k x1, 10k x3, 4k7 x4, 2k7 x1, 22k x1, 100 x3, 330 x2


cách sử dụng giống hệt lúc thí nghiệm nhé. module pic có thể lấy nguồn từ mạch nạp nên ko cần mua thêm adapter cấp nguồn. Những bài thí nghiệm tiêu thụ công suất lớn cần cấp nguồn ngoài cho an toàn

Chú ý: Sau này nếu dùng chip 3v3 phải làm theo thứ tự: GỠ JUMPER TRÊN MẠCH NẠP RA TRƯỚC -> CẤP NGUỒN CHO MODULE PIC -> CẮM VÀO MẠCH NẠP

Chip 5v như 16F877A, 16F84A, 16F887,..... dùng như bình thường lúc học thí nghiệm

Vài tấm ảnh chụp trong qúa trình test mạch:


xem thêm tại: www.facebook.com

Mạch nguyên lý dc lấy từ C:\Program Files\Microchip\PICkit 2 v2\PICkit2 User Guide 51553E.pdf trong phần Appendix B. PICkit 2 Schematics và dc lược bỏ những phần ít dùng như Programmer to go,... chỉ lấy phần nạp nên mới dc gọi là Student Edition nghĩa là phiên bản dành cho SV, dc 1 số thầy bên BK nghiên cứu, thay thế bằng các linh kiện dễ tìm ở VN và đưa vào học tập tại các trường BK khắp cả nước. Mình chỉ vẽ lại layout thôi nên mọi người cứ yên tâm làm theo.

Một số bào viết tham khảo:
programmer-mach-nap-pickit2-se-9701/

bài bên dưới do tác giả của Burn-E viết. Nếu thích các bạn có thể mua Burn-E với giá 200k ở tiệm đối diện trường nhưng Burn-E nạp bằng chương trình riêng.
/mach-nap-lam-mach-nap-pickit2-ho-tro-pic-5v-3v3-31228/

Trong quá trình làm nếu có trục trặc có thể tham khảo bài này để sửa chữa hoặc comment tại đây để mọi người cùng thảo luận
Sửa chữa Pickit 2

Thông báo về mạch nạp
Như đã nêu, BK đã đưa pickit2 vào học tập dưới dạng 1 bo + 1 bịch linh kiện = 160k cách đây vài tháng. Trường mình có thể do dc công ty RP tài trợ mạch nạp và kit thực hành nên ko cần thiết làm vậy.
Nguồn: http://icvn.net

Nghiên cứu ứng dụng PIC

Được đăng bởi NetVN Thứ Hai, 23 tháng 4, 2012 0 nhận xét
Bộ nguồn xung
Sơ đồ:


Bài 1: Điều khiển LED

  • Một bài ứng dụng đầu tiên đơn giản nhất để hiểu cách điều khiển IO của một MCU (PIC)

Code:

//========================================================
// Ten chuong trinh : dieu khien IO vdk
// Nguoi thuc hien : Le son trong Le
// Ngay thuc hien : 03/04/2012
// Phien ban : 1.0
//Trinh bien dich: CCS
// Mo ta phan cung : Dung PIC16F887 - thach anh 7.3728MHz
// ket noi LED (tich cuc [0])
//----------------------------------------------------------------
// Ngay hoan thanh :
// Ngay kiem tra :
// Nguoi kiem tra :
//----------------------------------------------------------------
//========================================================
#include <16f887.h> //khai bao chip cho trinh dich biet
#device *= 16 ADC = 10 //khai bao con tro chuong trinh la 16bit
#fuses HS, NOWDT, NOPROTECT,NOPUT, NOBROWNOUT, NODEBUG //config
#use delay (clock = 7.3728MHz) //khai bao nguon cap dao dong thach anh 7.3728MHz
#define LED PIN_D0 //dinh nghia Macro (ten thay the) cho pin RD0
void main (void)
{
while (true) //vong lap
{
output_low(LED); //xuat muc [0] ra pin RD0 (led off)
delay_ms(500); //lam tre 500ms
output_high(LED); //xuat muc [1] ra pin RD0 (led on)
delay_ms(500); //
}
}
Link download bai 1

Bài 2: Sử dụng ngắt timer



  • Bài này nhằm mục đích mô tả hoạt động của bộ đếm timer, sử dụng bộ định thời timer để điều khiển chu kỳ on/off của led_yelow. Từ ví dụ ta thấy hoạt động on/off của led_yelow hoàn toàn độc lập với led_red (led_red mô tả trạng thái hoạt động của chương trình chính)

Code:
//========================================================
// Ten chuong trinh : HD Su dung timer  
// Nguoi thuc hien : Le son trong Le
// Ngay thuc hien : 08/04/2012
// Phien ban : 1.0
//Trinh bien dich: CCS
// Mo ta phan cung : Dung PIC16F887 - thach anh 7.3728MHz
//                   ket noi LED_red (tich cuc [0]) bao trang thai hoat dong cua chuong trinh chinh
//                   ket noi LED_yelow (tich cuc [0]) bao trang thai hoat dong ham ngat timer
//----------------------------------------------------------------
// Ngay hoan thanh :
// Ngay kiem tra :
// Nguoi kiem tra :
//----------------------------------------------------------------
//========================================================
/*
   mo ta hoat dong cua ngat timer: Chuong trinh chinh (main) van miet mai thuc hien cong viec cua minh theo trinh tu song song voi do thi bo dem timer cung dang hoat dong.. nhung toi khi bo dem timer tran thi yeu cau ngat xay ra tuc thi chuong trinh chinh dung lai va nhay vao ham (void interrup_timer1 (void)) thuc hien sau khi phuc vu xong tro lai ctrinh chinh tiep tuc cong viec. 
*/

#include <16f887.h> //khai bao chip cho trinh dich biet
#device *= 16 ADC = 10 //khai bao con tro chuong trinh la 16bit
#fuses HS, NOWDT, NOPROTECT,NOPUT, NOBROWNOUT, NODEBUG //config
#use delay (clock = 7.3728MHz) //khai bao nguon cap dao dong thach anh 7.3728MHz (Tosc =0.5425us)
#define LED_red PIN_D0 //dinh nghia Macro (ten thay the) cho pin RD0
#define LED_yelow PIN_D1 //dinh nghia Macro (ten thay the) cho pin RD1

#INT_TIMER1
void interrup_timer1 (void)
{
   int1  x; //bien x gia tri 1bit
/*
   timer1 co bo dem 16bit = 65535
   lenh set_timer1(value); dat gia tri bat dau cho timer dem len den gia tri tran FFFF -> ngat timer xay ra tinh thoi gian ngat xay ra Tosc*(65535-535)
*/
   set_timer1(535); // 0.5425us*(65535-535)=~35.26ms
   x=!x;            //thuc hien dao (NOT) bit x va gan nguoc lai vao bien x
   output_bit(LED_yelow,x); //xuat muc [x] ra pin RD1

}
void main (void)
{
   setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );
   enable_interrupts(int_timer1);
   enable_interrupts(global);
   set_timer1(535);
   while (true) //vong lap
   {
      output_low(LED_red); //xuat muc [0] ra pin RD0 (led on)
      delay_ms(1500); //lam tre 1500ms
      output_high(LED_red); //xuat muc [1] ra pin RD0 (led off)
      delay_ms(1500); //
   }
}

[Code PIC] Mạch đo điện dung

Được đăng bởi NetVN Chủ Nhật, 22 tháng 4, 2012 0 nhận xét
Code PIC mạch đo điện dung:
************************************************** *****************************
Project : Frequency Measurement
Author : pk
************************************************** *****************************/
#include <16f887.h>
#device *=16
#FUSES NOWDT, NOPUT,XT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock = 4M)


#define LCD_ENABLE_PIN PIN_D3
#define LCD_RS_PIN PIN_D1
#define LCD_RW_PIN PIN_D2
#define LCD_DATA4 PIN_D4
#define LCD_DATA5 PIN_D5
#define LCD_DATA6 PIN_D6
#define LCD_DATA7 PIN_D7

/*
#define LCD_ENABLE_PIN PIN_C0
#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_C3
#define LCD_DATA4 PIN_E2
#define LCD_DATA5 PIN_E1
#define LCD_DATA6 PIN_E0
#define LCD_DATA7 PIN_A5
*/

#include <lcd.c>
#use fast_io(c)
//************************************************** ****************************
int i;
float temp,verify;
//************************************************** ****************************

#INT_CCP1
void synchronous_re(){
temp = get_timer1();
set_timer1(0);
}
//------------------------------------------------------------------------------
#INT_CCP2
void synchronous_fe(){
temp = get_timer1();
set_timer1(0);
}
//************************************************** ****************************
void lcd_put_int(int num){
int temp;
unsigned char i = 0, c[5];
temp = num;
if (temp != 0) {
while(temp){
c[i++] = temp%10;
temp /= 10;
}
while(i) lcd_putc(c[--i] + '0');
}
else lcd_putc('0');
}
//************************************************** ****************************
void lcd_put_float(float num){
unsigned int temp;

temp = num/1;
lcd_put_int(temp);
temp = (num - temp)*100;
lcd_putc(',');
lcd_put_int(temp);

}
//************************************************** ****************************
void main(){
set_tris_c(0xff);
set_tris_b(0xff);

lcd_init();
lcd_putc("STARTING");
for(i = 1; i < 9; i++){
lcd_putc(".");
delay_ms(100);
}
SETUP_TIMER_1(T1_INTERNAL|T1_DIV_BY_4);
//SETUP_TIMER_1(T1_INTERNAL|T1_DIV_BY_1);

SETUP_CCP1(CCP_CAPTURE_RE);
SETUP_CCP2(CCP_CAPTURE_FE);

ENABLE_INTERRUPTS(INT_CCP1);
ENABLE_INTERRUPTS(INT_CCP2);
ENABLE_INTERRUPTS(global);

lcd_putc('\f');
lcd_putc("TAN SO HIEN TAI:");

while(1){
if(temp != verify){
verify = temp;
lcd_gotoxy(1,2);
lcd_putc(" ");
lcd_gotoxy(5,2);
lcd_put_float(500000/temp);
lcd_putc("Hz");
delay_ms(100);
}
}
}

Code mẫu PIC - Giao Tiếp I2C Với IC Thời gian thực DS1307

Được đăng bởi NetVN Thứ Sáu, 13 tháng 4, 2012 0 nhận xét
Chương trình thực hiện giao tiếp I2C giữa PIC 16F877A và IC DS1307 để cài đặt thời gian, đọc thời gian từ DS1307, hiển thị lên LCD, truyền qua RS232.
Với LCD, chương trình sẽ đọc dữ liệu DS1307 và cập nhật LCD liên tục, còn khi truyền lên máy tính sẽ dựa vào ngắt RB0 đưa vào từ xung 1Hz của DS1307, tức là mỗi 1s sẽ truyền dữ liệu 1 lần.
Trong chương trình có sử dụng các thư viện: lcd_lib_4bit.cds1307.c.

Sơ đồ nguyên lý mô phỏng trên Proteus:




Truyền lên hyper terminal:



Mã nguồn chương trình chính:



#include "16f877a.h"
#include "def_877a.h"


#device *=16 ADC=10
#use delay(clock=20000000)
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use i2c(Master, sda = PIN_C4, scl=PIN_C3)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)


#include "lcd_lib_4bit.c"
#include "ds1307.c"


#define Slave_add 0x68
#define Read 1
#define Write 0


void send(int8 a);


int8 sec,min,hrs,day,month,yr,dow;


//ngat o chan RB0: Truyen len cong RS232
#int_EXT
void EXT_isr(void) //moi 1s truyen len may tinh 1 lan
{
   ds1307_get_date(day,month,yr,dow); 
   ds1307_get_time(hrs,min,sec);
   send(hrs);
   putc(45);
   send(min);
   putc(45);
   send(sec);
   putc(10);
   return;
}
void main()
{
   enable_interrupts(INT_EXT);//cho phep ngat RB0
   ext_int_edge(0,H_TO_L);//dat suon ngat
   enable_interrupts(GLOBAL);//cho phep ngat toan cuc
   
   LCD_init(); //Khoi tao LCD.
   delay_ms(10);
   ds1307_init();// khoi tao DS1307, tao xung 1Hz o chan 7 DS1307.
   // Set date : 12-4-2012
   // Set time : thu 5 - 12 gio, 59 phút 10 giây
   ds1307_set_date_time(12,4,12,5,12,59,10);
   


   while(1) 
   { 
      ds1307_get_date(day,month,yr,dow); 
      ds1307_get_time(hrs,min,sec);
      
      //Truyen len LCD
      //o day chi hien gio, phut, giay. cac thong tin khac thuc hien tuong tu.
      LCD_PutCmd(0x80);
      LCD_PutChar(hrs/10+48);
      LCD_PutChar(hrs%10+48);
      LCD_PutChar(45);
      LCD_PutChar(min/10+48);
      LCD_PutChar(min%10+48);
      LCD_PutChar(45);
      LCD_PutChar(sec/10+48);
      LCD_PutChar(sec%10+48);
   }
}
void send(int8 a)
{
    if(a<10)
     {
         putc(a+48);         
     }
     if(a>9&&a<100)
     {
          unsigned char c=a/10;
          unsigned char d=a%10;
          putc(c+48);
          putc(d+48);       
     }
     if(a>99)
     {
          unsigned char t=a/100;
          unsigned char c=a/10-10*t;
          unsigned char d=a%10;
          putc(t+48);
          putc(c+48);
          putc(d+48);
     }
}


Thư viện lcd_lib_4bit.c:


#include <stddef.h>


#define LCD_RS          PIN_D2
//#define LCD_RW          PIN_A1
#define LCD_EN          PIN_D3


#define LCD_D4          PIN_D4
#define LCD_D5          PIN_D5
#define LCD_D6          PIN_D6
#define LCD_D7          PIN_D7


// misc display defines-
#define Line_1          0x80
#define Line_2          0xC0
#define Clear_Scr       0x01


// prototype statements
#separate void LCD_Init ( void );// ham khoi tao LCD
#separate void LCD_SetPosition ( unsigned int cX );//Thiet lap vi tri con tro
#separate void LCD_PutChar ( unsigned int cX );// Ham viet1kitu/1chuoi len LCD
#separate void LCD_PutCmd ( unsigned int cX) ;// Ham gui lenh len LCD
#separate void LCD_PulseEnable ( void );// Xung kich hoat
#separate void LCD_SetData ( unsigned int cX );// Dat du lieu len chan Data
// D/n Cong
#use standard_io (C)
#use standard_io (D)


//khoi tao LCD**********************************************
#separate void LCD_Init ( void )
    {
    LCD_SetData ( 0x00 );
    delay_ms(200);       /* wait enough time after Vdd rise >> 15ms */
    output_low ( LCD_RS );// che do gui lenh
    LCD_SetData ( 0x03 );   /* init with specific nibbles to start 4-bit mode */
    LCD_PulseEnable();
    LCD_PulseEnable();
    LCD_PulseEnable();
    LCD_SetData ( 0x02 );   /* set 4-bit interface */
    LCD_PulseEnable();      /* send dual nibbles hereafter, MSN first */
    LCD_PutCmd ( 0x2C );    /* function set (all lines, 5x7 characters) */
    LCD_PutCmd ( 0x0C );    /* display ON, cursor off, no blink */
    LCD_PutCmd ( 0x06 );    /* entry mode set, increment & scroll left */
    LCD_PutCmd ( 0x01 );    /* clear display */
    }


#separate void LCD_SetPosition ( unsigned int cX )
    {
    /* this subroutine works specifically for 4-bit Port A */
    LCD_SetData ( swap ( cX ) | 0x08 );
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );
    LCD_PulseEnable();
    }


#separate void LCD_PutChar ( unsigned int cX )
    {
    /* this subroutine works specifically for 4-bit Port A */
        output_high ( LCD_RS );
        LCD_PutCmd( cX );
        output_low ( LCD_RS );
    }


#separate void LCD_PutCmd ( unsigned int cX )
    {
    /* this subroutine works specifically for 4-bit Port A */
    LCD_SetData ( swap ( cX ) );     /* send high nibble */
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );     /* send low nibble */
    LCD_PulseEnable();
    }
#separate void LCD_PulseEnable ( void )
    {
    output_high ( LCD_EN );
    delay_us ( 3 );         // was 10
    output_low ( LCD_EN );
    delay_ms ( 3 );         // was 5
    }


#separate void LCD_SetData ( unsigned int cX )
    {
    output_bit ( LCD_D4, cX & 0x01 );
    output_bit ( LCD_D5, cX & 0x02 );
    output_bit ( LCD_D6, cX & 0x04 );
    output_bit ( LCD_D7, cX & 0x08 );
    }

Thư viện ds1307.c:


BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);


void ds1307_init(void) 

   BYTE initsec = 0;
   BYTE initmin=0;
   BYTE inithr=0;                  
   BYTE initdow=0;
   BYTE initday=0;                   
   BYTE initmth=0;
   BYTE inityear=0;
   i2c_start(); 
   i2c_write(0xD0);      // WR to RTC 
   i2c_write(0x00);      // REG 0 
   i2c_start(); 
   i2c_write(0xD1);      // RD from RTC 
   initsec  = bcd2bin(i2c_read() & 0x7f); 
   initmin  = bcd2bin(i2c_read() & 0x7f); 
   inithr   = bcd2bin(i2c_read() & 0x3f); 
   initdow  = bcd2bin(i2c_read() & 0x7f);   // REG 3 
   initday  = bcd2bin(i2c_read() & 0x3f);   // REG 4 
   initmth  = bcd2bin(i2c_read() & 0x1f);   // REG 5 
   inityear = bcd2bin(i2c_read(0));         // REG 6 
   i2c_stop(); 
   delay_us(3);


   i2c_start(); 
   i2c_write(0xD0);      // WR to RTC 
   i2c_write(0x00);      // REG 0 
   i2c_write(bin2bcd(initsec));      // Start oscillator with current "seconds value 
   i2c_write(bin2bcd(initmin));      // REG 1 
   i2c_write(bin2bcd(inithr));       // REG 2 
   i2c_write(bin2bcd(initdow));      // REG 3 
   i2c_write(bin2bcd(initday));      // REG 4 
   i2c_write(bin2bcd(initmth));      // REG 5 
   i2c_write(bin2bcd(inityear));     // REG 6 
   i2c_start(); 
   i2c_write(0xD0);      // WR to RTC 
   i2c_write(0x07);      // Control Register 
   i2c_write(0x90);      //  squarewave output pin 1Hz
   i2c_stop(); 





void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
  sec &= 0x7F;
  hr &= 0x3F;


  i2c_start();
  i2c_write(0xD0);              // I2C write address
  i2c_write(0x00);              // Start at REG 0 - Seconds
  i2c_write(bin2bcd(sec));      // REG 0
  i2c_write(bin2bcd(min));      // REG 1
  i2c_write(bin2bcd(hr));       // REG 2
  i2c_write(bin2bcd(dow));      // REG 3
  i2c_write(bin2bcd(day));      // REG 4
  i2c_write(bin2bcd(mth));      // REG 5
  i2c_write(bin2bcd(year));     // REG 6
  i2c_write(0x90);              // REG 7 - 1Hz squarewave output pin
  i2c_stop();
}


void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x03);              // Start at REG 3 - Day of week
  i2c_start();
  i2c_write(0xD1);
  dow  = bcd2bin(i2c_read() & 0x7f);   // REG 3
  day  = bcd2bin(i2c_read() & 0x3f);   // REG 4
  mth  = bcd2bin(i2c_read() & 0x1f);   // REG 5
  year = bcd2bin(i2c_read(0));         // REG 6
  i2c_stop();
}


void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x00);                     // Start at REG 0 - Seconds
  i2c_start();
  i2c_write(0xD1);
  sec = bcd2bin(i2c_read() & 0x7f);
  min = bcd2bin(i2c_read() & 0x7f);
  hr  = bcd2bin(i2c_read(0) & 0x3f);
  i2c_stop();


}


BYTE bin2bcd(BYTE binary_value)
{
  BYTE temp;
  BYTE retval;


  temp = binary_value;
  retval = 0;


  while(1)
  {
    // Get the tens digit by doing multiple subtraction
    // of 10 from the binary value.
    if(temp >= 10)
    {
      temp -= 10;
      retval += 0x10;
    }
    else // Get the ones digit by adding the remainder.
    {
      retval += temp;
      break;
    }
  }


  return(retval);
}




// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
  BYTE temp;


  temp = bcd_value;
  // Shifting upper digit right by 1 is same as multiplying by 8.
  temp >>= 1;
  // Isolate the bits for the upper digit.
  temp &= 0x78;


  // Now return: (Tens * 8) + (Tens * 2) + Ones


  return(temp + (temp >> 2) + (bcd_value & 0x0f));


Lập Trình RoBot Tự Động Đơn Giản Với VĐK PIC16F877A

Được đăng bởi NetVN Thứ Hai, 27 tháng 2, 2012 1 nhận xét

Tóm tắt
Tài liệu hướng dẫn lập trình cho robot tự động dò đường theo vạch trắng và điều khiển các cơ cấu (nâng hạ, gắp nhả quà) một cách cơ bản nhất.Vi điều khiển được sử dụng trong tài liệu là PIC16F877A của Microchip.Lập trình bằng ngôn ngữ C với trình biên dịch CCS.

1 TÓM TẮT VỀ THIẾT KẾ ROBOT TỰ ĐỘNG
Robot tự động trong các cuộc thi Robocon gồm 3 thành phần chính: Cơ khí, Mạch điện tử, Lập trình.

1.1 Cơ khí
Một robot đơn giản gồm 2 động cơ truyền động cho 2 bánh xe bên trái và bên phải giúp robot di chuyển. Phía trước có thể là 1 hoặc 2 bánh tự do (bánh tự lựa, omni, mắt trâu,…). Để thực hiện được các công việc như nâng hạ trục, gắp nhả đẩy quá, robot được trang bị thêm các động cơ khác để truyền động cho các cơ cấu này. 
Tất cả các bộ phận trên được bố trí trên một khung bằng nhôm, sắt,… 
Phần hướng dẫn chi tiết về thiết kế cơ khí sẽ được trình bày trong một tài liệu khác. Tài liệu này chỉ tập trung vào phần lập trình.
Mô hình robot dò dường đơn giản


1.2 Mạch điện tử

Sơ đồ hoạt động của robot tự động

1.2.1 Mạch ngõ vào (cảm biến, nút ấn, công tắc hành trình)
Với robot đơn giản, ngõ vào thường là mức logic lấy từ cảm biến quang (quang trở, quang diode), nút ấn hoặc công tắc hành trình. Từ đó mạch vi điều khiển xử lý các tín hiệu này để xuất ngõ ra (thường là động cơ DC) chophù hợp.
Cảm biến quang phải được che chắn cẩn thận để hạn chế ảnh hưởng từ cácnguồn ánh sáng bên ngoài.

Mạch cảm biến, nút ấn và công tắc hành trình


1.2.2 Mạch vi điều khiển
Mạch sử dụng vi điều khiển PIC16F877A của Microchip. Mạch nhận tín hiệu từ ngõ vào, xử lý và xuất ngõ ra qua một mạch cách ly bằng opto ra mạch công suất.



Mạch vi điều khiển


1.2.3 Mạch công suất điều khiển động cơ DC
Một số mạch thông dụng:





Mạch công suất sử dụng 1 FET và 1 relay



Mạch cầu H điều khiển động cơ với Half Bridge Driver IR2184


1.3 Lập trình
Đây là phần chính của tài liệu này. Ngôn ngữ lập trình được sử dụng là C, với trình biên dịch CCS cho vi điều khiển PIC của Microchip.
Kiến thức ban đầu: Lập trình C căn bản
Các tài liệu tham khảo:

Đây là các tài liệu cần đọc qua trước khi vào lập trình cho PIC để có thể biết các hàm nhận tín hiệu ngõ vào, xuất tín hiệu ngõ ra, ngắt, timer, counter, PWM,…
Các hàm quan trọng sẽ được nhắc lại ở phần 2.

2 LẬP TRÌNH CHO ROBOT TỰ ĐỘNG DÒ ĐƯỜNG ĐƠN GIẢN
Chương trình giúp robot chạy theo vạch trắng trên nền màu sậm.

2.1 Phần cứng
 8 cảm biến quang dò đường
 Mạch công suất điều khiển 2 động cơ
 Mạch vi điều khiển:
          o PORTD: nối với tín hiệu ra của 8 cảm biến
          o Động cơ trái:
                           Chân C0: điều khiển chiều (DIR_LEFT)
                           Chân C1: điều khiển cho phép chạy (EN_LEFT)
          o Động cơ phải:
                           Chân C3: điều khiển chiều (DIR_RIGHT)
                           Chân C2: điều khiển cho phép chạy (EN_RIGHT)
(Các ngõ vào và ngõ ra có thế nối với bất cứ PORT và chân nào của vi điều khiển)

2.2 Nguyên tắc điều khiển
2.2.1 Điều khiển động cơ


Tương tự đối với các động cơ điều khiển các cơ cấu.

2.2.2 Hướng di chuyển của robot




2.2.3 Xử lý tín hiệu cảm biến (xem hình vẽ)
Mục đích của việc dò đường là hướng cho robot đi theo 1 vạch thẳng màu trắng trên một nền màu đậm (đen, xanh,…)
Cảm biến được đặt ở giữa robot.
            o Khi cảm biến số 3,4 nằm trên vạch trắng (mức 1): robot chạy thẳng
            o Khi robot lệch sang trái: quay phải để điều chỉnh robot về đúng vạch
            o Khi robot lệch sang phải: quay trái để điều chỉnh robot về đúng vạch



Các mức độ lệch ra khỏi vạch trắng của robot


2.3 Chương trình điều khiển

#include <16f877A.h>
#include <def_877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
/* ĐỊNH NGHĨA CÁC CHÂN VÀ PORT */
#define DIR_LEFT RC0
#define  EN_LEFT         RC1
#define DIR_RIGHT RC3
#define  EN_RIGHT RC2

#define SENSOR PORTD
/* KHAI BÁO CÁC CHƯƠNG TRÌNH CON */
void motor_left_forward();
void motor_left_reverse();
void motor_left_stop();
void motor_right_forward();
void motor_right_reverse();
void motor_right_stop();
void forward();
void reverse();
void stop();
void turn_left();
void turn_right();
/* CÁC CHƯƠNG TRÌNH CON */
// Động cơ trái chạy thuận
void motor_left_forward()
{
DIR_LEFT=1; // chiều thuận
EN_LEFT=1; // cho phép chạy
}
// Động cơ trái chạy ngược
void motor_left_reverse()
{
DIR_LEFT=0; // chiều ngược
EN_LEFT=1; // cho phép chạy
}
// Động cơ trái dừng
void motor_left_stop()
{
EN_LEFT=0; // không cho phép chạy
}
// Động cơ phải chạy thuận
void motor_right_forward()
{
DIR_RIGHT=1;// chiều thuận
EN_RIGHT=1; // cho phép chạy
}
// Động cơ phải chạy ngược
void motor_right_reverse()
{
DIR_RIGHT=0;// chiều ngược
EN_RIGHT=1; // cho phép chạy
}
// Động cơ phải dừng
void motor_right_stop()
{
EN_RIGHT=0; // không cho phép chạy
}
// Chạy thẳng
void forward()
{
motor_left_forward();
motor_right_forward();
}
// Chạy lùi
void reverse()
{
motor_left_reverse();
motor_right_reverse();
}
// Dừng
void stop()
{
motor_left_stop();
motor_right_stop();
}
// Quay trái
void turn_left()
{
motor_left_forward();
motor_right_reverse(); // hoặc motor_right_stop();
}
// Quay phải
void turn_right()
{
motor_left_reverse(); // hoặc motor_left_stop();
motor_right_forward();
}
/* CHƯƠNG TRÌNH CHÍNH */
void main ()
{
TRISC=0x00; // PORTC là ngõ ra ( động cơ)
TRISD=0x00; // PORTD là ngõ vào (cảm biến quang)
PORTC=0x00; // Khởi tạo giá trị ban đầu 0x00 cho PORTC
while(1)
{
switch (SENSOR)
{
case 0b00011000: forward(); break;
case 0b00001100: turn_left(); break;
case 0b00000110: turn_left(); break;
case 0b00000011: turn_left(); break;
case 0b00000001: turn_left(); break;
case 0b00110000: turn_right(); break;
case 0b01100000: turn_right(); break;
case 0b11000000: turn_right(); break;
case 0b10000000: turn_right(); break;
}
}
}


3 CẢI TIẾN CHƯƠNG TRÌNH DÒ ĐƯỜNG
3.1 Điều khiển tốc độ động cơ với các trạng thái lệch khỏi vạch trắng
3.1.1 Nguyên lý
Đối với chương trình dò đường đơn giản, khi robot lệch trái hoặc lệch phải, robot sẽ quay phải hoặc quay trái để điều chỉnh cho dù lệch ít hay lệch nhiều. Như vậy, trong quá trình di chuyển, robot sẽ lắc liên tục vì phải quay trái, quay phải liên tục. Do đó, với các mức độ lệch ra khỏi vạch trắng khác nhau, ta điều chỉnh tốc độ 2 bánh trái, phải cho phù hợp để quá trình di chuyển theo vạch của robot được “nhuyễn” và “mượt” hơn.
Bảng giá trị tham khảo tốc độ động cơ trái và động cơ phải tương ứng với các trạng thái lệch khỏi vạch trẳng của robot:



3.1.2 Điều khiển tốc độ động cơ DC bằng phương pháp PWM
Đối với điều khiển tốc độ động cơ DC trong robot, phương pháp được sử dụng phổ biến nhất là điều chế độ rộng xung (Pulse Width Modulation) hay được gọi tắt là điều xung, băm xung hoặc PWM.
Nguyên lý của phương pháp này là bật tắt nhanh nguồn điện cấp vào động cơ tạo ra một tín hiệu xung. Khi việc bật tắt ở tần số đủ lớn (thường sử dụng từ 1kHz đến 20kHz), động cơ sẽ chạy với 1 tốc độ ổn định nhờ moment quay.
Thời gian cấp nguồn cho động cơ là T-on, thời gian tắt nguồn động cơ là T-off. Việc thay đổi thời gian T-on và T-off làm thay đổi điện áp hiệu dụng cấp cho động cơ. Đối với động cơ DC, tốc độ động cơ tương đối tỉ lệ thuận với điện áp cấp cho động cơ. Vì vậy, bằng cách thay đổi độ rộng của xung, ta đã thay đổi được tốc độ của động cơ DC.
Đại lượng biểu diễn mối quan hệ giữa T-on và T-off được gọi là duty cycle:
duty_cycle = Ton / ( Ton + Toff )
Ví dụ: Ta cấp nguồn động cơ trong 0.8ms, sau đó tắt 0.2ms.
Như vậy: T-on = 0.8ms; T-off = 1ms. Tần số PWM là:
f = 1 / ( Ton + Toff ) = 1 / ( 0.8ms + 0.2ms ) = 1/1ms = 1KHz
duty_cycle = Ton / ( Ton + Toff ) = 0.8 / ( 0.8 + 0.2 ) = 0.8 = 80%

Vì tốc độ động cơ DC tỉ lệ với duty cycle nên tốc độ động cơ đạt tương đương 80% tốc độ tối đa.


Tính toán duty cycle để điều khiển tốc độ động cơ DC


3.1.3 Điều xung PWM dùng vi điều khiển
 Điều xung PWM bằng phần mềm:
Điều xung PWM một cách đơn giản là đưa 1 chân nào đó của vi điều khiển lên mức 1, sau đó đưa xuống mức 0. Công việc này được lặp đi lặp lại liên tục sẽ tạo ra xung, và tốc độ của động cơ sẽ tương ứng với duty cycle.
Ví dụ: Điều xung trên chân A0 :
Code
RA0=1;
Delay_ms(Ton);
RA0=0;
Delay_ms(Toff);

Tuy nhiên, nếu thực hiện bằng cách này thì vi điều khiển sẽ luôn dành thời gian cho việc điều xung PWM. Do đó, các công việc khác như nhận tín hiệu từ cảm biến, điều khiển các cơ cấu sẽ bị ảnh hưởng.

 Điều xung PWM bằng phần cứng
Để giải quyết vấn đề việc điều xung PWM bằng phần mềm chiếm phần lớn thời gian hoạt động của vi điều khiển, PIC16F877A có hỗ trợ 2 kênh điều xung bằng phần cứng ở 2 chân C1 (CCP2)C2(CCP1) sử dụng TIMER2. Nghĩa là, khi ta khai báo điều xung PWM ở một tần số và duty cycle nào đó thì vi điều khiển sẽ thực hiện công việc xuất xung một cách liên tục và tự động cho đến khi ta thay đổi các giá trị đã khai báo. Khi đó, ta có thể làm các công việc khác một cách dễ dàng mà không phải mất thời gian cho việc duy trì xung PWM.

Các hàm hỗ trợ việc điều xung bằng phần cứng của CCS:
Ghi chú: Chỉ đề cập đến các đối số của các hàm được phục vụ cho việc điều xung PWM.
o setup_timer_2 (mode, period, postscale)
       mode: T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16
          period: 0-255
          postscale: 1
       Tần số điều xung PWM:
f = fosc / [ 4*mode*(period+1) ]
o setup_ccp1(mode) và setup_ccp2(mode)
      mode:
         CCP_PWM: chọn chế độ PWM.
         CCP_OFF: tắt chế độ PWM.
o set_pwm1_duty(value) và set_pwm2_duty(value)
 Nếu value là giá trị kiểu int 8bit:
duty_cycle = value / ( period+1 )
  Nếu value là giá trị long int 16bit:
                                                 duty_cycle = value&1023 / [4*( period+1 )]
 Nếu không cần điều xung quá “mịn” thì nên điều xung ở giá trị value 8bit cho đơn giản.
Ví dụ: Ta muốn điều xung PWM với tần số 10kHz với tần số thạch anh (fosc) sử dụng là 20MHz (value 8bit).
f=fosc/[4*mode*(period+1)] <=> 10000 =20000000/[ 4*mode*(period+1) ] <=> mode(period+1) = 500
Với mode = [1,4,16] và period = 0-255 ta có thể chọn:
       o mode = 4;   period = 124
       o mode = 16; period = 32
Để cho việc điều xung được “mịn” (chọn được nhiều giá trị duty cycle) ta chọn mode = 4 và period = 124.
Như vậy, để duty_cycle từ 0% đến 100% ta cho value từ 0 đến 125.
       o value = 30 =>  duty_cycle = 30 / ( 124+1 ) = 0.32 = 32%
       o value = 63 =>  duty_cycle = 63 / ( 124+1 ) = 0.504 = 50.4%
       o value = 113 =>  duty_cycle = 113 / ( 124+1 ) = 0.904 = 90.4%

Code:
   setup_timer_2(T2_DIV_BY_4,124,1);
   setup_ccp1(CCP_PWM);
   set_pwm1_duty(30);

Sử dụng CCP1 và CCP2 cho động cơ trái và động cơ phải, ta có thể điều khiển được tốc độ của 2 động cơ phù hợp trạng thái lệch khỏi vạch trắng của robot.
 Các chương trình con tham khảo:
Để việc lập trình được dễ dàng, ta nên tạo các chương trình con xử lý tốc độ. Sau đây là chương trình tham khảo của hàm speed.
o Speed (tốc độ động cơ trái, tốc độ động cơ phải)
        Tốc độ: -100 đến 100 (chạy ngược 100% đến chạy thuận 100%)
        Ví dụ: speed(80,60) => động cơ trái chạy 80%, phải 60%
// Các hàm hỗ trợ
void left_motor_forward(int value)
{
   MOTOR_LEFT_DIR=0;
   setup_timer_2(T2_DIV_BY_4,124,1);         // Dieu xung 10kHz
   setup_ccp2(CCP_PWM);
   set_pwm2_duty(value);
}
void right_motor_forward(int value)
{
   MOTOR_RIGHT_DIR=0;
   setup_timer_2(T2_DIV_BY_4,124,1);         // Dieu xung 10kHz
   setup_ccp1(CCP_PWM);
   set_pwm1_duty(value);
}
void left_motor_reverse(int value)
{
   MOTOR_LEFT_DIR=1;
   setup_timer_2(T2_DIV_BY_4,124,1);         // Dieu xung 10kHz
   setup_ccp2(CCP_PWM);
   set_pwm2_duty(value);
}
void right_motor_reverse(int value)
{
   MOTOR_RIGHT_DIR=1;
   setup_timer_2(T2_DIV_BY_4,124,1);         // Dieu xung 10kHz
   setup_ccp1(CCP_PWM);
   set_pwm1_duty(value);
}
void left_motor_stop()
{
   setup_ccp1(CCP_OFF);
}
void right_motor_stop()
{
   setup_ccp1(CCP_OFF);
}
// Chương trình xử lý tốc độ 2 động cơ
// 0:Stop,100:FORWARD 100%,-100:Reverse 100%
void speed (signed int left_motor_speed, signed int right_motor_speed)
{
   int left_pwm_value=0,right_pwm_value=0;
   /* Left motor */
   if( left_motor_speed >= 0 )
   {
      left_pwm_value = 1.25*left_motor_speed;   // (125*left_motor_speed/100)
      left_motor_forward(left_pwm_value);
   }
   else
   {
      left_motor_speed = -left_motor_speed;
      left_pwm_value = 1.25*left_motor_speed;  // (125*left_motor_speed/100)
      left_motor_reverse(left_pwm_value);
 }
    /* Right motor */
   if( right_motor_speed >= 0 )
   {
      right_pwm_value = 1.25*right_motor_speed;   // (125*left_motor_speed/100)
      right_motor_forward(right_pwm_value);
   }
   else
   {
      right_motor_speed = -right_motor_speed;
      right_pwm_value = 1.25*right_motor_speed;  // (125*left_motor_speed/100)
      right_motor_reverse(right_pwm_value);
   }
}


3.2 Nhận biết vạch ngang
Trong quá trình di chuyển của robot, sẽ có các vạch ngang màu trắng. Nhờ các vạch ngang này, robot biết được mình đang đi đến đâu và sẽ thực hiện công việc gì tiếp theo (quay trái, quay phải, nâng hạ trục, gắp nhả quà,…)
Một cách đơn giản, khi robot đến vạch trắng, tất cả 8 cảm biến sẽ lên mức 1 ứng với giá trị đọc được của cảm biến là 0b11111111 hay 0xFF. Ta dùng một biến đếm để biết thứ tự của vạch ngang đang gặp và thực hiện công việc mong muốn.
Code:
int n // đặt n là số vạch ngang đã nhận
if (SENSOR==0xFF)
{
n++; // tăng giá trị n lên 1 khi gặp vạch ngang
switch (n)
{
case 1:    (công việc 1) break;
case 2:    (công việc 2) break;
….
case n:    (công việc n) break;
}
}
else (chương trình dò đường)

 Tuy nhiên, vì nhiều lý do khác nhau (nhiễu do ánh sáng bên ngoài, các cảm biến có độ nhạy không đều nhau hoặc robot tiếp cận với vạch ngang không theo phương vuông góc), một vài cảm biến khi tiếp xúc với màu trắng nhưng không nhận biết (vẫn giữ trạng thái mức 0 – màu sậm). Điều này gây khó khăn cho việc nhận biết vạch ngang. Vì vậy, khi 4/8 cảm biến ở mức 1, ta nhận đó là một vạch ngang để khắc phục các ảnh hưởng này.
Code:
//KIEM TRA VACH NGANG: 1: co vach, 0:khong co vach
int check_cross_line()
{
   int temp_sensor=0,led_in_line=0,i=0;
   temp_sensor=SENSOR;
   for (i=0;i<8;i++)
  {
   if ((temp_sensor&0x01)==0x01) led_in_line++;
      if (led_in_line==4) break;
      temp_sensor=temp_sensor>>1;
   }
   if (led_in_line==4)
      return 1;
   else
      return 0;
}

 Do chương trình nhận vạch ngang được gọi liên tục để kiểm tra có vạch ngang xuất hiện hay không nên sẽ dẫn đến tình trạng khi robot đến vạch ngang, biến đếm số vạch tăng thêm 1. Sau đó, khi robot chưa kịp chạy qua vạch ngang mà hàm kiểm tra được gọi dẫn đến việc biến đếm tăng liên tục.
Việc này khiến cho robot thực hiện sai công việc.
Hướng giải quyết tình huống này như sau:
       o Khi robot gặp vạch ngang: chạy thẳng
       o Khi hết vạch ngang: biến đếm số vạch tăng thêm 1
       o Thực hiện công việc tương ứng
Code:
while (check_cross_line() == 1) // gặp vạch ngang
{
speed(100,100); // chạy thẳng
}
number_cross_line++; // tăng biến đếm số vạch ngang thêm 1

3.3 Xử lý khi robot lệch hoàn toàn khỏi vạch
Trường hợp robot lệch ra khỏi vạch (quay quá mạnh hoặc bị va chạm), giá trị cảm biến đọc được là 0x00, như vậy robot sẽ bị mất phương hướng.
Để giải quyết trường hợp này, ta đặt một biến trạng thái là biến toàn cục.
Gọi biến này là line_status:
       o Line_status=0: giữa vạch;
       o Line_status=1: lệch trái;
       o Line_status=2: lệch phải;
Khi đọc giá trị cảm biến để dò đường , ta gán luôn giá trị cho biến này. Như vậy khi robot lệch hẳn ra khỏi vạch, ta vẫn biết được trạng thái trước đó để biết quay trái hoặc quay phải để hướng robot di chuyển về
phía line.
Code
switch (SENSOR)
{
case 0b00000000: // lệch ra hẳn khỏi vạch
{
if (line_status==1) // trạng thái cũ là lệch trái
turn_right(); break; // quay phải để di chuyển về phía vạch
if (line_status==2) // trạng thái cũ là lệch phải
turn_left(); break; // quay trái để di chuyển về phía vạch
}
// Trạng thái lệch thông thường
case 0b00011000: forward(); line_status=0; break;
case 0b00001100: turn_left(); line_status=1; break;
case 0b00000110: turn_left(); line_status=1; break;
case 0b00000011: turn_left(); line_status=1; break;
case 0b00000001: turn_left(); line_status=1; break;
case 0b00110000: turn_right(); line_status=2 ;break;
case 0b01100000: turn_right(); line_status=2 ;break;
case 0b11000000: turn_right(); line_status=2 ;break;
case 0b10000000: turn_right(); line_status=2 ;break;
}

3.4 Ứng dụng encoder
3.4.1 Kiến thức cơ bản về encoder
Trong Robot, ta thường sử dụng incremental encoder (encoder tương đối) hay còn gọi là rotary encoder. Mục đích của việc sử dụng encoder trong robot là đếm số vòng quay để tính số vòng quay của động cơ (bánh xe), từ đó suy ra quãng đường di chuyển và tốc độ của robot.
Encoder thường được sử dụng trong Robot

3.4.2 Sử dụng PIC để nhận và đếm xung từ encoder
Để nhận xung từ encoder, ta có thể sử dụng ngắt ngoài, ngắt timer hoặc đơn giản là tham dò mức logic của các chân vi điều khiển một cách liên tục. Phần sau đây giới thiệu cách nhận và đếm xung của PIC16F877A dùng ngắt ngoài B0 (nối với kênh A của encoder) và chân B1 (nối với kênh B của encoder). Ta có thể làm tương tự đối với các cách nhận xung khác.
 Khởi tạo ngắt ngoài theo cạnh lên tại chân B0:
Code:
ext_int_edge(0,L_TO_H); // Ngắt cạnh lên tại RB0
enable_interrupts(INT_EXT); // Cho phép ngắt ngoài
enable_interrupts(GLOBAL); // Cho phép ngắt toàn cục
 Chương trình con phục vụ ngắt:
Code:
#int_EXT
void  EXT_isr(void) //Chương trình được gọi khi có tác động cạnh lên tại chân B0
{
   if (RB1==1) pulse++; // Nếu kênh B mức cao thì tăng giá trị xung thêm 1
   else pulse--;       // Nếu kênh B mức cao thì giảm giá trị xung xuống 1
}

 Từ giá trị xung tính được tại các thời điểm ta có thể tính ra các thông số mong muốn.






(Nguồn: Cao Hoàng Long, EM-BOT Robot Team)

Lưu trữ bài viết

Người theo dõi

Thống kê truy cập