Lap Trinh Pic

19
Ngôn ngữ là: HTPIC Có lẽ bài toán nháy led là bài toán đơn giản và tạo hứng thú cho các bạn học vi điều khiển. Tôi xin mạn phép up chương trình nháy led đơn giản và xin các bạn cho ý kiến là liệu có thể tối ưu chương trình này đến mức nào nữa? Miêu tả phần cứng: nối các chân của PORTD với các 8led. Các chân còn lại của led nối với một con trở hạn dòng 330Ohm, sau đó nối với GND. Đây là sơ đồ nguyên lý: Hình 1: Nháy 8led rất đẹp . Phần mềm: dùng HTPIC. Hiện tuợng: các bạn chạy thử xem thế nào

Transcript of Lap Trinh Pic

Page 1: Lap Trinh Pic

Ngôn ngữ là: HTPIC

Có lẽ bài toán nháy led là bài toán đơn giản và tạo hứng thú cho các bạn học vi điều khiển. Tôi xin mạn phép up chương trình nháy led đơn giản và xin các bạn cho ý kiến là liệu có thể tối ưu chương trình này đến mức nào nữa?

Miêu tả phần cứng: nối các chân của PORTD với các 8led. Các chân còn lại của led nối với một con trở hạn dòng 330Ohm, sau đó nối với GND.

Đây là sơ đồ nguyên lý:

Hình 1: Nháy 8led rất đẹp .Phần mềm: dùng HTPIC.

Hiện tuợng: các bạn chạy thử xem thế nào

Giải pháp: có 2 giải pháp là dùng ngắt hoặc dùng delay.

Chương trình đầu là dùng delay:

Sau đây là chương trình:

Page 2: Lap Trinh Pic

#include<pic.h>__CONFIG(HS & PWRTEN & BOREN & LVPDIS & WDTDIS );//================================================================//== ham Delay doi so la so miligiay can gay trevoid delayMS(unsigned int time){

while(time--){TMR0 = 6;T0IF = 0; // xoa co ngat while(!T0IF);

};}

// == Ham khoi tao cho chip PIC16F877Avoid init(void){

// Khoi tao I/O cho cac portADCON1 = 0x07; // PortA dung la I/O PortTRISA = 0xFF; // Port A as inputTRISB = 0xFF;TRISC = 0xFF;TRISD = 0x00;// PortD as output

// Khoi tao cho cac thanh ghiOPTION = 0x00; // dung prescaler cho timer0 voi ti le la 1:2

}

// Chuong trinh chinhvoid main(void){

unsigned char i; init();while(1){

for(i = 0;i<8;i++){ PORTD = (1<<i) + (1<<(7-i));delayMS(5000);

};};

}

Câu lênh PORTD = (1<<i) + (1<<(7-i)); là dùng toán tử dịch bít.

File gửi kèm có 2 file: PJ1.c và PJ2.c . PJ1.C là chương trình dùng delay, PJ2 là dùng ngắt.

Xin mọi người cho ý kiến.

Đây là chương trình dùng ngắt timer0.

Code:

#include<pic.h>

__CONFIG(HS & PWRTEN & BOREN & LVPDIS & WDTDIS );

//================================================================// Hàm ng?t Timer0void interrupt inter0(void){

static unsigned char i;static unsigned int counter; // bien dem su kien ngat timer0if(T0IF){ // neu co ngat Timer0 xay ra

Page 3: Lap Trinh Pic

++ counter;if(counter == 500){

PORTD = (1<<i) + (1<<(7-i));++i;if(i==8) i=0;counter = 0;

};TMR0 = 6;T0IF = 0 ; // xoa co ngat, cong viec khong the thieu

sau ham ngat};

}

// == Ham khoi tao cho chip PIC16F877Avoid init(void){

// Khoi tao I/O cho cac portTRISD = 0x00;// PortD as output

// Khoi tao cho cac thanh ghiOPTION = 0x00; // dung prescaler cho timer0 voi ti le la 1:2

// Khoi tao cho ngat Timer0GIE = 1; // cho phep ngat toan cucT0IE = 1; // cho phep ngat timer0T0IF = 0; // xoa co ngatTMR0 = 6; // khoi tao

}

// Chuong trinh chinhvoid main(void){

init();while(1); // de con tro PC khong nhay lung tung,con lam gi

thi lam :D}

Thuật giải của chương trình dùng ngắt đó là: dùng một biến tĩnh kiểu static để đếm số lần xuất hiện ngắt timer0.

Trong chương trình này mình sau 500 ngắt timer0 thì mới quét led1 lần.

Ngoài ra cũng dùng thêm biến static i để biết được đang quét led nào. Do đó dùng ngắt sẽ tiện hơn nhiều. Và dùng đếm sự kiện ngắt thì ta có thể không cần dùng Prescaler với tỉ lệ quá cao, tránh được sai số nhiều.

Không biết mọi người có ý kiến thế nào?

Giải mã LED7 thanh

Tiếp theo tôi xin đưa cho mọi người xem một chương trình của tui không biết liệu nó đã tối ưu chưa? Đã hiệu quả chưa?

Mô tả phần cứng: có 4 led 7 thanh. Các chân của PORTD 7->1 nối với các chân a->g của led7. Các chân RA5 đến RA3 nối vào cực bazơ của con uA1015 lần lượt nối với các cực Anot của 4 led.

Đây là sch: vì to quá nên cắt thành 2 nhìn cho rõ:

Page 4: Lap Trinh Pic
Page 5: Lap Trinh Pic

Hình 2: Quét led 7 thanh.Yêu cầu của chương trình là: hiển thị ra 4 led các giá trị tăng dần từ 0000 đến 9999 sau đó lại quay lại.

Chương trình này lấy phần giải mã của anh 4MD. chương trình của anh ấy dùng cả delay. Nhưng tôi nghĩ là khi dùng ngắt rùi thì dùng delay làm gì cho phí. Do đó việc dùng ngắt làm cho ta đỡ tốn thời gian làm những việc linh tinh.

Các bạn cho ý kiến về giải thuật này.

Code:

#include<pic.h>const unsigned char Font[]={ 0b00000011, 0b10011111, 0b00100101, 0b00001101, 0b10011001,\

0b01001001, 0b01000001, 0b00011111, 0b00000001, 0b00001001};

__CONFIG(HS & PWRTEN & BOREN & LVPDIS & WDTDIS );

//------------------------------------Interruptvoid interrupt MyInt(void){

static int counter1,counter2;// counter1 dem so lan timer0 tran// counter2 dem so lan led duoc quetstatic unsigned int number;static unsigned int a[4]={0,0,0,0};static unsigned char j;

Page 6: Lap Trinh Pic

if(T0IF){++counter1;if( counter1 == 500){

counter1 = 0;PORTD = 0xFF;PORTA = 0xFF - (1<<(5-j));// bat mot

ledPORTD = Font[a[j]];if(++j==4) {

j=0;++counter2;

};};if(counter2 == 500){

++number;if(number>9999) number= 0;counter2 = 0;a[3] = number/1000;a[2] = (number/100)%10;a[1] = (number/10)%10;a[0] = number%10;

};TMR0 = 6;T0IF = 0 ;// xoa co ngat};

}

//------------------------------------initvoid init(void)

{//-------------------------init for PORTsOPTION = 0b00000000;ADCON1 = 0b00000111;TRISA = 0b00000000;TRISB = 0b11111111;TRISC = 0b11111111;TRISD = 0b00000000;TRISE = 0b11111111;//-------------------------init for interruptGIE = 1;T0IE = 1;TMR0 = 6;

}

//------------------------------------MAINvoid main(){

init();while(1); // Trong này làm gì thì làm

}

Anh 4MD cho ý kiến với em luôn.

Chương trình của mình có cái hay là khi bạn vừa dùng ngắt Timer0 để quét led bạn vừa có thể tận dụng nó để làm việc khác nữa như đếm số lần quét hoặc là delay để làm cái gì đó.

Cái này giống kiểu tiết kiệm chân vi điều khiển vậy . Dưới đây có file gửi kèm là 3 file .c của 3 bài trên.

Page 7: Lap Trinh Pic

Chúc các bạn thành công.OK, mình xin thay đoạn chương trình đó bằng cách gọi hàm:Code:

Convert(a,4,number);

Với hàm Convert được khai báo và định nghĩa ở trên hàm MyInt như sau:Code:

// ========== Ham chuyen doivoid Convert(unsigned char *a,unsigned char index, unsigned int number){

unsigned char i;for(i=0;i< index; i++){

*(a+i) = number%10;number = number/10;

}; }

Các bạn đổi lại kiểu dữ liệu của mảng a trong chương trình lại thành kiểu Unsigned char.

Đoạn code đã được test bằng phần cứng.Đảm bảo thay thế đúng.

Mình xin đưa lại code mới:

Code:

/*;========================================================; Ten chuong trinh : Quet 4led 7 thanh; Nguoi thuc hien : Ngo Hai Bac (NOHB); Ngay thuc hien : 12/04/06; Phien ban : 2.0; Mo ta phan cung : Dung PIC16F877A - thach anh 20MHz; 4 led 7 anot chung, cac catot noi voi PORTD, 4 chan anot noi voi cuc E trans A1015; cuc B cua trans noi voi chan 7->5 cua PORTA;----------------------------------------------------------------; Ngay hoan thanh : ; Ngay kiem tra: ; Nguoi kiem tra : ;----------------------------------------------------------------; Chu thich : ;========================================================*/#include<pic.h>__CONFIG(HS & PWRTEN & BOREN & LVPDIS & WDTDIS );

const unsigned char Font[]={ 0b00000011, 0b10011111, 0b00100101, 0b00001101, 0b10011001,\

0b01001001, 0b01000001, 0b00011111, 0b00000001, 0b00001001};

// ========== Ham chuyen doivoid Convert(unsigned char *a,unsigned char index, unsigned int number){

unsigned char i;for(i=0;i< index; i++){

*(a+i) = number%10;

Page 8: Lap Trinh Pic

number = number/10;};

}

//===== hàm khởi tạovoid interrupt MyInt(void){

static int counter1,counter2;// counter1 dem so lan Timer0 tran// counter2 dem so lan ca 4 led7 thanh duoc quetstatic volatile unsigned int number;static volatile unsigned char a[4]={0,0,0,0};static volatile unsigned char j; // bien dem kiem tra xem

led nao duoc quetif(T0IF & T0IE){

TMR0 = 6;T0IF = 0 ;// xoa co ngat++counter1;if( counter1 == 3){

counter1 = 0;PORTD = 0xFF;PORTA = 0xFF - (1<<(5- j)) ;PORTD = Font[a[j]];if(++j==4) {

j=0;++counter2;

};};if(counter2 == 200){

if(++number>9999) number= 0;counter2 = 0;Convert(a,4,number);

};};

}

//------------------------------------initvoid init(void)

{//-------------------------init for PORTsOPTION = 0b00000000;ADCON1 = 0b00000111;TRISA = 0b00000000;TRISB = 0b11111111;TRISC = 0b11111111;TRISD = 0b00000000;PORTD = Font[0];TRISE = 0b11111111;//-------------------------init for interruptGIE = 1;T0IE = 1;TMR0 = 6;

}

//------------------------------------MAINvoid main(){

init();while(1);

}

// ============== Hết code

Page 9: Lap Trinh Pic

Đây là chương trình khi PC gửi dữ liệu đến PIC thì PIC sẽ phản hồi lại kí tự mà nó đã nhận được. Là một phần trong bài tập lớn của tôi nên tôi sẽ post dần lên cho anh em tham khảo và cho ý kiến về độ tối ưu của chương trình.Code:

/*========================================================; Ten chuong trinh : giao tiep USART voi PC, nhan duoc thi hien thi lai; Nguoi thuc hien : ngohaibac; Ngay thuc hien : ; Phien ban : 1.0; Mo ta phan cung : Dung PIC16F877A - thach anh 20MHz; chan RC7/TX noi voi chan R1OUT cua MAX232; chan RC6/RX noi voi chan T1IN cua MAX232;----------------------------------------------------------------; Ngay hoan thanh : ; Ngay kiem tra: ; Nguoi kiem tra : ;----------------------------------------------------------------; Chu thich : Chuong trinh dung giao tiep USART

;========================================================*/#include<pic.h>

__CONFIG(HS & PWRTEN & BOREN & LVPDIS & WDTDIS );

// ham init - khoi tao void initUART(void){// Khoi tao cho USART

TRISC = TRISC | 0b11000000; // Bit 7,6 la RX va TX phai la Input

SPEN = 1 ; // Enable Serial Port communication.SYNC = 0; // che do khong dong bo Asynchronous// cho che do truyenTXEN = 1; //enable truyenTX9 = 0 ; // chon che do 8 truyen bit du lieuBRGH = 1; // High - speedSPBRG = 129; //Baud = 9600; voi HS, Baud Rate =

Fosc/(16(X+1)) TXIE = 0; // khong dung ngat Truyen// Che do nhan du lieuRCIE = 1; // dung ngat nhanPEIE = 1; // cho phep ngat ngoai viGIE = 1; // cho phep ngat toan cucRX9 = 0; // nhan 8 bitCREN = 1; // lien tuc nhan du lieu; = 0 k lien

tuc nhan du lieu

}

// ham truyen du lieu 1 ký tựvoid putch(unsigned char byte) {

/* output one byte */while(!TXIF); /* set when register is empty */// continue;TXREG = byte;

}

Page 10: Lap Trinh Pic

void init(void){initUART();

}// ham ngatvoid interrupt MyInt(void){

unsigned char temp;if(RCIF){ // Neu

co ngat nhan du lieu noi tieptemp = RCREG;RCIF = 0; // Xoa

co ngat RCIFputch(temp);

};}

// ham chinh void main(void){

//unsigned char a[] =" anh yeu em nhieu lam, em biet k?";//unsigned char i = 0;init();//for(i= 0; i<33; i++) putch(a[i]);//for(i= 0; i<10; i++) putch(i+48);while(1);

}

Chương trình này chỉ đơn giản là một ví dụ về truyền nhận dữ liệu còn nếu các bạn muốn truyền, nhận một sâu thì các bạn phải dùng Timeout cho nó để chống mất dữ liệu như sự cố đường dây mà PIC nhà ta vẫn chờ mỏi cả cổ mà vẫn k nhận được hết dữ liệu mà nó cần thì chết .

Chương trình đã được test và chạy ngon lành.

Chúc các bạn thành công.Có lẽ chương trình hiển thị số lên led7 đoạn đã được mịnh viết bên dientuvietnam.net nên sẽ không viết lại nữa nha. Nhưng máy mình không vào được site này. Nên đành post lên bên này vậy.

Sau đây là chương trình đếm xung từ chân RC1/T1OSI/CCP2 để hiển thị lên 4led 7 thanh. Một chương trình cũng rất đơn giản.Xin mời các bạn xem và cho ý kiến về chương trình này:Code:

/*;========================================================; Ten chuong trinh : Quet 4led 7 thanh; Nguoi thuc hien : Ngo Hai Bac (NOHB); Ngay thuc hien : ; Phien ban : 1.0; Mo ta phan cung : Dung PIC16F877A - thach anh 20MHz; 4 led 7 anot chung, cac catot noi voi PORTD, 4 chan anot noi voi cuc E trans A1015; cuc B cua trans noi voi chan 7->5 cua PORTA; Xung ngoai duoc cho vao chan RC1/T1OSI/CCP2;----------------------------------------------------------------; Ngay hoan thanh :

Page 11: Lap Trinh Pic

; Ngay kiem tra: ; Nguoi kiem tra : ;----------------------------------------------------------------; Chu thich : ;========================================================*/#include<pic.h>__CONFIG(HS & PWRTEN & BOREN & LVPDIS & WDTDIS );

const unsigned char Font[]={ 0b00000011, 0b10011111, 0b00100101, 0b00001101, 0b10011001,\

0b01001001, 0b01000001, 0b00011111, 0b00000001, 0b00001001};

// Chuyen doivoid Convert(unsigned char *a,unsigned char index, unsigned int number){

unsigned char i;for(i=0;i< index; i++){

*(a+i) = number%10;number = number/10;

}; }

//===== Ham khoi taovoid interrupt MyInt(void){

static volatile unsigned int counter1,counter2;// counter1 dem so lan Timer0 tran// counter2 dem so lan ca 4 led7 thanh duoc quetstatic volatile unsigned int number;static volatile unsigned char a[4]={0,0,0,0};static volatile unsigned char j; // bien dem kiem tra xem

led nao duoc quetif(T0IF & T0IE){

TMR0 = 6;T0IF = 0 ;// xoa co ngat++counter1;if( counter1 == 3){

counter1 = 0;PORTD = 0xFF;PORTA = 0xFF - (1<<(5- j)) ;PORTD = Font[a[j]];if(++j==4) {

j=0;++counter2;

};};if(counter2 == 2000){

number = (TMR1H << 8) | TMR1L;TMR1ON = 0 ; // ngung Timer1TMR1H = TMR1L = 0;TMR1ON = 1 ; // bat lai Timer1 if(number>9999) number= 0;counter2 = 0;Convert(a, 4, number);

};};

}

//------------------------------------init

Page 12: Lap Trinh Pic

void init(void){

//================= init for PORTsOPTION = 0b00000000;ADCON1 = 0b00000111;TRISA = 0b00000000;TRISB = 0b11111111;TRISC = 0b11111111;TRISD = 0b00000000;PORTD = Font[0];TRISE = 0b11111111;//================ Khoi tao cho Timer0GIE = 1;T0IE = 1;TMR0 = 6;

// ========= Khoi tao cho dem Timer1TMR1CS = 1;

// Timer1 hoat dong o che do Counter ModeT1SYNC = 1;

// TMR1 hoat dong o che do dem khong dong boT1OSCEN = 1;

// Dem xung tu chan RC1/T1OSI/CCP2T1CKPS1 = T1CKPS0 = 0; // Chon

Prescaler = 1:1TMR1H = TMR1L = 0;TMR1IE = 0;

// Khong dung ngat Timer1TMR1ON = 1;

// Bat Timer1

}

//------------------------------------MAINvoid main(){

init();while(1);

}// ============= Kết thúc

Chương trình sau nhận lệnh từ PC truyền xuống. Các bạn dựa vào cấu trúc chương trình có thể tự lập cho mình chương trình để làm. Đây là một phần nhỏ trong chương trình thiết kế bộ PID điều khiển động cơ một chiều 12V của tôi:

Code:

/*========================================================; Ten chuong trinh : giao tiep USART voi PC, nhan duoc thi hien thi lai; Nguoi thuc hien : ngohaibac; Ngay thuc hien : ; Phien ban : 1.0; Mo ta phan cung : Dung PIC16F877A - thach anh 20MHz; chan RC7/TX noi voi chan R1OUT cua MAX232; chan RC6/RX noi voi chan T1IN cua MAX232;----------------------------------------------------------------; Ngay hoan thanh : ; Ngay kiem tra: ; Nguoi kiem tra : ;----------------------------------------------------------------

Page 13: Lap Trinh Pic

; Chu thich : Chuong trinh dung giao tiep USART

;========================================================*/#include<pic.h>

__CONFIG(HS & PWRTEN & BOREN & LVPDIS & WDTDIS );

// ham init - khoi tao void initUART(void){// Khoi tao cho USART

TRISC = TRISC | 0b11000000; // Bit 7,6 la RX va TX phai la Input

SPEN = 1 ; // Enable Serial Port communication.SYNC = 0; // che do khong dong bo Asynchronous// cho che do truyenTXEN = 1; //enable truyenTX9 = 0 ; // chon che do 8 truyen bit du lieuBRGH = 1; // High - speedSPBRG = 129; //Baud = 9600; voi HS, Baud Rate =

Fosc/(16(X+1)) TXIE = 0; // khong dung ngat Truyen// Che do nhan du lieuRCIE = 1; // dung ngat nhanPEIE = 1; // cho phep ngat ngoai viGIE = 1; // cho phep ngat toan cucRX9 = 0; // nhan 8 bitCREN = 1; // lien tuc nhan du lieu; = 0 k lien

tuc nhan du lieu

}

// Chuyen doivoid Convert(unsigned char *a,unsigned char index, unsigned int number){

unsigned char i;for(i=0;i< index; i++){

*(a+i) = number%10;number = number/10;

}; }

// ham truyen du lieuvoid putch(unsigned char byte) {

/* output one byte */while(!TXIF); /* set when register is empty */// continue;TXREG = byte;

}

// ==== Ham ghi len tren mot gia tri cua so co 4 chu sovoid puts(unsigned int number){ // truyen 4 so cua number

unsigned char i;unsigned char a[] = {0,0,0,0};Convert(a,4,number);for(i= 0;i<2;i++) putch(a[i]+48);putch(0x2C);for(i= 2;i<4;i++) putch(a[i]+48);putch(0x20);

}

Page 14: Lap Trinh Pic

// ======= Ham ghi len tren mot vector gom 4 phan tuvoid putsVector(unsigned char *a,unsigned char n){

unsigned char i;for(i = 0;i<n;i++) putch(a[i]);

}

// Ham khoi tao chungvoid init(void){

initUART();//================ Khoi tao cho Timer0

GIE = 1;T0IE = 1;TMR0 = 6;

}// ham ngatvoid interrupt MyInt(void){

unsigned char temp, i,j;static volatile unsigned char counter4, allow;// temp: bien dem nhan,allow: cho phep nhan du lieustatic volatile unsigned char K[17];static volatile unsigned char Kp;static volatile unsigned char Ki;static volatile unsigned char Kd;static volatile unsigned char n;//Kp, Ki, Kd la tham so PID, n la toc doif(T0IF & T0IE){

TMR0 = 6;T0IF = 0 ;// xoa co ngat

};if(RCIF){ // Neu

co ngat nhan du lieu noi tieptemp = RCREG;RCIF = 0; // Xoa

co ngat RCIFswitch(temp){

case 'B': // === Bat dau cho dong co chay

putch('B'); allow = 0;break;

case 'K': // === Tat dong co

putch('K'); allow = 0;break;

case 'A': // === Nhap cac gia tri cho Kp,Ki,Kd

putch('A');allow = 1; // chuyen sang nhap cho

cac tham so cua mang.break;

};if (allow){

K[counter4++] = temp;if(counter4 == 17) {

allow = 0; putsVector(K,17);

};};

Page 15: Lap Trinh Pic

};}

// ham chinh void main(void){

//unsigned char a[] =" anh yeu em nhieu lam, em biet k?";unsigned char i = 0;init();//for(i= 0; i<33; i++) putch(a[i]);//for(i= 0; i<10; i++) putch(i+48);while(1);

}

Chào các bác.Em mới học về Pic.Mong các bác chỉ giáoEm dùng Htpic.Em viết 1 chương trình đơn giản sử dụng timer0.Nhưng chả hiểu tại sao thời gian delay ko chính xác(em mô phỏng bằng proteus).Em delay 1 giây mà mô phỏng chạy những 15 giây(sai số lớn quá)Mà ko hiểu tại sao lệnh while(1) lại ko lặp lại.Khi đèn chạy được 1 chu kỳ thì nó tắt luôn chứ ko lặp lại.các bác xem giúp em vớiCode:

//========================================================//Bai toan phanh xe.Phanh duoc noi vao RB0//khi phanh thi RB0 o muc thap//binh thuong RB0 o muc cao//co 8 led o RD8 den RD0 se sang theo quy luat(khi phanh)//10000000,01000000...00000001,11111111,00000000//sau do lap lai neu chua nha phanh//thoi gian delay la 1 giay//thach anh 20 Mhz

//========================================================#include<pic.h>#define out PORTD__CONFIG(HS & PWRTEN & BOREN & LVPDIS &WDTDIS );void DL(unsigned int giay);//--------------------------------------------------------------------------------------------------const unsigned char a[]={0b10000000,0b01000000,0b00100000,0b00010000,0b00001000,0b00000100,0b00000010,0b00000001,0b11111111,0b00000000};//========================================================void main() { unsigned char i; TRISB = 0b11111111; //Dinh nghia cong B la INPUT

RBPU =0; //co dien tro trong keo len nguon TRISD = 0b00000000;i=0;while(1) { if(RB0==0) //nhan phanh { out=a[i]; i=i+1; DL(25000); //delay 1giay if(i==11) i=0;

Page 16: Lap Trinh Pic

} else { out=0; i=0; } }} //------------------------------------------------------------------------void DL(unsigned int giay) { while(giay--) { //delay 40 microgiay PSA=1; //bo chia dung cho wdt T0CS=0; //dung dem thoi gian TMR0=56; while(!TMR0IF); TMR0IF=0; }}//=============================THE END===========================