Thông báo

Collapse
No announcement yet.

Tạo trễ dùng C

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

  • Tạo trễ dùng C

    Đáng lẽ ra tôi phải giới thiệu cho các bạn các header file trước nhưng tôi quên mang theo mong các bạn thông cảm. Tôi xin giới thiệu dùng delay trước đã.

    Có lẽ việc lập trình cho vi điều khiển một hàm không thể thiếu đó là trễ: như trễ khi bạn nháy led chẳng hạn( ví dụ đơn giản nhất), ...

    Việc gây trễ trong Keil C có thể có nhiều cách khác nhau:

    Hàm delay có tham số là thời gian cần gây trễ tính theo ms

    1/Dùng vòng lặp while, for

    dùng kiểu nào thì cũng đơn giản chỉ là vòng lặp mà thôi. Trong vòng lặp này chúng ta sẽ chẳng làm gì cả nên vi điều khiển sẽ bị mất thời gian trong các vòng lặp này.

    Với tần số thạch anh 11.0582 MHz thì mỗi vòng lặp khi các bạn debug sẽ thấy là chúng ta mất thời gian thực khoảng 8.28 us. Do đó để có thể gây trễ 1ms thì các bạn cần dùng xấp xỉ 121 vòng lặp kiểu này.

    Do đó hàm sẽ như sau:

    Code:
    void delay(usigned char time){
        while(time--){
               unsigned char temp = 121;
               while(temp--); // chẳng làm gì cả
        };
    }
    Việc chuyển đổi giữa vòng for với while trong trường hợp này rất đơn giản thôi. Nhưng khi đó bạn lại phải khai báo thêm một biến đếm như thế sẽ tốn bộ nhớ. Chương trình trên là tối ưu nhất rồi.

    2/Dùng timer0,timer1,..

    Cái này tôi xin phân tích sau cùng với việc giới thiệu các #include. Để có thể hệ thống hết được. Cho nó có logic. Chứ nếu tôi đưa ra luôn các bạn mới học sẽ không hiểu là nó ở đâu ra.
    Last edited by ngohaibac; 11-01-2006, 16:35.
    Technical sale at WT Microelectronics S'pore
    Hỗ trợ dự án sử dụng các hãng Texas Instrument, STMicro, Freescale, Fairchild, International Rectifier, Ublox, Lumiled, Maxim
    Liên hệ: 0915.560.511 hoặc ngo.haibac@wtmec.com

  • #2
    Delay (tiếp)

    Tiếp tục với hàm delay() theo cách dùng bộ định thời.

    Các bạn đọc bài ở trên cũng thấy được là chúng ta lập trình với các thanh ghi tương tự như trong ASM mà thôi.

    TMOD là thanh ghi 8 bít dùng để thiết lập bộ định thời , các bạn xem lại thanh ghi này.

    Dùng bộ định thời có 3 chế độ: chế độ 0, chế độ 1, chế độ 2. Chúng ta sẽ sử dụng chế độ khởi động bộ định thời bằng phần mềm tức TMOD.3 và TMOD.7 =0
    Việc xác định chế độ nào phụ thuộc vào giá trị của 2 bit TM1 và TM0 của từng timer( các bạn xem định nghĩa từng bít trong thanh ghi TMOD)

    TM1=0 , TM0 =0 chế độ 0
    TM1=0, TM0 =1 chế độ 1
    TM1=1, TM0 =1 chế độ 2

    Chế độ 1 là chế độ 16 bít không tự nạp lại, cách sử dụng bằng cách nạp giá trị cho các thanh ghi TH1,TL1( với Timer1), hoặc TL0,TH0( với Timer0). Khi khởi động timer bằng cách setb TR1 hoặc TR0 thì nó sẽ đếm từTHTL -> 0xFFFF khi từ 0xFFFF->0x0000 thì cờ TF1 hoặc TF0 sẽ bật lên sau đó chúng bị xóa thành 0. Chúng ta dùng cờ này để biết khi nào chuyển qua 0x0000.

    Chế độ 0 là chế độ 13 bít tương tự như chế độ 0 nhưng giá trị chỉ tăng đến 0x1FFF.

    Chế độ 2, chế độ 8 bít tự nạp lại, chỉ cần thiết lập cho chế

    Tiếp theo là chúng ta tính thời gian của mỗi lần tăng bộ định thời. Tấn số của bộ định thời bằng 1/12 tần số của thạch anh, do đó với tần số 11,0592MHz thì chu kì máy bằng 1.085us.

    Do vậy với chế độ 1 tối đa chúng ta sẽ gây trễ được là 65536*1.085 = 71106.56 us = 71.10656 ms.

    Chế độ 2 max = 256 *1.085 =277.76 us

    Chế độ 0 bạn tự tính.

    Từ đó bạn tính toán nha. Chúng ta muốn trễ nhiều thì chúng ta thêm vòng lặp vào.

    ---------------------------
    Tôi chỉ cần gây trễ 1ms = 1000 us>277.76 nên dùng timer0( 16 bit) ở chế độ 0 thì bạn tính toán giá trị nạp cho timer0 như sau:

    thời gian trễ = (65536 - giá trị nạp vào TH,TL+ 1) * 1.085.

    Sau đó đổi giá trị ra số hex. Các bạn dùng Calculator của windows để đổi.

    => TH0 = FC, TL0 = 67

    Vậy chương trình sẽ như sau:
    Code:
    void delay(unsigned char time){
    
    while(time--){
        TMOD = 0x01; // dùng timer0 ở chế độ 1( 16 bit)
        TH0 = 0xFC;// nạp giá trị cho timer
        TL0 = 0x67;
        TR0 = 1; // khởi động bộ định thời
        while( TF0); // chờ khi nào cờ TF1 =1
        TF0 = 0 ; // xóa cờ tràn
        TR0 = 0; // dừng bộ định thời
    };
    }
    Các bạn thấy thế nào, rất là đơn giản đúng không

    Chúc thành công.
    Last edited by ngohaibac; 10-01-2006, 10:44.
    Technical sale at WT Microelectronics S'pore
    Hỗ trợ dự án sử dụng các hãng Texas Instrument, STMicro, Freescale, Fairchild, International Rectifier, Ublox, Lumiled, Maxim
    Liên hệ: 0915.560.511 hoặc ngo.haibac@wtmec.com

    Comment


    • #3
      Hình như viết thế này đúng hơn?

      void delay(unsigned char time){
      while(time--){
      TR0=0; //Dừng bộ định thời
      AH0 = 0xFC;// nạp giá trị cho timer
      AL0 = 0x66;
      TR0 = 1; // Chạy bộ định thời
      TF = 0;//Xóa cờ tràn lần trước
      while( TF0); // chờ khi nào cờ TF0 =1
      };
      }

      Comment


      • #4
        while(time--){
        AL0 = 0x66;
        AH0 = 0xFC;// nạp giá trị cho timer
        TF = 0;//Xóa cờ tràn lần trước
        while( TF0); // chờ khi nào cờ TF0 =1
        };
        Last edited by qmk; 09-01-2006, 17:35.
        Vẫn biết mỗi lần xa là một lần về lại...

        Comment


        • #5
          Nguyên văn bởi qmk
          while(time--){
          AL0 = 0x66;
          AH0 = 0xFC;// nạp giá trị cho timer
          TF = 0;//Xóa cờ tràn lần trước
          while( TF0); // chờ khi nào cờ TF0 =1
          };
          Anh qmk ơi.

          Anh không khởi động TR0 thì sao mà chờ TF0 đến bao giờ.

          Cờ TF0 khi bị lên 1 sẽ tự động xóa đi mà. Không giống cờ TI và RI phải xóa bằng phần mềm. cần gì phải xóa cờ này khi mà ta chưa dùng đến bộ định thời lần nào. Với lại ở vòng lặp tiếp theo thì TF0 đã tự bị xóa rồi.

          Bạn thaithutrang cũng như thế. Viết như thế là thừa. Vì bộ định thời 0 , mode 0(16 bit không tự nạp lại)sẽ tự động dừng sau khi đếm đến 0 và cờ sẽ tự xóa. Hoàn toàn không giống mode 1( 8 bit autoreload- tự nạp lại)


          Hình như viết thế này đúng hơn?
          void delay(unsigned char time){
          while(time--){
          TR0=0; //Dừng bộ định thời // thừa
          AH0 = 0xFC;// nạp giá trị cho timer
          AL0 = 0x66;
          TR0 = 1; // Chạy bộ định thời
          TF = 0;//Xóa cờ tràn lần trước // thừa
          while( TF0); // chờ khi nào cờ TF0 =1
          };
          }
          Chúc thành công.
          Technical sale at WT Microelectronics S'pore
          Hỗ trợ dự án sử dụng các hãng Texas Instrument, STMicro, Freescale, Fairchild, International Rectifier, Ublox, Lumiled, Maxim
          Liên hệ: 0915.560.511 hoặc ngo.haibac@wtmec.com

          Comment


          • #6
            Lâu lắm không làm cái này nhưng có một số điểm lưu ý :
            1) Chỉ thấy có TH0 = 0 x XX ;
            TL0 = 0x XX ; chứ không có câu lệnh : AH0 và AL0.
            2) Nên viết trong 16 bit timer ( không nạp lại ) vì 16 bit này gồm gần như cả mấy cái trường hợp khác.
            ---
            Về timer thì đã có chủ đề nói về Timer / Counter của ATYLA khi ngày đầu diễn đàn được thành lập.
            // Xin viết lại :
            void trethoigian_50ms()
            { TH0 =0x3C;
            TL0=0xAF;
            TR0 =1; // cho nó chạy timer ( không chạy thì không biết đến khi nào tràn )
            while (!TF0 ); Kiểm tra cờ tràn (1 lần )
            TF0 =0 ; // xóa cờ tràn
            TR0 =0 ; // dừng bộ định thời ( nếu thấy cần thiết ).

            --- Ngắt xảy ra do có điều kiện ngắt . các ngắt hoạt động không phụ thuộc vào chương chính đang thực thi. ( tức là không biết bị ngắt thế nào ).
            Module RF chuyên dụng điều khiển, truyền dữ liệu, thiết kế đề tài, dự án điện tử - chuyển giao công nghệ... ĐT: 0904964977 - email: dientuqueduong@yahoo.com

            Comment


            • #7
              một mẫu nguồn trễ ( lớn hơn 50ms):

              void delay(unsigned char i )
              { unsigned char j =0;
              for(;j<i;j++)
              {
              TMOD = 0x01 ; // chế độ 16 bit
              TH0 = 0x3C; //
              TL0=0xAF ;
              TR0=1 ; // khởi động
              while(!TF0);
              TF0 =0; // xóa tràn
              TR0 =0 ; // Dừng bộ định thời
              }}

              /*------------------------ Led nhấp nháy -----------------*/
              void main()
              {
              while(1) // lặp vô hạn
              {
              P1_0 = 0;
              delay(100);
              P1_0 =1;
              delay(100);
              } // kết thúc while
              } // kết thúc main

              /*------- Đơn giản phải không nào ----------*/
              Module RF chuyên dụng điều khiển, truyền dữ liệu, thiết kế đề tài, dự án điện tử - chuyển giao công nghệ... ĐT: 0904964977 - email: dientuqueduong@yahoo.com

              Comment


              • #8
                Hi hi... được thảo luận với mod box "8051" rồi. Em chưa hiểu em sai chỗ nào? anh DP đọc kỹ bài em tý.
                Em post lại bài của nhé:

                void delay(unsigned char time){
                while(time--){
                TR0=0; //Dừng bộ định thời // thừa
                AH0 = 0xFC;// nạp giá trị cho timer
                AL0 = 0x66;
                TR0 = 1; // Chạy bộ định thời
                TF = 0;//Xóa cờ tràn lần trước // thừa
                while( TF0); // chờ khi nào cờ TF0 =1
                };
                }
                Dòng đậm là ý bạn NHB bảo thừa vì cờ TF0 tự động xóa. Còn mình nói là mình đúng, nó ko tự động xóa (vì nó tự động xóa nếu vào ngắt của nó,tất nhiên việc ETx=1,rồi EA=1...là những cái tối thiểu nói ra mất hay)
                Chú ý: đây là hàm bình thường chứ ko phải ngắt đâu nhé.

                Comment


                • #9
                  while(time--){
                  AL0 = 0x66;
                  AH0 = 0xFC;// nạp giá trị cho timer
                  TF = 0;//Xóa cờ tràn lần trước
                  while( TF0); // chờ khi nào cờ TF0 =1
                  };

                  Cái này là viết delay bằng timer. Đã dùng delay thì ngắt không enable. Không enable ngắt thì phải tự xóa TF.
                  Đương nhiên là timer phải đang chạy. Chứ nó không chạy thì nói làm gì. Đầu tiền vào chương trình cứ cho timer chạy. Muốn chạy thế nào thì chạy có ảnh hưởng gì đâu (tốn nguồn ????) Lúc nào muốn delay.
                  Như Trang nói là trường hợp này dùng được nhưng trường hợp khác thì không. Quan trọng mình hiểu cái gì mình viết.
                  Em Trang nói đúng đó không vào ngắt thì nó không tự xóa cờ mà đã dùng ngắt thì chẳng ai chơi delay kiểu này cả.
                  Vẫn biết mỗi lần xa là một lần về lại...

                  Comment


                  • #10
                    Than thở!!!

                    Có tới 2-3 anh đều bảo em sai, vậy do đâu? có lẽ chưa chuẩn hóa được ngôn ngữ,hay một lý do "thấy tên con gái" nên ko đọc kỹ vội phán xét.
                    Chuẩn hóa theo cách của em về 8951:

                    -Cờ cho phép ngắt toàn cục: EA
                    -Cờ cho phép ngắt: timer1 thì ET1,Timer0 thì ET0...
                    -Cờ ngắt: Timer1: TF1,Timer0: TF0...
                    Ngắt xảy ra khi,ví dụ Timer1: EA=1 and ET1=1 and ET1=1

                    Vào một số ngắt tự động xóa =0
                    Nếu ko dùng ngắt thì nó sẽ ko tự động xóa,nên mình phải xóa bằng tay.

                    Ví dụ:chương trình phục vụ ngắt cho timer1 cho 89.
                    Ngat_T1: CLR TR1 ;Dung bo dinh thoi 1
                    MOV TH1,#xxH ;Nap gia tri cho bo dinh thoi
                    MOV TL1,#xxH
                    SETB TR1 ;Chay bo dinh thoi 1
                    //Xu ly ....
                    RETI

                    Comment


                    • #11
                      Bạn Trang nói đúng rồi ,cái chương trình delay trên là dùng theo kĩ thuật hỏi vòng ko
                      dùng ngắt , không xóa cái TF0=0 thì vòng lặp sau làm sao mà đếm được .
                      còn lệnh TR0=0 thì nên có để dừng timer để ct nạp lại thanh ghi định thời
                      SHARE KHO PHIM LỚN

                      Comment


                      • #12
                        Tuyệt quá, mấy bác giảng về delay dùng timer rất là hay, tôi hiểu thêm được nhiều điều, vậy mà trước giờ cứ delay đại, o biết là bao nhiêu.
                        À, tu mới nảy ra 1 ý, o biết thực hiện được o? Ta có thể viết hàm delay (time) vơi giá trị thời gian tùy ý bất chấp tần số thạch anh. Chẳng hạn:
                        void Hdelay (unsigned long fxtal, unsigned int time)
                        {
                        //////////
                        }
                        Mời các cao thủ thử xem!
                        !e

                        Comment


                        • #13
                          Hic đến bao giờ tôi mới được xứng đáng với hai chữ "cao thủ " đây?

                          Nhưng không sao tôi biết gì nói đó vậy.

                          Cái này là không thể thực hiện nếu bạn không biết tần số thạch anh. Vì thời gian trễ phụ thuộc vào tần số của nguồn tạo xung giao động.

                          Một vi điều khiển khi ta lập trình thì tần số thạch anh là cố định. Thế bạn định lúc thì dùng thạch anh tần số này, lúc thì dùng tấn số khác à? Không nên thay đổi tần số thạch anh.

                          Còn hàm của tôi đưa ra với tham số là số mili giây cần trễ thì thoải mái còn gì chứ bạn. Nếu cần thời gian trễ quá lớn cỡ 1 giò, 1 ngày thì bạn cho thêm vòng lặp vào đó là ổn mà. Mà có ai lại gây trễ lớn thế cơ chứ.

                          chúc thành công.
                          Technical sale at WT Microelectronics S'pore
                          Hỗ trợ dự án sử dụng các hãng Texas Instrument, STMicro, Freescale, Fairchild, International Rectifier, Ublox, Lumiled, Maxim
                          Liên hệ: 0915.560.511 hoặc ngo.haibac@wtmec.com

                          Comment


                          • #14
                            [QUOTE=ngohaibac]Hic đến bao giờ tôi mới được xứng đáng với hai chữ "cao thủ " đây?

                            Nhưng không sao tôi biết gì nói đó vậy.

                            Cái này là không thể thực hiện nếu bạn không biết tần số thạch anh. Vì thời gian trễ phụ thuộc vào tần số của nguồn tạo xung giao động.

                            Một vi điều khiển khi ta lập trình thì tần số thạch anh là cố định. Thế bạn định lúc thì dùng thạch anh tần số này, lúc thì dùng tấn số khác à? Không nên thay đổi tần số thạch anh.

                            Còn hàm của tôi đưa ra với tham số là số mili giây cần trễ thì thoải mái còn gì chứ bạn. Nếu cần thời gian trễ quá lớn cỡ 1 giò, 1 ngày thì bạn cho thêm vòng lặp vào đó là ổn mà. Mà có ai lại gây trễ lớn thế cơ chứ.

                            .................................................. ....
                            À, ý của tu là vầy: ta tạo 1 hàm truyền tham số là tần số thạch anh và thời gian delay:
                            void delay( unsigned long fxtal, unsigned int time)
                            {
                            //tính toán giá tri cho tl0, th0
                            }
                            Sau đó lưu thành file thư viện: Tdelay.h
                            Rối sau này trong chương trình khác, ta khai báo thư viện

                            #include Tdelay.h

                            void main (void)
                            {
                            delay(11059200, 20);// gọi hàm delay 20ms vơi tần số thạch anh là 11,0592 MHz
                            ....................
                            }

                            Các huynh thấy thế nào? Liệu có được không?
                            !e

                            Comment


                            • #15
                              Hi! mình là lính mới. Xin hỏi các bác về con C8051F120 của SILABS. Ai biết xin chỉ dùm, Thanks!!

                              Comment

                              Về tác giả

                              Collapse

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

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

                              Collapse

                              Đang tải...
                              X