Xem thêm

C trong lập trình nhúng: Tổng quan về lập trình C trong vi điều khiển

Huy Erick
Lập trình C trong vi điều khiển có những đặc điểm riêng so với lập trình C thông thường. Trong bài viết này, chúng ta sẽ tìm hiểu một số khái niệm và ví dụ...

lập trình c trong vi điều khiển có những đặc điểm riêng so với lập trình C thông thường. Trong bài viết này, chúng ta sẽ tìm hiểu một số khái niệm và ví dụ cụ thể về việc sử dụng C trong lập trình nhúng.

Mục tiêu

  • Các thành phần và cú pháp của ngôn ngữ C
  • Các kiểu dữ liệu cơ bản như char, short, long (unsigned và signed)
  • Tìm hiểu về hàm main và cách sử dụng nó trong chương trình
  • Hiểu về biến và biểu thức
  • Sử dụng printf và scanf cho việc nhập/ xuất dữ liệu
  • Hiểu điều kiện if và while và cách sử dụng chúng trong câu lệnh điều kiện
  • Hiểu về hàm và cách sử dụng chúng với đầu vào và đầu ra

Giới thiệu về C

C là một ngôn ngữ lập trình cấu trúc. Trước khi bắt đầu viết code, chúng ta cần xác định rõ mục tiêu và các bước cần thực hiện để đạt được mục tiêu đó.

Flowchart là một công cụ quan trọng trong việc thiết kế phần mềm. Nó giúp chúng ta hình dung về một chương trình giống như một bản thiết kế cho ngôi nhà. Trước khi bắt đầu lập trình, chúng ta cần xác định công việc cần thực hiện và các bước để thực hiện công việc đó.

Trong lập trình vi điều khiển hoặc các hệ thống lớn, chúng ta cần có một cấu trúc rõ ràng cho chương trình. Chương trình cấu trúc trong C thường có 3 dạng cơ bản: tuần tự, quyết định, lặp lại và ngắt.

Flowchart

Flowchart là một công cụ thường được sử dụng trong quá trình học môn lập trình C. Nó giúp chúng ta biểu diễn các bước thực hiện của chương trình một cách hợp lý. Có 7 khối thông dụng trong flowchart như hình bên trên:

  • Entry point: Bắt đầu chương trình
  • Conditional: Cấu trúc rẽ nhánh if
  • Input/ Output: Đầu vào/ đầu ra của hệ thống
  • Process: Quá trình xử lý
  • Connectors: Kết nối giữa các bước trong thuật toán
  • Function: Mô tả một hàm, subroutine hoặc procedure
  • Exit point: Kết thúc chương trình

Thiết kế máy nướng bánh

Trong ví dụ này, chúng ta sẽ sử dụng flowchart để thiết kế thuật toán điều khiển máy nướng bánh.

Flowchart bên trên cho thấy cách hoạt động của máy nướng bánh như sau:

  • Có một nút để khởi động máy. Nếu người dùng nhấn nút này, máy sẽ nướng bánh.
  • Trong quá trình nướng, máy sẽ kiểm tra nhiệt độ hiện tại. Nếu nhiệt độ nhỏ hơn nhiệt độ làm chín bánh, máy sẽ tăng nhiệt độ. Khi nhiệt độ vượt quá nhiệt độ làm chín, máy sẽ ngừng tăng nhiệt.

Trước khi viết một chương trình, chúng ta cần thực hiện ít nhất 4 bước:

  1. Xác định đầu vào/đầu ra và cách làm việc của hệ thống.
  2. Xác định các dữ liệu cần thiết và cách thu thập và thay đổi chúng.
  3. Phát triển thuật toán và chuỗi hoạt động sử dụng flowchart hoặc pseudo code.
  4. Gỡ lỗi để cải thiện chất lượng và hiệu suất của code.

Thuật ngữ thường gặp

Trước khi nói về cấu trúc của C, hãy tìm hiểu một chút về mối quan hệ của C với vi điều khiển và cách để chúng ta đưa code C vào vi điều khiển.

  • Compiler (trình biên dịch): Chuyển ngôn ngữ bậc cao (C) thành mã máy có thể đọc được. Ví dụ: C code (z = x+y;) → Assembly code (ADD R2,R1,R0) → Machine code (0xEB010200)
  • Assembler: Chuyển ngôn ngữ assembly thành mã máy. Ví dụ: Assembly code (ADD R2,R1,R0) → Machine code (0xEB010200)
  • Interpreter (trình thông dịch): Thực hiện trực tiếp trên ngôn ngữ bậc cao. Ví dụ: Khi người dùng gõ một lệnh, interpreter sẽ thực thi lệnh đó ngay lập tức.
  • Linker: Kết nối các thành phần của phần mềm lại với nhau. Ví dụ: Chương trình uart cần 3 file để compile và link là startup.s, uart.c, main.c
  • Loader: Đưa object code vào bộ nhớ. Trong hệ thống nhúng, loader thường đưa object code vào trong flash ROM.
  • Debugger: Thiết bị dùng để đảm bảo hệ thống hoạt động chính xác và là công cụ quan trọng để gỡ lỗi và quan sát thông tin.

Cấu trúc và cách tổ chức

Cấu trúc và cách tổ chức chương trình trong C có sự tự do và linh hoạt. Dưới đây là 3 phong cách khác nhau cho cùng một chương trình trả về một số bất kỳ:

Style 1

unsigned long M=1;  unsigned long Random(void){     M=1664525*M+1013904223;     return(M); }

Style 2

unsigned long M=1;  unsigned long Random(void){     M = 1664525*M +1013904223;      return(M); }

Style 3

unsigned long M=1;  unsigned long Random(void){     M = 1664525*M+1013904223;      return(M); }

Chương trình trên sử dụng biến M để tính toán một số bất kỳ. Chúng ta có thể thấy rằng có nhiều cách để viết chương trình theo phong cách khác nhau. Khi viết code, chúng ta có thể tự do lựa chọn phong cách phù hợp.

Các dấu chấm câu cũng rất quan trọng trong C. Dấu chấm câu thường gặp và cú pháp sử dụng chúng như sau:

  • ;: Kết thúc câu lệnh
  • :: Định nghĩa nhãn
  • ,: Phân chia các thành phần trong một list
  • (): Đánh dấu bắt đầu và kết thúc của một chuỗi parameter
  • {}: Đánh dấu bắt đầu và kết thúc của một compund statement
  • []: Đánh dấu bắt đầu và kết thúc của một array index
  • "": Đánh dấu bắt đầu và kết thúc của một chuỗi
  • '': Đánh dấu bắt đầu và kết thúc của một ký tự
  • <>: Đánh dấu bắt đầu và kết thúc của một thư viện
  • .: Dùng để truy cập các phần tử trong một cấu trúc

Những dấu chấm câu này rất quan trọng trong C, và việc hiểu rõ về chúng sẽ giúp tránh những lỗi thường gặp trong quá trình lập trình.

Cấu trúc chương trình C

Một chương trình C thường có 4 phần:

Phần 0: Documentation Section

Phần này mô tả thông tin về nội dung của file, bao gồm mục đích viết file, người viết, thời gian viết và các thông tin cập nhật.

Phần 1: Pre-processor Directives Section

Phần này xác định các thư viện và các yêu cầu trước khi biên dịch chương trình. Các thư viện được đưa vào chương trình bằng cách sử dụng các từ khóa #include. Ví dụ: #include để sử dụng thư viện chuẩn của hệ điều hành, hoặc #include "uart.h" để sử dụng thư viện do người dùng tự viết.

Phần 2: Global Declarations Section

Phần này khai báo các biến toàn cục và các hàm sẽ được sử dụng trong chương trình.

Phần 3: Functions Section (MAIN)

Phần này chứa chương trình chính của chương trình. Mỗi chương trình C chỉ có một hàm main, đó là nơi chương trình bắt đầu thực hiện.

Trước khi thực hiện chương trình, chúng ta cần khai báo các biến và các hàm sẽ được sử dụng trong chương trình. Chúng ta cũng cần xác định các hoạt động mà chương trình sẽ thực hiện.

Function

Hàm là một chuỗi các hoạt động trong chương trình. Nó có thể có một hoặc nhiều tham số và một giá trị trả về. Chúng ta cần khai báo và định nghĩa các hàm trước khi sử dụng chúng trong chương trình.

Function Syntax

Một hàm được xác định bởi tên, tham số đầu vào, tham số đầu ra và kiểu dữ liệu của nó. Chúng ta cần định nghĩa chính xác các hoạt động được thực thi bởi hàm khi nó được gọi.

Function Parameters

Ví dụ: Hàm sum trong chương trình dưới đây có 2 input và 1 output. Một điểm quan trọng là sau khi các hoạt động trong chương trình con được thực hiện, chúng sẽ trả lại vị trí ban đầu nơi chương trình con được gọi.

unsigned long sum(unsigned long a, unsigned long b){     return a + b; }

Vòng lặp và câu lệnh điều kiện

Chúng ta cũng có thể sử dụng các vòng lặp và câu lệnh điều kiện trong chương trình C. Ví dụ:

unsigned long side; unsigned long area;  while(side != 0){     printf("Enter the room side (0 to quit): ");     scanf("%ld", &side);      if(side > 0){         area = Calc_Area(side);         printf("The area with side %ld m is %ld square meters\n", side, area);     } else {         printf("Invalid input! Size cannot be negative\n");     } }

Trong ví dụ trên, chúng ta sử dụng vòng lặp while để thực hiện việc thực hiện các tính toán với giá trị nhập vào từ bàn phím. Chúng ta sử dụng câu lệnh if để kiểm tra và xử lý các giá trị không hợp lệ.

1