10 4.104 8051 9 Acquy adc pic All datasheet ALTIUM Altium Designer AM-FM Arduino ARM ARM là gì Ấn Tượng Bản tin công nghệ Bản tin Thiết Bị Số Barobo bất động sản biến Binary Bit board lpc2378 Bộ chuyển đổi ADC Bộ Đếm Bộ điều khiển cửa cuốn Bộ Định Thời Buy Khóa Số Điện Tử Buy Mạch đếm sản phẩm Buy Mạch giao thông Buy Mạch nạp Buy Matrix Byte C cho AVR các hàm vào ra các loại lõi arm các mạch DAC cơ bản các ngắt trong pic Cách đọc điện trở Cách Đọc Giá Trị Điện Trở Cách đọc giá trị tụ điện Cách hàn linh kiện dán cách làm mạch khóa số cách tạo linh kiện dán cad/cam Cài Đặt cài đặt proteus 8 cảm biến Cấu Kiện Logic Khả Trình cấu tạo cấu trúc arm cấu trúc lệnh CCS Chân chân Transistor Chip Khả Trình chuyển đổi Chuyển đổi số tương tự Chuyển Đổi Tương Tự/Số - ADC Chuyển động số chương trình City Clip Điện Tử Code 8051 - ASM Code 8051 - C Code 8051-C code ASM code ASM mẫu 8086 Code AVR - C code C Code Lập Trình Code led sao băng code maupic code mẫu 8051 Code Mẫu 8086 Code Mẫu cho ARM - LPC1343 code mẫu pic Code PIC - C codemaupic Counter Cổng Vào Ra Cơ Bản Cuộn Cảm Cửa cuốn DA DAC Debug Decimal Delay8051 Dev-C++ Diode DIY Dò đường Do It Yourself doanh nghiệp Download DTMF Mobile đảo chiều động cơ Điện Trở Điện Tử Điện Tử Cơ Bản điều chế độ rộng xung điều chế xung PWM điều khiển bằng điện thoại Điều khiển cửa cuốn Điều khiển cửa cuốn bằng điện thoại điều khiển động cơ đo điện áp đo nhiệt độ đo nhiệt độ hiển thị lên lcd trên 8051 Đo Nhiệt Độ LM35 + LCD Đo Nhiệt Độ LM35 + Led 7 thanh đọc màu điện trở đồ chơi động cơ chân không Động cơ nhiên liệu Động cơ robo đồng hồ thời gian thực Ebook Đại Học ebook điện tử Ebook đồ án Ebook Tin Học Encoder Encoder là gì Full Giải Thuật Giải thuật PID Giáo Dục giao tiếp i2c pic 16f877a giao tiếp i2c pic16f877a với ic ds1307 giao tiếp máy tính qua rs232 Giao Tiếp Máy Tính VB6 giao tiếp rs232 giao tiếp spi giữa 2 pic giao tiếp spi trong pic Giáo Trình Điện Tử Giới thiệu 8051 Giới thiệu cơ bản GPIO Graphic Design hàm Hàn linh kiện dán Hexadecimal Hệ Hexa Hệ Nhị Phân Hệ Thập Lục Phân Hệ Thập Phân hiển thị lên lcd 16x2 Hoạt Động Học Học 8051 qua các ví dụ đơn giản Học ALtium Designer học AVR Học Corel Draw X3 Học Eagle HỌC LẬP TRÌNH 16F877A Học Lập Trình 8051 Học Lập Trình C Học Orcad Học Protues hoc-lam-robot-do-duong-qua-video Hồng ngoại hướng dẫn hướng dẫn Altium Designer hướng dẫn đo đồng hồ VOM hướng dẫn keil - C lập trình 8051 hướng dẫn làm led sao băng hướng dẫn làm led trái tim hướng dẫn lập trình ARM Hướng Dẫn Lập Trình ARM - LPC1343 hướng dẫn lập trình ARM-LPC2378 hướng dẫn lập trình CCS hướng dẫn lập trình PIC Hướng Dẫn Led Trái Tim hướng dẫn module sim548c hướng dẫn sử dụng keil hướng dẫn sử dụng proteus 8 Hyper Terminal hercules 3.2.4 I/O IC 555 IC 7447 IC 74HC151 IC 74HC154 IC 74HC245 IC 74HC595 IC 74LS138 IC DS1307 IC đồng hồ thời gian thực IC LM324 IC LM342 IC LM7805 IC số IC số opamp LM324 IC Thông Dụng IC555 Interrupt Keil 4 Full keil arm Keil C Keil uVision3 kế toán kiểm toán khái niệm Khái Niệm Cơ Bản Kho Vật Liệu khóa điện tử khóa số dùng 8051 khóa số dùng 89s52 Khóa Số Điện Tử khuếch đại kiểm tra Kinh doanh maketing kinh tế quản lí Kỹ Thuật Kỹ Thuật Vi Xử Lý làm mạch điện lý thú Làm quen AVR Lap Trinh Dieu Khien Robot Lập Trình lập trình 8051 Lập Trình AVR Lập Trình C lập trình c++ Lập Trình Led Quảng Cáo Lập Trình Nhúng Lập trình pic Lập trình Robot Lập Trình Vi Điều Khiển Lập Trình Với AVR Studio LCD 16x2 Lcd16x2 Led Clock Led Quay led sao băng led trai tim Led Trái Tim Lịch sử ra đời Linh Kiện Cơ Bản linh kiện điện tử Loa LPC 2378 LSB lý thú Mã AVR - C Mạch 7seg Mạch Amply.Mạch Loa Mạch Autorobo Mạch bảo vệ Mạch Cảm Biến mạch cảm ứng sờ tay Mạch Cầu H Mạch cube Mạch Đếm Sản Phẩm Mạch điện cơ bản Mạch điện hay Mạch Điện Ứng Dụng Mạch Điều khiển động cơ Mạch Động Cơ Mạch đồng hồ Mạch đồng hồ 4 led Mạch giao thông Mạch IC số Mạch in mạch khóa số mạch khuếch đại thuật toán mạch led chúc mừng năm mới mạch led đẹp Mạch Led đơn Mạch Led Quảng Cáo mach led trai tim mạch led trái tim Mạch Led Vumeter mạch lý thú Mạch Ma trận Phím Mạch Matrix Mạch nạp Mạch nguồn Mạch Nút Bấm mạch sóng rf mạch tăng áp Mạch thu phát Mạch tổ hợp MSI Mạch trái tim Mạch Vi điều khiển Microbicho module module GSM/GPS Module Sim548 Module Sim548 giao tiếp với vi điều khiển PIC Module Sim548C Mosfet Motor Mô Phỏng Phần Cứng Mô Tả Phần Cứng MSB mua led sao băng News Ngắt Ngắt Trong LPC23xx ngân hàng Ngôn Ngữ Ngôn Ngữ C Ngôn Ngữ Tự Học Lập Trình C Ngôn Ngữ VHDL Nguyên Lý nguyên lý ic 555 Nguyên Tắc nháy led Nhập môn C Nhỏ Gọn Nibble opamp People Phần Mềm phần mềm altium Designer Phần mềm điện tử Phần Mềm Điện Tử Phần Mềm Điện Tử Hay Phần Mềm Hay Phần Mềm Led Quảng Cáo phần mềm proteus 8 Phần mềm vi tính Phần Mền Phương pháp hàn linh kiện dán PIC pic16f877a Print Design Proteus Proteus 7.8 SP2 FULL PWM quà tặng bạn gái quà tặng độc đáo quản trị doanh nghiệp quản trị kinh doanh quét led 7 đoạn Relay robocon Robot ROBOT DÒ ĐƯỜNG rút gọn mạch logic tổ hợp Sach Dien Tu Sản Phẩm Thú Vị Sản Phẩm Thương Mại Sáng tạo Short Smart Home SMD sơ đồ nguyên lý spi Sports Sử Dụng Sử Dụng Đồng Hồ sử dụng đồng hồ VOM sử dụng ngắt trong pic sự khác nhau Sức mạnh số Tải tài chính tài chính doanh nghiệp tài chính ngân hàng Tài Khoản Chia Sẻ Tài Liệu Tài Liệu 8051 tài liệu avr Tài liệu Điện Tử Tài Liệu Pic Tài liệu robocon tài liệu về ngân hàng Tài Liệu Vi Điều Khiển tailieuvn Tạo cổng Com ảo Tạo cổng nối tiếp ảo tạo dự án trong keil arm Tạo Project trong Vi Xử Lý ARM tạo thư viện altium designer tạo xung vuông Tạp chí Tạp Chí Hay tăng áp Tập lệnh AT Team Support TEAMPLATE PROTEUS Test thị trường tài chính Thiết Bị Thú Vị Thiết kế robot Thiết lập Fuse Bits Thiết Lập Pin Thuật Toán Thuật Toán Điều Khiển PID Thuật Toán Quine MCCluskey Thư viện Protues Thực Hành Thyristor Timer Timer/Counter Tin Học Chia Sẻ Tổ Chức Bộ Nhớ tổng quan về proteus 8 Transistor Tranzito Tranzitor Trao đổi học tập Travel Trình Biên Dịch Trình Dịch Trong Suốt Truyền Thông Nối Tiếp Không Đồng Bộ- UART truyền thông nối tiếp RS232 Tụ điện TUT - 8051 - ASM TUT - 8051 - KeilC tự hành Tự Học C Tự Học Lập Trình C Tý hon UART Update USB Ứng Dụng Led Quảng Cáo ứng dụng mạch khuếch đại thuật toán vẽ mạch in vẽ mạch nguyên lý VHDL Vi Điều Khiển Vi điều khiển - Ứng dụng vi điều khiển PIC Vi mạch số Vi Xử Lý Vi Xử Lý 8051 Vi Xử Lý 8086 Vi Xử Lý ARM Vi Xử Lý PIC Video Video Mach Điện Virtual Serial Port Driver VOM vxl Web Design xác định góc quay động cơ xử lý chuỗi

Như phamhoangvuong.com đã trình bày ở các bài học trước, khi bạn đã hiểu AVR, để thực hiện các ứng dụng, bạn có thể không nhất thiết phải luôn lập trình bằng Assembly(ASM). Ngôn ngữ cấp cao như C sẽ giúp cho bạn xây dựng các ứng dụng nhanh chóng và dễ dàng hơn, tuy nhiên không vì thế mà bạn “quên” ASM, lập trình bằng C kết hợp ASM là giải pháp hay nhất. Một chú ý là chúng ta chỉ sử dụng C để đơn giản hóa lập trình tính toán, cấu trúc điều khiển…lập trình C cho AVR không có nghĩa là bạn không cần biết cấu trúc và cách thức hoạt động  của chip. phamhoangvuong.com không có ý định nói về ngôn ngữ C ở đây nhưng chỉ giới thiệu một cách cơ bản nhất về cách viết chương trình cho AVR bằng C, cụ thể là C trong avr-gcc. Để có thể hiểu và viết những chương trình phức tạp hơn, bạn cần tự trang bị kiến thức về C, tài liệu này sẽ không giúp bạn phần đó. Tuy nhiên, nếu bạn chưa từng lập trình bằng C thì bạn cũng yên tâm đọc tài liệu này, vì ít ra phamhoangvuong.com sẽ giải thích những gì phamhoangvuong.com viết.
I. Một số khái niệm C cho AVR.
      Một chương trình C cho AVR thường bao gồm các thành phần như: chú thích (comments), biểu thức (expressions), câu lệnh (statements), khối (blocks), toán tử, cấu trúc điều khiển (Flow controls), hàm (functions)…
      Chú thích (comments): có 2 cách để tạo phần chú thích trong C là chú thích từng dòng bằng 2 dấu “//” như trong dòng đầu của đoạn ví dụ “//day la chu thich, khong duoc bien dich” hoặc chú thích block bằng cách kẹp block cần chú thích vào giữa /* ….*/ ví dụ:
/*
Ban co the type bat ky chu thich nao trong block nay
Ngay ca khi ban xuong dong
Phan chu thich thuong co mau chu la green
*/
      Tiền xử lí (preprocessor):  là một tiện ích của ngôn ngữ C, các preprocessor được trình biên dịch xử lí trước tất cả các phần khác, các preprocessor có chức năng tương tự các Directive trong ASM cho AVR.Các preprocessor được bắt đầu bằng dấu “#”, trong số các preprocessors trong ngôn ngữ C có hai preprocessors được sử dụng phổ biến nhất là#include và #define. Preprocessor #include chỉ định 1 file được đính kèm trong quá trình biên dịch (tương đương .INCLUDE trong ASM) và #define để định nghĩa 1 chuổi thay thế hoặc 1 macro. Xem các ví dụ sau:
#include "avr/io.h"  *đính kèm nội dung file io.h trong lúc biên dịch (file io.h nằm trong thư mục con avr của thư mục include trong thư mục cài đặt của WinAVR).*/
#define max (a,b)   ((a)>(b)? (a): (b))  /*định nghĩa một macro tìm số lớn nhất trong  2 số a và b, trong chương trình nếu bạn gọi x=max(2,3) thì kết quả thu được x=3.*/
      Biểu thức (Expressions):  là 1 phần của các câu lệnh, biểu thức có thể bao gồm biến, toán tử, gọi hàm…, biểu thức trả về 1 giá trị đơn. Biểu thức không phải là 1 câu lệnh hoàn chỉnh. Ví dụ: PORTB=val.
      Câu lệnh (Statement): thường là 1 dòng lệnh hoàn chỉnh, có thể bao gồm các keywords, biểu thức và các câu lệnh khác và được kết thúc bằng dấu “;”. Ví dụ: unsigned char val=1; val*=2; …là các câu lệnh.
      Khối (Blocks):  là sự kết hợp của nhiều câu lệnh để thực hiện chung 1 nhiệm vụ nào đó, khối được bao bởi 2 dấu mở khối “{“ và đóng khối “}”: ví dụ 1 khối:
while(1){      
      PORTB=val;
      _delay_loop_2(65000);
      val*=2;
      if (!val) val=1;      
}
      Toán tử (Operators):  là những ký hiệu báo cho trình biên dịch các nhiệm vụ cần thực hiện, các bảng bên dưới tóm tắt các toán tử C dùng cho lập trình AVR:
  • Bảng 1 các toán tử đại số: dùng thực hiện các phép toán đại số quen thuộc, trong đó đáng chú ý là các toán tử “++” (tăng thêm 1) và “--“ (bớt đi 1), chú ý phân biệt  y=x++  và y=++x, ví dụ ta có x=3 trong khi y=x++  nghĩa là gán x cho y rồi sau đó tăng x thêm 1, điều này không ảnh hưởng đến y (cuối cùng y=3, x=4) trong khi y=++x nghĩa là tăng x trước rồi mới gán cho y (cuối cùng y=x=4), tương tự cho các trường hợp của toán tử “--“ .

  • Bảng 2 Toán tử truy cập và kích thức: toán tử [] thường được sử dụng khi bạn dùng mảng trong lúc lập trình, phần tử thứ của mảng sẽ được truy xuất thông qua [i], chú ý mảng trong C bắt đầu từ 0.

  • Bảng 3 Toán tử Logic và quan hệ: thực hiện các phép so sánh và logic, thường được dùng làm điều kiện trong các cấu trúc điều khiển, chú ý toán tử so sánh bằng “==”, toán tử này khác với toán tử gán “=”, trong khi y = x nghĩa là lấy giá trị của x gán cho y thì (y== x) nghĩa là “nếu y bằng x”.

  • Bảng 4 Toán tử thao tác Bit (Bitwise operator): là các toán tử thực hiện trên từng bit nhị phân của các con số, các toán tử dịch trái “<<” và dịch phải ">>" rất thường được sử dụng khi xử lí số.

  • Bảng 5 các toán tử khác: là 1 số toán tử đặc biệt rất hay sử dụng nhưng chúng ta thường không để ý vì vai trò của chúng rất dễ nhận thấy. Đặc biệt chú ý toán tử “?:” là 1 toán tử rất đặc biệt của C so với các ngôn ngữ lập trình khác, “?:” là toán tử 3 ngôi duy nhất có thể dùng thay thế cho cấu trúc “if” đơn giản.

II. Cấu trúc điều khiển và hàm.
2.1 Cấu trúc điều khiển (Flow Controls).
      Các cấu trúc điều khiển biến ý tưởng của bạn thành hiện thực. Một số cấu trúc điều khiển cơ bản trong C như sau:
      “If (điều kiện) statement;”:  nếu điều kiện là đúng thì thực hiện statement theo sau, statement có thể được trình bày cùng dòng hoặc dòng sau điều khiển If. Điều kiện có thể là một biểu thức bất kỳ, có thể là sự kết hợp của nhiều điều kiện bằng các toán tử quan hệ AND (&&), OR (||)…Điều kiện được cho là đúng khi nó khác 0, ví dụ if (1) thì điều kiện hiển nhiên là đúng. Xét một vài ví dụ dùng cấu trúc if như sau:
      If (!val) val=1; nghĩa là nếu val bằng 0 thì chương trình sẽ gán cho val giá trị là 1,  “!” là toán tử NOT, NOT của một số khác 0 thì bằng 0, ngược lại, NOT của 0 thì thu được kết quả là 1. Trong ví dụ này, nếu val bằng 0 thì !val sẽ bằng 1, như thế điều kiện sẽ trở thành đúng và câu lệnh “val=1” được thực thi.
      If (x==1 && y==2) result=’A’; nghĩa là nếu x bằng 1 và y bằng 2 thì gán ký tự ‘A’ cho biến result. Trong ví dụ này, toán tử logic “&&” được sử dụng để “nối” 2 điều kiện lại, bạn hoàn toàn có thể sử dụng nhiều toán tử logic khác nếu cần thiết.
      Trong trường hợp bạn muốn thực thi nhiều câu lệnh cùng lúc nếu một điều kiện nào đó thỏa thì bạn cần đặt tất cả các câu lệnh đó trong 1 khối như bên dưới:
If (điều kiện) {
      Statement1;
      Statement2;
      
}
      “If (điều kiện ) statement1; else statement2; ”: nếu điều kiện đúng thì thực hiện statement1, ngược lại thực thi statement2.  Việc đặt các statement và else..trên cùng 1 dòng hay trên những dòng khác nhau đều không ảnh hưởng đến kết quả. Tương tự trường hợp trên, nếu có nhiều statements thì cần đặt chúng trong 1 khối.
If (điều kiện) {
      Statement1;
      Statement2;
      
}else {
      Statement1;
      Statement2;
      
}
      Ngoài ra, bạn cũng có thể đặt nhiều cấu trúc if…else… lồng vào nhau.
      Cấu trúc switch: trong trường hợp có nhiều khả năng có thể xảy ra cho 1 biểu thức (hay 1 biến), ứng với mỗi khả năng bạn cần chương trình thực hiện một việc nào đó, khi này bạn nên sử dụng cấu trúc switch. Cấu trúc này được trình bày như bên dưới.
switch (biểu thức) {
case hằng_số_1:
      các statement1;
break;
case hằng_số_2:
      các statement2;
break;

default:
      các statement khác;
}
      Hãy xét 1 ví dụ bạn kết nối 2 chip AVR với nhau, 1 chip làm Master sẽ ra các lệnh điều khiển chip Slave, chip Slave nhận mã lệnh từ Master và thực hiện các công việc được thoả hiệp trước. Giả sử mã lệnh được lưu trong biến Command, dưới đây là chương trình ví dụ cách xử lí của chip Slave ứng với từng mã lệnh.
switch (Command) {
case 1:
      PWM=255;
      ON_Motor();
      break;
case 2:
      PWM=0;
      OFF_Motor();;
      break;

default:
      Get_Cmd();
break;
}Ngoài ra, bạn cũng có thể đặt nhiều cấu trúc if…else… lồng vào nhau.
      Nếu Command=1, gán giá trị 255 cho biến PWM và gọi chương trình con ON_Motor(). Trong trường hợp này, break được sử dụng, break nghĩa là thoát khỏi cấu trúc điều khiển hiện tại ngay lập tức, như vậy sau khi thực hiện 2 lệnh, switch kết thúc mà không cần xét đến các trường hợp khác. Bây giờ, nếu Command=2, gán giá trị 0 cho biến PWM và gọi chương trình con OFF_Motor(), trong tất cả các trường hợp còn lại (default), thực hiện chương trình con Get_Cmd().
      “while (điều kiện ) statement1;”: là một cấu trúc lặp (Loop), ý nghĩa của cấu trúc while là khi điều kiện còn đúng thì sẽ thực hiện statement1 (hoặc các statements nếu chúng được đặt trong 1 khối {} như trong trường hợp của if được giới thiệu ở trên). Cẩn thận, bạn rất dễ rơi vào một vòng lặp “không lối thoát” với while nếu điều kiện luôn luôn đúng.
      “for (biểu_thức_1; biểu_thức_2; biểu_thức_3) statement;”: là một cấu trúc lặp khác, trong cấu trúc for, biểu_thức_1 thường được hiểu là khởi tạo, biểu_thức_2 là điều kiện và biểu_thức_3 là biểu thức được thực hiện sau. Cấu trúc for này tương đương với cấu trúc while sau: 
biểu_thức_1;
while (biểu_thức_2){
      statement;
      biểu_thức_3;
}
         Các biểu thức trong cấu trúc for có thể vắng mặt trong cấu trúc nhung các dấu “;” thì không được bỏ. Nếu bạn viết for( ; ; ) tương đương với vòng lặp vô tận while (1).
      Cấu trúc for thường được dùng để thực hiện 1 hay những công việc nào đó trong số lần nào đó, ví dụ bên dưới thực hiện xuất các giá trị từ 0 đến 200 ra PORTB, sau mỗi lần xuất sẽ gọi lệnh delay trong 65000 chu kỳ máy.
for (uint8_t  i=0; i<=200; i++){
PORTB=i;
_delay_loop_2(65000);
}
      Chú ý, bạn có thể thực hiện việc khai báo 1 biến (xem phần khai báo biến bên dưới) ngay trong cấu trúc for nếu biến lần đầu được sử dụng. Ví dụ trên được hiểu như sau: khai báo 1 biến i kiểu byte không âm, gán giá trị khởi đầu cho i=0 (chỉ thực hiện 1 lần duy nhất), kiểm tra điều kiện i<=200 (nhỏ hơn hoặc bằng 200), nếu điều kiện còn đúng, thực hiện 2 statements trong block {}, sau đó quay về để thực hiện i++ (tăng i thêm 1) rồi lại kiểm tra điều kiện i<=200 và quá trình lặp lại. Như thế đoạn code trong {} được thực thi khoảng 201 lần trước khi biến i bằng 201 và điều kiện i<=200 sai.
2.2 Hàm (Functions).
      Ngôn ngữ C bao gồm tập hợp của rất nhiều hàm, mỗi hàm thực hiện một chức năng cụ thể, các hàm trong C thường được thiết kết rất nhỏ gọn, để có các hàm phức tạp người dùng cần tự tạo ra. Hàm C cho AVR được định nghĩa trong thư viện avr-libc, ngoài các hàm C thông thường, avr-libc còn chứa rất nhiều các hàm riêng dùng riêng cho chip AVR, các hàm này được khai báo trong các file header riêng, để sử dụng hàm nào, bạn cần #include file header tương ứng (tham khảo tài liệu “avr-libc user manual” để biết thêm chi tiết, trong tài liệu này, khi cần sử dụng một hàm nào phamhoangvuong.com sẽ nói rõ file header cần thiết).
      Ví dụ: _delay_loop_2(65000) là một hàm được định nghĩa trong file “delay.h” (trong thư mục C:\WinAVR\avr\include\util), hàm này thực hiện việc delay khoảng 65000 chu kỳ máy. Có 4 hàm delay bạn có thể sử dụng sau khi include file đó là:
  • _delay_loop_1(uint8_t  __count) : delay theo một số lần chu kỳ máy nhất định (biến __count), số lượng chu kỳ delay là số 8 bit (từ 0 đến 255).
  • _delay_loop_2(uint16_t  __count) : delay theo một số lần chu kỳ máy nhất định (biến __count), số lượng chu kỳ delay là số 16 bit (từ 0 đến 65535).
    (Chú ý: thực chất 2 hàm delay trên được định nghĩa trong file header “delay_basic.h”).
  • _delay_us(double  __us): delay 1 microsecond.
  • _delay_ms(double  __ms): delay 1 milisecond.
      Chú ý: để dùng 2 hàm _delay_us và _delay_ms cần định nghĩa tần số xung clock trong Makefile (biến F_CPU), sử dụng 2 hàm này trực tiếp thường cho kết quả không như mong muốn, phamhoangvuong.com sẽ trình bày cách sử dụng 2 hàm này trong ví dụ bên dưới.
      Main:  một chương trình C cho AVR phải bao gồm 1 chương trình chính main, tất cả các nội dung chính sẽ được đặt bên trong chương trình chính. Cấu trúc chương trình chính có thể như sau:
int main(void){
      //noi dung chinh
      return 0; //gia tri tra ve cho chuong trinh chinh
}
      Trong đó, int là kiểu giá trị trả về của main, từ khóa void  nói rằng chương trình chính của chúng ta không cần bất kỳ tham số nào kèm theo.
      Còn rất nhiều các vấn đề liên quan đến C cho AVR, chúng ta sẽ tìm hiểu trong lúc viết các ví dụ cụ thể.
III. Ví dụ minh họa.
      Để minh họa các khái niệm và phương pháp lập trình C cho AVR, phamhoangvuong.com sẽ giải thích ví dụ quét LED viết bằng C mà chúng ta thực hiện trong bài hướng dẫn WinAVR. Đoạn code được trình bày trong  List 1.
List 1. ví dụ quét LED bằng C.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//file: main.c

#include 
#include 
unsigned char val=1;
int main(void){
      DDRB=0xFF; //xử dụng PORTD làm đường xuất dữ liệu
      while(1){
            PORTB=val;
            _delay_loop_2(65000);
            val*=2;
            if (!val) val=1;  
      }
      return 0;
}
      Trước hết là preprocessor đính kèm các file khi biên dịch, #include là đính kèm file header io.h, file này thực ra không phải là file chứa các thông tin về chip nhưng nó sẽ làm một nhiệm vụ trung gian là đính kèm 1 file khác tương ứng với biến MCU trong Makefile, ví dụ trong Makefile, MCU=atmega8 thì dòng “#include ” được thực thi, file iom8.hđược tự động đính kèm kèm vào và file iom8.h mới thực chất chứa các định nghĩa cho chip ATmega8 (các định nghĩa về địa chỉ thanh ghi, kích thước bộ nhớ,…). Điều này giúp bạn không cần nhớ hết tất cả các file header của từng chip AVR. Nếu “không an tâm”, bạn có thể thêm dòng  #include iom8.h sau  khi include io.h (điều này không thật sự cần thiết). Ngoài ra, mỗi lần include file io.h sẽ có 4 file header khác được tự động đính kèm là “avr/sfr_defs.h”, “avr/portpins.h”, “avr/common.h”, và  “avr/version.h”. Tóm lại bạn cần (hoặc phải) include file io.h và khai báo loại chip AVR trong file Makefile (dùng MFile, như hướng dẫn ở trên) là có thể an tâm viết chương trình C cho AVR.
      - Dòng thứ 4 include file header delay.h để sử dụng lệnh delay như đã đề cập ở trên.
      - Dòng 5 : khai báo 1 biến tên val trong bộ nhớ SRAM, kiểu của val là unsigned char là kiểu dữ liệu 8 bit không dấu có khoảng giá trị từ 0 đến 255. Biến val được dùng làm biến tạm để chứa giá trước khi xuất ra PORTB. Biến trong C được khai báo bằng cách đặt kiểu biến trước sau đó tên biến. Một số kiêu dữ liệu cơ bản trong C được tóm tắt trong bảng 6.
Bảng 6 các kiểu dữ liệu trong C.
Tên kiểu dữ liệu (Data type)
Số byte
Khoảng dữ liệu (Range)
char
1
–127 to 127 or 0 to 255
unsigned char
1
0 to 255
signed char
1
–127 to 127
int
2
–32,767 to 32,767
unsigned int
2
0 to 65,535
signed int
2
Như kiểu int
short int
2
Như kiểu int
unsigned short int
2
0 to 65,535
signed short int
2
Như kiểu short int
long int
4
–2,147,483,647 to 2,147,483,647
signed long int
4
Như kiểu long int
unsigned long int
4
0 to 4,294,967,295
long long int
8
–(263–1) to 263–1 (C99 only)
signed long long int
8
same as long long int (C99 only)
unsigned long long int
8
0 to 264–1 (C99 only)
float
4
6 digits of precision
double
8
10 digits of precision
long double
12
10 digits of precision
      Một số kiểu dữ liệu thông dụng nhất là char (1 byte), int (2 byte) và float. Từ khóa unsigned được thêm trước 1 kiểu dữ liệu nguyên để chỉ định các số nguyên dương, khi đó khoảng giá trị nguyên sẽ được tăng lên gần 2 lần. Ví dụ char chỉ các số nguyên từ -127 đến 127 thường được dùng để chỉ mã ASCII của các ký tự trong bảng mã ASCII, nhưng unsigned char sẽ bao gồm các số nguyên dương từ 0 đến 255 và thường được dùng khi làm việc với các thanh ghi 8 bit.
      Ngoài ra, avr-libc còn định nghĩa một số kiểu dữ liệu thay thế, chúng ta có thể dùng các kiểu dữ liệu này thay cho các kiểu thông thường, xem tóm tắt như bên dưới.

      Một khai báo uint8_t  val  tương đương usigned char val, sử dụng kiểu khai báo nào là do thói quen của người sử dụng. Chú ý là theo mặc định, một biến mới được khai báo theo cách thông thường như trên sẽ được đặt trong SRAM, như các bạn đã biết SRAM trong AVR tương đối nhỏ vì thế nên khai báo và sử dụng hợp lí biến, đừng khai báo quá nhiều biến nếu bạn không sử dụng hết, đừng khai báo kiểu biến quá lớn so với giá trị thật sử dụng, tuy nhiên cũng không được khai báo kiểu dữ liệu có kích thước quá nhỏ so với giá trị mà biến đó có thể vươn tới. Sử dụng bộ nhớ chương trình (flash program memory) để lưu trữ dữ liệu không đổi là một kỹ thuật khác để tiết kiệm bộ SRAM, phamhoangvuong.com sẽ đề cập vấn đề này trong 1 bài khác.
      Cuối cùng về việc khai báo biến, một biến có thể được gán giá trị khởi tạo ngay lúc khai báo như trong trường hợp của chúng ta, biến val=1 lúc được khai báo.
      -  Dòng 6 “int main(void){” bắt đầu chương trình chính.
      - Dòng 7: “DDRB=0xFF” gán giá trị hexadecimal 0xFF (11111111) cho thanh thi điều khiển của Port B, DDRB, Port B khi đó sẽ trở thành Port xuất
      -  Dòng 8 “while (1){”: bắt đầu 1 vòng lặp vô tận.
      -  Dòng 9 và dòng 10: xuất val ra PORTB và gọi lệnh delay.
      - Bạn cần chú ý 11 và 12, 2 dòng này có chức năng “xoay” giá trị của biến val để xuất ra PORTB tạo hiệu ứng xoay vòng. val*=2 được hiểu là val=val*2, đây là 1 kiểu viết thu gọn của C, nếu toán hạng thứ nhất và kết quả trả về là cùng 1 biến, chúng ta có thể bỏ bớt 1 tên biến và di chuyển toán tử về bên phải toán tử gán “=”. Ví dụ: i = i + 6 được rút gọn thành i + = 6.

      Như thế sau câu lệnh val*=2  giá trị của val được tăng lên 2 lần. Ý nghĩa thật sự của việc gấp đôi biến val là gì? Hãy nhìn vào giá trị nhị phân của val, lúc khai báo val, chúng ta gán cho val = 1 hay val = 00000001 (nhị phân), sau khi gấp đôi lần thứ nhất, val = 2=00000010, tiếp tục gấp đôi lần thứ hai, val = 4=00000100…có thể bạn đã thấy chuyện gì xảy ra? Đây là câu trả lời: “trong thao tác với số nhị phân, gấp đôi một số nghĩa là di chuyển số đó sang trái 1 vị trí”…Quá trình gấp đôi sẽ tiếp diễn đến lúc val = 128=10000000, nếu tiếp tục gấp đôi, bạn nghĩ val = 256 ? Tuy nhiên bạn nhớ rằng chúng ta đã khai báo biến val có kiểu unsigned char (8 bits), trong khi đó 256=100000000 (9 bits), nếu gán val = 256, chỉ có 8 bits thấp (00000000) của 256 sẽ được gán cho val, kết quả là val = 0. Nói một cách khác, sau khi val=128, val = 0, câu lệnh: “ if (!val) val=1; ” sẽ giúp cho quá trình quét lặp quay lại từ đầu nếu  val = 0. Mọi thứ đã rõ.
      Cuối cùng vì chương trình chính của chúng ta có kiểu int (int main…) chúng ta cần “trả về” một giá trị nào đó, “return 0;” thực hiện trả về 0 (bạn có thể trả về giá trị nào tùy ý). 
Nguồn :hocavr.com
Sáng Lập Bởi:
phamhoangvuong.com

nguồn: hocavr.com

Code AVR - C, học AVR, Làm quen AVR, Lập Trình AVR, Mã AVR - C, tài liệu avr, Tài Liệu Vi Điều Khiển,V

Đăng nhận xét

Author Name

{picture https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN0PUWA2genMqX3Sm26mBTX_30OJgDenoIi4K6BR-E1vl3nI7LALp0X759QZgzqrMcGBB7jEbdZnubJbp4n2ZZ22KT196CWCg9DLs3MfEivocdmkjZEPEn-A42hyphenhyphen9dmsca0VIDQr_LjqM/s512-Ic42/pham-van-ngoc-anh.jpg}

Tôi là Ngọc Anh. Tôi đến từ Nghệ An. Tôi tốt nghiệp một trường đại học tại Sài Gòn. Hiện tôi đang phát triển công ty riêng. Liên lạc với tôi qua:

{facebook https://www.facebook.com/phamvanngocanh}
{twitter https://twitter.com/nghiphong1993}
{google https://plus.google.com/+dientuchiase/posts}
{youtube https://www.youtube.com/channel/UCeJKhA_goBNFmDw6RKNtmYQ}

Biểu mẫu liên hệ

Tên

Email *

Thông báo *

Được tạo bởi Blogger.