PDA

View Full Version : Lỗi không ngắt được trong CCS


bazooka2006
21-08-2008, 12:23 AM
Mình viết Ct điều khiển động cơ bước từ máy tính. Cụ thể là điều khiển 1 mâm quay, trên hành trình mâm có công tắc giới hạn, nối vào portB. Cấu trúc ct như sau:
- Phần khai báo biến, mức ưu tiên, RS232...
- Các hàm phát xung cho động cơ (dùng delay_us trong CCS).
- Hàm phục vụ ngắt nối tiếp (INT_RDA): báo ngắt khi có kí tự gởi xuống, ứng với mỗi kí tự thì gọi hàm phát xung tương ứng
- Hàm phục vụ ngắt PortB (INT_RB): khi công tắc báo ngắt thì gọi hàm phát xung.

Ý định của mình là khi gửi kí tự A chẳng hạn, hàm ngắt RDA cho mâm quay trái, gặp công tắc thì hàm ngắt RB cho dừng, delay 1s rồi quay ngược lại 1 góc nào đó.

Mình đã test thử từng phần riêng, là gửi A thì mâm quay trái tốt, tác động bằng tay lên công tắc thì mâm quay ngược lại tốt, nghĩa là đáp ứng ngắt tốt. Nhưng khi đang quay trái mà gặp công tắc thì không ngắt được. phải đến khi thực hiện hết quay trái của ngắt RDA, nếu t/h ngắt RB còn thì nó mới thực hiện ngắt RB.
Lưu ý là mình đã đặt mức ưu tiên ngắt RB cao hơn RDA rồi.

Ở đây mình phán đoán nó bị lỗi như giống như trường hợp cảnh báo "Warning 216 : Interrupts disable during call to prevent re_entrancy:tên hàm"
lỗi này hình như là 1 ngắt có dùng các hàm delay_us, delay_ms mà ở ngoài cũng có 1 hàm delay này đang chạy thì ngắt sẽ bị disable? Đây là link trên CCSInfo, do trình độ AV có hạn nên mình ko hiểu nhiều lắm: http://www.ccsinfo.com/forum/viewtopic.php?t=27037&postdays=0&postorder=asc&start=0
Trường hợp của mình là đều dùng Delay_us trong cả 2 ngắt.

Mình chỉ là newbie với PIC, ai có kinh nghiệm có thể giúp mình khắc phục không?

phamminhtuan
21-08-2008, 12:36 AM
Bạn có thể post code lên được không, có thể sẽ dễ giải quyết vấn đề hơn, chú ý là ngắt INT_RB là ngắt on change, xử lý không tốt ở đây cũng nảy sinh vấn đề rồi.

bazooka2006
21-08-2008, 02:01 AM
Ct của mình dùng đk 1 tay máy 3 trục dùng 3 đcơ bước nên nó dài dòng quá, ban đầu post lên sợ ko ai đọc.
Mình tóm tắt là có 3 motor bước, mỗi cái quay 1 trục, trên hành trình có gắn 3 ctắc để set vị trí home, ctắc nối vào chân ngắt của RB.
Giao tiếp RS232 báo ngắt khi bộ đệm nhận dữ liệu đầy.
Hoạt động: gửi 1 kí tự xuống PIC thì ngắt nối tiếp RDA gọi hàm quay động cơ tương ứng. Gửi kí tự "O" thì ngắt RDA đk 3 trục về vtrí home, bằng cách là khi mỗi trục gặp ctắc, hàm ngắt RB đặt mức ưu tiên cao hơn sẽ ngắt hàm RDA, cho dừng và quay 3 trục về home.
Vấn đề ở đây là ngắt RB ko ngắt đc hàm RDA đang thực thi, nên 3 động cơ không dừng như mong muốn. Nếu ngắt RDA ko chạy thì ngắt RB vẫn hoạt động tốt. Mình cũng thử là cho RB ngắt khi chạy phát xung ngoài hàm main, thì vẫn ko ngắt đc. Trình dịch cảnh báo Warning 216 như mình nói.
đây là code, mọi ngừoi chịu khó xem giúp mình:
#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#priority rb,rda
#byte porta=0x05
#byte portb=0x06
#byte portd=0x08

#bit catch=porta.3 // ngo ra nam cham

#bit clock1=porta.2 // Step motor 1
#bit en_step1=porta.1
#bit dir1=porta.0

#bit clock2=portd.7 // step motor 2
#bit en_step2=portd.6
#bit dir2=portd.5

#bit en_step3=portd.3 // step motor 3
#bit dir3=portd.2
#bit clock3=portd.1

int count1; // bien dem so xung motor1
int16 count2,count3; // motor2 va 3
char ss;


void rotate_high1() // ham phat xung cho motor 1
{ // quay toc do cao
clock1=1;
delay_us(30000);
clock1=0;
delay_us(500);
}

void rotate_low1() // motor 1 toc do thap
{
clock1=1;
delay_us(50000);
clock1=0;
delay_us(500);
}

void rotate_high2()
{
clock2=1;
delay_us(1000);
clock2=0;
delay_us(100);
}

void rotate_low2()
{
clock2=1;
delay_us(2000);
clock2=0;
delay_us(100);
}

void rotate3()
{
clock3=1;
delay_us(700);
clock3=0;
delay_us(100);
}
//**************************************************
void left_right() // ham quay motor 1
{
int tam;
tam=count1;
en_step1=1;
while (count1>0)
{
count1--;
if ((count1>30)&&(count1<(tam-30)))
{
rotate_high1();
}
else
{
rotate_low1();
}
}
count1=0;
delay_ms(500);
}
//************************************************** **
void go_up_down() // ham quay motor 2
{
en_step2=1;
while (count2>0)
{
count2--;
if (dir2==0)
{
rotate_low2();
}
else
{
rotate_high2();
}
}
count2=0;
delay_ms(500);
en_step2=0;
}
//************************************************** ***
void in_out() // ham quay motor 3
{
en_step3=1;
while (count3>0)
{
count3--;
rotate3();
}
delay_ms(1000);
en_step3=0;
count3=0;
}

//************************************************** *****

#int_RB
void rb_isr() // ham phuc vu ngat RB
{
int current;
int last;
set_tris_b(0xff);
current=input_b();
last=current;
delay_ms(50);
set_tris_b(0xff);
current=input_b();
if (current==last)
{
clear_interrupt(int_RDA);
if (!bit_test(current,4)) // ctac tren mam xoay bao ngat
{
if (home) // chi thuc hien khi o che do home:
{ // quay mam ben phai 60 do
en_step1=0;
count1=70;
dir1=1;
en_step1=1;
while (count1>0)
{
count1--;
if ((count1>30)&&(count1<(70-30)))
{
rotate_high1();
}
else
{
rotate_low1();
}
}
count1=0;

}
}

if (!bit_test(current,5)) // ctac trong bao ngat
{
en_step3=0;
delay_ms(500);
count3=2000;
dir3=0;
in_out();
}

if (!bit_test(current,6)) //ctac tren bao ngat
{
en_step2=0;
delay_ms(500);
count2=500;
dir2=1;
go_up_down();
count2=0;
}

if (!bit_test(current,7)) // cam bien phat hien co vat den
{
putc('y');
delay_ms(10);
}
}
clear_interrupt(int_RB);
}

//************************************************** **************
#int_RDA // ham phuc vu ngat noi tiep
void RDA_isr()
{
delay_us(50);
ss=getc();
if (ss=='u') // di len
{
count2=2000;
dir2=0;
go_up_down();
printf("done");
}

if (ss=='d') // di xuong
{
count2=2000;
dir2=1;
go_up_down();
printf("done");
}

if (ss=='l') // quay trai
{
count1=70; //1 lan quay 60 do
dir1=0;
left_right();
printf("done");
}

if (ss=='r') // quay phai
{
count1=70;
dir1=1;
left_right();
printf("done");
}

if (ss=='i') //di vao
{
count3=4000; //1 lan di chuyen 30mm
dir3=1;
in_out();
printf("done");
}

if (ss=='o') // di ra
{
count3=4000;
dir3=0;
in_out();
printf("done");
}

if (ss=='#') // test comm
{
putc('!');
delay_us(100);
}

if (ss=='O') // go home: dieu khien tay may
{ // ve vi tri home
home=1;
count1=100;
dir1=0;
left_right();
count2=2000;
dir2=0;
go_up_down();
count3=2666;
dir3=1;
in_out();
home=0;
}

if (ss=='1') // chuong trinh di chuyen cho vat 1
{
count2=10000; // chay xuong
dir2=1;
go_up_down();

catch=1; // gap vat

count2=10000; // di len
dir2=0;
go_up_down();

count1=102; // xoay 90 do
dir1=1;
left_right();

count3=13333; // di ra
dir3=0;
in_out();

count2=10000; // ha xuong
dir2=1;
go_up_down();

catch=0; // nha vat

count2=10000; // di len
dir2=0;
go_up_down();

count1=102; // xoay 90 do
dir1=0;
left_right();

count3=13333; // di vao
dir3=1;
in_out();

}
clear_interrupt(int_rda);
}

void main()
{
enable_interrupts(INT_RB|H_TO_L);
enable_interrupts(GLOBAL);
ext_int_edge(H_TO_L);
enable_interrupts(INT_RDA);
set_tris_d(0x00);
set_tris_b(0xff);
set_tris_a(0x00);
printf("reset");


while (1)
{

}
}

phamminhtuan
21-08-2008, 11:44 AM
#include <16F877A.h>
...
#priority rb,rda

...
#int_RB
void rb_isr() // ham phuc vu ngat RB
{
int current;
int last;
set_tris_b(0xff);
current=input_b();
last=current;
delay_ms(50);
set_tris_b(0xff);
current=input_b();
if (current==last)
{
clear_interrupt(int_RDA);
if (!bit_test(current,4)) // ctac tren mam xoay bao ngat
{
if (home) // chi thuc hien khi o che do home:
{ // quay mam ben phai 60 do
en_step1=0;
count1=70;
dir1=1;
en_step1=1;
while (count1>0)
{
count1--;
if ((count1>30)&&(count1<(70-30)))
{
rotate_high1();
}
else
{
rotate_low1();
}
}
count1=0;

}
}

if (!bit_test(current,5)) // ctac trong bao ngat
{
en_step3=0;
delay_ms(500);
count3=2000;
dir3=0;
in_out();
}

if (!bit_test(current,6)) //ctac tren bao ngat
{
en_step2=0;
delay_ms(500);
count2=500;
dir2=1;
go_up_down();
count2=0;
}

if (!bit_test(current,7)) // cam bien phat hien co vat den
{
putc('y');
delay_ms(10);
}
}
clear_interrupt(int_RB);
}

//************************************************** **************
#int_RDA // ham phuc vu ngat noi tiep
void RDA_isr()
{
delay_us(50);
ss=getc();
if (ss=='u') // di len
{
count2=2000;
dir2=0;
go_up_down();
printf("done");
}

if (ss=='d') // di xuong
{
count2=2000;
dir2=1;
go_up_down();
printf("done");
}

if (ss=='l') // quay trai
{
count1=70; //1 lan quay 60 do
dir1=0;
left_right();
printf("done");
}

if (ss=='r') // quay phai
{
count1=70;
dir1=1;
left_right();
printf("done");
}

if (ss=='i') //di vao
{
count3=4000; //1 lan di chuyen 30mm
dir3=1;
in_out();
printf("done");
}

if (ss=='o') // di ra
{
count3=4000;
dir3=0;
in_out();
printf("done");
}

if (ss=='#') // test comm
{
putc('!');
delay_us(100);
}

if (ss=='O') // go home: dieu khien tay may
{ // ve vi tri home
home=1;
count1=100;
dir1=0;
left_right();
count2=2000;
dir2=0;
go_up_down();
count3=2666;
dir3=1;
in_out();
home=0;
}

if (ss=='1') // chuong trinh di chuyen cho vat 1
{
count2=10000; // chay xuong
dir2=1;
go_up_down();

catch=1; // gap vat

count2=10000; // di len
dir2=0;
go_up_down();

count1=102; // xoay 90 do
dir1=1;
left_right();

count3=13333; // di ra
dir3=0;
in_out();

count2=10000; // ha xuong
dir2=1;
go_up_down();

catch=0; // nha vat

count2=10000; // di len
dir2=0;
go_up_down();

count1=102; // xoay 90 do
dir1=0;
left_right();

count3=13333; // di vao
dir3=1;
in_out();

}
clear_interrupt(int_rda);
}

void main()
{
enable_interrupts(INT_RB|H_TO_L);
enable_interrupts(GLOBAL);
ext_int_edge(H_TO_L);
enable_interrupts(INT_RDA);
set_tris_d(0x00);
set_tris_b(0xff);
set_tris_a(0x00);
printf("reset");


while (1)
{

}
}

Mình có quote cho bạn những đoạn code trên, bạn cần lưu ý những điều sau để tự sửa lại chương trình:


Trong PIC16F877A không có ưu tiên ngắt, do đó chỉ dẫn #priority không có tác dụng
Khi xảy ra bất kì 1 ngắt nào, thì GIE = 0 để tránh xảy ra các ngắt chồng nhau, nó chỉ được set = 1 khi có lệnh RETFIE, có nghĩa là khi xảy ra 1 ngắt bất kì thì chỉ khi thực hiện xong ngắt đó mới có thể giải quyết ngắt tiếp theo
Khi xử lý 1 ngắt, trước khi kết thúc trình phục vụ ngắt, bạn phải xóa cờ ngắt đó bằng lệnh clear_interrupt();, nếu không sau khi thoát ra khỏi ngắt đó, nó sẽ quay trở lại
enable_interrupts(INT_RB|H_TO_L); không có OR với H_TO_L, tuy nhiên do giá trị H_TO_L = 0, nên chương trình bạn không bị ảnh hưởng
Dưới đây là file list C/ASM đơn giản để bạn thấy rõ điều đó


#include<16f877a.h>
#use delay(clock=4Mhz)
#use rs232(baud=9600, UART1)
#INT_RDA
void rda(){
unsigned char c;
c = getc(); //Lệnh này sau khi đọc xong kí tự, thì cờ ngắt tự động bị xóa
output_b(0xAA);
}

#INT_RB
void rb(){
output_b(0x55);
clear_interrupt(INT_RB);
}

void main(){
enable_interrupts(INT_RDA);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);

while(1);
}
đây là file list, lược bớt đoạn đầu, là đoạn chỉ lưu các thanh ghi và lựa chọn nhảy đến vị trí các chương trình phục vụ ngắt, không hề có lệnh nào xóa cờ ngắt

.................... #INT_RDA
.................... void rda(){
.................... unsigned char c;
.................... c = getc();
003C: BTFSS 0C.5
003D: GOTO 03C
003E: MOVF 1A,W
003F: MOVWF 28
.................... output_b(0xAA);
0040: BSF 03.5
0041: CLRF 06
0042: MOVLW AA
0043: BCF 03.5
0044: MOVWF 06
.................... }
....................
0045: BCF 0C.5
0046: BCF 0A.3
0047: BCF 0A.4
0048: GOTO 023
.................... #INT_RB
.................... void rb(){
.................... output_b(0x55);
0049: BSF 03.5
004A: CLRF 06
004B: MOVLW 55
004C: BCF 03.5
004D: MOVWF 06
.................... clear_interrupt(INT_RB);
004E: BCF 0B.0 //Chỉ khi có lệnh này, thì cờ ngắt của INT_RB mới được xóa
.................... }

bazooka2006
21-08-2008, 02:48 PM
Trong PIC16F877A không có ưu tiên ngắt, do đó chỉ dẫn #priority không có tác dụng

Cám ơn bạn minhtuan, quả thực trong datasheet 16f87xA ko hề nhắc đến điều này, mình nhầm to chỗ này rồi.

Khi xảy ra bất kì 1 ngắt nào, thì GIE = 0 để tránh xảy ra các ngắt chồng nhau, nó chỉ được set = 1 khi có lệnh RETFIE, có nghĩa là khi xảy ra 1 ngắt bất kì thì chỉ khi thực hiện xong ngắt đó mới có thể giải quyết ngắt tiếp theo.


Một câu hỏi đặt ra là ngay khi thực hiện ngắt 1, có thể tự set bit GIE lên 1 để nhận các ngắt khác không?
Thứ 2 là vấn đề của mình vẫn chưa giải quyết được. Như mình đã nói, mình đã test thử là thay vì cho chạy đcơ trong ngắt RDA, thì mình đưa đoạn đó ra ngoài main(), trong ngắt RDA chỉ set 1 bit cờ rồi thoát. Hàm main sẽ lặp vòng hỏi cờ này, nếu thấy =1 thì cho chạy đcơ. Và, khi đoạn này đang chạy, nếu ctắc báo ngắt RB, vẫn ko thể dừng được, nghĩa là ko thực thi ngắt RB được. Chỉ khi hàm quay đcơ này chạy xong, nếu ngắt RB còn, hay mình tự tác động thì nó ngắt tốt.
Và nếu đưa đoạn ct quay đcơ ra ngoài main như trên, thì CCS báo "Warning 216 : Interrupt disable..." như đã nói.
Có lẽ việc dùng delay_ms/us trong các ISR khi ở ngoài cũng có hàm này đang chạy sẽ thực sự gây bug là disable các ISR chăng?

phamminhtuan
21-08-2008, 03:29 PM
Cám ơn bạn minhtuan, quả thực trong datasheet 16f87xA ko hề nhắc đến điều này, mình nhầm to chỗ này rồi.


Một câu hỏi đặt ra là ngay khi thực hiện ngắt 1, có thể tự set bit GIE lên 1 để nhận các ngắt khác không?
Thứ 2 là vấn đề của mình vẫn chưa giải quyết được. Như mình đã nói, mình đã test thử là thay vì cho chạy đcơ trong ngắt RDA, thì mình đưa đoạn đó ra ngoài main(), trong ngắt RDA chỉ set 1 bit cờ rồi thoát. Hàm main sẽ lặp vòng hỏi cờ này, nếu thấy =1 thì cho chạy đcơ. Và, khi đoạn này đang chạy, nếu ctắc báo ngắt RB, vẫn ko thể dừng được, nghĩa là ko thực thi ngắt RB được. Chỉ khi hàm quay đcơ này chạy xong, nếu ngắt RB còn, hay mình tự tác động thì nó ngắt tốt.
Và nếu đưa đoạn ct quay đcơ ra ngoài main như trên, thì CCS báo "Warning 216 : Interrupt disable..." như đã nói.
Có lẽ việc dùng delay_ms/us trong các ISR khi ở ngoài cũng có hàm này đang chạy sẽ thực sự gây bug là disable các ISR chăng?




Dĩ nhiên, nếu bạn cứ set GIE lên, thì ngắt tiếp theo sẽ xảy ra trong khi đang thực thi ngắt cũ, và các giá trị mà CCS lưu lại sẽ bị đè lên bởi cái mới, giá trị con trỏ chương trình lưu lại chính là cái nơi xảy ra ngắt sau, thế nên chắc chắn 1 điều là chương trình của bạn chỉ có thể trở về tại vị trí nằm trong chương trình xử lý ngắt cũ(tại nơi xảy ra ngắt mới), và không thể trở về tại chương trình chính.
Việc bạn xác định ngắt RB không xảy ra trong khi động cơ đang quay bạn cần kiểm chứng bằng LED chẳng hạn
Còn hàm delay, bạn dịch thử 1 đoạn có delay, xem file list thì thấy rõ ngay, ví dụ bạn xem sau đây nhé, nó chỉ là những dòng lệnh bình thường như bao dòng lệnh khác thôi, chẳng tác động gì tới ngắt cả, thế nên, delay ở đâu cũng thế cả, có ngắt thì phục vụ ngắt.

.................... #use delay(clock=4Mhz)

0053: MOVLW 29
0054: MOVWF 04
0055: BCF 03.7
0056: MOVF 00,W
0057: BTFSC 03.2
0058: GOTO 067
0059: MOVLW 01
005A: MOVWF 78
005B: CLRF 77
005C: DECFSZ 77,F
005D: GOTO 05C
005E: DECFSZ 78,F
005F: GOTO 05B
0060: MOVLW 4A
0061: MOVWF 77
0062: DECFSZ 77,F
0063: GOTO 062
0064: GOTO 065
0065: DECFSZ 00,F
0066: GOTO 059
0067: BCF 0A.3
0068: BCF 0A.4
0069: GOTO 087 (RETURN)
//và
.................... delay_ms(1000);
0082: MOVLW 04
0083: MOVWF 28
0084: MOVLW FA
0085: MOVWF 29
0086: GOTO 053
0087: DECFSZ 28,F
0088: GOTO 084
Bạn thấy rõ, CCS C sẽ tính toán các giá trị nạp vào các ô nhớ RAM ở địa chỉ 28 và 29, sau đó nhảy tới chương trình delay ở địa chỉ 53 để thực thi hàm delay, đến khi thực thi xong, thì lại nhảy 87, làm cho xong hết thì ra khỏi delay, bạn thấy đấy, delay chẳng liên quan gì đến xử lý ngắt cả. Bạn hãy viết các chương trình đơn giản hơn để kiểm nghiệm

quangduy
08-09-2008, 02:59 PM
code trên không sai nhưng ccsc sai mấy ông mở cái set 16f877a.h ra và coi có set đúng
hay khong tôi từng bị cái này với 16f887.h rồi hầu như ngát RB sai cả sửa lai code theo 16f877a.h thì ok, => phien bản của các cong cụ lạp trình cấp cao chưa chăc hoản toàn đúng ==> khong tin thì sài 16f887 bien dịch mọi phien bản ccsc khác nhau = không chạy RB nếu khong sủa lại 16f887.h

vuxuansyhut
17-05-2010, 06:28 AM
mình đang gặp lỗi tương tự như trên. Không thể dùng ngắt rb và Rda trong cùng chương trình. Khi bỏ hoàn toàn ngắt rb thì chương trình chạy bình thường, còn khi thêm vào thì lại không chạy được. Ai đã giải quyết được vấn đề này xin giúp đỡ mình

nguyenung
27-05-2010, 05:51 PM
mình dùng ngắt và hàm delay cùng lúc không được. mình lập trình bằng CCS
dùng ngắt timer.Khi có cả delay và timer thì chỉ có "ngắt" chạy còn delay thì hoạt đông không chính xác. Delay_ms(2000) mà đợi tới cả chục giây mới có. Bạn nào biết nguyên nhân không và xin cho cách khắc phục vấn đề trên ( mình muốn dùng cả 2 delay và ngắt timer ). Thanks

tungbka
28-05-2010, 01:18 AM
Mình cũng đang viết 1 chương trình điều khiển động cơ 1 chiều, dữ liệu được nhập từ máy tính. Trong chương trình có dùng 3 ngắt là RDA, RB0 và ngắt của timer1 để tạo chu kỳ trích mẫu.
Có điều đáng nói là khi chạy thì chương trình thường bị treo sau khoảng 1-2s. Mình nghĩ là có xung đột về ngắt nên đã disable ngắt RDA sau khi nhận được dữ liệu từ máy tính. Và quả thật sau khi disable thì chương trình chạy ngon.
Tuy nhiên, khi đang chạy mà muốn truyền thêm dữ liệu từ PC xuống để thay đổi các thông số thì lại ko được (Vì đã disable ngắt RDA). Mình đã thử nhiều cách nhưng vẫn không thay đổi được gì.
Mong mọi người cho ý kiến để cải thiện chương trình của mình. Thanks.
Sau đây là chương trình của mình:


#include <16f877a.h>
#include <def_877a.h>
#include <stdlib.h>
#fuses NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBRO WNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bi ts=8)
#include <lcd_lib_4bit.c>
void ht(int16 a);
void init();
void pid();
void nhapheso();
void display(int16 n);
void truyen();
int16 count=0, tocdo=0, C, temp, temp1, k, tocdodat ;
signed int16 e2=0;
signed int16 e1=0;
int16 e_sum=0;
int16 e_del=0;
int16 duty=0;
float Kp=0;
float Ki=0;
float Kd=0;
int flag=0;
float u, T=0.01;

unsigned char text[30], text2[5] ;
unsigned char a1[5], dem=0, i=0, j=0,i1=0;

#INT_RDA
void Receive_isr()
{
text[dem]=getc();
if(text[dem]=='@') //kiem tra dieu kien ket thuc
{
flag =1; //ket thuc nhan, bat co bao
dem=0;
}
else dem++;
}
#INT_EXT
void ngatR0() {

count++;//set_timer0(0);

}
#int_timer1
void Timer11_isr() { // Ham duoc goi khi TImer1 tran (65535->0)

set_timer1(53036);
tocdo= 30*(count + get_timer0());
// printf("%ld\t",tocdo);
count = 0;
set_timer0(0);

}
void main(){
init();
lcd_putcmd(0x01);
while(true){
truyen(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
pid();
if(RC1==0) set_PWM1_duty(duty);
if(RC1==1) set_PWM1_duty(1023 - duty);
lcd_putcmd(0x80);
ht(tocdo);
printf("n%4Lu",tocdo);
display(tocdo);

//lcd_putchar("hi");


}
}
void init()
{
lcd_init();
nhapheso();
setup_timer_0 (RTCC_DIV_1|RTCC_EXT_L_TO_H); // Timer0 is Counter
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_4, 255, 1);//4*4*256*1/20000000=204.8us=4.8khz
set_timer0(0);
set_timer1(53036);
enable_interrupts(INT_RTCC);
enable_interrupts(int_timer1);
enable_interrupts(int_ext);
ext_int_edge(L_TO_H);
enable_interrupts(GLOBAL);
lcd_putcmd(0x80);
count=0;
trisc=0;
trisd=0;
trisa=255;
trisb=1;

}
void pid(){
e2 = tocdodat - tocdo;
e_sum += e2;
// e_del = e2 - e1;
// e1 = e2;
u = u + Kp*e2 + Ki*e_sum*T;
if (u>24){
u=24;
e_sum -=e2;
}
if (u<0){
u = 0;
e_sum -=e2;
}
duty = u*1023/24;
}
void ht(long a) {
int nghin,tram,chuc,dvi;
nghin=a/1000;
tram=(a%1000)/100;
chuc=(a%100)/10;
dvi=(a%10);
lcd_putchar(nghin+48);
lcd_putchar(tram+48);
lcd_putchar(chuc+48);
lcd_putchar(dvi+48);
}
void nhapheso(){
lcd_putchar("nhap tu PC");
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);
while(!flag) ;

}
void truyen()
{
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);
if(flag){

//if ((strchr(text,'T')) && (strrchr(text, '@')))

text2[0] = text[0];
text2[1] = text[1];
text2[2] = text[2];
text2[3] = text[3];
text2[4] = text[4];
tocdodat = atol(text2);

//----------------------------------------
while (text[i] != 'P')
i++;
while (text[j] != 'I')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

Kp = atof(a1);

printf("P%f",Kp);
delay_ms(100);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
i = j;
while (text[j] != 'D')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

Ki = atof(a1);
printf("I%f",Ki);
delay_ms(100);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
i = j;
while (text[j] != 'C')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

Kd = atof(a1);
printf("D%f",Kd);
delay_ms(100);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
i = j;
while (text[j] != '@')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

C = atol(a1);
printf("C%Lu",C);
flag=0;
i=0; j=0;
dem=0;
if(C==1) RC1=1;
If(C==0) RC1=0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

}
disable_interrupts(int_rda);
disable_interrupts(global);
}
void display(int16 n){
int nghin,tram,chuc,dvi;
nghin = n/1000;
tram = (n%1000)/100;
chuc = (n%100)/10;
dvi = n%10;
PORTB=dvi<<1; RD0=0; delay_ms(1);RD0=1;
PORTB=chuc<<1; RD1=0; delay_ms(1);RD1=1;
PORTB=tram<<1; RC4=0; delay_ms(1);RC4=1;
PORTB=nghin<<1; RC5=0; delay_ms(1);RC5=1;

}

changnhoc123
03-06-2013, 10:47 PM
Mình cũng đang viết 1 chương trình điều khiển động cơ 1 chiều, dữ liệu được nhập từ máy tính. Trong chương trình có dùng 3 ngắt là RDA, RB0 và ngắt của timer1 để tạo chu kỳ trích mẫu.
Có điều đáng nói là khi chạy thì chương trình thường bị treo sau khoảng 1-2s. Mình nghĩ là có xung đột về ngắt nên đã disable ngắt RDA sau khi nhận được dữ liệu từ máy tính. Và quả thật sau khi disable thì chương trình chạy ngon.
Tuy nhiên, khi đang chạy mà muốn truyền thêm dữ liệu từ PC xuống để thay đổi các thông số thì lại ko được (Vì đã disable ngắt RDA). Mình đã thử nhiều cách nhưng vẫn không thay đổi được gì.
Mong mọi người cho ý kiến để cải thiện chương trình của mình. Thanks.
Sau đây là chương trình của mình:


#include <16f877a.h>
#include <def_877a.h>
#include <stdlib.h>
#fuses NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBRO WNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bi ts=8)
#include <lcd_lib_4bit.c>
void ht(int16 a);
void init();
void pid();
void nhapheso();
void display(int16 n);
void truyen();
int16 count=0, tocdo=0, C, temp, temp1, k, tocdodat ;
signed int16 e2=0;
signed int16 e1=0;
int16 e_sum=0;
int16 e_del=0;
int16 duty=0;
float Kp=0;
float Ki=0;
float Kd=0;
int flag=0;
float u, T=0.01;

unsigned char text[30], text2[5] ;
unsigned char a1[5], dem=0, i=0, j=0,i1=0;

#INT_RDA
void Receive_isr()
{
text[dem]=getc();
if(text[dem]=='@') //kiem tra dieu kien ket thuc
{
flag =1; //ket thuc nhan, bat co bao
dem=0;
}
else dem++;
}
#INT_EXT
void ngatR0() {

count++;//set_timer0(0);

}
#int_timer1
void Timer11_isr() { // Ham duoc goi khi TImer1 tran (65535->0)

set_timer1(53036);
tocdo= 30*(count + get_timer0());
// printf("%ld\t",tocdo);
count = 0;
set_timer0(0);

}
void main(){
init();
lcd_putcmd(0x01);
while(true){
truyen(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
pid();
if(RC1==0) set_PWM1_duty(duty);
if(RC1==1) set_PWM1_duty(1023 - duty);
lcd_putcmd(0x80);
ht(tocdo);
printf("n%4Lu",tocdo);
display(tocdo);

//lcd_putchar("hi");


}
}
void init()
{
lcd_init();
nhapheso();
setup_timer_0 (RTCC_DIV_1|RTCC_EXT_L_TO_H); // Timer0 is Counter
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_4, 255, 1);//4*4*256*1/20000000=204.8us=4.8khz
set_timer0(0);
set_timer1(53036);
enable_interrupts(INT_RTCC);
enable_interrupts(int_timer1);
enable_interrupts(int_ext);
ext_int_edge(L_TO_H);
enable_interrupts(GLOBAL);
lcd_putcmd(0x80);
count=0;
trisc=0;
trisd=0;
trisa=255;
trisb=1;

}
void pid(){
e2 = tocdodat - tocdo;
e_sum += e2;
// e_del = e2 - e1;
// e1 = e2;
u = u + Kp*e2 + Ki*e_sum*T;
if (u>24){
u=24;
e_sum -=e2;
}
if (u<0){
u = 0;
e_sum -=e2;
}
duty = u*1023/24;
}
void ht(long a) {
int nghin,tram,chuc,dvi;
nghin=a/1000;
tram=(a%1000)/100;
chuc=(a%100)/10;
dvi=(a%10);
lcd_putchar(nghin+48);
lcd_putchar(tram+48);
lcd_putchar(chuc+48);
lcd_putchar(dvi+48);
}
void nhapheso(){
lcd_putchar("nhap tu PC");
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);
while(!flag) ;

}
void truyen()
{
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);
if(flag){

//if ((strchr(text,'T')) && (strrchr(text, '@')))

text2[0] = text[0];
text2[1] = text[1];
text2[2] = text[2];
text2[3] = text[3];
text2[4] = text[4];
tocdodat = atol(text2);

//----------------------------------------
while (text[i] != 'P')
i++;
while (text[j] != 'I')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

Kp = atof(a1);

printf("P%f",Kp);
delay_ms(100);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
i = j;
while (text[j] != 'D')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

Ki = atof(a1);
printf("I%f",Ki);
delay_ms(100);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
i = j;
while (text[j] != 'C')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

Kd = atof(a1);
printf("D%f",Kd);
delay_ms(100);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
i = j;
while (text[j] != '@')
j++;
i1 = i;
temp = j - i;
for (i = 0; i < temp; i++)
a1[i] = text[i1 + i + 1];

C = atol(a1);
printf("C%Lu",C);
flag=0;
i=0; j=0;
dem=0;
if(C==1) RC1=1;
If(C==0) RC1=0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

}
disable_interrupts(int_rda);
disable_interrupts(global);
}
void display(int16 n){
int nghin,tram,chuc,dvi;
nghin = n/1000;
tram = (n%1000)/100;
chuc = (n%100)/10;
dvi = n%10;
PORTB=dvi<<1; RD0=0; delay_ms(1);RD0=1;
PORTB=chuc<<1; RD1=0; delay_ms(1);RD1=1;
PORTB=tram<<1; RC4=0; delay_ms(1);RC4=1;
PORTB=nghin<<1; RC5=0; delay_ms(1);RC5=1;

}

bạn dis rda kiểu gì vậy, chỉ mình với, mình cũng bị lỗi này

Ham học
31-08-2015, 10:00 AM
lỗi dòng portb=0; là lỗi j zây mọi người, sữa sao được đây
#INCLUDE<16F877A.H>
#FUSES HS,NOWDT,NOPROTECT,NOLVP
#USE DELAY(CLOCK=40000000)
#use fast_io(b)
#byte port=0x06
int8 sck,slx,bx,bl,gt;
void main()
{
set_tris_b(0);
while(true)
{
sck=8;
bl=0;
portb=(0);
delay_ms(1000);
while(sck>0)
{
bx=1;
slx=sck;
while(slx>0)
{
gt=bl|bx;
portb=gt;
delay_ms(1000);
bx=bx<<1;
slx--;
}
bl=gt;
sck--;
}

}

}