แนะนำการใช้งานบอร์ด Arduino Uno R4 WiFi ในเบื้องต้น#

Keywords: Arduino Uno R4 WiFi, RA4M1, Arm Cortex-M4, ESP32-S3, WiFi / BLE, FreeRTOS


บอร์ด Arduino Uno R4#

ทีมผู้พัฒนา Arduino ได้เปิดตัวบอร์ด Arduino Uno R4 ในเดือนมีนาคม พ.ศ. 2566 โดยแบ่งออกเป็น 2 รุ่นคือ

  • Arduino Uno R4 WiFi
  • Arduino Uno R4 Minima: ไม่มีโมดูล WiFi และไม่มีวงจร 12x8 LED Matrix

และถือว่าเป็นบอร์ดรุ่นถัดจาก Arduino Uno R3 เนื่องจากมีขนาดและรูปร่างของบอร์ดเหมือนกัน และใช้แรงดันไฟเลี้ยงสำหรับชิปไมโครคอนโทรลเลอร์ 5V บอร์ด Uno R4 WiFi มีราคาสูงกว่าบอร์ด Uno R4 Minima

รูป: บอร์ด Uno R4 Minima และ Uno R4 WiFi

รูป: บอร์ด Uno R4 WiFi Variant (Low-cost)

เอกสารที่เกี่ยวข้อง#


ข้อมูลเชิงเทคนิคของบอร์ด Uno R4#

ชิปตัวประมวลผล#

MCU: Renesas RA4M1 (R7FA4M1AB3CFM#AA0)

  • CPU Core: 32-bit Arm Cortex-M4F (Armv7E-M Architecture)
  • CPU Clock Speed: 48MHz
  • On-chip Memory:
    • Flash: 256 kB
    • SRAM: 32 kB
    • Data EEPROM: 8 kB
  • Voltage Range: 1.6V ~ 5.5V
  • Chip Package: 64-LFQFP
  • Single-Precision Floating-point unit (FPU)
  • Memory Protection Unit (MPU)
  • 128-bit Unique ID
  • Timers:
    • 2-Channel General PWM Timer 32-Bit (GPT32)
    • 6-Channel General PWM Timer 16-Bit (GPT16)
    • 2-Channel Low Power Asynchronous General-Purpose Timer 16-bit (AGT)
    • 1× Watchdog Timer (WDT)
  • 4× Serial Communications Interface (SCI)
  • 2× Serial Peripheral Interface (SPI)
  • 2× I2C bus Interface
  • 1× Analog Temperature Sensor (TSN)
  • 1× RTC (Real-Time Clock)
  • 1× CAN bus Controller (No CAN transceiver onboard)
  • Analog:
    • 14-bit ADC (Digital-to-Analog Converter)
    • 12-bit DAC (Analog-to-Digital Converter)
    • 2× Low-Power Analog Comparators (ACMPLP)
    • 4× Operational Amplifiers (OPAMP)
  • Security:
    • AES128/256 (Encryption)
    • GHASH (Hash Function)
    • TRNG (True Random Number Generator)

ในส่วนถัดไปของบทความ จะกล่าวถึงเฉพาะบอร์ด Arduino Uno R4 WiFi

วงจรบนบอร์ด#

  • I/O Operating Voltage: 5V (not 3.3V)
  • 1× USB Type-C Connector
  • 20× Digital I/O: 8mA (max) per I/O pin
    • D0 ~ D13 pins
    • A0/D14 ~ A5/D19 pins
  • 6× PWM Output (12-bit resolution): D3, D5, D6, D9, D10, D11 pins
  • Analog Input (14-bit resolution): A0 ~ A5 pins
  • Analog Output (12-bit resolution): A0 pin
  • OpAmp In+ / In- Pins: A1 / A2 pins
  • OpAmp Out: A3 pin
  • Onboard LED: D13 pin
  • UART/Serial: D0=Rx0, D1=Tx0 (Serial1)
  • SPI (2x3 ICSP Header): COPI=D11, 5V, CIPO=D12, SCK=D13, /RESET, GND
  • I2C: A4=SDA, A5=SCL (Wire)
  • I2C1: D18=SDA, D19=SCL (Wire1)
  • CAN busns: D10=CANRX, D13=CANTX
  • DAC output: A0 pin
  • Reset Button
  • 4× LEDs
    • DL1 (TX LED): P109 pin
    • DL2 (RX LED): ESP_TXD0 pin
    • DL3 (5V Power ON LED)
    • DL4 (SCK LED): P102 pin (Arduino D13 pin)
  • VRTC (VBATT) & GND pins (for battery backup, 1.6V~3.6V)
  • OFF pin
  • 1× Qwiic/STEMMA Connector for I2C bus (Wire1)
    • 1mm-pitch, 4-pin, JST Connector
    • 3.3V logic level
  • LED Matrix: 12 x 8 LEDs
  • Power Supply
    • VIN pin: 6V ~ 24V (Barrel Plug / DC Jack)
    • Linear Voltage Regulator (3.3V output): SGM2205-3.3XKC3G/TR
    • Step-down (Buck) Voltage Regulator (5V output): ISL854102FRZ-T
    • USB Type-C 5V supply + PTC Resettable Fuse + ESD protection diode
  • USB Bridge for USB_D+ and USB_D- signals
  • 2×3 ESP Pin Header (for ESP32-S3 firmware upload)
  • 1× ESP32-S3-MINI-1-N8 Module (8MB Flash)
    • Xtensa dual-core 32-bit LX7, 240MHz
    • 3.3V operating voltage
    • Logic-level translator IC: TXB0108DQSR

ข้อสังเกต

  • ชิป RA4M1 ทำงานด้วยแรงดันไฟเลี้ยง 5V ในขณะที่โมดูล ESP32-S3 ทำงานด้วยแรงดันไฟเลี้ยง 3.3V ดังนั้นจึงมีการใช้ไอซี TXB0108DQSR (8-bit Bidirectional Voltage Level Shifter) เพื่อเชื่อมต่อสัญญาณที่มีระดับแรงดันไฟฟ้าต่างกันในทั้งสองทิศทางของสัญญาณ
  • บอร์ด Uno R4 WiFi ใช้แรงดันไฟเลี้ยง 5V ได้จาก USB Type-C หรือจะใช้แรงดันไฟเลี้ยงในช่วง 6V ~ 24V ผ่านทาง VIN หรือต่อผ่าน DC Jack ไปยังไดโอดป้องกันการต่อกลับขั้ว (Schottky Diode) และมีวงจรที่ทำหน้าที่ลดระดับแรงดันไฟฟ้า Step-down (Buck) DC-DC Converter ให้ได้แรงดันไฟฟ้า 5V
  • แรงดันไฟเลี้ยง 3.3V สำหรับ ESP32-S3 ได้จากการแปลง 5V ให้เป็น 3.3V โดยใช้ไอซี Linear Voltage Regulator
  • วงจร 12x8 LED Matrix ใช้ขาจำนวน 11 ขา ต่อไปนี้ในการควบคุม: P003, P004, P011, P012, P013, P015, P204, P206, P212, P213

รูป: แผนผังแสดงตำแหน่งขาบนบอร์ด Uni R4 WiFi

รูป: แผนผังแสดงความเชื่อมโยงระหว่างขาของชิปและขาของบอร์ด Uni R4 WiFi

รูป: แผนผังแสดงระดับแรงดันไฟเลี้ยงสำหรับวงจรบนบอร์ด Uno R4 WiFi

รูป: แผนผังแสดงวงจร LED Matrix ของบอร์ด Uno R4 WiFi

รายการของขา I/O สำหรับ Uno R4 WiFi

- P301 = D0 / RX
- P302 = D1 / TX
- P104 = D2 
- P105 = D3~ 
- P106 = D4
- P107 = D5~ 
- P111 = D6~
- P112 = D7 
- P304 = D8
- P303 = D9~
- P103 = D10~
- P411 = D11~
- P410 = D12
- P102 = D13
- P014 = D14 / A0 / DAC
- P000 = D15 / A1
- P001 = D16 / A2
- P002 = D17 / A3
- P101 = D18 / A4 / SDA 
- P100 = D19 / A5 / SCL
- P500 = D20 / Analog voltage measure pin 
- P408 = D21 / USB switch, drive high for connecting USB to RA4
- P109 = D22 / TX <--> ESP_RXD0
- P110 = D23 / RX <--> ESP_TXD0
- P501 = D24 / TX WIFI --> ESP_IO6
- P502 = D25 / RX WIFI <-- ESP_IO5
- P400 = D26 / QWIC SCL (3.3V logic)
- P401 = D27 / QWIC SDA (3.3V logic)
- P003 = D28  
- P004 = D29
- P011 = D30
- P012 = D31
- P013 = D32
- P015 = D33 
- P204 = D34
- P205 = D35
- P206 = D36
- P212 = D37
- P213 = D38

 


▷ การใช้งานโมดูล Espressif ESP32-S3#

ESP32-S3 SoC บนบอร์ด Uno R4 WiFi ทำหน้าที่ ดังต่อไปนี้

  • USB Device: ทำหน้าที่เป็นอุปกรณ์ USB (VID=0x2341, PID=0x1002) เชื่อมต่อกับคอมพิวเตอร์ของผู้ใช้
  • CMSIS-DAP Programmer ใช้สำหรับการอัปโหลดหรือโปรแกรมไฟล์เฟิร์มแวร์ จากคอมพิวเตอร์ของผู้ใช้ผ่านทางพอร์ต USB สำหรับชิป RA4M1 (ต่อกับขา SWCLK และ SWDIO)
  • USB Bridge เป็นตัวกลางในการเชื่อมต่อข้อมูลด้วย USB-Serial (USB CDC, Baudrate=115200) ระหว่างคอมพิวเตอร์ของผู้ใช้ผ่านทางพอร์ต USB
  • เชื่อมต่อกับชิป RA4M1 ผ่านทางขา TX / RX หนึ่งคู่ (Baudrate=115200) สำหรับการสื่อสารด้วย AT Commands เพื่อใช้ในการสื่อสารผ่าน WiFi / BLE
    • ESP32-S3: GPIO44 (U0RXD) / GPIO43 (U0TXD) pins
    • RA4M1: P109 (TXD) / P110 (RXD) pins
  • Firmware: uno-r4-wifi-usb-bridge

บอร์ด Uno R4 WiFi มีวงจรที่ใช้ไอซี Analog Switch (2:1 Multiplexer) เพื่อใช้เลือกการเชื่อมต่อระหว่างสัญญาณ USB D+/D- ของพอร์ต USB Type-C ไปยังขา USB D+/D- ของชิป ESP32-S3 (default) หรือ ขาของชิป RA4M1 โดยตรง

รูป: บางส่วนจาก Schematic แสดงให้เห็นวงจร Analog Mux เพื่อเลือกการเชื่อมต่อ พอร์ต USB Type-C USB D+/D- ไปยัง ESP32-S3 หรือ RA4M1 โดยมีสัญญาณควบคุมจากขา P408 (D21)

หากต้องการอัปเดตเฟิร์มแวร์ (Firmware Update) สำหรับ ESP3-S3 (uno-r4-wifi-usb-bridge) ก็สามารถทำได้ง่าย ผ่านทางพอร์ต USB นอกจากนั้นแล้ว บอร์ด Uno R4 WiFi ยังมีคอนเนกเตอร์ 2x3 Male Pin header สามารถใช้เป็นช่องทางการอัปโหลดไฟล์เฟิร์มแวร์ให้กับ ESP32-S3 ได้โดยตรง

  • ESP_IO42: MTMS Debugging (Pin 1)
  • ESP_IO41: MTDI Debugging (Pin 2)
  • ESP_TXD0: Serial Transmit (UART-Tx) (Pin 3)
  • ESP_DOWNLOAD: Boot (Pin 4)
  • ESP_RXD0: Serial Receive (UART-Rx) (Pin 5)
  • GND: Ground (Pin 6)

การเขียนโปรแกรมด้วย Arduino IDE#

ในการเขียนโปรแกรมด้วย Arduino Sketch สำหรับบอร์ด Uno R4 โดยใช้ซอฟต์แวร์ Arduino IDE ก่อนอื่นให้ติดตั้งซอฟต์แวร์ต่อไปนี้ ภายใต้ Boards Manager: Arduino Core for Renesas

รูป: การติดตั้ง Arduino Board Manager สำหรับบอร์ด Uno R4

รูป: ตัวอย่างการเขียนโค้ด Arduino Sketch เพื่อทำให้ LED บนบอร์ด (ตรงกับขา Arduino D13)

รูป: การอัปเดต Arduino Core for Uno R4 ให้เป็นเวอร์ชันล่าสุด (ในตัวอย่างคือ v1.5.2)

 

อีกตัวอย่างหนึ่งเป็นการทำให้ LED ที่มีอยู่บนบอร์ด (LED_BUILTIN) สว่างขึ้นและดับลง สลับไปมา โดยใช้การสร้างสัญญาณ PWM

#include <WiFiS3.h>

#define LED_PIN LED_BUILTIN   // D13

uint8_t brightness = 0;
int8_t fadeStep = 1;
unsigned long lastUpdate = 0;

void setup() {
  Serial.begin(115200);  
  Serial.print( "WiFiS3 firmware version: " );
  Serial.println( WiFi.firmwareVersion() );
  pinMode(LED_PIN, OUTPUT);
  analogWriteResolution(8); // use 8-bit PWM resolution
}

void loop() {
  unsigned long now = millis();
  if (now - lastUpdate >= 5) { // speed of breathing
    lastUpdate = now;
    brightness += fadeStep;
    if (brightness == 0 || brightness == 255) {
      fadeStep = -fadeStep; // reverse direction
    }
    analogWrite(LED_PIN, brightness);
  }
}

การสร้างสัญญาณ PWM อาจใช้อีกวิธีหนึ่งคือ การใช้คลาส PwmOut ของ Arduino Core for Renesas และมีตัวอย่างโค้ด ดังนี้ สัญญาณ PWM มีความถี่ 1000 Hz และมีค่า Duty Cycle เพิ่มขึ้นและลดลง สลับไปมาระหว่าง 0..100%

#include <Arduino.h>
#include <pwm.h>

PwmOut pwm_led(LED_BUILTIN);

void setup() {
    pwm_led.begin( 1000 /*Hz*/, 0.0f /*duty cycle in perceentage*/ );
}

void loop() {
    static int duty = 0;
    static int step = 1;
    pwm_led.pulse_perc(duty);
    duty += step;
    if (duty >= 100 || duty <= 0) {
        step = -step;
    }
    delay(10);
}

ข้อสังเกต

  • ไลบรารี่สำหรับ Arduino ที่สามารถใช้กับบอร์ด เช่น Uno / Nano อาจยังใช้ไม่ได้กับบอร์ด Uno R4 / WiFi ลองดูตัวอย่างรายการไลบรารี่ที่ทางทีมงาน Arduino ได้ทดสอบ: Uno R4 Library Compatibility

การเขียนโปรแกรมเพื่อเชื่อมต่อ WiFi โดยใช้โมดูล ESP32-S3 สำหรับบอร์ด Uno R4 WiFi จะต้องใช้ไลบรารีที่มีชื่อว่า WiFiS3 การตรวจสอบเวอร์ชันของเฟิร์มแวร์ WiFiS3 ทำได้โดยใช้คำสั่ง WiFi.firmwareVersion() จากไลบรารี <WiFiS3.h>

 


การอัปเดตเฟิร์มแวร์สำหรับ ESP32-S3#

หากต้องการจะอัปเดตเฟิร์มแวร์ให้กับ ESP32S3 ก็สามารถทำได้มากกว่าหนึ่งวิธี วิธีหนึ่งคือ การทำให้ ESP32-S3 เข้าสู่โหมด BOOT Loader โดยการต่อขา ESP_DOWNLOAD (GPIO-0 ของ ESP32-S3) กับ GND แล้วป้อนไฟเลี้ยงให้บอร์ด (ถอดแล้วเสียบสาย USB ใหม่อีกครั้ง) จากนั้นก็สามารถใช้โปรแกรม esptool.py ของ Espressif ตามคำสั่งตัวอย่างดังนี้ (S3-ALL.bin เป็นชื่อไฟล์เฟิร์มแวร์สำหรับ ESP32-S3) เสร็จแล้วให้รีเซตการทำงานของบอร์ด

esptool -b 115200 write_flash 0x0 S3-ALL.bin

รูป: ตัวอย่างการใช้คำสั่ง esptool สำหรับอัปโหลดเฟิร์มแวร์ (.bin) ไปยัง ESP32-S3 บนบอร์ด Uno R4 WiFi

[อัปเดต]: ไฟล์ Firmware สำหรับ ESP32-S3 สามารถดาวน์โหลดได้จาก github.com/arduino/uno-r4-wifi-usb-bridge/ [อัปเดต] ผู้ใช้สามารถดาวน์โหลดไฟล์ .zip สำหรับระบบปฏิบัติการต่าง ๆ และภายในมีไฟล์คำสั่ง espflash กับไฟล์เฟิร์มแวร์ .bin

ตัวอย่างการทำคำสั่ง espflash ที่มาพร้อมกับไฟล์ unor4wifi-update-linux.zip (Release v0.6.0)

สำหรับ Ubuntu ทำคำสั่งใน Terminal

$ ./bin/espflash write-bin -p /dev/ttyACM0 -b 115200 \
    0x0 firmware/UNOR4-WIFI-S3-0.6.0.bin

สำหรับ Windows (หมายเลขพอร์ตที่ใช้เป็นตัวอย่างคือ COM21) ทำคำสั่งใน Windows PowerPhell

> bin\espflash.exe write-bin -p COM21 -b 115200 `
    0x0 firmware\UNOR4-WIFI-S3-0.6.0.bin

รูป: ตัวอย่างการทำคำสั่ง espflash ใน Ubuntu

ข้อสังเกต: หากใช้คำสั่ง espflash แล้วไม่สามารถเชื่อมต่อกับบอร์ดได้ (Unable to connect) แม้ว่าจะอัปโหลด Arduino Sketch ได้ตามปรกติ ให้ลองใช้คำสั่ง esptool โดยจะต้องทำให้ ESP-S3 เข้าสู่ Bootloader Mode ก่อน ตัวอย่างการทำคำสั่งสำหรับ Windows มีดังนี้

> esptool -p COM22 -b 115200 `
    write_flash 0x0 firmware\UNOR4-WIFI-S3-0.6.0.bin

รูป: ตัวอย่างการทำคำสั่ง esptool ใน Windows

 


ตัวอย่างการใช้งาน Serial#

บอร์ด Uno R4 WiFi มีช่องทางการสื่อสารแบบ Serial มากกว่าหนึ่งช่องทาง หากมีการเปิดใช้งาน USB (โดยใช้ TinyUSB Stack) การเรียกใช้งาน Serial ในโค้ด Arduino Sketch จะหมายถึง SerialUSB ซึ่งเป็นการสื่อสารข้อมูลผ่าน USB CDC (Communications Device Class)

นอกจากนี้ ชิป RA4M1 ยังมีวงจรภายในรองรับ UART / Hardware Serial ได้หลายชุด โดยสามารถใช้งานผ่าน เช่น Serial1 และ Serial2 ซึ่งถูกสร้างจากคลาส UART

การตั้งค่าขา I/O สำหรับ UART สำหรับ Arduino มีดังนี้

  • UART1 เชื่อมต่อกับ ESP32-S3 และตรงกับ Serial2
    • UART1_TX_PIN = Arduino Pin 22
    • UART1_RX_PIN = Arduino Pin 23
  • UART2 จะตรงกับขา D1/D0 ตามลำดับ และตรงกับ Serial1
    • UART2_TX_PIN = Arduino Pin 1
    • UART2_RX_PIN = Arduino Pin 0
  • UART3 จะใช้สำหรับการสื่อสารกับ ESP32-S3 เพื่อใช้งาน Wi-Fi/BLE Modem
    • UART3_TX_PIN = Arduino Pin 24
    • UART3_RX_PIN = Arduino Pin 25

ในโค้ดตัวอย่างถัดไป มีการเปิดใช้งาน Serial และ Serial1 (ใช้ Baudrate 115200) โดยใช้ Tx/Rx ตามที่มีการกำหนดไว้แล้วโดย Arduino API แต่ MySerial ซึ่งสร้างจากคลาส UART เป็นตัวอย่างเลือกใช้ขา Tx / Rx (ใช้ Baudrate 9600) เพื่อใช้งานออกทางขา 18/A4 และ 19/A5

หากจะลองใช้โมดูล USB-to-Serial เชื่อมต่อกับขา Tx/Rx ซึ่งมีแรงดันไฟฟ้า (I/O Voltage) เป็น 5V และแนะนำให้ใช้ชิป CP210x ของ Silicon Labs เนื่องจากมีคุณสมบัติ 5V Input tolerant

#define LED_PIN LED_BUILTIN // D13 pin

#define USER_TX_PIN (18u)  // Pin A4
#define USER_RX_PIN (19u)  // Pin A5

UART MySerial(USER_TX_PIN, USER_RX_PIN); 

void setup() {  
  Serial.begin( 115200 );
  Serial1.begin( 115200 );
  MySerial.begin( 9600 );
  pinMode( LED_PIN, OUTPUT );
  delay(1000);

  // Show the default Arduino UART pins
  Serial.println( UART1_TX_PIN ); // 22
  Serial.println( UART1_RX_PIN ); // 23
  Serial.println( UART2_TX_PIN ); // 1
  Serial.println( UART2_RX_PIN ); // 0
  Serial.println( UART3_TX_PIN ); // 24
  Serial.println( UART3_RX_PIN ); // 25
}

void loop() {
  int state = !digitalRead(LED_PIN);
  digitalWrite( LED_PIN, state );
  Serial1.print( state ? 'H' : 'L' );
  MySerial.print( state ? '1' : '0' );
  delay(500);
}

รูป: ตัวอย่างคลื่นสัญญาณที่วัดด้วยออสซิลโลสโคปที่ขา Tx=18/A4 (BAUD=9600) และ Tx=1 (BAUD=115200) และให้สังเกตว่า ลอจิก High มีแรงดันอยู่ที่ประมาณ 5V

 


ตัวอย่างการใช้งาน FreeRTOS#

ตัวอย่างนี้สาธิตการใช้งาน FreeRTOS ในรูปแบบของ Arduino Library (Arduino_FreeRTOS)

โดยมีการสร้าง FreeRTOS Tasks หรือ มีการแบ่งงานออกเป็น 2 ส่วน ดังนี้

  • BlinkTask: ทำให้ LED กระพริบ ด้วยอัตราคงที่
  • WiFiScan: ตรวจสอบเครือข่าย Wi-Fi รอบ ๆ และแสดงรายการที่ตรวจพบผ่านทาง Serial
#include <Arduino_FreeRTOS.h>
#include <WiFiS3.h>  

// LED pin for Uno R4 WiFi (built-in)
const int ledPin = LED_BUILTIN;

// WiFi scan interval (in milliseconds)
const TickType_t wifiScanDelay = (10000 / portTICK_PERIOD_MS);

// LED Blinking Task
void BlinkTask(void *pvParameters) {
  pinMode(ledPin, OUTPUT);
  while (1) {
    digitalWrite(ledPin, HIGH);
    vTaskDelay(500 / portTICK_PERIOD_MS);
    digitalWrite(ledPin, LOW);
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

// WiFi Scan Task
void WifiScanTask(void *pvParameters) {
  Serial.println("Starting WiFi scan task...");

  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("No WiFi module detected.");
    vTaskSuspend(NULL);
  }
  while (1) {
    Serial.println("WiFi scanning...");
    int networks = WiFi.scanNetworks();

    if (networks == 0) {
      Serial.println("No Wi-Fi networks found.");
    } else {
      Serial.print(networks);
      Serial.println(" network(s) found:");
      for (int i = 0; i < networks; i++) {
        Serial.print("  ");
        Serial.print(i + 1);
        Serial.print(": ");
        Serial.print(WiFi.SSID(i));
        Serial.print(" (RSSI: ");
        Serial.print(WiFi.RSSI(i));
        Serial.print(" dBm, ");
        printEncryptionType(WiFi.encryptionType(i));
        Serial.println(")");
      }
    }
    vTaskDelay(wifiScanDelay);
  }
}

void printEncryptionType(uint8_t type) {
  switch (type) {
    case ENC_TYPE_WEP: Serial.print("WEP"); break;
    case ENC_TYPE_TKIP: Serial.print("WPA"); break;
    case ENC_TYPE_CCMP: Serial.print("WPA2"); break;
    case ENC_TYPE_NONE: Serial.print("Open"); break;
    case ENC_TYPE_AUTO: Serial.print("Auto"); break;
    default: Serial.print("Unknown"); break;
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial);
  delay(100);
  // Create FreeRTOS tasks
  xTaskCreate(BlinkTask, "Blink", 128, NULL, 1, NULL);
  xTaskCreate(WifiScanTask, "WiFiScan", 512, NULL, 1, NULL);

  Serial.println("\n\n\n");
  Serial.flush();

  // Start the FreeRTOS scheduler
  vTaskStartScheduler();
}

void loop() {
}

ในตัวอย่างนี้ การทำงานของ FreeRTOS Task Scheduler จะเริ่มทำงานหลังจากเรียกฟังก์ชัน vTaskStartScheduler() แต่ถ้าจะตั้งค่าให้เริ่มทำงานโดยอัตโนมัติ โดยไม่ต้องทำคำสั่งดังกล่าวใน Arduino Sketch ก็มีแนวทางดังนี้

รูป: แนวทางการตั้งค่าให้ FreeRTOS Task Scheduler เริ่มทำงานโดยอัตโนมัติ

หากต้องการตรวจสอบ FreeRTOS Config ก็สามารถดูได้จากไฟล์ FreeRTOSConfig.h

รูป: ตัวอย่างจากไฟล์ FreeRTOSConfig.h ของไลบรารี (Arduino_FreeRTOS)

ผู้ใช้สามารถตั้งค่าใช้งานได้ โดยจะต้องแก้ไขไฟล์ FreeRTOSConfig.h

Windows: ให้ไปยังไดเรกทอรี

C:\Users\%USERNAME%\AppData\Local\Arduino15\packages\arduino\hardware\

แล้วเปิดแก้ไขไฟล์ในไดเรกทอรีต่อไปนี้ (1.4.1 คือ ตัวเลขเวอร์ชันของไลบรารีที่ได้ลองใช้งาน)

renesas_uno\1.4.1\libraries\Arduino_FreeRTOS\src\FreeRTOSConfig.h

ตรวจสอบการตั้งค่าเพิ่มเติม

#define configUSE_MUTEXES                   1
#define configUSE_RECURSIVE_MUTEXES         1
#define configUSE_TIME_SLICING              1
#define INCLUDE_xTaskGetHandle              1
#define INCLUDE_eTaskGetState               1

ตัวอย่างโค้ดตรวจสอบการตั้งค่าสำหรับ FreeRTOS Configuration

#include <Arduino_FreeRTOS.h> // based on FreeRTOS-Kernel-v10.5.1

// Hardware support: Arduino UNO R4 and Arduino Portenta C33
TaskHandle_t task1_handle, task2_handle;

void setup() {
  Serial.begin(115200);
  while (!Serial);

  pinMode( LED_BUILTIN, OUTPUT );
  digitalWrite( LED_BUILTIN, LOW );

  Serial.println( String("configTICK_RATE_HZ            : ") 
                  + configTICK_RATE_HZ );
  Serial.println( String("configCPU_CLOCK_HZ            : ")
                  + configCPU_CLOCK_HZ );
  Serial.println( String("configMAX_PRIORITIES          : ") 
                  + configMAX_PRIORITIES );
  Serial.println( String("configMINIMAL_STACK_SIZE      : ") 
                  + configMINIMAL_STACK_SIZE );   
  Serial.println( String("configUSE_TIME_SLICING        : ") 
                  + configUSE_TIME_SLICING ); 
  Serial.println( String("configUSE_COUNTING_SEMAPHORES : ")
                  + configUSE_COUNTING_SEMAPHORES );
  Serial.println( String("configUSE_MUTEXES             : ") 
                  + configUSE_MUTEXES );
  Serial.println( String("configUSE_RECURSIVE_MUTEXES   : " ) 
                  + configUSE_RECURSIVE_MUTEXES );

  BaseType_t ret_val = xTaskCreate (
      task1_func,
      "Task 1",
      128, 
      NULL, 
      1, 
      &task1_handle
    );
  if (ret_val != pdPASS) {
    Serial.println( "Failed to create Task 1!!!" );
    error_handler();
  }

  ret_val = xTaskCreate (
      task2_func,
      "Task 2",
      128, 
      NULL, 
      1,
      &task2_handle
    );

  if (ret_val != pdPASS) {
    Serial.println("Failed to create Task 2!!!");
    error_handler();
  }

  Serial.println( "Starting the FreeRTOS scheduler ...");
  vTaskStartScheduler();
  for(;;);
}

void loop() {
  // 
}

void task1_func(void *pvParameters) {
  (void)pvParameters; // not used
  TickType_t lastWakeTime = xTaskGetTickCount();
  for(;;) {
    digitalWrite(LED_BUILTIN, LOW );
    vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS(1000) );
  }
}

void task2_func(void *pvParameters) {
  (void)pvParameters; // not used
  vTaskDelay( pdMS_TO_TICKS(500) );
  TickType_t lastWakeTime = xTaskGetTickCount();
  for(;;) {
    digitalWrite(LED_BUILTIN, HIGH );
    vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS(1000) );
  }
}

void error_handler() {
   Serial.println("The system will be reset...\n\n\n");
   delay(5000);
   NVIC_SystemReset();
}

ตัวอย่างการลองใช้ FreeRTOS Mutex

#include <Arduino_FreeRTOS.h>

// Global variables
int flag = 0;
TaskHandle_t task_handle1;
TaskHandle_t task_handle2;
SemaphoreHandle_t xMutex;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  // Create a mutex 
  xMutex = xSemaphoreCreateMutex();
  if (xMutex == NULL) {
     Serial.println( "Mutex creation failed!!!" );
     while (1);
  }

  int task_stack_size = configMINIMAL_STACK_SIZE;
  int task_priority = 2;

  // Create two tasks
  xTaskCreate(task_func1, 
                "Task 1", 
                task_stack_size, 
                NULL, 
                task_priority, 
                &task_handle1 );

  xTaskCreate(task_func2, 
                "Task 2", 
                task_stack_size, 
                NULL, 
                task_priority, 
                &task_handle2 );

  // Start the FreeRTOS scheduler.
  vTaskStartScheduler();
  for(;;);
}

void loop() {
  // ...
}

void task_func1(void *pvParameters) {
  (void)pvParameters; // not used
  while (1) {
    // Request the mutex before entering the critical section
    if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
      // Critical section
      if (flag==0) {
        flag = 1;
        Serial.println( String("Task 1: ") + (flag ? "Tick":"Tock") );
        Serial.flush();
        vTaskDelay(500 / portTICK_PERIOD_MS);
      }
      // Release the mutex after leaving the critical section
      xSemaphoreGive(xMutex);
    }
    taskYIELD();
  }
}

void task_func2(void *pvParameters) {
  (void)pvParameters; // not used
  while (1) {
    // Request the mutex before entering the critical section
    if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
      // Critical section
      if (flag==1) {  
        flag = 0;
        Serial.println( String("Task 2: ") + (flag ? "Tick":"Tock") );
        Serial.flush();
        vTaskDelay(500 / portTICK_PERIOD_MS);
      }
      // Release the mutex after leaving the critical section
      xSemaphoreGive(xMutex);
    }
    taskYIELD();
  }
}

 


ตัวอย่างการใช้งาน LED Matrix#

บอร์ด Uno R4 WiFi มี LED Matrix ตัวอย่างนี้สาธิตการแสดงรูปสัญลักษณ์บน LED Matrix โดยใช้คำสั่งจากไลบรารี Arduino_LED_Matrix และแสดงรูปสัญลักษณ์ Heart ที่มีขนาดเล็กกับใหญ่ สลับกันแสดงผล โดยใช้ FreeRTOS Task นอกจากนั้นแล้วยังมีการใช้คำสั่ง analogWrite(...) สำหรับกำหนดความสว่างของ LED บนบอร์ด

#include <Arduino_FreeRTOS.h>
#include <Arduino_LED_Matrix.h>

ArduinoLEDMatrix matrix;

// Hardware support: Arduino UNO R4 and Arduino Portenta C33
TaskHandle_t task1_handle, task2_handle;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  BaseType_t ret_val = xTaskCreate( 
                         task1_func, "Task 1", 128, NULL, 1, &task1_handle );
  if (ret_val != pdPASS) {
    Serial.println( "Failed to create Task 1!!!" );
    error_handler();
  }
  ret_val = xTaskCreate( task2_func, "Task 2", 128, NULL, 1, &task2_handle );
  if (ret_val != pdPASS) {
    Serial.println("Failed to create Task 2!!!");
    error_handler();
  }
  Serial.println( "Starting the FreeRTOS scheduler ...");
  vTaskStartScheduler();
  for(;;);
}

void loop() {
  //
}

void task1_func(void *pvParameters) {
  (void)pvParameters; // not used
  TickType_t lastWakeTime = xTaskGetTickCount();
  int value = 0;
  pinMode( LED_BUILTIN, OUTPUT );
  analogWriteResolution(8);
  for(;;) {
    analogWrite( LED_BUILTIN, (value > 255) ? 511-value: value );
    value = (value+1) % 512;
    vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS(5) );
  }
}

void task2_func(void *pvParameters) {
  (void)pvParameters; // not used
  TickType_t lastWakeTime = xTaskGetTickCount();
  matrix.begin();
  int index = 0;
  for(;;) {
    matrix.loadFrame( (index==0) ?
                      LEDMATRIX_HEART_BIG : LEDMATRIX_HEART_SMALL );
    index = (index+1) % 2;
    vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS(200) );
  }
}

void error_handler() {
   Serial.println("The system will be reset...\n\n\n");
   delay(5000);
   NVIC_SystemReset();
}

 


ตัวอย่างการใช้งาน WiFi + MQTT Client#

ตัวอย่างถัดไปสาธิตการเชื่อมต่อเครือข่าย WiFi และส่ง-รับข้อความด้วย MQTT โดยใช้ Public MQTT Broker เช่น broker.emqx.io

// Uno R4 WiFi (Arduino Core for Uno R4 v1.4.1)
#include <WiFiS3.h>

// This sketch uses the PubSubClient library v2.8
// https://github.com/knolleary/pubsubclient/
#include <PubSubClient.h> 

// This file defines WIFI_SSID, WIFI_PASS, MQTT_USER and MQTT_PASS.
#include "secrets.h" 

// Select one of the following public MQTT brokers.
//#define MQTT_BROKER  "test.mosquitto.org"
//#define MQTT_BROKER  "broker.hivemq.com"
#define MQTT_BROKER    "broker.emqx.io"
#define MQTT_PORT      (1883) // no authentication for MQTT connection

// Set the topic for publishing and subscribing MQTT messages
#define SUB_TOPIC      "iotorium/arduino-mqtt/#"
#define PUB_TOPIC      "iotorium/arduino-mqtt/msg"
#define INTERVAL_MSEC  (5000) // The publishing time interval

// Global variables
WiFiClient net;                  // WiFi client
PubSubClient mqttClient(net);    // MQTT client
String ClientID = "MQTTClient";  // The prefix for MQTT client ID 
uint32_t last_pub_msec = 0;      // used to keep the timestamp value

void setup() {
  Serial.begin( 115200 ); // Initialize the Serial port
  while (!Serial) { delay(1); } // for built-in USB-Serial (USB-CDC)
  delay(1000);
  Serial.flush();
  Serial.println("\n\n\nArduino WiFi MQTT Client Demo...");

  // Connect to the WiFi network.
  connectWiFi(); 
  // String macAddr = WiFi.macAddress();
  String macAddr = getMACAddress();
  Serial.println( "MAC adddress: " + macAddr );
  macAddr.replace(":", "");
  if (macAddr.length() == 12) {
    ClientID += "-" + macAddr.substring(6);
  }
  // Initialize the MQTT broker.
  mqttClient.setServer( MQTT_BROKER, MQTT_PORT ); 
  // Set the callback function for MQTT events.
  mqttClient.setCallback( onMessageReceived ); 
  // Set buffer size for MQTT connection.
  mqttClient.setBufferSize( 512 ); 
  // Connect to the MQTT broker.
  connectMQTT(); 
}

void loop() {
  static uint32_t msg_cnt = 0; // published message count
  boolean is_connected;
  // Reconnect the MQTT broker if disconnected.
  if ( !(is_connected = mqttClient.connected()) ) {
    is_connected = connectMQTT();
  }
  if (is_connected) {
    mqttClient.loop(); // Process the MQTT event (non-blocking call).
    uint32_t now = millis();
    if ( now - last_pub_msec >= INTERVAL_MSEC ) {
      last_pub_msec = now; // Update the message publish timestamp.
      String msg = "Hello from ";
      msg += ClientID;
      msg += ", message ID=";
      msg += ++msg_cnt; // Increment the message count
      mqttClient.publish( PUB_TOPIC, msg.c_str(), false /*retained*/ );
      Serial.println( String("Published: ") + msg + "\n" );
      Serial.flush();
    }
  }
  delay(1);
}

// Connect to the WiFi access point.
void connectWiFi() {
  Serial.println("Arduino Uno R4 WiFi");
  Serial.println( String("ESP32S3 firmware version: ")
                  + WiFi.firmwareVersion() );
  WiFi.disconnect(); // Disconnect and reconnect WiFi.
  WiFi.begin( WIFI_SSID, WIFI_PASS ); // Start the WiFi client.
  // Connect the WiFi network first (if not already connected)
  while (WiFi.status() != WL_CONNECTED) { 
     Serial.print(".");
     delay(100); 
  }
  Serial.println( "\n\nWiFi Connected: ");
  // Show the IP address assigned by DHCP server / WiFi AP.
  delay(10);
  Serial.println( String ("IP address: ") + WiFi.localIP().toString() );
}

// Connect to the MQTT broker
boolean connectMQTT() {
  uint32_t repeat_count = 0;
  // Connect/reconnect the MQTT broker.
  Serial.println("Connecting the MQTT broker....\n");
  while (!mqttClient.connect(ClientID.c_str(), MQTT_USER, MQTT_PASS)) {
    repeat_count++;
    if (repeat_count >= 5) return false;
  }
  if (repeat_count > 0) {
    Serial.println( String("MQTT broker connected: ")
                   + MQTT_BROKER + "port " + MQTT_PORT);
  }
  mqttClient.subscribe( SUB_TOPIC, 1 /*QoS*/ );
  return true;
}

// This is the callback function for the incoming MQTT message.
void onMessageReceived( char *topic, byte *payload, unsigned int len ) {
  uint32_t now_msec = millis(); // Get the timestamp for message reception.
  ((char *)payload)[len] = '\0'; // Make a NULL-terminated string.
  Serial.println( "Message received:" );
  Serial.println( String("  Topic: '") + topic + "'" );
  Serial.println( String("Payload: '") + (char *)payload + "'" ); 
  Serial.println( String("    RTT: ") + (now_msec-last_pub_msec) + " msec\n" );
  Serial.flush();
}

// Get the MAC address as a String object.
String getMACAddress() {
  char sbuf[20];
  byte mac[6];
  WiFi.macAddress(mac);
  for ( int i=0; i < 6; i++) {
    sprintf( sbuf+(3*i), "%02X%s", mac[i], (i < 5) ? ":" : "" );
  }
  return String( sbuf );
}

การทำงานของโค้ดตัวอย่างนี้ จะต้องมีไฟล์ชื่อ secrets.h ด้วย เพื่อใช้ในการเชื่อมต่อ WiFi และ MQTT Broker ในรูปแบบต่อไปนี้

#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASS "YOUR_WIFI_PASSWORD"
#define MQTT_USER ""   // empty string
#define MQTT_PASS ""   // empty string

 


ตัวอย่างการใช้งาน BLE Scan#

ตัวอย่างถัดไปสาธิตการใช้งาน ESP32-S3 เพื่อให้ทำหน้าที่เป็นตัวสแกนหาอุปกรณ์ประเภท BLE ที่ทำงานอยู่ในบริเวณใกล้เคียง โดยจะให้เวลาในการสแกน 5 วินาที จากนั้นจึงหยุดการสแกน

การทำงานของโค้ดนี้ จะต้องใช้ไลบรารี <ArduinoBLE.h> (ทดลองใช้เวอร์ชัน v1.50) ซึ่งพัฒนาโดยทีมงานของ Arduino

#include <ArduinoBLE.h>

const unsigned long SCAN_TIME_MS = 5000;
bool scanning = false;
unsigned long scanStart = 0;

void printManufacturerData(BLEDevice &device) {
  uint8_t buf[64];
  int len = device.manufacturerData(buf, sizeof(buf));
  if (len < 2) {
    Serial.print(" | MFG: none");
    return;
  }
  uint16_t companyID = buf[0] | (buf[1] << 8);
  Serial.print(" | MFG ID: 0x");
  if (companyID < 0x1000) Serial.print("0");
  Serial.print(companyID, HEX);

  // Vendor identification
  if (companyID == 0x004C) {
    Serial.print(" (Apple)");
  } else if (companyID == 0x0006) {
    Serial.print(" (Microsoft)");
  } else if (companyID == 0x00E0 || companyID == 0x0131) {
    Serial.print(" (Google / Android)");
  } else if (companyID == 0x0075) {
    Serial.print(" (Samsung)");
  } else {
    Serial.print(" (Unknown)");
  }

  // Show raw manufacturer payload
  Serial.print(" | Data:");
  for (int i = 2; i < len; i++) {
    Serial.print(" ");
    if (buf[i] < 16) Serial.print("0");
    Serial.print(buf[i], HEX);
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("UNO R4 BLE Scanner");
  if (!BLE.begin()) {
    Serial.println("BLE start failed!");
    while (1);
  }
  Serial.println("Starting BLE scan (5 seconds)...");
  BLE.scan(); // Start BLE scan
  scanning = true;
  scanStart = millis();
}

void loop() {
  BLEDevice device = BLE.available();
  if (device) {
    Serial.print("Found device: ");
    if (device.hasLocalName()) {
      Serial.print(device.localName());
    } else {
      Serial.print("(no name)");
    }
    Serial.print(" | Addr: ");
    Serial.print(device.address());
    Serial.print(" | RSSI: ");
    Serial.print(device.rssi());
    Serial.print(" dBm");
    printManufacturerData(device);
    Serial.println();
  }
  // Stop scan after timeout
  if (scanning && (millis() - scanStart >= SCAN_TIME_MS)) {
    BLE.stopScan();
    scanning = false;
    Serial.println("Scan finished.");
  }

  BLE.poll();
}

 


ตัวอย่างการใช้งาน BLE UART Service#

ตัวอย่างถัดไป สาธิตการเปิดบริการที่เรียกว่า BLE UART Service กล่าวคือ ทำให้อุปกรณ์ ESP32-S3 ทำหน้าที่เป็น BLE Server และอนุญาตให้อุปกรณ์อื่น (BLE Client) เชื่อมต่อเข้ามา จากนั้นจึงสามารถรับหรือส่งข้อมูลแบบ UART แบบไร้สายได้

#include <ArduinoBLE.h> // v1.50 by Arduino

// Nordic UART UUIDs
BLEService uartService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");

BLECharacteristic txChar(
  "6E400003-B5A3-F393-E0A9-E50E24DCCA9E",
  BLENotify,
  64 //bytes
);

BLECharacteristic rxChar(
  "6E400002-B5A3-F393-E0A9-E50E24DCCA9E",
  BLEWrite,
  64 // bytes
);

BLEDevice central;
unsigned long lastTx = 0;

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n\nUNO R4 BLE UART (ArduinoBLE) Demo");

  if (!BLE.begin()) {
    Serial.println("BLE init failed");
    while (1);
  }
  BLE.setLocalName("UNO-R4-UART");
  BLE.setDeviceName("UNO-R4-UART");
  BLE.setAdvertisedService(uartService);

  uartService.addCharacteristic(txChar);
  uartService.addCharacteristic(rxChar);
  BLE.addService(uartService);

  BLE.advertise();
  Serial.println("Advertising...");
}

void loop() {
  static uint32_t cnt = 0;

  BLE.poll();

  if (!central) {
    central = BLE.central();
    if (central) {
      Serial.print("Connected: ");
      Serial.println(central.address());
    }
    return;
  }

  if (!central.connected()) {
    Serial.println("Disconnected");
    central = BLEDevice();
    return;
  }
  /* RX */
  if (rxChar.written()) {
    int len = rxChar.valueLength();
    const uint8_t *data = rxChar.value();
    Serial.print("RX: ");
    Serial.write(data, len);
    Serial.println();
  }
  /* TX (notify only) */
  if (txChar.subscribed() && millis() - lastTx > 1000) {
    lastTx = millis();
    char msg[64];
    snprintf(msg, sizeof(msg), 
             "Hello from Uno R4 WiFi #%lu\r\n", ++cnt);
    txChar.writeValue((uint8_t*)msg, strlen(msg));
  }
}

รูป: ตัวอย่างการเชื่อมต่อด้วย BLE UART

 


ตัวอย่างการใช้งาน BLE UART + FreeRTOS#

ตัวอย่างนี้สาธิตการใช้งาน BLE เพื่อให้บริการ BLE UART Service แต่มีการใช้งานร่วมกับ FreeRTOS โดยมีการสร้างทาสก์ ให้ทำงานในส่วนที่เกี่ยวข้องกับ BLE

#include <Arduino_FreeRTOS.h>
#include <ArduinoBLE.h>  // v1.50 by Arduino

// LED pin for Uno R4 WiFi (built-in)
const int ledPin = LED_BUILTIN;

/* Nordic UART UUIDs */
BLEService uartService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");

BLECharacteristic txChar(
  "6E400003-B5A3-F393-E0A9-E50E24DCCA9E",
  BLENotify,
  64  //bytes
);

BLECharacteristic rxChar(
  "6E400002-B5A3-F393-E0A9-E50E24DCCA9E",
  BLEWrite,
  64  // bytes
);

BLEDevice central;
unsigned long lastTx = 0;

// LED Blinking Task
void BlinkTask(void *pvParameters) {
  pinMode(ledPin, OUTPUT);
  while (1) {
    digitalWrite(ledPin, HIGH);
    vTaskDelay(500 / portTICK_PERIOD_MS);
    digitalWrite(ledPin, LOW);
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void BLETask(void *pvParameters) {
  uint32_t cnt = 0;
  Serial.println("BLE task...");

  if (!BLE.begin()) {
    Serial.println("BLE init failed");
    while (1)
      vTaskDelay(1000);
  }
  BLE.setLocalName("UNO-R4-UART");
  BLE.setDeviceName("UNO-R4-UART");
  BLE.setAdvertisedService(uartService);

  uartService.addCharacteristic(txChar);
  uartService.addCharacteristic(rxChar);
  BLE.addService(uartService);

  BLE.advertise();
  Serial.println("Advertising...");

  while (1) {
    BLE.poll();

    if (!central) {
      central = BLE.central();
      if (central) {
        Serial.print("Connected: ");
        Serial.println(central.address());
      }
      vTaskDelay(pdMS_TO_TICKS(5));
      continue;
    }

    if (!central.connected()) {
      Serial.println("Disconnected");
      central = BLEDevice();
      vTaskDelay(pdMS_TO_TICKS(5));
      continue;
    }

    //RX: BLE client -> Uno R4 WiFi
    if (rxChar.written()) {
      char buf[65];
      int len = rxChar.valueLength();

      memcpy(buf, rxChar.value(), len);
      buf[len] = '\0'; // Null-terminated C string
      Serial.print("RX: ");
      Serial.println(buf);
    }
    // TX: Uno R4 WiFi -> BLE Client
    if (txChar.subscribed() && millis() - lastTx > 1000) {
      lastTx = millis();
      char msg[64];
      snprintf(msg, sizeof(msg),
               "Hello from UNO R4 #%lu\r\n", ++cnt);
      txChar.writeValue((uint8_t *)msg, strlen(msg));
    }
    vTaskDelay(pdMS_TO_TICKS(5));
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial) {}
  delay(100);
  Serial.println("\n\n\n");
  Serial.flush();
  Serial.println("Uno R4 Wifi: BLE + FreeRTOS Demo");
  // Create FreeRTOS tasks
  xTaskCreate(BlinkTask, "Blink", 128, NULL, 1, NULL);
  xTaskCreate(BLETask, "BLE", 1024, NULL, 2, NULL);
  Serial.println("Tasks created");
  // Start the FreeRTOS scheduler
  vTaskStartScheduler();
}

void loop() {
}

รูป: ตัวอย่างการเชื่อมต่อกับ Uno R4 WiFi โดยใข้แอปพลิเคชัน BluetoothSerial Terminal บนสมาร์โฟน Android

 


ตัวอย่างการใช้งาน FspTimer#

หากต้องการใช้วงจร Timer (เช่น GPT ขนาด 32 บิต และ APT ขนาด 16 บิต) ภายในชิปไมโครคอนโทรลเลอร์ RA4M1 ก็สามารถใช้คลาส FspTimer ในไลบรารี <FspTimer.h> ซึ่งเป็นส่วนหนึ่งของ Arduino Core for Renesas

โหมดการทำงานของวงจร Timer มีให้เลือก 2 แบบ คือ วงจรนับความความถี่คงที่ (TIMER_MODE_PERIODIC) และวงจรสร้างสัญญาณ PWM (TIMER_MODE_PWM)

คำสั่ง begin(...) ของ FspTimer สำหรับการทำงานด้วยความถี่คงที่ และสามารถกำหนดฟังก์ชัน Callback ได้ มีรูปแบบดังนี้

    bool begin( timer_mode_t mode,
                uint8_t type, 
                uint8_t channel,
                float freq_hz, 
                float duty_perc, 
                GPTimerCbk_f cbk = nullptr, 
                void *ctx = nullptr );
#include <Arduino.h>
#include <FspTimer.h>

FspTimer timer; // FspTimer instance
volatile bool led_state = false; // LED state

void timerCallback(timer_callback_args_t *p_args) { // ISR for timer overflow
    (void)p_args;            // unused
    led_state = !led_state;  // toggle state
}

void timerInit() {
    timer_mode_t timer_mode = TIMER_MODE_PERIODIC;
    uint8_t timer_type = GPT_TIMER;
    float timer_freq_hz = 10.0f;  // 10 Hz

    int timer_index = FspTimer::get_available_timer(timer_type);
    if (timer_index < 0) {
        timer_index = FspTimer::get_available_timer(timer_type, true);
    }

    if (timer_index < 0) {
        Serial.println("Timer init failed.");
        while (1);
    }
    // Configure the FSR timer instance
    timer.begin(
        timer_mode,
        timer_type,
        timer_index,
        timer_freq_hz,
        0.0,
        timerCallback,
        nullptr
    );
    timer.setup_overflow_irq();
    timer.open();
    timer.start();
}

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
    timerInit();
}

void loop() {
    // LED update 
    digitalWrite(LED_BUILTIN, led_state);
}

 


ตัวอย่างการใช้งานสำหรับ Uno R4 WiFi + SPI ADC / DAC#

ผู้อ่านสามารถศึกษาตัวอย่างการเขียนโค้ด Arduino สำหรับ Uno R4 WiFi จากบทความต่อไปนี้ เพื่อใช้งานบัส SPI สำหรับไอซีหรือโมดูลอิเล็กทรอนิกส์ ADC / DAC ต่อไปนี้

สาธิตการใช้คำสั่งของ SPI:

  • SPI.begin()
  • SPI.beginTransaction(...)
  • SPI.transfer16(...)
  • SPI.transfer(...)
  • SPI.endTransaction()

และตัวอย่างการใช้คำสั่งสำหรับใช้งาน Built-in ADC / DAC:

  • analogReadResolution(...)
  • analogRead(...)
  • analogWriteResolution(...)
  • analogWrite(...)

 


กล่าวสรุป#

บทความนี้ได้นำเสนอข้อมูลเกี่ยวกับวงจรบนบอร์ดและการใช้งาน Arduino Uno R4 WiFi และการเขียนโปรแกรม Arduino Sketch โดยใช้ Arduino IDE ในเบื้องต้น นอกเหนือจากบอร์ดที่ผลิตโดย Arduino แล้ว ยังมีบอร์ดที่เรียกว่า Arduino Uno R4 compatible ซึ่งมีราคาถูกกว่า ผลิตมาจากประเทศจีน และสามารถใช้แทนกันได้ เหมาะสำหรับผู้ที่สนใจลองใช้งานบอร์ดดังกล่าวในเบื้องต้น ในบทความนี้ได้นำเสนอตัวอย่างการใช้งาน FreeRTOS และทดลองใช้งานกับบอร์ด Uno R4 WiFI

 


This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Created: 2024-08-17 | Last Updated: 2026-01-24