Đăng Nhập

Vui lòng khai báo chính xác tên truy cập và mật khẩu!

Quên mật khẩu?

    HỌC LẬP TRÌNH KEIL C CHO 8051

      Admin
      Admin

      Giới tính : Nam

      Đến từ : TPHCM

      Ngày Tham gia : 03/04/2011

      Tổng số bài gửi : 2292

      #1

       Fri Sep 09, 2011 11:43 pm

      [You must be registered and logged in to see this link.]




      Trong
      lập trình vi xử lý ngôn ngữ thường dùng là ngôn ngữ lập trình ASM và
      ngôn ngữ C . Ngôn ngữ lập trình ASM hay lập trình hợp ngữ là ngôn ngữ
      lập trình trực tiếp cho vi điều khiển ( lập trình trực tiếp ) còn ngôn
      ngữ C hay còn gọi là lập trình hướng đối tượng nó gần với ngôn ngữ con
      người hơn . Điều này có nghĩa là với ASM người lập trình ra lệnh trực
      tiếp thông qua ngôn ngữ câu lệnh có tính ràng buộc còn ngôn ngữ C sử
      dụng các cấu trúc điều kiện và vòng lặp theo ý muốn .Nói về ngôn ngữ C
      thì ưu điểm của ngôn ngữ C là nó dễ hiểu nhưng cấu trúc lại dài và
      phức tạp so với ngôn ngữ ASM .

      Tìm hiểu lập trình C cho 8051.
      1. Giới thiệu :
      C là một ngôn ngữ khá mạnh và có rất nhiều người dung. Nhưng với vi xử lý ta chỉ cần biết một vài vấn đề cơ bản sau :
      + Các kiểu toán tử của C .
      + Các kiểu dữ liệu (int , float , double , char , unsigned char , …)
      + Các hàm trong C
      +Cấu trúc cơ bản của một chương trình.
      + Cấu trúc điều khiển hay các tập lệnh.
      2. Kiến thức cơ bản về C :
      a. Các kiểu toán tử của C
      Toán tử gán (=)
      Các toán tử số học ( + , - ,* , / , % )
      + cộng
      - trừ
      * nhân
      / chia
      % lấy phần dư (trong phép chia)
      Các toán tử gán phức hợp : (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)
      a -= 5; tương đương với a = a - 5;
      a /= b; tương đương với a = a / b;
      a*=2 ; tương đương với a = a*2
      ………..
      Tăng và giảm ( ++ , -- )
      a++; <=> a+=1; <=> a=a+1;
      a--; <=> a+=1 <=> a=a-1
      Tiền tố hay hậu tố ( ++a ; a++ )
      B=3;
      B=3;A=++B;
      // A là 4, B là 4
      Hay :B=3;
      A=B++;
      // A là 3, B là 4
      Các toán tử quan hệ ( = = , != ,< , > , <= , >= )
      = = Bằng
      != Khác
      > Lớn hơn
      < Nhỏ hơn
      > = Lớn hơn hoặc bằng
      < = Nhỏ hơn hoặc bằng
      Các toán tử logic (!, &&, || )
      ! NOT
      && AND
      || OR
      Các toán tử thao tác bit (&, |, ^, ~, <<, >> )
      & AND Logical AND
      | OR Logical OR
      ^ XOR Logical exclusive OR
      ~ NOT Đảo ngược bit
      << SHL Dịch bit sang trái
      >> SHR Dịch bit sang phải
      *Thứ tự ưu tiên
      1 () [ ] -> .
      2
      ++ -- tăng/giảm
      ~ Đảo ngược bit
      ! NOT
      & * Toán tử con trỏ
      + - Dương hoặc âm
      3 * / % Toán tử số học
      4 + - Toán tử số học
      5 << >> Dịch bit
      6 < <= > >= Toán tử quan hệ
      7 == != Toán tử quan hệ
      8 & ^ | Toán tử thao tác bit
      9 && || Toán tử logic
      10 ?: Toán tử điều kiện
      11 = += -= *= /= %=
      >>= <<= &= ^= |= Toán tử gán
      12 , Dấu phẩy
      b. Các kiểu biến dữ liệu :
      Char : 1byte ( -128 ; 127 )
      Unsigned char : 1byte ( 0; 255)
      Enum : 2byte ( -32,768 ; 32,768 )
      Short : 2byte ( -32,768 ; 32,768 )
      Unsigned short : 2byte ( 0 ; 65,535 )
      Int : 2byte ( -32,768 ; +32,767 )
      Unsigned int : 2byte (0 ; 65,535 )
      Long : 4byte (- 2,147,483,648 ; +2,147,483,647 )
      Unsigned long : 4byte (0 ; 4,294,697,295 )
      ………….
      Khai báo biến:
      Cấu trúc :
      Kiểu biến Tên biến
      VD :
      unsigned char x;
      Ta cũng có thể gán luôn giá trị ban đầu cho biến. Nghĩa là thay vì:
      unsigned char x;
      x=0;
      ta viết là : unsigned char x=0;
      Hoặc ta cũng có thể khai báo nhiêu biến một lúc:
      unsigned char x,y,z;
      Ngoài ra dung cho vi điều khiển trình biên dich chuyên dụng còn hỗ trợ các biến sau
      Dạng biến Số Bit Số Byte Miền giá trị
      Bit 1 0 0 ; 1
      sbit 1 0 0 ; 1
      sfr 8 1 0 đến 255
      sf16 16 & ; ;nbs p; 2 ; ; ; ;0 đến 65,535
      Trong
      đó bit có thể dung như các biến trong C nhưng các biến còn lại thì liên
      quan đến các thanh ghi hoặc địa chỉ cổng cua 8051( có nghĩa là khi khai
      bao biến kiểu bit thì không cần định địa chỉ trong RAM các biến khác
      phải địn rõ địa chỉ trong RAM vì nó là các dạng biến đặc biệt gọi là
      special function registers (SFR)
      VD: bit kiemtra;
      sfr P1_0=0x90
      Các SFR được khai báo trong thư viện
      at89x51.h và at89x52.h

      c. Các hàm trong C
      Có hai loai hàm trong C :
      +Hàm trả lai giá trị:
      Kiểu giá trị hàm trả lại Tên hàm(Biến truyền vào hàm)
      {
      // Các câu lệnh xử lý
      }
      VD;
      unsigned char cong(unsigned char x, unsigned char y)
      + Hàm không trả lại giá trị
      void Tên hàm( Biến truyền vào hàm)
      {
      // các câu lệnh xử lý
      }
      VD:
      void cong(unsigned char x,unsigned char y)
      {
      //các câu lệnh
      }
      (*) Hàm có thể có biến truyền vào hoặc không
      + Hàm không có biến truyền vào
      unsigned char Tên hàm(void)
      {
      //câu lệnh
      }
      + Hàm có biến truyền vào
      void Tên hàm(unsigned char x)
      {
      //các câu lệnh
      }
      (**) Số biến truyền vào là tùy ý miễn sao là đủ bộ nhớ , các biến ngăn cách nhau bằng dấu “,”.
      VD: void Tên hàm(unsigned char x,unsigned char y,unsigned char z)
      (***) Ngoài ra trong Keil C còn co một loại hàm là hàm ngắt:
      Cấu trúc:
      void Tên hàm(void) interrupt nguồn ngắt using băng thanh ghi
      {
      }
      Hàm ngắt không được phép trả lại giá tri hay truyền tham biến vào hàm
      Tên hàm : tùy chọn
      Interrupt : từ khóa chỉ hàm ngắt
      Nguồn ngắt : từ 0 đến 5 theo bảng vecter ngắt
      Ngắt do Cờ Địa chỉ vector Nguồn ngắt
      Reset hệ thống RST 0000H -
      Ngắt ngoài 0 IE0 0003H 0
      Timer 0 TF0 000BH 1
      Ngắt ngoài 1 IE1 001 3H 2
      Timer 1 TF1 001BH 3
      Port nối tiếp RI hoặc TI 0023H 4
      Timer 2 TF2 hoặc EXF2 002BH 5
      Băng thanh ghi trên RAM chon từ 0 đến 3.
      d. Các câu lệnh cơ bản của C
      + Cấu trúc điều kiện: if , else
      Cấu trúc if : if (điều kiện) lệnh ( đưa ra điều kiện và tuyên bố thưc hiện)
      VD : if (x<10) x++; // nếu x< 10 thì tăng x thêm 1
      Cấu
      trúc if & else : if (điều kiện) lệnh1 else lệnh 2 ( thỏa mãn điều
      kiện if thì thực hiện lệnh 1 còn ngược lại thực hiện lệnh 2
      VD : if (x=10) x++;
      Elese x--;
      + Cấu trúc lặp :
      - Vòng lặp while .
      Dạng của nó như sau:
      while (biểu hiện) lệnh
      Cấu trúc hay găp trong chương trình vi xử lý là
      while(1)
      {
      //vòng lặp mãi mãi ;
      }
      Tạo vòng lặp mãi mãi trong lập trình VXL .Chương trình chính sẽ được viết trong dấu
      ngoặc.
      - Vòng lặp do-while
      Dạng thức:
      do lệnh while (điều kiện);
      VD:
      do
      {
      x++; // cho nay cac ban co the viet nhieu cau lenh ,
      }
      while(x>10)
      tăng giá trị của x cho đến khi x > 10
      Chức
      năng của nó là hoàn toàn giống vòng lặp while chỉ trừ có một điều là
      điều kiện điều khiển vòng lặp được tính toán sau khi lệnh được thực
      hiện, vì vậy lệnh sẽ được thực hiện ít nhất một lần ngay cả khi điều
      kiện không bao giờ được thoả mãn .Như ví dụ trên kể cả x >10 thì nó
      vẫn tăng giá trị 1 lần trước khi thoát
      - Vòng lặp for:
      Cấu trúc : for (khởi tạo;điều kiện;tăng giá trị) lệnh
      và chức năng chính của nó là lặp lại lệnh chừng nào điều kiện còn mang giá trị đúng, như
      trong
      vòng lặp while. Nhưng thêm vào đó, for cung cấp chỗ dành cho lệnh khởi
      tạo và lệnh tăng. Vì vậy vòng lặp này được thiết kế đặc biệt lặp lại một
      hành động với một số lần xác định.
      Cách thức hoạt động của nó như sau:
      (*) Khởi tạo được thực hiện. Nói chung nó đặt một giá khí ban đầu cho biến điều khiển. Lệnh này được thực hiện chỉ một lần.
      (**) Điều kiện được kiểm tra, nếu nó là đúng vòng lặp tiếp tục còn nếu không vòng lặp kết thúc và lệnh được bỏ qua.
      (***) Lệnh được thực hiện. Nó có thể là một lệnh đơn hoặc là một khối lệnh được bao trong một cặp ngoặc nhọn.
      (****) Cuối cùng, thực hiện để tăng biến điều khiển và vòng lặp quay trở lại bước kiềm tra điều kiện.
      Phần
      khởi tạo và lệnh tăng không bắt buộc phải có. Chúng có thể được bỏ qua
      nhưng vẫn phải có dấu chấm phẩy ngăn cách giữa các phần. Vì vậy, chúng
      ta có thể viết for (;n<10;) hoặc for (;n<10;n++).
      Bằng cách sử
      dụng dấu phẩy, chúng ta có thể dùng nhiều lệnh trong bất kì trường nào
      trong vòng for, như là trong phần khởi tạo. Ví dụ chúng ta có thể khởi
      tạo một lúc nhiều biến trong vòng lặp:
      for ( n=0, i=100 ; n!=i ; n++, i-- )
      {
      // các câu lệnh;
      }
      VD: Tạo hàm delayms dung vòng lăp for
      void delay (unsigned int ms) // ham tao thoi gian tre ms
      {
      unsigned int i ; // hoặc ta có thể khai báo int i j;
      unsigned char j ;
      for (i=0;i
      {
      for (j=0;j<125;j++)
      {} // khong lam gi ca
      }
      }
      + Các lệnh rẽ nhánh và lệnh nhảy
      Lệnh break.
      Sử
      dụng break chúng ta có thể thoát khỏi vòng lặp ngay cả khi điều kiện để
      nó kết thúc chưa được thoả mãn. Lệnh này có thể được dùng để kết thúc
      một vòng lặp không xác định hay buộc nó phải kết thúc giữa chừng thay vì
      kết thúc một cách bình thường. Ví dụ, chúng ta sẽ dừng việc đếm ngược
      trước khi nó kết thúc.
      // break loop example
      #include
      int main ()
      {
      int n;
      for (n=10; n>0; n--) {
      cout << n << ", ";
      if (n==3)
      {
      cout << "dung dem”;
      break; //dem den 3 thi dung;
      } }
      return 0;
      }
      Lệnh continue.
      Lệnh continue làm cho chương trình bỏ qua phần còn lại của vòng lặp và nhảy sang lần lặp tiếp
      theo. Ví dụ chúng ta sẽ bỏ qua số 5 trong phần đếm ngược:
      #include
      int main ()
      {
      for (int n=10; n>0; n--) {
      if (n==5) continue;
      cout << n << ", ";
      }
      cout << "FIRE!";
      return 0;
      }
      Hàm exit.
      Mục đích của exit là kết thúc chương trình và trả về một mã xác định. Dạng thức của nó như sau
      void exit (int exit code);
      exit code được dùng bởi một số hệ điều hành hoặc có thể được dùng bởi các chương trình gọi.
      Theo
      quy ước, mã trả về 0 có nghĩa là chương trình kết thúc bình thường còn
      các giá trị khác 0 có nghĩa là có lỗi. các lệnh trên chủ yếu chỉ dùng
      lệnh break để thoát khỏi vòng lặp . Các lệnh khác thường rất ít dược sử
      dụng
      Cấu trúc lựa chọn: switch
      Cú pháp của lệnh switch hơi đặc
      biệt một chút. Mục đích của nó là kiểm tra một vài giá trị hằng cho một
      biểu thức, tương tự với những gì chúng ta làm ở đầu bài này khi liên
      kết một vài lệnh if và else if với nhau. Dạng thức của nó như sau:
      switch (expression)
      {
      case constant1:
      block of instructions 1
      break;
      case constant2:
      block of instructions 2
      break;
      .
      .
      .
      default:
      default block of instructions
      }

      hoạt động theo cách sau: switch tính biểu thức và kiểm tra xem nó có
      bằng constant1 hay không, nếu đúng thì nó thực hiện block of
      instructions 1 cho đến khi tìm thấy từ khoá break, sau đó nhảy đến phần
      cuối của cấu trúc lựa chọn switch. Còn nếu không, switch sẽ kiểm tra xem
      biểu thức có bằng constant2 hay không. Nếu đúng nó sẽ thực hiện block
      of instructions 2 cho đến khi tìm thấy từ khoá break. Cuối cùng, nếu giá
      trị biểu thức không bằng bất kỳ hằng nào được chỉ định ở trên (bạn có
      thể chỉ định bao nhiêu câu lệnh case tuỳ thích), chương trình sẽ thực
      hiện các lệnh trong phần default: Nếu nó tồn tại vì phần này không bắt
      buộc phải có.

      e. Cấu trúc cơ bản của của một chương trình C cho 8051 :
      + Phần đầu tiên là liệt kê các header file
      Các bạn dùng bằng từ khóa
      #include “Tên các header”
      Hoặc :
      #incude
      Khi
      bạn viết theo cách thứ nhất thì trình biên dịch sẽ tìm kiếm file .h
      hoặc .c này trong thư mục hiện tại chứa dự án của bạn, nếu không có thì
      sẽ tìm kiếm trong thư mục Inc trong thư mục cài đặt KeilC.
      Viết theo cách thứ hai thì trình biên dịch sẽ tìm luôn trong thư mục /INC luôn.
      Để
      có thể sử dụng đúng các file .h cho các vi điều khiển mở thư mục /inc
      trong thư mục này có các thư mục con như tên của hãng sản xuất. Ví dụ
      như của Atmel thì bạn tìm trong thư mục /Atmel thì sẽ thấy được file
      reg51.h
      Phần thứ 2 : Định nghĩa các macro (thiết lập vĩ mô). Cách
      khai báo sử dụng từ khóa #define. Ví dụ:để khai báo mặc led 1 được nối
      với chân 0 của port 1 ta viết như sau
      #define led1 P1_0
      + Các hàm ngắt như ngắt (timer0, timer1, ngắt nối tiếp, ngắt ngoài )nêu ở phần khai báo biến . Copy lại như sau :
      Cấu trúc:
      void Tên hàm(void) interrupt nguồn ngắt using băng thanh ghi
      {
      }
      Hàm ngắt không được phép trả lại giá tri hay truyền tham biến vào hàm
      Tên hàm : tùy chọn
      Interrupt : từ khóa chỉ hàm ngắt
      Nguồn ngắt : từ 0 đến 5 theo bảng vecter ngắt

      Ngắt do Cờ Địa chỉ vector Nguồn ngắt
      Reset hệ thống RST 0000H -
      Ngắt ngoài 0 IE0 0003H 0
      Timer 0 TF0 000BH 1
      Ngắt ngoài 1 IE1 0013H 2
      Timer 1 TF1 001BH 3
      Port nối tiếp RI hoặc TI 0023H 4
      Timer 2 TF2 hoặc EXF2 002BH 5
      Băng thanh ghi trên RAM chon từ 0 đến 3.
      void ngat4(void) interrupt 4 using 2
      {
      //các câu lệnh
      }
      Cú pháp các ngắt khác cũng tương tự chỉ thay số 4 bằng số thứ tự của ngắt trong bảng vector ngắt.
      + Các hàm con như Delay, khởi tạo,..
      Việc gây trễ trong Keil C có nhiều cách khác nhau
      - Dùng vòng lặp while for :
      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. Viết chương trình
      như sau:
      //*****************************
      void delay (unsigned int ms) // ham tao thoi gian tre ms
      {
      unsigned int i ;
      unsigned char j ; //khai bao bien 1 byte
      for (i=0;i
      {
      for (j=0;j<125;j++)
      {} // khong lam gi ca
      }
      }
      - Dùng Timer 0 hoặc Timer 1
      Tiếp
      tục với hàm delay() theo cách dùng bộ định thời thì ta thấy nó cũng
      giống như ngôn ngữ ASM biên dịch với Topview Simulator .
      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 : Chế độ định thời 13 bit , số đếm 0000H – 1FFFH
      TM1=0, TM0 =1 chế độ 1 : Chế độ định thời 16 bit , số đếm 0000H - FFFFH
      TM1=1, TM0 =0 chế độ 2 : Chế độ định thời 8 bit tự động nạp số đếm 00H - FFH
      TM1=1, TM0 =1 chế độ 3 : Chế độ định thời chia sẻ số đếm 00H – FFH
      VD : Gây trễ 1 ms = 1000us ta dùng chế độ định thời 16 bit sử dụng timer 0
      Tdelay=1000 sử dụng calculator của hệ điều hành Windows XP trong Start\Program\Accessories\Calculator ta được
      TH0=FC
      TL0=18
      Vậy chương trình sẽ như sau :
      void delay(unsigned ms)
      {
      while (ms--)
      {
      TMOD=0x01; //dùng timer 0 chế độ 1 ( 16bit )
      TH0=0xfc;
      TL0=0x18; //hai câu lệnh nạp giá tri đếm
      TR0=1; // cho phép timer 0 hoạt động
      while (TF0); //chờ TF0=1(cờ tràn =1 )
      TF0=0; //xóa cờ tràn
      TR0=0; // ngừng Timer
      }
      }
      + Chương trình chính:
      void main(void)
      {
      //cấu trúc lệnh điều khiển
      }
      đối tượng của chương trình là vi điều khiển nên hàm main không có giá trị trả về và không có tham số đưa vào.