2023年3月24日星期五

[Ameba] RTL8720DN 與 溫溼度感測 DHT20 實作 (BW16)

實作要點

本次實作使用 RTL8720DN 透過 I2C 介面讀取 DHT20 溫溼度感測及在透過 I2C 介面將讀取結果顯示於 OLED SSD1306。這次使用 VSCODE + Arduino 插件的方式實作程式寫作。

硬體清單

軟體實作

軟體主題有 2 個項目,
OLED SSD1306 及 DHT20.OLED SSD1306 使用 u8g2 程式庫。 DHT20 的程式庫則使用 DFRobot 的 DHT20 程式庫 https://github.com/DFRobot/DFRobot_DHT20 )

u8g2 library 先在 Arduino IDE 裝好 u8g2 程式庫



DHT20 程式庫

準備就緒後,進行程式段。


void setup(){
  Serial.begin(115200);
 
  //Initialize sensor
  while(dht20.begin()){
    Serial.println("Initialize sensor failed");
    delay(1000);
  }
  
  u8g2.begin();
  u8g2.setFont(u8g2_font_8x13_mf);
  u8g2.setFontPosTop();
  fontHigh = u8g2.getMaxCharHeight();
  fontWidth = u8g2.getMaxCharWidth();
  
  u8g2.clear();
  u8g2.setCursor(0,0);
  u8g2.print("temp:");
  u8g2.updateDisplay();
  delay(100);
  u8g2.setCursor(0,fontHigh);
  u8g2.print("Humidity:");
  u8g2.updateDisplay();
}

void loop(){
  //Get ambient temperature
  tempValue = dht20.getTemperature();
  Serial.print("temp:"); Serial.print(tempValue);Serial.print("C");
  delay(100);
  
  //clean temp display
  u8g2.setCursor(fontWidth * 5 + 1,0);
  u8g2.print("    ");
  u8g2.updateDisplay();
  //display temp value to oled
  delay(10);
  String tempStr = String(tempValue,2);
  u8g2.setCursor(fontWidth * 5 + 1,0);
  u8g2.print(tempStr + "C");
  u8g2.updateDisplay();
  delay(500);
 
  //Get relative humidity
  humidityValue = dht20.getHumidity()*100;
  Serial.print("  humidity:"); Serial.print(humidityValue);Serial.println(" %RH");
  delay(100);
  
  //clean temp display
  u8g2.setCursor(fontWidth * 9 + 1,fontHigh);
  u8g2.print("    ");
  u8g2.updateDisplay();
  
  //display temp value to oled
  delay(10);
  String humidityStr = String(humidityValue,2);
  u8g2.setCursor(fontWidth * 9 + 1,fontHigh);
  u8g2.print(humidityStr + "%");
  u8g2.updateDisplay();
  delay(1000);
}
RTL8720DN,BW16

Github 原始碼

https://github.com/cold63/Arduino_Code/tree/main/Ameba_DHT20

相關連結

A1 Pico / RTL8720DN
https://www.makdev.net/2021/09/ameba-ameba-bw16-arduino-ide.html

RTL8720DN 擴展板
https://www.makdev.net/2022/09/ameba-bw16-type-c-shield.html

2023年1月4日星期三

[Ameba] RTL8720DN 與 V7RC App 藍芽控制

Ameba 與手機連結

V7RC 是由 嵐奕科技 所開發的 App , 可以在 iOS 及 Android 系統運行。 V7RC App 可透過 藍芽及 WiFi 控制一般遙控車或是遠端控制應用。 在這裡做簡單直覺的範例做為基礎,望在爾後做更多的應用。

首先,開啟 範例
File / Examples / AmebaBLE / BLEUartService

ESP32,RTL8720DN,BW16

直接編譯並上傳至 RTL8720DN

V7RC App

設定連接藍芽

ESP32,RTL8720DN,BW16,V7RC

選定 車輛模式

ESP32,RTL8720DN,BW16,V7RC

開啟 Arduino IDE 的 Serial Monitor

移動 左右舵 及 上下舵
節錄一小段反饋

Received string: SRV1500150015001500#

SRV1500150015001500# 是由 V7RC 反饋的訊息

所以是
SRV (前綴碼) + 4 組 4 位數 + '#' 結束符
所組成的
前綴碼會依不同模式,而有所不同.
例如:
車輛: SRV
坦克: SRT

只要針對反饋的數值做處理就可以對我們的標的做控制。
到這裡,可以操作 左右舵及上下舵 看看有甚麼變化,這裡就不贅述

建立結構


typedef struct{
    bool reciveCMDFlag;
    int  ReciveValue;
    int  Pin;
    AmebaServo Servo;

}_rCMD;

uint8_t DefinePin[2] = {3,12};

定義 3,12 為PWM 輸出腳位

建立 - 解析反饋訊息


void ParseCMDString(String cmd)
{
    int comdLength = cmd.length();
    if(cmd.charAt(comdLength - 1) != '#')
        return;
    if(cmd.indexOf("SRV") > -1 ){
        int x = 3;
        int ValueIndex = 0;
        while(x < comdLength - 1){
            if(x + 3 < comdLength){
                String _NumString = cmd.substring(x,x + 4);
                
                if(ValueIndex < MaxNumValue){
                    if(bleReciveData[ValueIndex].ReciveValue != _NumString.toInt()){
                        bleReciveData[ValueIndex].ReciveValue = _NumString.toInt();
                        bleReciveData[ValueIndex].reciveCMDFlag = true;
                    }
                }
            }
            ValueIndex++;
            x += 4;
            Serial.println();
        }
        
    }
}

這個解析函式,將放在 writeCB call back function 裡
會自動填入 bleReciveDate 這個 Arrary.

當 reciveCMDFlag 為 true , 在 loop()裡就會個別對 sg90 Servo 控制。


void loop()
{

    while(Count < MaxNumValue) {
        
            if(bleReciveData[Count].reciveCMDFlag && bleReciveData[Count].Pin == 3){
                bleReciveData[Count].reciveCMDFlag = false;

                int Angle = map(bleReciveData[Count].ReciveValue,1000,2000,0,180);
                bleReciveData[Count].Servo.write(Angle);
            }
            

            if(bleReciveData[Count].reciveCMDFlag && bleReciveData[Count].Pin == 12){
                bleReciveData[Count].reciveCMDFlag = false;

                int Angle = map(bleReciveData[Count].ReciveValue,1000,2000,0,180);
                bleReciveData[Count].Servo.write(Angle);

            }

        
        Count++;
    }
    Count = 0;
    delay(1);
}

 

另外,在原範例的


Rx.setWriteProperty(true);

改為


Rx.setWriteNRProperty(true);

這個範例是控制 2個 SG90 Servo,若控制不同裝置時,例如: 驅動馬達,就要視情況再修改程式

 

原始程式碼

https://github.com/cold63/Arduino_Code/tree/main/V7RC_RTL8720DN

 

相關連結

iOS V7RC App
https://apps.apple.com/tw/app/v7rc/id1390983964
Android V7RC App
https://play.google.com/store/apps/details?id=com.v7idea.v7rcliteandroidsdkversion&hl=zh_TW&gl=US

 

[Ameba] RTL8720DN GPIO 中斷

使用中斷

GPIO 中斷對於 MCU 來說是非常好用的功能,並可以幫助時序的問題。可以用來偵測輸入開關,或是遮斷器的應用,抑或是用來偵測時脈的 Timing。 Ameba 的GPIO 中斷使用方法有稍微的不同,我們用簡單的範例來玩玩看。

觸發點

標準的時脈 (或是另一個說法 -> 方波) ,有上升段 (RISE) 及 下升段 (FALL)。 在 Setup() 就需要指定觸發點在何處,這會和您的電路有關。以這次的範例是以 RTL8720DN 擴展為例,User key 指定 IO Pin 為 6 ,接入開關後接地。 所以觸發點為 下升段(FALL)

波形示意圖

ESP32,RTL8720DN


User Key Button 電路

 

範例說明

範例在 ”File” -> “Example” -> “AmebaGPIO” -> “LED_InterruptCtrl”
打開後先另存 Save as ...
針對 擴展板 修改,指定 IO 6 為 偵測腳,IO 9 為 A1 Pico 的 LED


int button = 6;
int led    = 9;

觸發點為 FALL -> INPUT_IRQ_FALL


pinMode(button, INPUT_IRQ_FALL);

用 digitalSetIrqHandler f指定反饋 function


digitalSetIrqHandler(button, button_handler);

void button_handler(uint32_t id, uint32_t event) {}

這個範例的結果是 按 User Key 並放開,LED 會亮。再按一次 LED 會滅。

範例程式碼

https://github.com/cold63/Arduino_Code/tree/main/Interrupt_Ctrl_LED

 

2022年12月23日星期五

[STM32] FreeRTOS 手動移植至 CubeIDE 過程記錄

FreeRTOS

FreeRTOS 是一種即時作業系統,非常適用於微控制器應用。當然 STM32 也是在其中最適合於 FreeRTOS 操作的微控制器,這次來介紹 CubeIDE 環境中如何手動加入 FreeRTOS 系統。這次使用的開發板是 NUCLEO-L476RG,IDE 是 CubeIDE。

下載 FreeRTOS

在 FreerRTOS (https://www.freertos.org/) 直接下載,目前是 FreeRTOSv202112.00 這個版本

STM32,FreeRTOS

建構 FreeRTOS

下載後,解開壓縮檔。有幾個資料夾及檔案 (FreeRTOS,FreeRTOS-Plus,tools .....etc),我們只要 " FreeRTOS " 這個資料夾及內容。我採取的是刪除法,先建立一個空的資料夾,然後將 FreeRTOS 複製到剛建立的資料夾內。

複製完成後,直接在這個臨時資料夾內操作。

FreeRTOS 資料夾內有 Demo , License , Source , Test 等等內容。保留 License , Source,其他都刪除。

直接到 Source\portable 內 ,保留 GCC , 及 MemMang 這兩個資料夾,其他刪除。

L476RG 是個 M4 及含 FPU 運算的微控制器,所以

在 Source\portable\GCC 內, 只保留 ARM_CM4F 資料夾。

回到 MemMang 內
保留 heap_4.c , 其餘刪除

到這裡我們需要的檔案已經完成了。

CubeIDE 開啟新專案

我們設定 2 個 GPIO-OUT , 分別是 LD1 & LD2

STM32,FreeRTOS

在 NVIC 中斷設定, 優先權設為 NVIC_PriorityGroup_4

STM32,FreeRTOS

接著產生 BSP code。

調整

產生 BSP code 後,開始做相對應的設定。
複製 FreeRTOS code。

在 "建構 FreeRTOS" 所以建立的資料夾, 直接用拖拉的方式。複製到 CubeIDE 左側的 Project Exploper。

STM32,FreeRTOS

開啟 Project / Properties 對話框

找 C/C++ General / Paths and Symbols , 分別在 Includes , Source Location 這兩個標籤 (Tab) 設定

Includes :

FreeRTOS/Source/include
FreeRTOS/Source/portable/GCC/ARM_CM4F

STM32,FreeRTOS

Source Location :

加入 FreeRTOS/Source

STM32,FreeRTOS

修改 stm32l4xx_it.c


void SysTick_Handler(void)
void PendSV_Handler(void)
void SVC_Handler(void)

3個 function 用 /**/ 注釋掉

建立 FreeRTOSConfig.h


在 FreeRTOS 中找到
FreeRTOS/Demo/CORTEX_M4F_STM32F407ZG-SK/ FreeRTOSConfig.h
複製到 專案資料夾的 Core/Inc 內


內容做小修改


#ifdef __ICCARM__
    #include 
    extern uint32_t SystemCoreClock;
#endif

改成符合 CubeIDE


#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include 
    extern uint32_t SystemCoreClock;
#endif

以下 2 個參數改為 0


#define configUSE_IDLE_HOOK                0
#define configUSE_TICK_HOOK                0

範例: 測試點亮 LED

到這裡, 開始寫 code
首先在 main() 前複製 這 2 個空 function


void vApplicationMallocFailedHook( void )
{
    /* vApplicationMallocFailedHook() will only be called if
    configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
    function that will get called if a call to pvPortMalloc() fails.
    pvPortMalloc() is called internally by the kernel whenever a task, queue,
    timer or semaphore is created.  It is also called by various parts of the
    demo application.  If heap_1.c or heap_2.c are used, then the size of the
    heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
    FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
    to query the size of free heap space that remains (although it does not
    provide information on how the remaining heap might be fragmented). */
    taskDISABLE_INTERRUPTS();


    for( ;; );
}




void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
    /* This function will get called if a task overflows its stack.   If the
    parameters are corrupt then inspect pxCurrentTCB to find which was the
    offending task. */


    ( void ) pxTask;
    ( void ) pcTaskName;


    for( ;; );
}

我們有 2 個 LED , 所以分別用 2 個 Thread 控制


static void Blink1_Task(void *pvParameters)
{
TickType_t xlastFlashTime;
xlastFlashTime = xTaskGetTickCount();


while(1){
     vTaskDelayUntil(&xlastFlashTime,500);


     HAL_GPIO_TogglePin(GPIOA, LD1_Pin);


}


}


static void Blink2_Task(void *pvParameters)
{
TickType_t xlastFlashTime;
xlastFlashTime = xTaskGetTickCount();


while(1){
     vTaskDelayUntil(&xlastFlashTime,500);


     HAL_GPIO_TogglePin(GPIOA, LD2_Pin);


}


}

在 main()


  xTaskCreate(Blink1_Task,"Blink1",128,NULL,1,NULL);
  xTaskCreate(Blink2_Task,"Blink2",128,NULL,2,NULL);
  vTaskStartScheduler();

執行效果是這 2 個 LED 看起來會像是同時間點亮。


範例 Source code 放在 Github,
https://github.com/cold63/STM32_Code/tree/master/Freertos_M4F

 

2022年9月30日星期五

[Ameba] RTL8720DN /BW16 二合一擴展板 Shield

支援兩款 RTL8720DN 開發板

  • A1 Pico - Kevin's Lab 
  • BW16 kit - Ai Thinker

 

 

規劃初衷

希望在實做Iot 應用作品時,可以很輕鬆的接入各種感測器及模組。並全力專心在程式開發上,減少在接線錯誤造成開發時間延宕。且同時保有擴展性,保留排針排及使用 Grove 連接器,使開發板增加擴展性。

硬體規格

  • 尺寸: 81.3 x 81.3 mm
  • 孔位 : Arduino uno 固定孔。
  • 電源輸入 : 6V ~ 18V 
  • 電源連接器: DC Jack 2.1(內正外負) , 可用變壓器(電流建議 >1A) 或是 2 顆 3.7V 鋰電池 (例如 18650) 串聯成 7.4V
  • Grove 接口 x 2 。 1 組 UART , 1 組 I2C

ESP32,BW16,RTL8720DN

BW16,RTL8720DN,ESP32



RTL8720DN,BW16,ESP32


支援外接模組

BW16,RTL8720DN,ESP32
  • PMS5003空氣偵測器
  • L9110S 模組 & TT 馬達
  • TFT LCD  / 240 x 320 Pixel
  • 伺服馬達
  • Buzzer
  • OLED SSD1306
  • RGB LED
  • MPU6050
  • HS-SR04 超音波
  • DHT20 溫溼度感測 / Grove 連接器
  • WS2812 LED


BW16,RTL8720DN,ESP32

注意事項

  • 接入開發板及模組時,請注意電源正負極方向,避免開發板及模組損壞
  • 使用 伺服馬達及 TT 馬達時,請務必使用 外接電源。有防呆機制,只使用 USB 5V 時,伺服馬達及 TT 馬達接口並不會有 5V 輸出。

如何購買

RTL8720DN 擴展板

 

相關

影片展示 :YouTube
開發板 : A1 Pico

 

2022年8月29日星期一

[PI PICO RP2040] HC-SR04 應用 @ C/C++

這個實驗是偶然搜尋到一個國外朋友使用 Raspberry pi Pico 控制 HC-SR04 的範例 Video (https://www.youtube.com/watch?v=5cWDgrbZers),我也想練習看看。順便優化他的程式 (https://github.com/KleistRobotics/Pico-Ultrasonic) 。

HC-SR04 是個 超聲波傳感器,可用來確認與物體的距離。偵測範圍可以到 2cm ~ 400cm 之間。以下是它的規格。

  • 電源: +5V DC
  • 靜態電流: <2mA
  • 工作電流: 15mA
  • 有效角度:<15°
  • 測距距離:2cm – 400 cm/1″ – 13ft
  • 測量角度:30度
  • 觸發輸入脈衝寬度:10uS TTL脈衝

信號傳輸和接收之間的時間能讓我們計算到物體的距離,因為我們知道聲音在空氣中的速度。

環境溫度 20ºC (68ºF) 時空氣中的聲速 = 343m/s

計算與物體的距離 = (行程時間 / 2) x 聲速

聲速為 343m/S = 0.0343 cm/uS = 1/29.1 cm/uS

HC-SR04 Spec. (來源 : https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf )

開始前必須在 Trigger 產生 10uS TTL 訊號, SR04 Module 便會自動產生 40KHz 聲波,接收回波後反映在 Echo pin 上,產生下緣信號。

PI PICO,SR04

在程式上


uint64_t sr04_sonic::getPulse(int trigPin,int echoPin)
{
    gpio_put(trigPin,1);
    sleep_us(10);
    gpio_put(trigPin,0);


    uint64_t width = 0;


    while(gpio_get(echoPin) == 0) tight_loop_contents();
    absolute_time_t startTime = get_absolute_time();
    while(gpio_get(echoPin) == 1){
        width++;
        sleep_us(1);
       if(width > timeout) return 0;
    }
    absolute_time_t endTime = get_absolute_time();
    return absolute_time_diff_us(startTime,endTime);
}


uint64_t sr04_sonic::getCM()
{
    uint64_t pulseLength = getPulse(this->trigPin,this->echoPin);
    return pulseLength /29.1/2; //or multiply by 0.0343
}

電路

完整程式碼

Github : https://github.com/cold63/Pico_C_Project/tree/main/sonic_sr04

 

2022年8月22日星期一

[PI PICO] Probe Debug 製作及使用

使用 C/C++ SDK 開發 Raspberry pi Pico 程式,編譯完成後產生 UF2 檔案。然後將這個檔案複製到 Pico 開發板上完成燒錄動作,就如同 Pi Pico 官方網站的示範展示 (https://www.raspberrypi.com/documentation/microcontrollers/c_sdk.html#your-first-binaries )。但若是頻繁修改的狀態下,這樣的操作方式就有點不方便使用了。

Pi Pico 還有如同其他 ARM 平台一樣有 SWD Debug port, 所以可以走這個路徑做板子燒錄及進行程式除錯。

在官方文件 (https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf ) 的 58 頁 (Appendix A: Using Picoprobe ) 及 62 頁msys, 說明了透過另一個 Pico 板 做為 Probe Debug 功能,及接線方法。

PI Pico RP2040

Debug Probe 電路

Pi Pico RP2040

J1 是 標準的 10 pin JTAG 連接器,預留。
J2 連接至 Pi Pico 的 SWD CLK 及 SWIO,如果需要有 printf 功能, 則分別接入 TX , RX。VSYS 可不用接,Target 的 Pi Pico 獨立接入 USB 做為電源輸入。

實物連接

PI Pico RP2040

Demo 影片

原始電路圖 及 Gerber

https://github.com/cold63/Pico_C_Project/tree/main/Debug_Probe