Thông báo

Collapse
No announcement yet.

[Need Help] Hàm delay dùng timer() ko hoạt động!!

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

  • [Need Help] Hàm delay dùng timer() ko hoạt động!!

    Em cần viết hàm delay chính xác. Đọc bên luồng 8051 có đoạn code:
    //-----------------------------------------
    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;
    }
    }
    //---------------------------------------------
    em hiểu ý tưởng như sau: nếu làm trên avr
    cho vào vòng lặp for n lần:
    {
    giá trị định trước của thanh TCNT0=0x..;
    cho timer chạy
    kiểm tra cờ ngắt TOV0 trên thanh TIFR: nếu ==0 tiếp tục, ==1 <được bật> thoát
    xóa TOV0=0.
    }
    cụ thể em làm thế này:
    //--------------------------------------------------
    void delay_100us(int x) // x là giá trị nhân với 100us
    {
    int i;


    for(i=0;i<x;i++)
    {
    TCCR0=0x02; // prescale= clk/8
    TCNT0=0x9B; // innitial =155
    TIMSK=(1<<TOIE0); //enables timer interrupts0
    while(TIFR=0x00) continue;
    TIMSK=0x00; TIFR=0x00; // kiểm tra cờ ngắt timer0 TOV0 trong thanh TIFR
    }
    }
    ngoài ra còn có trình phục vụ ngắt tràn đẻ set lại TCNT0 sau mỗi lần tràn:
    ISR(TIMER1_OVF_vect)
    {

    TCNT0=0x9B;
    TIFR=0x00;
    }
    em đã set bit cho phép ngắt toàn cục trong hàm main() // sei();
    để TIMSK ở hàm main hay trong void delay_100us() thì kết quả vẫn vậy.
    //--------------------------------------------------
    Nhưng kết quả vẫn hàm delay vẫn ko hoạt đôgj
    Em đoán lý do sau nhưng chưa biết khắc phục:
    - dao động chọn cho đoạn trong hàm void delay_100us cần chọn là dao động nội, (em dùng d dộng thạch anh/8). Nhưng ko biết set thế nào, đọc trong datasheet là set fuse, nhưng ko biết set fuse CKSEL trong avrstudio liệu có ổn ko; set xong chíp có thể chạy ở mode thạch anh ngoài 8Mhz lại như ban đầu ko.
    Em đã đọc 2 luồng về fuse cho avr, nhưng từ trước tới giờ cứ cắm thạch anh vào xong là nạp code để học mấy bài tập nhỏ nhỏ luôn, chưa bao giờ em động đến fuse (đọc datasheet thì cũng hiểu sơ sơ và CKSEL). Khi dùng avrstudio thi e chọn dao động thạch anh từ :menu Project \ Config Options \ điền frequency là 8Mhz (ở phía dưới ô devide At16) \ OK. Vậy thôi!
    -Nhầm lẫn vị trí giữa TIMSK và TIFR.


    Mong mọi người giúp đỡ, 2 ngày loay hoay mà chưa xong;
    Còn đây là đoạn code bạn em viết trên CCS cho PIC thành công:
    //----------------------------------------------------------------
    void delay_100us(int x)
    {
    INT i;
    TMROIF=0; // bit enables _timer_interrupt
    for (i=0;i<x;i++)
    {
    set_timer0(6 ); // set innitial value
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); // set internal clock as a source and prescale==2
    while (TMROIF==0) ; //while (TMROIF==0) ; continue;
    TMROIF=0;
    }
    }
    //----------------------------------------------------------------
    Last edited by bkfam; 21-07-2010, 23:08.

  • #2
    Mình có 1 vài ý kiến thế này :
    -Thứ nhất, bạn ko nên dùng ngắt và hỏi vòng của timer0 đồng thời mà chỉ dùng 1 loại thôi : Ngắt hoặc hỏi vòng.
    -Thứ hai, khi bạn set fuse như thế nào thì nếu muốn thay đổi chỉ còn cách là nạp lại chip rồi set thông qua mạch nạp, và set fuse trong avr studio là an toàn nhất.
    -Thứ ba, Khi bạn muốn xóa cờ TIFR thì bạn phải set nó lên "1" chứ ko phải set nó về "0"(AVR mà lị )
    Last edited by enter88; 22-07-2010, 09:26.

    Comment


    • #3
      - em hiểu đơn giản tròng vòng for của em: cho lặp x lần 100us. Các bác có thể chỉ rõ giúp em code từng phương pháp ngắt và hỏi vòng là thế nào. Em chỉ hiểu đơn giản ngắt sau 100us, hỏi while(TIFR=0x00) của em là để continue vòng for và nhân 100us với x lần lặp.
      -vụ xóa cờ ngắt phải set TOV0 của thanh TIFR=1 thì em đọc lại datasheet thì đúng là vậy, nhưng cũng thấy nó bảo khi timer0 tràn thì cờ đó cũng set(one). Vậy là khi dựng cờ là set(one), xóa nó cũng "writting a logic one to flag" ??
      em sửa code thế này thì delay được nhưng sai thời gian
      //--------------------------------------------------------------------
      void delay_100us(unsigned long x)
      {
      unsigned long i;
      TIFR=0x00;
      for(i=0;i<x;i++)
      {
      TCCR0=0x02; // prescale= clk/8
      TCNT0=0x9B; // innitial =155
      while(TIFR==0);// continue;
      TIFR=0x00; // xóa sau khi tràn
      }
      }

      //--------------------------------------------------
      trong trình phục vụ ngắt em vẫn đặt lại giá trị cho TCNT0, và xóa cờ ngắt TIFR=0x01 !!!

      Khi chạy cho delay khoảng 60 triệu us=60s thì thấy led nhấp nháy ở khoảng chu kì 2s. Sai toét.
      Sai ở đâu vậy các anh: do tần số thạch anh, hay avr có đặc trưng về clock nào khác!!
      -
      Last edited by bkfam; 22-07-2010, 22:11.

      Comment


      • #4
        Mình lại xin có ý kiến như thế này:
        1- Hỏi vòng và ngắt(cụ thể ở đây là với timer0) là 2 cách để phát hiện timer0 là tràn:
        + Hỏi vòng là bạn sẽ liên tục kiểm tra cờ ngắt timer0 được set lên =1. Nhưng sau đó bạn phải có câu lệnh để xóa nó đi.Cụ thể là như thế này :
        while((TIFR&0x01)==0x00);// đợi cho cờ ngắt set=1
        TIFR=0x01;//Nếu cờ ngắt =1 thì xóa nó đi.

        +Còn ngắt thì khi mà cờ báo ngắt tràn timer0 bật nên thì nó sẽ tự động nhảy đến 1 chương trình con xử lý ngắt. Khi mà nó thực hiện xong chương trình con xử lý ngắt đó thì nó sẽ tự động xóa cờ báo ngắt tràn timer0. Do đó trong chương trình ngắt sẽ ko cần câu lệnh xóa cờ ngắt tràn.
        2- Trong chương trình của bạn thì chỉ cần dùng hỏi vòng hoặc ngắt thôi nếu bạn dùng cả hỏi vòng và ngắt dễ gây ra lỗi.
        3- Với các giá trị trong TCNT0 thì mình thấy bạn sẽ chọn dao động với f=8MHz và nếu bạn ko có thạch anh 8MHz thì bạn nên chọn bộ dao động nội .Cụ thể bạn set cái SUT_CKSEL như sau:
        SUT_CKSEL : "Int. RC Osc. 8 MHz; Start-up time: 6 CK + 4 ms"

        Comment


        • #5
          Trình biên dịch hỗ trợ hàm delay mà. Tội gì cho mất công thế ?

          Comment


          • #6
            em đã sửa theo như anh enter88, chỉ dùng hỏi vòng, kết quả vẫn vậy + em đã set lại fuse nhưng tần số ra vẫn lớn hơn nhiều so với ý mình.
            Làm theo kiểu chỉ dùng trình phục vụ ngắt thì hoàn toàn ko hoạt động, ko delay được chút nào:
            //--------------------------------kiểu dùng trình phục vụ ngắt-----------------------------
            void delay_100us(unsigned long x)
            {

            TIMSK=(1<<TOIE0);
            TCCR0=0x02; // prescale= clk/8
            TCNT0=0x9B; // innitial =155
            }

            ISR(TIMER0_OVF_vect)
            {
            count++; // count va x em de la bien toan cuc
            if(count==x)
            {TIMSK=0x00; // disable overFlow _INterrupt
            count=0;
            TCNT0=0xff;} // cho timer overflow luon
            else
            { TCNT0=0x9B;
            TIMSK=(1<<TOIE0);}

            }
            //-------------------------------------------------
            Mong tin các bác..

            Comment


            • #7
              Nguyên văn bởi bkfam Xem bài viết
              em đã sửa theo như anh enter88, chỉ dùng hỏi vòng, kết quả vẫn vậy + em đã set lại fuse nhưng tần số ra vẫn lớn hơn nhiều so với ý mình.
              Làm theo kiểu chỉ dùng trình phục vụ ngắt thì hoàn toàn ko hoạt động, ko delay được chút nào:
              //--------------------------------kiểu dùng trình phục vụ ngắt-----------------------------
              void delay_100us(unsigned long x)
              {

              TIMSK=(1<<TOIE0);
              TCCR0=0x02; // prescale= clk/8
              TCNT0=0x9B; // innitial =155
              }

              ISR(TIMER0_OVF_vect)
              {
              count++; // count va x em de la bien toan cuc
              if(count==x)
              {TIMSK=0x00; // disable overFlow _INterrupt
              count=0;
              TCNT0=0xff;} // cho timer overflow luon
              else
              { TCNT0=0x9B;
              TIMSK=(1<<TOIE0);}

              }
              //-------------------------------------------------
              Mong tin các bác..
              Chương trình này của bạn còn thiếu 1 chỗ nên nó ko delay(Đối với ngắt). Đó là trong cái chương trình con của phải có 1 vòng lặp. Cụ thể như sau:
              void delay_100us(unsigned long x)
              {
              TIMSK=(1<<TOIE0);
              TCCR0=0x02; // prescale= clk/8
              TCNT0=0x9B; // innitial =155
              while(count !=x);//Phải có thêm cái này thì mới có trễ
              TIMSK=0x00;
              count=0;
              }
              Còn chuơng trình ngắt sẽ sửa thành như sau:
              ISR(TIMER0_OVF_vect)
              {
              TCCR0=0x00;
              count++;
              TCNT0=0x9B;
              TCCR0=0x02;
              }
              Như thế này thì nó sẽ tạo trễ

              Comment


              • #8
                trong while là: count!=x nghe ko ổn bác ạ. Vì sau lần ngắt đầu tiên nó cứ đứng im đấy luôn. Em sửa trong while đó là TIFR==0x00. Nhưng tóm lại là cả hai cách đều vẫn im re, không delay được chút nào.
                Vẫn chỉ có cách hỏi vòng ở bài post #3 là nó delay được nhưng tần số chạy lớn hơn cỡ 30 lần ý mình. Không hiểu lỗi ở thạch anh, fuse hay còn cái config nào trong avrstudio không nữa. Vậy là sang ngày thứ 5 vật vã ... Các đại huynh giúp cho!

                Comment


                • #9
                  Ô kìa! Bạn bkfam vui tính nhỉ. Mình thử phân tích nhá:
                  trong while là: count!=x nghe ko ổn bác ạ. Vì sau lần ngắt đầu tiên nó cứ đứng im đấy luôn đúng rồi và lần ngắt tiếp theo nó cũng vậy, đến khi nào count=x thì thôi và khi ấy có phải sẽ trễ là
                  100us * x ko ?
                  - Có thể là bạn set fuse chưa đúng ,mình test thử chương trình trên ổn mà.

                  Comment


                  • #10
                    Bác test trên soft mô phỏng?? Em đã set các fuse của 7 bit LOW 0xEF: 11101111: (chỉ program bit SUT0).
                    Cop nguyên đoạn của bác, vẫn ko chạy, sửa lại chút chỗ on/off thanh TCCR0 vẫn không chạy!!
                    Em thử bỏ x, cho điều kiện count != giá trị cụ thể luôn, cũng ko được. Có vẻ như khi gọi hàm này hoàn toàn không bật timer lên để đếm vậy

                    Comment


                    • #11
                      Dùng codevision cho nhanh bạn à. Vài cái khai báo tự sinh mã_Chuẩn ko cần chỉnh.


                      Add: 97 Quán Nam - Lê Chân - Hải Phòng.
                      Tel: 031 518648 Phone: 0904 283 505

                      Comment


                      • #12
                        //--------------------------------------------------------------------------
                        void delay_100us(unsigned long x)
                        {
                        TCCR0=0x02; // prescale= clk/8
                        TCNT0=0x9B; // innitial =155
                        while(count!=x);
                        TCCR0=0x00;
                        //TIMSK=0x00; // Bỏ dòng này đi thay bằng TCCR0
                        count=0;
                        }

                        interrupt [TIM0_OVF] void timer0_ovf_isr(void)
                        {
                        // Place your code here
                        TCCR0=0x02;
                        TCNT0=0x9B;
                        count++;
                        }
                        //-------------------------------------------------------------------------
                        Vẫn giữ nguyên code như vậy sang codevission chạy ngon; Avrstudio nó bị nhầm lẫn tần số clock thế nào em ko hiểu, huynh nào rành về avrstudio giải thích giúp em.
                        Em vẫn thích dùng avrstudio hơn. Gặp lỗi này làm mất 5 ngày sợ quá rồi, có khi lại trở về máng lợn cũ Cvision

                        Comment


                        • #13
                          Nguyên văn bởi bkfam Xem bài viết
                          //--------------------------------------------------------------------------
                          void delay_100us(unsigned long x)
                          {
                          TCCR0=0x02; // prescale= clk/8
                          TCNT0=0x9B; // innitial =155
                          while(count!=x);
                          TCCR0=0x00;
                          //TIMSK=0x00; // Bỏ dòng này đi thay bằng TCCR0
                          count=0;
                          }

                          interrupt [TIM0_OVF] void timer0_ovf_isr(void)
                          {
                          // Place your code here
                          TCCR0=0x02;
                          TCNT0=0x9B;
                          count++;
                          }
                          //-------------------------------------------------------------------------
                          Vẫn giữ nguyên code như vậy sang codevission chạy ngon; Avrstudio nó bị nhầm lẫn tần số clock thế nào em ko hiểu, huynh nào rành về avrstudio giải thích giúp em.
                          Em vẫn thích dùng avrstudio hơn. Gặp lỗi này làm mất 5 ngày sợ quá rồi, có khi lại trở về máng lợn cũ Cvision
                          Vấn đề này thì bạn nên chịu khó đọc help của AVR studio và tự hiểu thì hay hơn. Với người mới học thì nên sử dụng AVR studio để lập trình thì sẽ nhớ hơn là tự phát sinh code như codevision.

                          Comment

                          Về tác giả

                          Collapse

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

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

                          Collapse

                          Đang tải...
                          X