Thông báo

Collapse
No announcement yet.

giải thích về vòng lặp for

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

  • giải thích về vòng lặp for

    Mình đang tìm hiểu lập trình cho 89, mà cái luồng này đã lâu lắm rồi (năm2005)
    Dành cho người mới tìm hiểu 8051 ,
    các bạn giải thích cho mình cái code này với:
    #include<regx51.h>//khai báo cho chương trình mình dùng thư viện của 8051
    #define led P1_0//Led được nối với P1_0,chú ý viết hoa chữ "P"nhé
    void delay(unsigned int ms)//hàm này tạo độ trễ thời gian, dơn vị là ms
    {
    unsigned int i;
    unsigned char j;//khai báo kiểu "char"mỗi biến chỉ chiếm 1 byte
    for(i=0;i<ms;i++)
    for(j=0;j<120;j++)
    {}//không làm gì cả
    }
    main()//Chương trình chính
    {
    While(1)//tạo vòng lặp vô hạn
    {
    led=0;//tắt led
    delay(1000);//tạo độ trễ 1000ms=1s
    led=1;//bật led
    delay(1000);
    }
    }
    tại sao vòng for: unsigned int i;
    for(i=0;i<ms;i++)


    khai báo biến kiểu int , i<ms , vậy i sẽ đem so sánh với ms, vậy ms có giá trị là bao nhiêu? Giá trị này có trong thư viện regX51.h không? Khi nào thì dừng vòng lặp?

  • #2
    Trả lời bạn như sau
    void delay(unsigned int ms)
    đối số là ms
    giá trị ms chính là
    giá trị trong vòng for: unsigned int i;
    for(i=0;i<ms;i++)

    khi gọi hàm delay(1000); thì ms=1000

    Giải pháp điện tử của bạn

    Comment


    • #3
      Cám ơn bạn, có thế thôi mà mình nghĩ mãi không ra, tại mình mới học C mà, cho mình hỏi thêm tại sao phải dùng 2 vòng for
      for(i=0,i<ms;i++) và
      for(j=0,j<120;j++)
      Thời gian trễ ở đây được tính là bao nhiêu?

      Comment


      • #4
        for(i=0;i<ms;i++)
        for(j=0;j<120;j++)
        {}//không làm gì cả
        đoạn chương trình trên làm nhiệm vụ tạo trễ với thời gian trễ: t_delay=ms*120
        nếu dùng thạch anh 12MHZ thì 1 chu kỳ lệnh là (1/12.12MHZ)=1us, nên thời gian trễ của đoạn code là: ms*120us
        vậy nếu ta truyền số liệu ms là giá trị bao nhiêu thì ta được thời gian tương ứng với công thức trên!
        |

        Comment


        • #5
          Mình chưa thử, nhưng với thạch anh ngoài là 12MHz thì cần thay số 120 thành 250 thì mới đúng: mỗi đơn vị biến (ms) truyền vào tương ứng với một ms trễ.
          Thử lại xem sao đã...
          Hôm nay trời nắng chang chang.
          Mèo con đi học chẳng mang thứ gì.
          Chỉ mang một cái bút chì.
          Và mang một mẩu bánh mì con con.

          Comment


          • #6
            Để tạo hàm trễ 1ms (mỗi đơn vị của biến ms truyền vào tương ứng với 1ms) thì hàm delay sửa là: Biến j khai báo kiểu unsigned int, giá trị 120 giữ nguyên.
            Tuy nhiên, chỉ tương đối chính xác thôi: mỗi ms sai số +/- khoảng 15us. Muốn tạo trễ chính xác phải dùng bộ timer.
            Hôm nay trời nắng chang chang.
            Mèo con đi học chẳng mang thứ gì.
            Chỉ mang một cái bút chì.
            Và mang một mẩu bánh mì con con.

            Comment


            • #7
              mình giới thiệu thêm về dùng timer nhé.

              void delay() // hàm tạo trễ 500 uS
              {
              TMOD=0x21; // thanh ghi chọn chế độ cho timer: timer1 chạy ở chế độ 1.
              TH0=0xfe; // đặt giá trị 0xfe vào thanh ghi TH0
              TL0=0x0c; // đặt giá trị 0x0C vào thanh ghi TL0
              TR0=1; // khởi động timer0
              while(TF0==0)
              {} // chờ cho tới khi cờ báo tràn ( đủ thời gian thì TF0=1 )
              TR0=0; // Ngưng hoạt động của timer0 và xoá cờ báo về 0 để cho lần tạo trễ lần sau.
              TF0=0;
              }
              cách tính giá trị của TH0 và TL0 như sau: muốn có độ trễ là uS ( uS < 65536) thì lấy 65536-uS = conlai . chuyển conlai sang mã hexa thì khi đó byte cao nạp vào TH0 byte thấp nạp vào TL0. ví dụ cần độ trễ là 500uS : 65536-500=65036 chuyển sang mã hexa = FE0C khi đó TH0=0xfe, TL0=0x0c.
              chỉ có tâm hồn là nơi duy nhất: có thể biến thiên đường thành địa ngục và ngược lại có thể biến địa ngục hóa thiên đường
              Everything should be made as simple as possible, but not simpler

              Comment


              • #8
                Mấy cái thanh ghi và cờ ngắt, có lẽ còn lâu em mới hiểu được , em đang tập bò mà...
                em giải thích 2 vòng for như thế này nhé:
                for(i=0;i<ms;i++)
                vi xử lí đọc từ biến đếm 0, vì 0<ms (ở đây chọn ms=1000) , nên nó nhảy đến vòng for thứ hai for(j=0;j<120;j++) , vòng for thứ hai: for(j=0;j<120;j++) thực hiện lệnh {;}// tức là không làm gì cả trong 120 chu kì máy, sau đó thoát khỏi vòng for thứ hai, nó trở lại vòng for thứ nhất for(i=0;i<ms;i++) nó tiếp tục tăng i thành 1, vì 1<ms (là 1000) nên tiếp tục thực hiện lệnh trong vòng for thứ hai: for(j=0;j<120;j++) vậy vòng for thư nhất thhực hiện ms lần (là 1000 lần), mỗi 1 lần thực hiện vòng for thứ nhất nó thực hiện vòng for thứ hai 120 lần, vậy ta có thời gian delay là ms*120 chu kì máy, (=120X1000) phải không ạ? Các Bác hãy ghé mắt nhìn qua, phán cho em 1 câu là đúng hay sai nhé!
                Last edited by L.T.M; 08-01-2013, 11:47.

                Comment


                • #9
                  Nguyên văn bởi L.T.M Xem bài viết
                  Mấy cái thanh ghi và cờ ngắt, có lẽ còn lâu em mới hiểu được , em đang tập bò mà...
                  em giải thích 2 vòng for như thế này nhé:
                  for(i=0;i<ms;i++)
                  vi xử lí đọc từ biến đếm 0, vì 0<ms (ở đây chọn ms=1000) , nên nó nhảy đến vòng for thứ hai for(j=0;j<120;j++) , vòng for thứ hai: for(j=0;j<120;j++) thực hiện lệnh {;}// tức là không làm gì cả trong 120 chu kì máy, sau đó thoát khỏi vòng for thứ hai, nó trở lại vòng for thứ nhất for(i=0;i<ms;i++) nó tiếp tục tăng i thành 1, vì 1<ms (là 1000) nên tiếp tục thực hiện lệnh trong vòng for thứ hai: for(j=0;j<120;j++) vậy vòng for thư nhất thhực hiện ms lần (là 1000 lần), mỗi 1 lần thực hiện vòng for thứ nhất nó thực hiện vòng for thứ hai 120 lần, vậy ta có thời gian delay là ms*120 chu kì máy, (=120X1000) phải không ạ? Các Bác hãy ghé mắt nhìn qua, phán cho em 1 câu là đúng hay sai nhé!
                  Mặc dù trong vòng for thứ 2 không làm gì cả (không có lệnh nào) nhưng không phải là thực hiện nó mất 120 chu kỳ máy. Bởi vì để thực hiện được vòng for CPU cần làm các việc như sau: Tăng biến j, so sánh j với 120 để quyết định lặp lại hay thoát ra... Nói thì ngắn gọn, viết bằng C cũng ngắn gọn nhưng khi dịch sang ngôn ngữ máy chỗ này cũng tốn lệnh phết...: Nếu biến j là kiểu unsigned char (1byte) thì mất khoảng 4-5 lệnh máy. Nếu biến j là kiểu usigned int(2 byte) thì mất 8-9 lệnh máy.
                  Mỗi lệnh máy VDK dòng 8051 thực hiện mất 1us với thạch anh 12MHz.
                  Tóm lại,
                  Khai báo biến j là unsigned int thì thời gian trễ = ms* 120*8 hoặc 9 chu kỳ máy ~= ms*1000us. Nói cách khác mỗi đơn vị của ms ứng với 1 milisecon.
                  Khai báo biến j là unsigned char thì mỗi đơn vị của ms chỉ ứng với khoảng 500us (0.5 milisecon)
                  Hôm nay trời nắng chang chang.
                  Mèo con đi học chẳng mang thứ gì.
                  Chỉ mang một cái bút chì.
                  Và mang một mẩu bánh mì con con.

                  Comment


                  • #10
                    Nguyên văn bởi L.T.M Xem bài viết
                    Mấy cái thanh ghi và cờ ngắt, có lẽ còn lâu em mới hiểu được , em đang tập bò mà...
                    em giải thích 2 vòng for như thế này nhé:
                    for(i=0;i<ms;i++)
                    vi xử lí đọc từ biến đếm 0, vì 0<ms (ở đây chọn ms=1000) , nên nó nhảy đến vòng for thứ hai for(j=0;j<120;j++) , vòng for thứ hai: for(j=0;j<120;j++) thực hiện lệnh {;}// tức là không làm gì cả trong 120 chu kì máy, sau đó thoát khỏi vòng for thứ hai, nó trở lại vòng for thứ nhất for(i=0;i<ms;i++) nó tiếp tục tăng i thành 1, vì 1<ms (là 1000) nên tiếp tục thực hiện lệnh trong vòng for thứ hai: for(j=0;j<120;j++) vậy vòng for thư nhất thhực hiện ms lần (là 1000 lần), mỗi 1 lần thực hiện vòng for thứ nhất nó thực hiện vòng for thứ hai 120 lần, vậy ta có thời gian delay là ms*120 chu kì máy, (=120X1000) phải không ạ? Các Bác hãy ghé mắt nhìn qua, phán cho em 1 câu là đúng hay sai nhé!
                    Chính xác đó bạn! nhưng quan trọng là bạn phải hiểu chu kỳ lệnh...còn nếu muốn delay chính xác hơn thì dùng timer, đỉnh hơn thì dùng wait_os trong RTOS
                    thân!
                    |

                    Comment


                    • #11
                      Cám ơn các Bác, vậy thời gian trễ phụ thuộc vào kiểu biến; int, char, long....
                      Có phải tại vì int có số bit là 16, char có số bit là 8 phải không ạ? Em thấy trong cuốn 8051 cơ bản của thầy Kiên tạo thời gian trễ chỉ cần 1 vòng for
                      long n;
                      for(n=0;n<time;n++)
                      {
                      ;//khong lam gi
                      }
                      vì khai báo biến kiểu long tạo được thời gian trễ lớn hơn gấp đôi kiểu int phải không ạ?

                      Comment


                      • #12
                        Nguyên văn bởi L.T.M Xem bài viết
                        Cám ơn các Bác, vậy thời gian trễ phụ thuộc vào kiểu biến; int, char, long....
                        Có phải tại vì int có số bit là 16, char có số bit là 8 phải không ạ? Em thấy trong cuốn 8051 cơ bản của thầy Kiên tạo thời gian trễ chỉ cần 1 vòng for
                        long n;
                        for(n=0;n<time;n++)
                        {
                        ;//khong lam gi
                        }
                        vì khai báo biến kiểu long tạo được thời gian trễ lớn hơn gấp đôi kiểu int phải không ạ?
                        theo trên thì thời gian trễ phụ thuộc vào số chu kỳ lệnh không làm gì:
                        khai báo long n; // có nghĩa là số n là số nguyên 16 bit= -(2^16 -1)/2 <n<(2^16 -1)/2
                        nên khai báo là unsigned long n; //nghĩa là số nguyên dương <n< 2^16 -1
                        còn khai báo unsigned int n thì n tối đa chỉ có 255 thôi( tức là trễ tối đa 255us)
                        nếu muốn khai báo unsigned int n // mà muốn trễ lớn hơn 255us thì ta dùng lệnh for lồng nhau
                        for(n=0;n<ms;n++)//ms<255
                        for(m=0;m<const;m++)
                        ;// không làm gì
                        khi đó trễ ms. const (us)
                        Hy vọng sẽ giúp được bạn!
                        Thân!
                        |

                        Comment


                        • #13
                          Nguyên văn bởi dinhnam123 Xem bài viết
                          theo trên thì thời gian trễ phụ thuộc vào số chu kỳ lệnh không làm gì:
                          khai báo long n; // có nghĩa là số n là số nguyên 16 bit= -(2^16 -1)/2 <n<(2^16 -1)/2
                          nên khai báo là unsigned long n; //nghĩa là số nguyên dương <n< 2^16 -1
                          còn khai báo unsigned int n thì n tối đa chỉ có 255 thôi( tức là trễ tối đa 255us)
                          nếu muốn khai báo unsigned int n // mà muốn trễ lớn hơn 255us thì ta dùng lệnh for lồng nhau
                          for(n=0;n<ms;n++)//ms<255
                          for(m=0;m<const;m++)
                          ;// không làm gì
                          khi đó trễ ms. const (us)
                          Hy vọng sẽ giúp được bạn!
                          Thân!
                          Bạn hiểu sai rồi, vòng lặp bên trong mặc dù không có lệnh nào nhưng không phải mỗi vòng tốn 1us (1 câu lệnh) vì MCU sẽ phải làm những việc như sau: Tăng biến đếm, So sánh biến đếm với giá trị giới hạn, quyết định làm tiếp (lặp lại nếu chưa đủ giới hạn) hay không (thoát ra nếu đã đủ giới hạn). Những việc đó làm MCU tốn nhiều dòng lệnh máy.
                          Thời gian để tăng và so sánh các biến có kích thước khác nhau cũng khác nhau (tăng biến 4 byte lâu hơn tăng biến 2 byte...).
                          Ngoài ra thời gian trễ còn phụ thuộc vào độ "thông minh" của trình biên dịch, phụ thuộc vào cấu hình phần cứng của CPU (8, 16 hay 32 bit...)
                          Tóm lại, thời gian trễ của hàm delay viết như trên không thể áp dụng một công thức chung nào.
                          Theo mình kiểm tra, với trình dịch Keil, MCU 8051, thạch anh 12MHZ:
                          - Biến kiểu char (1byte) tạo ra (gây trễ) 4-5us mỗi lần lặp.
                          - Biến kiểu int (2 byte) tạo ra (gây trễ) 8-9us mỗi vòng.
                          ....
                          Hôm nay trời nắng chang chang.
                          Mèo con đi học chẳng mang thứ gì.
                          Chỉ mang một cái bút chì.
                          Và mang một mẩu bánh mì con con.

                          Comment


                          • #14
                            Nguyên văn bởi Acxen_lupine Xem bài viết
                            Bạn hiểu sai rồi, vòng lặp bên trong mặc dù không có lệnh nào nhưng không phải mỗi vòng tốn 1us (1 câu lệnh) vì MCU sẽ phải làm những việc như sau: Tăng biến đếm, So sánh biến đếm với giá trị giới hạn, quyết định làm tiếp (lặp lại nếu chưa đủ giới hạn) hay không (thoát ra nếu đã đủ giới hạn). Những việc đó làm MCU tốn nhiều dòng lệnh máy.
                            Thời gian để tăng và so sánh các biến có kích thước khác nhau cũng khác nhau (tăng biến 4 byte lâu hơn tăng biến 2 byte...).
                            Ngoài ra thời gian trễ còn phụ thuộc vào độ "thông minh" của trình biên dịch, phụ thuộc vào cấu hình phần cứng của CPU (8, 16 hay 32 bit...)
                            Tóm lại, thời gian trễ của hàm delay viết như trên không thể áp dụng một công thức chung nào.
                            Theo mình kiểm tra, với trình dịch Keil, MCU 8051, thạch anh 12MHZ:
                            - Biến kiểu char (1byte) tạo ra (gây trễ) 4-5us mỗi lần lặp.
                            - Biến kiểu int (2 byte) tạo ra (gây trễ) 8-9us mỗi vòng.
                            ....
                            mình đang nói trường hợp dùng thạch anh 12MHZ còn nếu dùn loại khác thì 1 chu kỳ lệnh= 10^6/(12*HZ) us
                            trường hợp dùng for để tạo trể. độ chính xác của nó tương đối thôi. vì nó chịu ảnh hưởng của các lệnh cấu trúc đk,...nữa
                            nên nếu muốn chính xác hơn thì dùng timer của Vi xử lý.đề nghị bạn đọc lại cho kỹ.
                            cai bạn nói "- Biến kiểu char (1byte) tạo ra (gây trễ) 4-5us mỗi lần lặp.
                            - Biến kiểu int (2 byte) tạo ra (gây trễ) 8-9us mỗi vòng."
                            là không chính xác vì tùy thuộc quy định số lần không làm gì của vxl thì mới có tr và trình dịch quy định char máy byte, long ,int ....
                            nếu có gì trao đổi thì cứ mail cho mình dinhnambkhn@gmail.com
                            Hy vọng cái này sẽ giúp được L.T.M một phần nhỏ nào đó!
                            thân!
                            |

                            Comment


                            • #15
                              Nguyên văn bởi dinhnam123 Xem bài viết
                              mình đang nói trường hợp dùng thạch anh 12MHZ còn nếu dùn loại khác thì 1 chu kỳ lệnh= 10^6/(12*HZ) us
                              trường hợp dùng for để tạo trể. độ chính xác của nó tương đối thôi. vì nó chịu ảnh hưởng của các lệnh cấu trúc đk,...nữa
                              nên nếu muốn chính xác hơn thì dùng timer của Vi xử lý.đề nghị bạn đọc lại cho kỹ.
                              cai bạn nói "- Biến kiểu char (1byte) tạo ra (gây trễ) 4-5us mỗi lần lặp.
                              - Biến kiểu int (2 byte) tạo ra (gây trễ) 8-9us mỗi vòng."
                              là không chính xác vì tùy thuộc quy định số lần không làm gì của vxl thì mới có tr và trình dịch quy định char máy byte, long ,int ....
                              nếu có gì trao đổi thì cứ mail cho mình dinhnambkhn@gmail.com
                              Hy vọng cái này sẽ giúp được L.T.M một phần nhỏ nào đó!
                              thân!
                              Các bài trả lời của mình trong mục này không chỉ để giúp bạn L.N.M, mình thấy các bạn (cả bạn dinhnam123) cũng chưa hiểu rõ về các ngôn ngữ lập trình.
                              Ngôn ngữ C (là ngôn ngữ bậc cao - ngôn ngữ lập trình có cấu trúc) 1 lệnh của nó không tương đương với 1 lệnh máy thường là nhiều hơn, ít nhất là bằng.
                              Khác với ngôn ngữ ASEMBLY (lập trình bậc thấp) mỗi lệnh chương trình ASM tương đương với 1 lệnh máy. Mỗi lệnh máy thực hiện hết bao lâu tùy thuộc vào VXL và tần số thạch anh
                              Ngoài ra vòng lặp for(...;...;...) không phải là một lệnh mà là một cấu trúc khi dịch ra lệnh máy nó là một đoạn lệnh chứ không phải một lệnh.
                              Còn dùng Timer để định thời hay đo đếm thì là nghề của mình rồi...
                              Hôm nay trời nắng chang chang.
                              Mèo con đi học chẳng mang thứ gì.
                              Chỉ mang một cái bút chì.
                              Và mang một mẩu bánh mì con con.

                              Comment

                              Về tác giả

                              Collapse

                              L.T.M Tìm hiểu thêm về L.T.M

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

                              Collapse

                              Đang tải...
                              X