![]() |
hỏi về ngắt ngoài để đếm xung
Chào các bạn ! mình sử dụng pic6f877a để đếm xung ngoài đo tốc độ của một cái trục, mỗi khi cái trục quay vòng thì có 1 xung (từ mức cao xuống mức thấp).Có một vấn đề là mình phải dùng chân nào để đếm xung, và khai báo trong chương trình (mình dùng ccs) như thế nào.Vì hiện giờ mình đã sử dụng các chân T0CKI,T1CKI,các chân portb, RD5->RD7 trong mạch.Vậy ngoài các chân trên có còn cách nào đọc xung vào không, và khai báo cụ thể trong chương trình ra sao các bạn có thể chỉ giúp mình không?
|
tùy tốc độ của cái trục đó, bạn có thể dùng chân ngắt ngoài để xử lý nếu nó quá nhanh, còn nếu mà nó quay chậm, cứ dùng 1 chân I/O bất kỳ rồi rùng timer quét cũng OK.
|
bạn có thể nói cụ thể hơn quét timer là sao không? mình mới sử dụng pic nên còn gà lắm.
|
là dùng timer2(cái còn lại duy nhất mà bạn chưa dùng) sau khoảng thời gian do bạn tự tính rồi đếm số vòng quay của trục rùi suy ra tốc độ của nó.
Nếu trục quay tương đối chậm thì bạn dùng bất kỳ chân i/o nào còn lại của pic cũng được miễn là bạn set nó là input. nếu trục chạy quá nhanh thì bạn chịu khó chế cho nó 01 bộ bánh răng giảm tốc rồi từ công thức tỉ số truyền tương ứng tính ra số vòng quay của trục. |
Trích:
|
mình đã sử dụng 1 chân là input rồi.Cái trục của mình quay cũng chậm thôi (khoảng 0.5-2s/vòng).Tuy nhiên mình thử đưa vào thì số nó chạy liên tục.Nghĩa là cứ mức 1 thì nó tăng biến đếm liên tục, nếu ko có xung thì giá trị vào là 1.Trong chương trình phải viết như thế nào để khi có sự thay đổi trạng thái của chân input thì biến đếm mới tăng?mình dùng ccs để viết.Hiện giờ mình chỉ cần làm sao tính được số xung trong khoảng thời gian delta t là ổn.MÌnh sử dụng chân rc5 làm input. đoạn code mình như thế này,giá trị x sau đó xuất ra led 7 đoạn.
void docxung() { if (input(PIN_C5)==0) count=count+1; x=count; else x=count; } |
Trích:
đo tốc độ của trục nghĩa là bạn đếm liên tục số vòng quay của trục trong khoảng thời gian nhất định gọi là thời gian lấy mẩu(có chu kỳ nha bạn -->dùng ngắt timer) rồi sau khoảng thời gian đó bạn lấy số vòng quay đó chia cho thời gian mà bạn lấy mẩu sẽ ra tốc độ của trục. vd: bạn đếm liên tục ngõ vào rc5 trong khoảng 1s được 5 vòng thì tốc độ trục khi đó là 5 vòng/s. bạn nghiên cứu lại có nếu vẫn chưa thông thì cứ post lên mọi người sẽ hổ trợ bạn! |
đúng như bạn nói, bảng led tăng liên tục khi cấp nguồn, mình chỉ đang thắc mắc là dùng lệnh gì để "chốt" giá trị count khi nó quay hết 1 vòng, nghĩa là chỉ khi có sự thay đổi giá trị của chân input thì biến đếm mới tăng,mình chưa viết đoạn timer định thì sau 1 khoảng thời gian.đoạn code trên mình viết để hiển thị ra bảng led thôi chứ không phải giá trị cuối cùng mình tính ra ,nhưng nếu có giá trị đó thì có thể tính dc tốc độ.Tuy nhiên mình đang khúc mắc ở trên như đã nói đó.
|
void docxung()
{ if (input(PIN_C5)==0) // them doan nay ne ban while(input(PIN_C5)==0); // ko làm gì đến khi rc5 lên 1 /// count=count+1; x=count; else x=count; } /// nghĩa là khi đã vào trạng thái tích cực mức 0, thì chờ cho nó hết trạng thái đó rồi mới tăng biến đếm. đó là cách giải quyết vần đề bạn thắc mắc, còn đo tốc độ thì đúng như cách lequocbao nói. |
mình đã thử đoạn code trên nhưng không được bạn ơi.doạn code trên khi có chân input chuyển về 0 thì bảng led tăng liên tục.Vì trục quay chậm cho nên mỗi khi có xung xuống thì mất 1 khoảng thời gian nó mới chuyển mức(khoảng nửa giây), mà trong khoảng thời gian đó biến count tăng liên tục(vài chục giá trị) theo như code trên, như vậy là không đúng.Cái mình cần là làm sao khi thay đổi thì nó chỉ tăng lên 1 đơn vị thôi, và chờ cho tới khi tiếp tục thay đổi trạng thái .Mình chưa cần quan tâm tới chiều quay mà chỉ cần đếm được số lần thay đổi trạng thái chân input trước đã.
|
À mình đã giả quyết được rồi, đoạn code như sau
void docxung() { if (input(PIN_C5)==0) { while(input(PIN_C5)==0); // ko lam gi cho toi khi thay doi muc /// count=count+1; x=count; break; } else { x=count; break;} } vì không thoát ra khỏi vòng lặp sau khi tăng biến count, nên biến sẽ tăng liên tục. Nhân tiện hỏi các bạn luôn là mình định dùng timer0 để đếm giá trị xung vào(số vòng quay) trong vòng 10s chẳng hạn, vậy mình phải đặt đoạn code trên ở chỗ nào, và giá trị khai báo cho timer cụ thể ra sao? |
Trích:
vd: như bạn nói là pin_c5 sẽ ở mức logic 0 là khoảng 0.5s ,mà tạm tính thời gian để pic quét toàn bộ chương trình là 0.1s(vd thôi nha bạn hì hì) thì có phải là sau 0.5s biến count sẽ tăng lên 5 đơn vị (vì điều kiện để tăng biến count là pin_c5==0 vẫn thõa mãn ở 4 lần quét chưong trình còn lại)đúng không nào?trong khi bạn chỉ muốn là count chỉ tăng 1 đơn vị bạn chịu khó post toàn bộ code chương trình lên đây rùi mọi người sẽ hướng dẫn cho bạn là nên "nhét" đoạn code của bạn vào chổ nào! |
chương trình hiện tại mình kết hợp như sau
#include <16F877A.h> #priority EXT,TIMER1,timer0 #fuses NOWDT,PUT,XT,NOPROTECT,NOLVP,HS #device *=16 #use delay(clock=20000000) #use fast_io(b) #use fast_io(d) #use fast_io(c) #byte portb=0x06 #byte portd=0x08 #byte portc=0x07 #byte PORTB = 0x06 unsigned char led1,led2,led3; int16 count=0 ; int32 dem=0; int16 xung=0; int32 vantoc=0; int32 x=0; int32 timer=0; void convert_bcd(int32 x); void display(); #int_timer0 void interrupt_timer0() { set_timer0(6); { ++dem; if(dem >= 20000)// 20000*500us = 10s dem=0; {if (input(PIN_C5)==0) { while(input(PIN_C5)==0); count=count+1; xung=count; break;} else { xung=count; break;} } } vantoc=(xung/10);//tinh ra van toc (xung/giay) } //void docxung() void convert_bcd(int32 x) { led1 = x / 100; x = x %100; led2 = x / 10; led3 = x % 10; } void display() { char maled7[] = {0x7e,0x18,0xec,0xe6,0xd2,0xb6,0xbe,0x62,0xfe,0xf6 }; portb = (maled7[led3]); output_low(PIN_D5); delay_us(90); output_high(pin_D5); portb = (maled7[led2]); output_low(PIN_D6); delay_us(90); output_high(pin_D6); portb = (maled7[led1]); output_low(PIN_D7); delay_us(90); output_high(pin_D7); } //Chuong trinh chinh void main(void) { set_tris_b(0); set_tris_d(0x00); set_tris_c(0xFf);// dau vao la C7,C6,C5,C4,xung vao chan c5 enable_interrupts(int_timer0); setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); enable_interrupts(global); set_timer0(6);// T_dinhthi =delay= 2*(256 - 6)*1us = 500us //INitTIMER0=6;prescaler=2(do RTCC_div_2 while(true) { // hien thi so xung ra led 7 doan x=xung; convert_bcd(x); display(); } } chương trình như trên ý định của mình là xuất ra 3 led 7 đoạn giá trị xung đếm được sau 10s(dùng timer0 delay 10s , trong thời gian đó đếm số xung).Tuy nhiên khi nạp vào chip thì chạy không đúng, mỗi khi có xung thì nó tăng 1 giá trị, trên bảng led (3 led 7 đoạn) giá trị tăng dần chứ không đúng ý đồ.MÌnh đã thử đặt đoạn chương trình đoc xung vào nhiều chỗ nhưng chưa đúng.Mong các bạn giúp đỡ vì thời gian với mình cũng không còn nhiều. |
Trích:
+chương trình chính: -đọc liên tục chân rc5 nếu có sự thay đổi mức logic từ 1 sang 0 thì biến count tăng 1. - quét 3 led 7 đoạn với tham số truyền là x. - sau 1s thì xảy ra ngắt timer.(theo mình bạn nên kiểm tra tốc độ sau 1s or 0.5s là hợp lý hơn, do trục quay tương đối chậm nên hiển thị led 7 đoạn là vòng/s nha). +chương trình phục vụ ngắt timer:(vd sau 1s) - lấy biến x=count; - xóa biến count; -trở về chương trình chính. bạn tham khảo thử đoạn code trên mình đã sữa lại,còn nữa bạn chú ý các dấu {} nha,mình thấy bạn bỏ tứ tung hết.Còn nữa nếu không có gì đặt biệt thì bạn nên gom 2 hàm convert_bcd(x) và display() lại 1 lun cho gọn khi lập trình.khi đó bạn chỉ cần gọi hàm convert_bcd_display(x); là ok rùi. |
Cảm ơn bạn, mình đã giải quyết được vấn đề rồi.Nhưng vẫn còn một vài vấn đề nhỏ
Chương trình hoàn chỉnh như sau : #include <16F877A.h> #priority EXT,TIMER1,timer0 #fuses NOWDT,PUT,XT,NOPROTECT,NOLVP,HS #device *=16 #use delay(clock=20000000) #use fast_io(b) #use fast_io(d) #use fast_io(c) #byte portb=0x06 #byte portd=0x08 #byte portc=0x07 #byte PORTB = 0x06 unsigned char led1,led2,led3; int16 count=0 ; int32 dem=0; float vantoc; int32 x=0; void convert_bcd(int32 x); void docxung(); #int_timer0 void interrupt_timer0() { set_timer0(6); ++dem; if(dem ==18200)// 5s { dem=0; x=count; count=0; } }//ket thuc ngat timer void convert_bcd(int32 x) { led1 = x / 100; x = x %100; led2 = x / 10; led3 = x % 10; { char maled7[] = {0x7e,0x18,0xec,0xe6,0xd2,0xb6,0xbe,0x62,0xfe,0xf6 }; portb = (maled7[led3]); output_low(PIN_D5); delay_us(90); output_high(pin_D5); portb = (maled7[led2]); output_low(PIN_D6); delay_us(90); output_high(pin_D6); portb = (maled7[led1]); output_low(PIN_D7); delay_us(90); output_high(pin_D7); } } void docxung() { if(input(pin_c5)==0) { count++; while(input(pin_c5)==0) convert_bcd(x); } } void main(void) { set_tris_b(0); set_tris_d(0x00); set_tris_c(0xFf);// dau vao la C7,C6,C5,C4,xung vao chan c5 enable_interrupts(int_timer0); setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); enable_interrupts(global); set_timer0(6);// T_dinhthi =delay= 2*(256 - 6)*0.2us = 100us count=0; while(true) { docxung(); convert_bcd(x); }} Mình muốn hiển thị giá trị của vận tốc ra xung/s (hay vòng/s).Nhưng giá trị này tính ra theo thực tế phải là dạng số thực chứ không phải là số nguyên (3 led hiển thị giá trị số nguyên).MÌnh định chuyển giá trị đó sao cho nhìn trên led 7 đoạn có thể thấy được giá trị.Ví dụ 1.52 vòng/s thì hiển thị trên led là 152 chẳng hạn.Mình thêm đoạn như sau: vantoc=(count/10); x=vantoc*100; Tuy nhiên mình thấy hiển thị trên led không đúng.Không biết phải sử dụng các biến như thế nào để có được kết quả chính xác. Ngoài ra mình sử dụng công thức T_dinhthi =delay= 2*(256 - 6)*0.2us = 100us khi đó để có 10s thì giá trị của biến dem là 100000, nhưng mình thử lại thì không đúng, phải là 20000, vì mình dùng thạch anh 20mhz .Như vậy giá trị trên phải là 500us (T_dinhthi =delay= 2*(256 - 6)*1us = 500us) cho thạch anh 4mhz ?Thực tế là mình dùng đồng hồ bấm giờ tính ra như trên(viết 1 đoạn chương trình ngắn dịch led bằng timer thử nghiệm và dùng đồng hồ bấm giây kiểm tra.) Ai có thể giải thích tại sao chỉ dùm mình với . |
Độ phân giải của trục là 1xung/vòng thì làm sao mà có thể đo được phần lẽ <1 bây giờ bạn?
ý tưởng: -khi rc5==0 & flag ==0 --> enable timer & flag ==1 & time++. -khi rc5==0 again --> if (flag==1) then disable timer. { vận tốc=1/time; time=0; flag=0; } ngoài ra chỉ còn có cách là bạn tìm cách tăng độ phân giải của trục lên thì mới được. vậy bạn cho mình hỏi là con số 18200 ở trên là bạn tính như thế nào để ra đc 5s?bạn thử thay thằng ku thạch anh khác thử xem sao nha! |
Mình nói luôn cái đồ án mình đang làm, mong các bạn ai có thể chỉ giúp mình thêm vì thật sự là mình không biết hỏi ai, cứ mò mẫm làm thôi.Thầy hướng dẫn thì cũng không hỏi được nhiều mà thời gian thì cũng sắp hết.
Đồ án của mình là "tìm hiểu lý thuyết nâng bằng từ trường và đề xuất ứng dụng" Phần 1 của đồ án mình đã làm xong, đó là mình điều khiển 1 nam châm điện hút một vật "treo" lơ lửng.Để "treo " vật lơ lửng thì mình đã làm tàm tạm được rồi.Các vật treo dc này phải có gắn 1 nam châm vĩnh cữu để nam châm điện hút. Phần 2 của đồ án mình đang thực hiện đó là mình thiết kế 1 trục đo gió không có ma sát(do treo lơ lửng cái trục từ phần 1).Và mình dùng 1 mạch để đo tốc độ cái trục này Hai phần trên mình phải dùng 2 mạch khác nhau,vì mình thấy khả năng tính toán của con pic không đáp ứng nổi cho cả 2 công việc.Tuy nhiên 2 mạch này có khác nhau ở chỗ thạch anh sử dụng là 4mhz và 20 mhz(cả 2 dùng pic 16f877a). Mạch 20mhz bao gồm các port đưa ra và 3 led bảy đoạn hiển thị. Mạch thứ 2 dùng thạch anh 4mhz và có cổng com giao tiếp với máy tính. Ban đầu mình làm phần 1 trên mạch 20mhz, tuy nhiên sau đó có mình thấy nó không làm thêm được việc gì ngoài việc "treo " vật, vì nếu thêm vào nó sẽ không chính xác và mình làm trễ chương trình. Do đó mình sử dụng thêm 1 mạch thứ 2 với mục đích đọc xung và tính vận tốc.Tuy nhiên do mạch này sử dụng thạch anh 4mhz và không có hiển thị led cho nên mình hoán chuyển nhiệm vụ cho nó.Tuy nhiên khi cho nó thực hiện điều khiển " treo " vật thì nó chạy không được, mặc dù trong chương trình mình đã chỉnh sửa lại,tất nhiên phần cứng thì phải cắm các chân tương ứng như khi dùng mạch 20mz.Sai ở đây là nó đáp ứng chậm hơn mạch 20mhz cho nên không hút nhả nam châm kịp(phương pháp điều khiển hút nhả là điều khiển pwm nam châm).Như vậy cho mình hỏi: -Có cách nào cho mạch 4mhz chạy tốc độ như mạch 20mhz không? Nếu sửa lại phần cứng thì phải thay tụ bao nhiêu.(Mạch 20mhz dùng tụ 22pf , mạch 4mhz dùng tụ 33pf). -Mình kiểm tra lại,giá trị timer như mình tính trên khi dùng cho mỗi mạch là khác nhau.với giá trị 18200(mình tính chưa đúng như cũng gần con số đó, kiểm tra bằng đồng hồ bấm giây) thì mạch 4mhz delay 10s, mạch 20mhz delay 5s. cái đề tài này mình không biết ai đã làm chưa nên cũng không biết hỏi ai, tuy nhiên theo mình thì cũng áp dụng điều khiển hồi tiếp và các kiến thức điều khiển cơ bản,và mình cũng làm được ở một mức nào đó. Chỉ còn một số vấn đề như thế các bạn góp ý giúp mình với. |
phần đo tốc độ bạn tham khảo lại post #16 ,còn phần thạch anh thì mình mù tịt, chắc nhờ pác namqn giúp hộ một tay!
|
Mình vẫn chưa giả qứyt6 được chỗ đếm xung, đó là do trục quay chậm( khoảng >0.5s/vòng) nên xảy ra trường hợp là khi có tín hiệu 0 tồn tại khoảng vài trăm ms(có lẽ vậy) nên số xung đếm không đúng, vị dụ mình xuất ra led giá trị xung đếm được, thì khi có tín hiệu xung thì giá trị xuất ra rất lớn.Mình muốn viết sao cho khi giá trị xung xuống 0 thì chỉ tăng biến đếm lên 1 giá trị, nhưng vẫn chưa ổn.Mình đã dùng timer0 ở chế độ counter, timer1 định thì nhưng giá trị biến đếm vẫn tăng liên tục.
Chương trình sau mình viết để hiển thị giá trị của biến đếm của timer0 sau mỗi 5s, tuy nhiên giá trị hiển thị lớn hơn giá trị thực rất nhiều, không hiểu tại sao.Mình dùng chân RA4 để đọc xung : #include <16F877A.h> #priority EXT,TIMER1,timer0 #fuses NOWDT,PUT,XT,NOPROTECT,NOLVP,HS #device *=16 #use delay(clock=20000000) #use fast_io(b) #use fast_io(d) #byte porta=0x05 #byte portb=0x06 #byte portd=0x08 unsigned char led1,led2,led3; int16 count=0 ; int16 int_count1; int32 x=0; int32 sovong; void convert_bcd(int32 x); #define INTS_PER_SECOND1 95 //ngat sau moi 5s #int_timer0 void interrupt_timer0() { ++count; } #INT_TIMER1 // Chuong trinh ngat Timer 1 void Timer11_isr() // Ham duoc goi khi TImer1 tran (65535->0) { // Xap xi 19 lan / giay if(--int_count1==0) { int_count1 = INTS_PER_SECOND1; sovong = get_timer0(); count = 0; set_timer0(0); } } void init() { int_count1 = INTS_PER_SECOND1;//19 lan 1 giay setup_timer_0 (RTCC_DIV_1|RTCC_EXT_H_TO_L); // Timer0 is Counter set_timer0(0); set_timer1(0); setup_timer_1(T1_INTERNAL | T1_DIV_BY_4); // Timer1 is Timer enable_interrupts(INT_RTCC); enable_interrupts(INT_TIMER1); enable_interrupts(GLOBAL); count = 0; } void convert_bcd(int32 x) { led1 = x / 100; x = x %100; led2 = x / 10; led3 = x % 10; { char maled7[] = {0x7e,0x18,0xec,0xe6,0xd2,0xb6,0xbe,0x62,0xfe,0xf6 }; portb = (maled7[led3]); output_low(PIN_D5); delay_us(90); output_high(pin_D5); portb = (maled7[led2]); output_low(PIN_D6); delay_us(90); output_high(pin_D6); portb = (maled7[led1]); output_low(PIN_D7); delay_us(90); output_high(pin_D7); } } void main(void) { init(); set_tris_a(0xFf); set_tris_b(0x00); set_tris_d(0x00); // khoi tao gia tri sovong=0; while(true) { x=sovong; convert_bcd(x); }} |
TÔi nghĩ là bạn vẫn bị nhầm khá căn bản, nếu đếm ko ai lại đếm bằng mức cả mà phải đếm bằng chuyển mức (tức là đếm số lần chuyển mức) tôi giả định như sau :
#define dau_vao_truc input(pin_c5) int1 luu_trang_thai=0; int16 so_vong_quay=0; #int_timer0 void interrupt_timer0() { if(dau_vao_truc!=luu_trang_thai) { luu_trang_thai=dau_vao_tru; if(luu_trang_thai==0)so_vong_quay++; } } doan code tren se tang so dem vong quay len 1 moi khi co chuyen muc tu 1 ve 0; ban thu suy nghi them xem sao nhe. |
Múi giờ GMT. Hiện tại là 12:43 PM. |
Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam