Arduino – chào thế giới

Bất kỳ một chương trình học nào cũng cần nên bắt đầu một cách từ từ. Bởi vì thời điểm này chúng ta đều mới bắt đầu, nhiều khái niệm, kiến thức về lĩnh vực này gần như không có nhiều. Helloworld giúp các bạn có thể nắm được các kiến thức cơ bản về điện tử, làm sao để biên dịch, nạp được chương trình trong Arduino, cũng như nắm được một số kiến thức về kiến trúc chương trình của Arduino. Nội dung sẽ tìm hiểu ở phần này như sau:

  • Giới thiệu các khái niệm, linh kiện điện tử cơ bản.

  • Blink LED.

  • Nút nhấn và các ứng dụng.

  • Sử dụng chức năng PWM trong Arduino.

  • Đọc dữ liệu Analog từ cảm biến.

Giới thiệu một số khái niệm và linh kiện điện tử cơ bản

Trong phần này chúng ta sẽ tìm hiểu về 1 số khái niệm cũng như 1 số linh kiện điện tử cơ bản. Các kiến thức này cũng đã được trình bày chi tiết ở chương trình vật lí bậc phổ thông. Mỗi khái niệm hay linh kiện sẽ có những video giúp chúng ta dễ hiểu hơn những khái niệm cũng như cách hoạt động của các linh kiện điện tử thông dụng.

Điện áp, dòng điện và điện trở

Điện áp

Điện áp hay còn gọi là hiệu điện thế (từ tiếng Anh là voltage) là sự chênh lệch về điện áp giữa 2 điểm, nó là công thực hiện được để di chuyển một hạt điện tích trong trường tĩnh điện từ điểm này đến điểm kia. Hiệu điện thế có thể đại diện cho nguồn năng lượng (lực điện), hoặc sự mất đi, sử dụng, hoặc năng lượng lưu trữ (giảm thế).

voltage
Figure 1. Hình ảnh minh họa hiệu điện thế sinh ra dòng điện tương ứng với dòng chảy của nước trong ống dẫn.

Dòng điện

Dòng điện (tiếng Anh: electric current) là dòng chuyển dịch có hướng của các hạt mang điện. Trong mạch điện, các hạt mang điện phần lớn là các electron chuyển động bên trong dây dẫn. Kim loại là chất dẫn diện phổ biến nhất, kim loại có hạt nhân mang điện tích dương không thể di chhuyển, chỉ có các electron tích điện âm có khả năng di chuyển tự do trong vùng dẫn, do đó, trong kim loại các electron là các hạt mang điện.

Chiều dòng điện được quy ước là chiều đi từ cực dương qua dây dẫn và các thiết bị điện đến cực âm của nguồn. Do dòng điện được qui ước là dòng chuyển dời có hướng của các điện tích dương, chính vì thế, trong mạch điện với dây dẫn kim loại, các electron tích điện âm dịch chuyển ngược chiều với chiều của dòng điện trong dây dẫn.

Sự chuyển dịch có hướng của các điện tích sinh ra do tác động của điện trường gây ra bởi hiệu điện thế. Do đó, có thể hiểu là điện áp sinh ra dòng điện trong một mạch điện, hay nói đơn gỉan là “điện áp có trước dòng điện” trong mạch điện.

current
Figure 2. Hình ảnh minh họa hiệu điện thế sinh ra dòng điện trong mạch điện (Nguồn Assignment Point)

Chúng ta có thể xem giải thích về dòng điện và điện áp theo cách dễ hiểu hơn với một số video:

Điện trở

Điện trở (tiếng Anh: electric resistance) là một đại lượng đặc trưng cho khả năng cản trở dòng điện của một vật. Đơn vị của điện trở là Ω. Khái niệm điện trở của vật xuất phát từ định luật Ohm.

Điện trở gồm 2 tiếp điểm kết nối, thường được dùng để hạn chế cường độ dòng điện chạy trong mạch, điều chỉnh mức độ tín hiệu, dùng để chia điện áp, kích hoạt các linh kiện điện tử chủ động như transistor và có trong rất nhiều ứng dụng khác.

resistor
Figure 3. Hình ảnh của điện trở trong thực tế.

Định luật Ohm (Ohm’s law)

Đây là 1 định luật cơ bản nhưng rất quan trọng trong lĩnh vực điện, điện tử. Định luật này đề cập đến mối quan hệ giữa dòng điện, điện áp và điện trở. Tên định luật được đặt theo nhà phát minh ra nó, nhà vật lí nổi tiếng người Đức, Georg Simon Ohm (1789–1854).

Phát biểu định luật:

Cường độ dòng điện chạy qua dây dẫn tỉ lệ thuận với hiệu điện thế đặt vào 2 đầu dây dẫn và tỉ lệ nghịch với điện trở của dây dẫn.

Công thức của định luật Ohm:

ohm law image

Trong đó:

  • V: Ký hiệu của điện áp (Voltage).

  • I: Ký hiệu của dòng điện (Current).

  • R: Ký hiệu của điện trở (Resistor).

Ký hiệu của dòng điện là I bởi vì nó lấy chữ cái đầu của từ Intensity, có nghĩa là cường độ – đại lượng đặc trưng của dòng điện.

Một hình ảnh minh họa về định luật Ohm:

ohm law
Figure 4. Hình ảnh minh họa định luật Ohm (Nguồn: www.build-electronic-circuits.com)

Một video giải thích về định luật Ohm: https://www.youtube.com/watch?v=iLzfe_HxrWI

Tụ điện

capacitor
Figure 5. Hình ảnh các loại tụ điện trong thực tế.

Khái niệm

Tụ điện là linh kiện điện tử gồm 2 vật dẫn đặt gần nhau. Mỗi vật dẫn đó gọi là một bản của tụ điện. Khoảng không gian giữa hai bản có thể là chân không hay bị chiếm bởi một chất điện môi nào đó.

Tụ điện là một linh kiện được sử dụng rất phổ biến và gần như không thể thiếu trong các mạch điện tử, mỗi tụ điện đều có một công dụng nhất định như lọc nhiễu cho mạch, tạo dao động, truyền dẫn tín hiệu,…

Các thông số đặc trưng

  • Điện dung: Đại diện cho khả năng tích điện của tụ. Đơn vị là Fara (F).

  • Điện áp làm việc: Đó là giá trị điện áp cao nhất mà tụ điện có thể chịu được, thông thường giá trị này sẽ được ghi trên thân của tụ điện (nếu tụ đủ lớn). Nếu giá trị điện áp trên tụ lớn hơn giá trị điện áp làm việc thì lớp điện môi bên trong tụ điện sẽ bị đánh thủng và gây ra sự chập tụ, nổ tụ. Hiện tượng này khá nguy hiểm nên chúng ta cần cẩn thận khi chọn tụ điện cho mạch điện của mình.

  • Nhiệt độ làm việc: Đó là nhiệt độ ở vùng đặt tụ điện trong mạch điện. Tụ điện nên được chọn với nhiệt độ làm việc cao nhất của nơi chúng ta đặt tụ điện phải cao hơn nhiệt độ này.

Để hiểu rõ hơn về cách hoạt động của tụ điện, có thể tham khảo đường dẫn https://www.youtube.com/watch?v=5hFC9ugTGLs

Cuộn cảm

inductors
Figure 6. Hình ảnh về cuộn cảm trong thực tế (Nguồn: www.talkingelectronics.com)

Khái niệm

Cuộn cảm (tiếng Anh là coil hay inductor) là cuộn dây bao gồm nhiều vòng dây dẫn điện quấn quanh một lõi vật liệu từ. Dựa vào hiện tượng cảm ứng điện từ và hiện tượng từ hóa vật liệu từ mà người ta sử dụng cuộn cảm cho các mục đích khác nhau như làm phần ứng (stator) trong các máy phát điện xoay chiều, lọc nhiễu trong các mạch điện tử, tạo ra các nam châm điện, các công tắc điện tử, …​

Mỗi cuộn cảm có một độ tự cảm (hay hệ số tự cảm hoặc từ dung), kí hiệu là L, đo bằng đơn vị Henry (H) đặc trưng cho khả năng sinh suất điện động cảm ứng và tích lũy năng lượng điện từ.

Để hiểu rõ hơn về cách hoạt động và chức năng của cuộn cảm, chúng ta có thể tham khảo đường dẫn https://www.youtube.com/watch?v=NgwXkUt3XxQ

Breadboard

Breadboard là 1 dụng cụ giúp kết nối các thiết bị điện tử lại với nhau thông qua các lỗ cắm. Hình ảnh của breadboard cũng như cách hoạt động của nó được mô tả ở hình bên dưới:

breadboard
Figure 7. Hình ảnh của Breadboard.

Chớp tắt bóng LED

Kiến thức

LED là chữ viết tắt của Light Emitting Diodes, nó là bóng bán dẫn có thể phát sáng với màu sắc khác nhau tùy thuộc vào chất liệu bán dẫn. Để điều khiển được bóng LED cần cung cấp mức điện áp chênh lệch giữa cực âm và cực dương của bóng LED cao hơn mức điện áp Vf (datasheet), thường là 3.2VDC, và dòng điện nhỏ hơn mức chịu đựng của nó, thường là 15mA.

Chúng ta có thể hiểu rõ hơn cách hoạt động của LED tại đường dẫn https://www.youtube.com/watch?v=BH9LI973H8w

led symbol
Figure 8. Ký hiệu LED trên mạch điện. (Anode +, Cathode -)

Mạch có thể chạy được như sau:

led
Figure 9. Hình ảnh 1 mạch điện đơn giản của LED.
Điện trở giúp hạn chế dòng điện qua LED, để nó ở trạng thái hoạt động bình thường.

Đấu nối

Trên board IoT Maker UnoX có sẵn 1 LED kết nối với chân D2 của chip Atmega328 (chân số 3 trên board IoT Maker UnoX) nhằm debug chương trình.

led pin
Figure 10. Hình ảnh LED trên board IoT Maker UnoX.

Sử dụng dây micro USB để cấp nguồn và nạp chương trình cho board IoT Maker UnoX.

connectPC
Figure 11. Kết nối board IoT Maker UnoX với máy tính.

Mở phần mềm Arduino để tạo sketch và viết source code, tham khảo thông tin về [select-arduino-board][introduce-IoT-Arduino-Uno-board].

Có 2 phương pháp để điều khiển chớp, tắt LED được giới thiệu ở mục này đó là dùng hàm delay() hoặc dùng định thời với hàm millis().

Mã nguồn chớp tắt dùng Delay

Cách hoạt động chương trình được giải thích trong source code.

#define pinLed  3 // Định nghĩa pinLed là chân số 3.

void setup()      // Hàm setup() được gọi 1 lần duy nhất khi bật nguồn hoặc reset board
{
  pinMode(pinLed, OUTPUT);    // Cấu hình chân pinLed  là ngõ ra.
}


void loop() { // Hàm loop() sẽ được gọi liên tục khi chương trình hoạt động.

  digitalWrite(pinLed, HIGH); // Bật Led (HIGH - có nghĩa là mức điện áp 5VDC)
  delay(1000);                // Chờ 1000 mili giây  = 1s
  digitalWrite(pinLed, LOW);  // Tắt Led (LOW có nghĩa là mức điện áp 0VDC)
  delay(1000);                // Chờ 1000 mili giây  = 1s
}

Giải thích về 2 hàm pinMode() và digitalWrite() tại [pinMode-digitalWrite]

Mã nguồn chớp tắt dùng định thời

Khi thực hiện chương trình có sử dụng hàm delay(), vi điều khiển phải chờ cho đến khi hết thời gian delay mới thực hiện các tác vụ khác, thời gian delay nhỏ thì không sao, tuy nhiên nếu giá trị này lớn sẽ làm ảnh hưởng đến các tác vụ khác khi chạy cùng thời điểm, làm tăng độ trễ khi thực thi chương trình hoặc làm cho chương trình chạy không chính xác, việc dùng định thời với hàm millis() sẽ khắc phục tình trạng này.

#define pinLed  3     // Định nghĩa pinLed là chân số 3.

int ledState = LOW;   // khai báo biến lưu trạng thái của LED
unsigned long previousMillis = 0;
const long interval = 1000;

void setup()
{
  pinMode(pinLed, OUTPUT);
}

void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (ledState == LOW)
      ledState = HIGH;  // Đổi trạng thái
    else
      ledState = LOW;   // Đổi trạng thái
    digitalWrite(pinLed, ledState);
  }
}

Giải thích code

  • Biến ledState nhằm lưu trữ trạng thái của LED tại thời điểm hiện tại.

  • Biến interval là giá trị của 1 bước thời gian tính theo ms.

  • Lúc đầu giá trị previousMillis = 0; hàm millis() đã bắt đầu hoạt động và đếm thời gian, nó trả về số mili giây từ khi board được cấp nguồn hoặc reset board.

  • Lệnh currentMillis = millis() sẽ gán giá trị của biến curentMillis bằng với giá trị hiện tại của hàm millis() trả về. Nếu thời gian hiện tại - thời gian bắt đầu > interval, chương trình sẽ thực hiện 2 việc:

  • previousMillis = curentMillis nhằm reset giá trị đếm, để bắt đầu tính lại thời gian (chú ý rằng millis() vẫn tiếp tục chạy và biến curentMillis vẫn đang được gán giá trị của hàm millis()).

  • Đổi trạng thái của LED (nếu đang mức LOW thì chuyển sang HIGH).

Việc bật tắt LED chỉ thực hiện khi currentMillis – previousMillis >= interval, trong khoảng thời gian khác thì ta có thể thực thi các tác vụ khác của chương trình.
Chúng ta có thể tìm hiểu chi tiết về hàm millis() tại đường dẫn https://garretlab.web.fc2.com/en/arduino/inside/arduino/wiring.c/millis.html

Nút nhấn

Kiến thức

Nút nhấn sẽ giúp khởi động 1 hành động nào đó khi cần thiết. Những ứng dụng thực tế hầu như đều cần những kích hoạt từ bên ngoài thông qua các loại nút nhấn như nút nhấn cảm ứng, nút nhấn nhấn lưu trạng thái on/off, nút nhấn nhiều trạng thái…​ Trong phần này, chúng ta sẽ tìm hiểu những vấn đề về sử dụng nút nhấn thông qua các ví dụ mẫu. Các loại nút nhấn trong thực tế như hình bên dưới:

buttons image
Figure 12. Hình ảnh về các loại nút nhấn trong thực tế.

Với nút nhấn không gĩư trạng thái, khi nhấn nút và gĩư thì sẽ cho dòng điện chạy qua. Ngược lại, khi nhả hoặc không nhấn sẽ không cho dòng điện chạy qua. Nguyên lí hoạt động của nút nhấn không gĩư trạng thái như hình dưới:

button circuit 1
Figure 13. Mạch nguyên lí của nút nhấn không gĩư trạng thái.

Chớp, tắt LED sử dụng nút nhấn

Yêu cầu

Nhấn nút thì đèn LED sáng, không nhấn nút đèn LED sẽ tắt.

Linh kiện cần dùng

Đấu nối

Trên board IoT Maker UnoX đã có sẵn nút nhấn kết nối với chân D8 nên không cần đấu nối thêm nút nhấn.

buttonPin
Figure 14. Hình ảnh sơ đồ nguyên lí và nút nhấn thực tế trên board.

Điện trở kéo

Trong hình đấu nối của nút nhấn trên board IoT Maker UnoX có điện trở R12 nối lên nguồn. Đây được gọi là điện trở kéo lên. Điện trở kéo lên nguồn, hoặc kéo xuống ground (mass) được sử dụng rất thường xuyên trong vi điều khiển hoặc trong các mạch số (digital circuit).

Với vi điều khiển, 1 chân được cấu hình là INPUT (ngõ vào), nếu không có thiết bị hay mạch điện nào kết nối với nó. Khi vi điều khiển đọc trạng thái của chân đó thì chúng ta không xác định mức điện áp của nó được bởi nó có thể ở mức HIGH hoặc mức LOW, thuật ngữ thường được sử dụng để diễn tả trạng thái này là floating (trôi nổi).

Để khắc phục hiện tượng này, chúng ta sẽ kết nối chân này với 1 điện trở kéo lên nguồn (pull-up) hoặc 1 điện trở kéo xuống ground hay mass (pull-down) để đảm bảo chân đó chỉ ở 1 trong 2 trạng thái, hoặc HIGH, hoặc LOW.

Trên thực tế, điện trở kéo lên (pull-up) thường được sử dụng hơn so với điện trở kéo xuống (pull-down).

resistor pullup
Figure 15. Hình ảnh mạch điện khi sử dụng điện trở kéo lên.

Như vậy, khi không nhấn button, trạng thái của pin sẽ ở mức HIGH và khi button được nhấn thì trạng thái sẽ ở mức LOW.

Nếu mắc mạch điện như trên mà không dùng điện trở kéo thì sẽ xảy ra hiện tượng ngắn mạch.

Thông thường, giá trị điện trở kéo nằm trong khoảng 4.7KOhm đến 10KOhm là phù hợp.

Source code

const int buttonPin = 8;  //  Chân kết nối với nút nhấn trên board
const int ledPin =  3;    //  Chân kết nối với LED trên board
int buttonState = 0;      //  Biến đọc trạng thái của nút nhấn.

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(115200);
  Serial.println("init serial");
}

void loop()
{
  buttonState = digitalRead(buttonPin); //  Đọc trạng thái của nút nhấn.

  if (buttonState == LOW) {             //  Kiểm tra, nếu button đã được nhấn
    digitalWrite(ledPin, HIGH);         //  Bật LED
    Serial.println("PRESSED, LED ON");  //  In ra màn hình Serial chữ PRESSED, LED ON
  } else {
    digitalWrite(ledPin, LOW);
    Serial.println("NOTHING, LED OFF");
  }
}

Giải thích source code

  • Lệnh const int buttonPin = 8 khai báo chân số 8 được kết nối với button trên board, từ khóa const để chỉ rằng đây là 1 biến không thể thay đổi, thường thì nó được dùng để định nghĩa các chân kết nối hoặc các biến mà người dùng không muốn thay đổi giá trị của biến đó trong chương trình.

  • Lệnh Serial.begin(115200) nhằm khởi tạo giao tiếp Serial của vi điều khiển, giá trị 115200 là tốc độ truyền nhận dữ liệu.

  • Lệnh Serial.println("init serial") Nhằm in ra chữ init serial trên Serial monitor của Arduino IDE. Chúng ta sẽ tìm hiểu kĩ hơn về giao tiếp Serial ở chương tiếp theo [USB_Serial_communication]

Kết quả

  • Khi nhấn Button trên board IoT Maker UnoX thì LED debug trên board sẽ sáng. Không nhấn sẽ tắt.

  • Trên Serial monitor hiện ra dòng chữ HIGH khi nhấn nút và LOW khi không nhấn nút.

press button result
Figure 16. Hình ảnh trên Serial terminal của Arduino IDE

Chớp, tắt LED và chống dội phím khi nhấn (switch debouncing)

Một số board mạch khác, khi dùng nút nhấn, chúng ta nhận thấy có vài lần chương trình in ra dòng chữ “PRESSED, LED ON” và “NOTHING, LED OFF” xen kẽ nhau như khung màu vàng ở hình bên trên, nguyên nhân của hiện tượng này được giải thích như sau:

  • Nút nhấn là 1 linh kiện cơ khí, tại thời điểm bắt đầu nhấn nút, các tiếp điểm cơ khí tiếp xúc với nhau tạo ra sự nhiễu điện áp. Mặc dù chúng ta đã nhấn nút, tuy nhiên khi tiến hành đọc trạng thái của chân kết nối với nút nhấn, giá trị điện áp có lúc HIGH, có lúc LOW. Hiện tượng này được gọi là SWITCH BOUNCING.

  • Hiện tượng này diễn ra rất nhanh và mắt thường không nhìn thấy được, tuy nhiên vi điều khiển có tốc độ xử lí lệnh rất nhanh, nếu sử dụng serial terminal ta có thể thấy kết quả của hiện tượng này. Ngoài ra, chúng ta có thế sử dụng máy Oscilloscope để thấy rõ kết quả thực tế:

switch boucing
Figure 17. Một kết quả đo trên máy Oscilloscope mô tả hiện hiện Switch boucing(Nguồn www.pololu.com)
Nếu không khắc phục hiện tượng này, nó có thể làm hỏng chương trình của bạn.

Có 2 phương pháp để khắc phục tình trạng này đó là:

  • Sử dụng bằng phần cứng: Mắc thêm tụ điện song song với nút nhấn. Bình thường, tụ điện được nối với VCC và GND nên ở trạng thái tích lũy năng lượng (charge). Khi nhấn nút, tụ điện sẽ chuyển sang chế độ giải phóng năng lượng (discharge), giá trị điện áp tại chân kết nối với nút nhấn sẽ giảm 1 cách từ từ xuống 0V, việc làm chậm quá trình giảm điện áp này sẽ ngăn ngừa hiện tượng switch bouncing. Nút nhấn trên board IoT Maker UnoX có sử dụng chống dội phím bằng phần cứng này.

  • Sử dụng bằng phần mềm: Cũng dựa trên cách tạo 1 thời gian trễ nhất định (delay) đồng thời kiểm tra trạng thái trước đó của nút nhấn để có kết quả chính xác. Source code khi sử dụng phần mềm mô tả như bên dưới:

const int buttonPin = 8;  //  Chân kết nối với button trên board Iotmaker Uno X
const int ledPin =  3;    //  Chân kết nối với LED trên board
int ledState = HIGH;          //  Biến lưu trạng thái hiện tại của chân kết nối đến LED
int buttonState;              //  Biến lưu trạng thái hiện của nút nhấn
int lastButtonState = HIGH;   //  Biến lưu trạng thái trước đó của nút nhấn.

unsigned long lastDebounceTime = 0; //  Biến lưu thời gian delay chống dội phím ở lần cuối cùng.
unsigned long debounceDelay = 50;   //  Thời gian delay để chống dội phím nhấn

void setup()
{
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  digitalWrite(ledPin, ledState);
}

void loop()
{
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        ledState = !ledState;
      }
    }
  }

  digitalWrite(ledPin, ledState);

  lastButtonState = reading;
  }

Flow-work của chương trình

Biến reading đọc trạng thái của button ở thời điểm hiện tại và kiểm tra, nếu giá trị này khác trạng thái cuối của button (Giá trị thiết lập ban đầu là HIGH – không nhấn), có nghĩa là chúng ta đã nhấn nút thì chương trình bắt đầu đếm thời gian chống dội phím . Nếu thời gian lớn hơn giá trị đã cài đặt, chương trình sẽ kiểm tra lại 1 lần nữa trạng thái của nút nhấn, nếu nó vẫn giữ nguyên và không thay đổi (button vẫn đang được nhấn) thì sẽ :

  • Gán biến trạng thái của nút nhấn bằng biến reading.

  • Đảo trạng thái LED nếu button được nhấn (mức LOW).

Sau đó, điều khiển LED sáng bằng lệnh digitalWrite(), gán giá trị trạng thái nút nhấn bằng với biến reading để kiểm tra cho những vòng lặp sau. Như vậy, cứ mỗi lần nhấn nút và LED sẽ thay đổi trạng thái.

Sử dụng ngắt (interrupt) để điểu khiển LED,

Trong 2 ví dụ trước, chúng ta sử dụng nút nhấn để điều khiển LED trên board với cách thức hỏi vòng (polling), nghĩa là vi điều khiển sẽ kiểm tra liên tục trạng thái của nút nhấn trong vòng lặp loop, cách này thường chiếm dụng nhiều tài nguyên của CPU đồng thời độ đáp ứng của chương trình cũng không nhanh bằng cách sử dụng ngắt (interrupt).

Chip Atmage328P có 2 ngắt trên các chân D2 và D3. Nếu bạn muốn sử dụng chức năng ngắt cho các chân khác thì phải cài đặt thêm 1 số lệnh nữa, vấn đề này tương đối phức tạp và chúng ta không đề cập ở đây.

Yêu cầu

Nhấn button thì đèn LED trên board IoT Maker UnoX sẽ đảo trạng thái (nếu LED đang sáng thì sẽ tắt và ngược lại).

Đấu nối

interruptbtn
Figure 18. Hình ảnh kết nối chân ngắt trên mạch IoT Maker UnoX.

Source code

int ledPin = 3;     //  Chân kết nối với LED trên board Iotmaker Uno X
int btnPin = 2;     //  Chấn có chức năng interrupt trên board
int ledState = LOW; //  Gán trạng thái LED ban đầu là LOW

void blink()
{
  if (ledState == LOW) {
    ledState = HIGH;
  } else {
    ledState = LOW;
  }

  digitalWrite(ledPin, ledState);
}

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(btnPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(btnPin), blink, FALLING);
}

void loop()
{
  // Không phải làm gì
}

Giải thích chương trình

Lệnh attachInterrupt() bao gồm 3 đối số:

  • Lệnh digitalPinToInterrupt(btnPin): Chuyển chân digital hiện tại sang chức năng ngắt.

  • Blink(): Làm sẽ được gọi khi có sự kiện ngắt xảy ra.

  • FALLING: Phát hiện ngắt xảy ra nếu có 1 xung cạnh xuống ở chân ngắt. Đây là 1 trong các chế độ (mode) phát hiện có ngắt xảy ra, các mode là : LOW, RISING, FALLING, HIGH.

Chúng ta sẽ tìm hiểu sâu hơn về interrupt tại phần [timer-interrupt]

Sử dụng chức năng PWM

Analog và Digital

Trước khi tìm hiểu về PWM, chúng ta nên bắt đầu với 1 khái niệm đơn giản hơn nhưng vô cùng quan trọng trong điện tử, đó là Digital signalAnalog signal.

Từ đầu cuốn sách đến giờ, chúng ta chỉ sử dụng các mức điện áp VCC hoặc HIGH (mức 1) và 0V hoặc GND (mức 0). Trên thực tế, thế giới ta đang sống hầu như là các tín hiệu Analog. Ví dụ như màu sắc, nhiệt độ, độ ẩm hay cường độ ánh sáng của môi trường,…​

analog digital
Figure 19. Hình ảnh so sánh tín hiệu Analog và Digital.

Hiểu 1 cách đơn giản, Analog là những tín hiệu liên tục. Ví dụ trong dải điện áp từ 0-5VDC, tại 1 thời điểm, giá trị điện áp có thể là 1 số bất kì giữa 0 và 5 và thường được biểu diễn dưới giống như dạng sóng. Nó hiện hữu trong đời sống như âm thanh ta nghe được, hình ảnh ta thấy …​ Với Digital thì ngược lại, nó là những tín hiệu rời rạc. Ví dụ trong dải điện áp từ 0-5VDC, tại 1 thời điểm, giá trị điện áp chỉ có thể là 0V hoặc 5V, nó giống như 1 cái công tắc, 1 bức ảnh đen-trắng,…​

Trong máy tính, vi điều khiển hoặc các thiết bị điện tử, tín hiệu số thường được sử dụng bởi nó có thể dễ dàng lưu trữ cũng như xử lí dữ liệu. Để có thể xử lí, chuyển đổi dữ liệu tương tự sang dữ liệu số, người ta thường chia nhỏ các phần của tín hiệu tương tự (quá trình này gọi là lấy mẫu), sau đó các phần chia nhỏ này được gán cho các giá trị 0 hoặc 1.

Các vi điều khiển thường có bộ chuyển đổi dữ liệu tương tự sang dữ liệu số gọi là ADC (Analog to Digital Converter) và 1 số vi điều khiển có luôn 1 bộ chuyển đổi dữ liệu số sang tương tự (DAC).

PWM

PWM là chữ viết tắt của Pulse Width Modulation, dịch theo nghĩa tiếng Việt có nghĩa là điều chế độ rộng xung. Đây là 1 công nghệ giúp các tín hiệu số cho ra kết quả gần giống như tín hiệu tương tự. Tín hiệu điều khiển số tạo ra bởi các xung (pulse), đó là sự lặp lại của việc thay đổi điện áp giữa mức 0 và mức 1. Yếu tố đặc trưng của PWM là chu kì và độ rộng xung.

Ví dụ, với 1 bóng LED, trong 1 chu kì sáng, nếu thời gian ở mức HIGH dài hơn thời gian mức LOW thì đèn LED sẽ sáng mạnh, thời gian mức HIGH thấp hơn thời gian mức LOW thì đèn sẽ sáng thấp hơn. Lợi dụng tính tăng này ta có thể thay đổi thời gian mức HIGH và mức LOW để điều chỉnh cường độ sáng của bóng LED. Tỉ số giữa thời gian của mức HIGH và mức LOW được gọi là Duty cycle.

pwm cycle
Figure 20. Hình ảnh về sự thay đổi duty cycle trong PWM (nguồn www.arduino.cc).
pwm
Figure 21. Hình ảnh về mối tương quan giữa PWM và tín hiệu analogWrite (nguồn commons.wikimedia.org).

Fade LED

Fade LED là 1 ví dụ cơ bản giúp chúng ta có thể sử dụng PWM trong Arduino.

Yêu cầu

Tự động thay đổi cường độ sáng của LED trên board IoT Maker UnoX.

Linh kiện cần dùng

Sử dụng board IoT Maker UnoX, LED đã tích hợp sẵn trên board tại chân D3.

Source code

int ledPin = 3;       //  Chân kết nối với LED trên board Iotmaker Uno X
int brightness = 0;   //  Biến thiết lập cường độ sáng cho LED trên board
int fadeAmount = 15;  //  Biến thiết lập 1 bước thay đổi cường độ sáng.

void setup()
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  analogWrite(ledPin, brightness);

  brightness = brightness + fadeAmount;

  if (brightness <= 0 || brightness >= 255) {
    fadeAmount = -fadeAmount;
  }
  delay(30);
}

Giải thích source code

  • Biến brightness: Thiết lập cường độ sáng cho led, fadeAmount là 1 bước thay đổi cường độ sáng. Sử dụng hàm analogWrite() nhằm set giá trị cường độ sáng cho ledPin. LED sẽ sáng dần đến giá trị 255 sau đó sẽ tắt dần khi đến giá trị 0 và lặp đi lặp lại nhờ điều kiện trong câu lệnh if.

  • Giá trị từ 0 đến 255 tương ứng với Duty cycle từ 0% đến 100%.

Arduino không có bộ chuyển đổi DAC nhưng chúng ta có thể dùng PWM để có thể cho ra tín hiệu ngõ ra ở dạng gần như Analog, giá trị maximum = 255 là giá trị lớn nhất của chuyển đổi PWM chứ không liên quan đến bộ ADC (10 bits) của chip Atmega328.

Điều khiển LED RGB

Giới thiệu

LED RGB là module LED có 3 chân tín hiệu điều khiển tương ứng với 3 màu đỏ (Red), xanh lá (Green) và xanh dương (Blue). Chúng ta có thể phối hợp giữa các màu để tạo ra các hiệu ứng màu sắc đẹp mắt.

moduleRGB
Figure 22. Hình ảnh module LED RGB

Yêu cầu

Sử dụng button với 4 chế độ điều khiển:

  • Nhấn lần 1, LED sáng màu đỏ (Red).

  • Nhấn lần 2, LED sáng màu xanh lá (Green).

  • Nhấn lần 3, LED sáng màu xanh dương (Blue).

  • Nhấn lần 4, LED sáng cả 3 màu.

  • Nhấn lần 5, quay lại như lúc nhấn lần 1.

Linh kiện cần dùng

Đấu nối

Trên board IoT Maker UnoX có các chân kí hiệu ~ đều có thể sử dụng chức năng PWM.

Table 1. Bảng đấu nối chân của module LED RGB và board IoT Maker UnoX
Số thứ tự Chân trên Module LED RGB Chân trên board IoT Maker Uno X

1

R

9

2

G

10

3

B

11

4

V/G

3.3V hoặc GND

ledrgb
Figure 23. Hình ảnh kết nối module LED RGB với board IoT Maker UnoX

Source code

Nội dung source code đã được giải thích trong file.

#define pinLedRed     9         //  Chân kết nối với pin R của module LED-RGB
#define pinLedGreen   10        //  Chân kết nối với pin G của module LED-RGB
#define pinLedBlue    11        //  Chân kết nối với pin B của module LED-RGB
#define pinButton     8         //  Nút nhấn trên board Iotmaker Uno X

boolean lastPinButton = LOW;    //  Biến lưu trạng thái cuối của nút nhấn
boolean currentPinButton = LOW; //  Biến lưu trạng thái hiện tại của nút nhấn
int ledMode = 0;                //  Các chế độ của nút nhấn.

void setup()
{
  // Cài đặt các hướng của các chân
  pinMode (pinLedRed, OUTPUT);
  pinMode (pinLedGreen, OUTPUT);
  pinMode (pinLedBlue, OUTPUT);
  pinMode (pinButton, INPUT);
}

// Function chống dội phím khi nhấn (decoucing)
boolean debounce(boolean lastState)
{
  boolean currentState;                  // Biến currentState chỉ có 2 trạng trái LOW hoặc HIGH, khai báo kiểu boolean nhằm tiết kiệm tài nguyên CPU.
  currentState = digitalRead(pinButton); // Đọc trạng thái của button
  if (lastState != currentState) {       // Nếu nhấn Nút, chờ 20 mili giây, sau đó đọc lại trạng thái button 1 lần nữa.

    delay(20);
    currentState = digitalRead(pinButton);
  }
  return currentState;                   // Trả về trạng thái của button hiện tại
}

void setMode(int mode)
{
  if (mode == 1) {                      //  Màu đỏ: button nhấn lần 1

    digitalWrite(pinLedBlue, HIGH);
    digitalWrite(pinLedGreen, LOW);
    digitalWrite(pinLedRed, LOW);
  } else if (mode == 2) {               //  Màu xanh lá: button nhấn lần 2

    digitalWrite(pinLedBlue, LOW);
    digitalWrite(pinLedGreen, HIGH);
    digitalWrite(pinLedRed, LOW);
  } else if (mode == 3) {               //  Màu xanh dương: button nhấn lần 3

    digitalWrite(pinLedBlue, LOW);
    digitalWrite(pinLedGreen, LOW);
    digitalWrite(pinLedRed, HIGH);
  } else if (mode == 4) {               //  Sáng cả 3 màu: button nhấn lần 4

    int fadeAmount = 0;                 //  Bước thay đổi cường độ sáng
    int brightness;
    digitalWrite(pinLedBlue, LOW);
    digitalWrite(pinLedGreen, LOW);
    digitalWrite(pinLedRed, LOW);

    for (fadeAmount = 0; fadeAmount < 255; fadeAmount += 10) {
      brightness = fadeAmount;
      analogWrite(pinLedBlue, brightness);
      analogWrite(pinLedGreen, brightness);
      analogWrite(pinLedRed, brightness);
      delay(30);                        //  delay 30 mili giây để hiển thị kết quả
    }
  }
}
void loop()
{
  currentPinButton = debounce(lastPinButton);           //  Đọc trạng thái của nút nhấn ở function debounce()
  if (lastPinButton == HIGH && currentPinButton == LOW) //  Trạng thái nút nhấn đã thay đổi => đã nhấn phím
    ledMode++;
  lastPinButton = currentPinButton;                     //  Reset lại trạng thái nút nhấn.
  if (ledMode == 5)                                     //  Đang ở chế độ sáng 3 màu và nhấn button thì chuyển sang chế độ sáng màu đỏ (lặp lại chu kì)
    ledMode = 1;
  setMode(ledMode);                                     //  Đưa biến ledMode vào hàm setMode() để thực thi chế độ sáng tương ứng.
}
Với ledMode == 4, chương trình sẽ chạy hết vòng lặp for mới kiểm tra trạng thái của button. Ta có thể sử dụng interrupt để chương trình tối ưu hơn.

Đọc dữ liệu Analog

Ở phần trước chúng ta đã hiểu các khái niệm cơ bản về Analog, phần này chúng ta sẽ bắt tay vào làm 1 ứng dụng thực tế là “đọc cường độ ánh sáng của môi trường” để hiểu rõ hơn về cách hoạt động của nó.

Giới thiệu module cảm biến ánh sáng

Hình ảnh

module light sensor
Figure 24. Hình ảnh của module cảm biến cường độ ánh sáng.

Nguyên lí hoạt động

Chúng ta cùng tìm hiểu sơ đồ nguyên lí của module cảm biến ánh sáng để hiểu rõ hơn về cách nó hoạt động.

light sensor schema
Figure 25. Hình ảnh sơ đồ nguyên lí của module cảm biến cường độ ánh sáng.

Module cảm biến ánh sáng hoạt dựa vào sự thay đổi của cường độ của ánh sáng môi trường. Nếu trời tối thì cường độ ánh sáng yếu, điện trở của cảm biến ánh sáng trên module tăng lên (cường độ ánh sáng 0 Lux tương ứng với giá trị điện trở khoảng 1MOhm) và ngược lại, nếu cường độ ánh sáng tăng thì điện trở của cảm biến ánh sáng sẽ giảm (cường độ ánh sáng 10 Lux tương ứng với giá trị điện trở trong khoảng 8 – 20KOhm). Điện trở của sensor thay đổi dẫn đến giá trị điện áp tại điểm P1 sẽ thay đổi theo. Điều này kéo theo 2 sự thay đổi :

  • Thay đổi giá trị điện áp tại chân AO (Analog output), bằng cách kết nối các chân analog của vi điều khiển đến điểm này, ta có thể đọc giá trị điện áp analog và điều khiển được các thiết bị dựa theo cường độ ánh sáng.

  • Thay đổi giá trị điện áp tại chân INA+ của IC LM393, IC này là 1 op-amp có chức năng so sánh điện áp giữa 2 chân INA+ và INA-, chân OUTA là kết quả so sánh của 2 chân INA+ và INA-, nó có 2 trạng thái là mức cao (HIGH) và mức thấp (LOW). Biến trở được nối với chân INA- giúp người dùng có thể điều chỉnh điện áp tại chân INA- nhằm cài đặt trạng thái ngõ ra cho chân OUTA.

Trên module có thêm 2 LED, LED PWR để báo trạng nguồn (có nguồn điện cung cấp cho module, LED này sẽ sáng) và LED OUT để báo chân trạng thái của chân OUTA.

Điều khiển LED RGB theo cường độ ánh sáng của môi trường

Yêu cầu

Nếu trời tối thì LED sáng màu đỏ (Red), trời sáng vừa thì LED sáng màu xanh lá (Green), trời sáng mạnh LED sẽ sáng màu xanh dương (Blue).

Chuẩn bị

Đấu nối

Table 2. Bảng đấu nối chân của module LED RGB và board IoT Maker UnoX
Số thứ tự Chân trên module LED RGB Chân trên board IoT Maker UnoX

1

R

9

2

G

10

3

B

11

4

V/G

3.3V hoặc GND

Table 3. Bảng đấu nối chân của module cảm biến ánh sáng và board IoT Maker UnoX.
Số thứ tự Chân trên cảm biến ánh sáng Chân trên board IoT Maker UnoX

1

A0

A0

2

VCC

5V

3

GND

GND

led rgb light sensor
Figure 26. Hình ảnh kết nối module LED RGB và cảm biến ánh sáng với board IoT Maker UnoX

Source code

#define pinLedRed     9         //  Chân kết nối với pin R của module LED-RGB
#define pinLedGreen   10        //  Chân kết nối với pin G của module LED-RGB
#define pinLedBlue    11        //  Chân kết nối với pin B của module LED-RGB

#define pinAnaLight   A0        //  Chân kết nối với A0 của module cảm biến ánh sáng

void setup()
{
  // Cài đặt hướng cho các chân
  pinMode(pinLedRed, OUTPUT);
  pinMode(pinLedGreen, OUTPUT);
  pinMode(pinLedBlue, OUTPUT);
  // LED RGB OFF
  digitalWrite(pinLedRed, LOW);
  digitalWrite(pinLedGreen, LOW);
  digitalWrite(pinLedBlue, LOW);

  pinMode(pinAnaLight, INPUT);
  // Khởi tạo serial
  Serial.begin(115200);
  Serial.println("Initial serial");
}

void loop()
{
  unsigned int AnalogValue;
  AnalogValue = analogRead(pinAnaLight);  //  Đọc trạng thái chân A0 của module cảm biến ánh sáng
  Serial.println(AnalogValue);            //  In ra giá trị điện áp Analog
  if (AnalogValue < 350) {

    digitalWrite(pinLedRed, HIGH);
    digitalWrite(pinLedGreen, LOW);
    digitalWrite(pinLedBlue, LOW);

    Serial.println("The light intensity: HIGH");
  } else if (AnalogValue > 350 && AnalogValue < 800) {

    digitalWrite(pinLedRed, LOW);
    digitalWrite(pinLedGreen, HIGH);
    digitalWrite(pinLedBlue, LOW);
    Serial.println("The light intensity: MEDIUM");
  } else if (AnalogValue > 800) {

    digitalWrite(pinLedRed, LOW);
    digitalWrite(pinLedGreen, LOW);
    digitalWrite(pinLedBlue, HIGH);
    Serial.println("The light intensity: LOW");
  }

  delay(100);
}

Giải thích source code

  • Lệnh Serial.begin(115200) nhằm khởi tạo Serial nhằm hiển thị giá trị Analog đọc được ra màn hình Serial của Arduino, Serial.println("Initial serial") in ra chữ “Initial serial” và xuống dòng.

  • Hàm analogRead(pinAnaLight) sẽ đọc điện áp từ chân A0 của module cảm biến ánh sáng, để đưa vào bộ chuyển đổi ADC của vi điều khiển Atmega328P. Bộ ADC này là bộ ADC 10 bit, tương ứng với giá trị Analog nhỏ nhất là 0 và lớn nhất là 210 = 1024.

  • Các câu lệnh điều kiện if- else if ở phía dưới nhằm setup giá trị cường độ ánh sáng để điều khiển LED RGB sáng các màu đỏ, xanh lá, và xanh dương. Cụ thể :

  • Nếu giá trị Analog đọc được nhỏ hơn 350 (biểu thị cường độ ánh sánh mạnh), LED RGB sáng màu đỏ.

  • Nếu giá trị Analog đọc được lớn hơn 350 và nhỏ hơn 800 (biểu thị cường độ ánh sáng vừa), LED RGB sáng màu xanh lá.

  • Nếu giá trị Analog đọc được lớn hơn 800 (biểu thị cường độ ánh sánh yếu) LED RGB sáng màu xanh dương.

Tổng kết

Qua chương này, chúng ta đã có những hiểu biết cơ bản về các khái niệm, linh kiện điện tử, những ví dụ mẫu về điều khiển đèn LED, nút nhấn, đọc dữ liệu Analog, PWM. Chúng ta cũng đã hiểu về các chức năng cơ bản của vi điều khiển ATmega328 cũng như cách sử dụng board IoT Maker UnoX. Đây chỉ là những dự án mẫu và rất cơ bản, những thứ đáng học hỏi đang chờ chúng ta ở các phần tiếp theo của cuốn sách này.

Chúng ta có thể tham khảo thêm các ví dụ trong Arduino IDE tại mục File → Examples.

Leave a Comment