Nếu đây là lần đầu tiên đến với Điện Tử Việt Nam, bạn có thể đọc phần Hỏi đáp bằng cách nhấn vào liên kết. Có thể bạn cần đăng kí trước khi có thể gửi bài . Để bắt đầu xem bài viết, chọn diễn đàn bạn muốn thăm dưới đây.
mong các bác giúp e đoạn code thực hiện Delay 1s viết bằng C cho 8051 sử dụng bộ định thời ... cái hàm này trong ASM thì e viết được nhưng chuyển sang C thì e ko biết...cảm ơn các bác
- Nếu chỉ dùng timer thì bạn có thể tạo được độ trễ tối đa là 65,536ms với thạch anh 12M khi giá trị nạp vào TH, TL là 0000. Muốn tạo độ trễ lớn hơn thì bạn phải sử dụng thêm vòng lặp.
nếu mình muốn dùng ngắt bởi bộ định thời Timer 0 chẳng hạn thì cụ thể sẽ như thế nào
Nếu bạn dùng ngắt timer 0 thì sau tối đa 65,536ms timer0 sẽ ngắt một lần nhắc bạn làm một việc gì đó. Thông thường để tạo thời gian delay người ta không dùng ngắt timer, nếu dùng ngắt thì sẽ không gọi là delay nữa vì bản chất của delay là thời gian giữ chậm, trong thời gian này thì vdk sẽ chỉ chờ thôi, chẳng làm được việc gì khác cả. Bạn có thể tham khảo chương trình ngắt timer sau đây:
#include <at89x51.h>
void InitSystem();
void main (void)
{
InitSystem();
while(1);//Chờ ngắt timer0
}
void InitSystem()
{
TMOD = 0x01;//Timer0
TH0 = 0x00;
TL0 = 0x00;
ET0 = 1; //Cho phép ngắt Timer0
EA = 1; //Cho phép ngắt toàn cục
TR0 = 1;//Cho Timer0 chạy, đợi tràn
}
void Timer0Interrupt (void) interrupt TF0_VECTOR
{
TR0 = 0;//Dung Timer0
TH0 = 0x00;
TL0 = 0x00;
TR0 = 1;//Tiếp tục cho chạy
//Làm gì thì làm ở đây
}
cám ơn bạn Toan.Lv nhưng mà mình thắc mắc cái này, theo như bạn nói nhé:
nếu dùng ngắt thì sẽ không gọi là delay nữa vì bản chất của delay là thời gian giữ chậm, trong thời gian này thì vdk sẽ chỉ chờ thôi, chẳng làm được việc gì khác cả
...
Nhưng mà theo mình thấy thì kể cả khi dùng ngắt,trong cái bài toán Delay1s này thì lúc chờ ngắt Timer0 thì VĐK cũng chỉ chờ cho cờ TF được set thì cho phét ngắt thôi mà nhỉ ( cái vòng lặp vô tận While(1) {} ấy ) ...và như vậy mình đang thắc mắc là viết hàm delay sử dụng Timer đơn thuần như bạn Angort thì có khác j sử dụng ngắt của Timer...Mong bạn jải đáp hộ mình ..rất cảm ơn bạn
Việc sử dụng timer để tạo hàm delay đơn thuần so với việc sử dụng ngắt có sự khác nhau rất lớn mà rõ ràng và quan trọng nhất là việc phân quyền sử dụng tài nguyên CPU. Tôi có thể lấy một ví dụ đơn giản để bạn hình dung. Giả sử CPU của VDK là bạn, còn timer0 là cái đồng hồ đeo tay của bạn thế thì:
- Đối với hàm delay bình thường dùng timer:Giả sử bạn muốn chờ từ 2h đến 3h để làm một việc gì đó. bạn phải ngồi và nhìn kim đồng hồ quay. Bạn luôn luôn phải theo dõi cái kim đồng hồ mà không được phép làm bất kì điều gì khác ngoài việc đó. Tuy nhiên từ 2h đến 3h bạn còn rất nhiều kế hoạch cần làm, trong khi lại cứ phải ngồi chờ một cách vô vị, như thế thật là nhàm chán và lãng phí thời gian. Giải pháp cho bạn là hãy sử dụng chế độ hẹn giờ
- Dùng ngắt timer tương tự như việc bạn đặt hẹn giờ. Thay vì ngồi chờ từ 2h đến 3h bạn hãy đặt hẹn giờ, cứ sau bao nhiêu lâu thì cái đồng hồ nó lại nhắc bạn một lần để bạn biết đến lúc phải làm điều gì đó. Còn khi nó không nhắc thì bạn cứ làm việc của mình. Như vậy thì bạn vừa có thể làm được rất nhiều việc, vừa không quên việc cần làm.
Trong ví dụ ở bài trước, tôi chỉ viết mẫu cái hàm cho phép và phục vụ ngắt timer thôi, còn ở chương trình chính thì muốn làm gì thì làm, không làm thì ngồi chờ. Nhưng sự khác nhau cơ bản giữa delay và ngắt có thể thấy trong ví dụ vừa nêu. Mong có thể giúp ích cho bạn đôi điều.
cám ơn bạn Toan...đọc bài giải thích của bạn mình thấy rất hay và dễ hiểu... rất mong được các bạn giúp đỡ nhiều hơn vì mình hiện đang bắt đầu tìm hiểu về lĩnh vực này
mình trình bày 2 điểm theo như mình hiểu hiện tại sau đây : đối với hàm Delay Thứ nhất:
Trong hàm main, sau khi ta gọi hàm khởi tạo initSystem()
void main (void)
{
InitSystem();
while(1);//Chờ ngắt timer0
}
sau đó mình có thể làm những việc mình muốn chứ ko chỉ đơn jản là ngồi chờ ngắt Timer0...có thể thực hiện các lệnh khác, gọi các hàm khác .... Nhưng đúng sau một khoảng thời gian mà mình đã định trước ( bằng cách thiết lập TH0 và TL0 , giả sử ở đây là 1 giây đi ) , tức là cứ sau 1 giây( mình biết là 1s thì fải sử dụng thêm vòng lặp rồi nhưu mà để đơn giản chúng ta cứ giả sử như thế đi) , hay 1 triệu chu kì lệnh thì chưong trình chính sẽ lại chuyển sang chương trình con phục vụ ngắt Timer0Interrupt sau khi thực hiện ISR lại quay về main() ...sau 1 triệu chu kì lệnh lại cho fép ngắt.....cứ thế cứ thế ....
Thứ hai:
Trong ISR, mình thắc mắc điểm này
void Timer0Interrupt (void) interrupt TF0_VECTOR
{
TR0 = 0;//Dung Timer0
TH0 = 0x??;// cái này tự mình tính toán hoặc sủ dụng thêm vòng lặp để
TL0 = 0x??;// tạo khoảg thời gian trễ là 1s
TR0 = 1;//Tiếp tục cho chạy //Làm gì thì làm ở đây
}
Mình nghĩ là nếu để những lệnh "Làm gì thì làm ở đây" sau lệnh TR0=1 thì kể từ thời điểm set TR0=1 và thựuc hiện tiếp 1 số lệnh ( giả sử tổng số chu kì lệnh là 100 thì Timer sẽ hoạt động và sau khi ra khỏi chương trình con phục vụ ngắt , chỉ sau (1 triệu - 100) = 999900 chu kì lệnh tức là 0.9999s thì chưong trình chính sẽ lại cho fép ngắt Timer0 ....Tất nhiên sai số không đáng kể nhưng mình vẫn muốn biết rõ cơ chế của nó Mong bạn jải đáp hộ mình
mình biết là 1s thì fải sử dụng thêm vòng lặp rồi nhưu mà để đơn giản chúng ta cứ giả sử như thế đi
- Có một điểm bạn lưu ý là tổng độ dài của 2 thanh ghi TH0 và TL0 cũng chỉ là 16 bit, do đó timer0 chỉ có thể đếm được tối đa 65536 lần (tương ứng khoảng 65,536ms nếu thạch anh 12M)là chắc chắn sẽ tràn. Khi tràn thì chắc chắn cờ TF0 sẽ được bật lên. Nếu được cho phép ngắt thì chắc chắn lúc này ngắt tràn timer0 sẽ xảy ra. Như vậy nếu sử dụng timer0 thì chậm nhất là cứ sau 65,536ms CPU sẽ bị ngắt một lần--->Bạn không thể sử dụng vòng lặp kéo dài thời gian gây ngắt để sau 1s mới ngắt một lần. Tuy nhiên việc timer0 ngắt và việc bạn xử lý công việc cần thiết không nhất thiết phải tương ứng tỉ lệ 1-1. Bạn hoàn toàn có thể lập trình để cứ sau 10 lần ngắt (hoặc bao nhiêu đấy là tuỳ) bạn mới thực hiện một công việc nào đó. Còn các lần ngắt khác thì bạn lờ đi không làm gì cả.
Mình nghĩ là nếu để những lệnh "Làm gì thì làm ở đây" sau lệnh TR0=1 thì kể từ thời điểm set TR0=1 và thựuc hiện tiếp 1 số lệnh ( giả sử tổng số chu kì lệnh là 100 thì Timer sẽ hoạt động và sau khi ra khỏi chương trình con phục vụ ngắt , chỉ sau (1 triệu - 100) = 999900 chu kì lệnh tức là 0.9999s thì chưong trình chính sẽ lại cho fép ngắt Timer0 ....Tất nhiên sai số không đáng kể nhưng mình vẫn muốn biết rõ cơ chế của nó Mong bạn jải đáp hộ mình
- Trong chương trình phục vụ ngắt, CPU thực hiện các tác vụ sau:
+ Dừng timer (TR0 = 0) hết 1 chu kỳ máy
+ Nạp lại giá trị cho TH (TH0 = 0x00) hết 1 chu kỳ máy
+ Nạp lại giá trị cho TL (TL0 = 0x00) hết 1 chu kỳ máy
+ Cho phép timer0 tiếp tục đếm (TR0 = 1) hết 1 chu kỳ máy
Sau lệnh này thì timer lại bắt đầu thực hiện chu kỳ buồn bã của nó là đếm và đếm. Nó chỉ dừng lại trong 4 chu kỳ máy để CPU nạp lại các giá trị cần thiết cho TH và TL mà thôi.
+ Các lệnh thuộc vùng (//làm gì thì làm ở đây) không hề liên quan gì đến timer, đó là tác vụ của CPU vì thế thời gian thực hiện của các lệnh này không ảnh hưởng đến thời gian ngắt của timer. Tuy nhiên timer sẽ lại tiếp tục ngắt sau đúng thời gian quy định. Nếu như thời gian xử lý các tác vụ trong ngắt trước chưa xong thì sẽ xảy ra trường hợp ngắt trong ngắt. Vì thế các tác vụ xử lý trong ngắt người ta cố gắng để xử lý càng nhanh càng tốt. Nếu các việc cần làm quá dài, thì trong ngắt có thể bật một cờ để đánh dấu việc cần làm sau đó trở về chương trình chính để thực hiện việc đó.
Mình đã thử trên Proteus hàm Delay này và kết quả là khoảng thời jan trễ nhỏ hơn 1s bạn à...Led nhấp nháy liên tục .....còn khi mình set TH = 3CB0 (-50000) rồi dùng cơ chế ngắt như sau đây
//*********các chuong trình phuc vu ngat*********
void chuongtrinh_timer0 (void) interrupt 1 // so hieu ngat cua timer 0 la 1
{
count++;
while (count <= 20)
{
TR0=0;
TH0=0x3C;
TL0=0xB0;
if (count =20)
{
P2_0=~P2_0;
count = 0;
}
TR0=1;
}
}
thì khoảng thời gian trễ lại quá lớn hơn so với một giây, cỡ fải 7 8 s
thế là có sự khác nhau jữa khoảng thời jan lý thuyết 1s và thực tế...vậy đâu là nguyên nhân hả bạn??? Do Proteus hay do mình đã sai ở chỗ nào trong chương trình ... hay là fải nạp thử vào mạch thật thì mới chính xác và tại sao lại có sự khác nhau jữa Delay dùng Timer đơn thuần và Delay dùng ngắt cho timer ( với cùng já trị của TH0 và TL0 là 3CB0H)
chương trình chính đây
void main()
{
P2_0=1;
timer0_init(); // neu dung Delay bang Timer don thuan thi bo lenh nay di
Chắc do bạn có thể chưa khai báo timer0 trong đoạn chương trình của mình, mình đã thử lại thì nó đúng 1s, bạn thử lại xem nhé.
Đây là chương trình:
#include <at89x52.h>
Chắc do bạn có thể chưa khai báo timer0 trong đoạn chương trình của mình, mình đã thử lại thì nó đúng 1s, bạn thử lại xem nhé.
Đây là chương trình:
#include <at89x52.h>
void delay(unsigned char t){
unsigned char i;
for(i=0;i<t;i++){ TR0=0; // Dừng bộ định thời
TH0=0x3c; //-50000 us
TL0=0xb0;
TR0=1;
while(!TF0); //cho timer0 tràn
TF0=TR0=0;
Các bạn cho mình hỏi: Dòng chữ màu đỏ mình mới thêm trong chương trình trên là cần thiết hay không cần ?
Theo mình nghĩ là khi đó chưa khởi động bộ định thời nên không cần.
Cám ơn các bạn !
Last edited by Multi System; 07-05-2009, 16:21.
Lý do: thêm bớt chút ít
Uống rượu 1 mình, thấy trang này nhớ lại cách đây vài chục năm hàn thiếc với inox cực kỳ khó, phải dùng acid Hcl tác dụng lên kẻm Zn để có Zncl2 làm thuốc trợ hàn, lúc đó làm gì có acid Hcl và thuốc trợ hàn?
À, sản phẩm họ thiết kế ra, họ yêu cầu mình chứng minh là sau chỉnh sửa thì 1 là gỡ jump cắm lại không hư mạch, 2 là gỡ jump thì 220Vdc vẫn dùng được led áp thấp 20V mà không hư led như mình báo, nên họ hiểu rõ mà....
Bài học kiểu trực tuyến dù là loại đơn giản bậc nhất cũng vẫn cần chú tâm. Chỉ bật tai nghe lên thì không có loại nào thấm nổi đâu. Cách hay hơn, dễ hơn là kiếm phim tiếng Anh nào đó xem, ban đầu bật phụ đề tiếng Việt, nghe và...
Comment