Thông báo

Collapse
No announcement yet.

hỏi về hàm Delay 1s viết bằng C cho 8051

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • hỏi về hàm Delay 1s viết bằng C cho 8051

    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
    |

  • #2
    void delay() {
    for(i=0;i<20;i++) { //50000 x 20 = 1s
    TH0=0x3c; //-50000 us
    TL0=0xb0;
    TR0=1;
    while(!TF0); //cho timer0 tràn
    TF0=TR0=0;
    }
    }

    Comment


    • #3
      1s đây sao ? Nếu muốn delay 2s thì sao nhỉ ?
      Nhớ khai báo biến i nếu không nó báo lỗi.
      Last edited by Multi System; 02-05-2009, 01:27.

      Comment


      • #4
        cảm ơn bạn angort..nhưng 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
        |

        Comment


        • #5
          - 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
          }
          Thân mến,
          For a better world

          Comment


          • #6
            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
            |

            Comment


            • #7
              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.

              Thân mến,
              For a better world

              Comment


              • #8
                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
                |

                Comment


                • #9
                  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
                  |

                  Comment


                  • #10
                    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 đó.

                    Thân mến,
                    For a better world

                    Comment


                    • #11
                      Xin lỗi đã cắt ngang đoạn trao đổi của 2 bạn, cũng là delay các bạn có thể giải thích cơ chế của hàm này giúp mình với, mình mới tập làm quen.
                      void delay (unsigned int ms)
                      {
                      unsigned char i;
                      while(ms)
                      {
                      i = 200;
                      while (i--);
                      ms--;
                      }
                      }
                      Ý nghĩa của từng câu lệnh, và ứng với câu lệnh đó thì CPU xử lí thế nào?
                      Cám ơn các bạn !

                      Comment


                      • #12
                        cám ơn bạn Toan.Lv đã jải đáp cho mình những thắc mắc chắc còn phải nhờ ae nhiều
                        |

                        Comment


                        • #13
                          #2
                          void delay() {
                          for(i=0;i<20;i++) { //50000 x 20 = 1s
                          TH0=0x3c; //-50000 us
                          TL0=0xb0;
                          TR0=1;
                          while(!TF0); //cho timer0 tràn
                          TF0=TR0=0;
                          }
                          }
                          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
                          void timer0_init()
                          {
                          TMOD|=0x01;
                          ET0=1;
                          EA=1;
                          TR0=1;
                          TH0=0x3C; // 3CB0 tuong duong voi -50000
                          TL0=0xB0; //

                          }


                          //*********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

                          while (1)
                          {
                          //delay();
                          //P2_0=~P2_0;


                          }
                          }
                          |

                          Comment


                          • #14
                            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++){
                            TH0=0x3c; //-50000 us
                            TL0=0xb0;
                            TR0=1;
                            while(!TF0); //cho timer0 tràn
                            TF0=TR0=0;

                            }
                            }

                            void main(void){
                            TMOD=0x01;

                            while(1){
                            delay(20);
                            P1_0=1;
                            delay(20);
                            P1_0=0;
                            }
                            }

                            Comment


                            • #15
                              Nguyên văn bởi agnort Xem bài viết
                              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;

                              }
                              }

                              void main(void){
                              TMOD=0x01;

                              while(1){
                              delay(20);
                              P1_0=1;
                              delay(20);
                              P1_0=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

                              Comment

                              Về tác giả

                              Collapse

                              machithanh Tìm hiểu thêm về machithanh

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X