2022年6月10日星期五

[Ameba] 使用Arduino Wire 基本函式存取 24C02 EEPROM / I2C

什麼是 EEPROM ?

EEPROM 代表電子可擦除式可做讀寫的存儲器。它允許在使用非常少的功率的情況下長時間寫入和存儲值。大多數微控制器甚至在其電路中直接有 EEPROM,例如 ATmega328P(Arduino Uno 芯片),它有 1KB。但如果這還不夠呢?SD 卡具有更大的存儲容量,但也更複雜、體積更大且耗電量更大。

這次的範例使用 Arduino 的 Wire 基本函式, 不套用現成 Library 。從實做中理解控制原理。這次選用型號為 AT24C02B / 儲存空間 2Kbit

Datasheet ( https://ww1.microchip.com/downloads/en/DeviceDoc/doc5126.pdf)

輸出腳位

24C02,Arduino

開發板

此次使用的是 自行開發的 A1 Lite / Realtek RL8720DN 。連結在此 (連結) ,在這就不多做介紹。
在 A1 Lite 使用 I2C 前先將預裝的提升電阻用焊接的方式將 JP2 , JP3 短接起來

A1 Lite,Arduino,RTL8720DN,BW16

接線

AT24C02ConnectA1 Lite
A0GND 
A1GND 
A2GND 
GNDGNDGND
SDA 8
SCL 7
WPGND 
VCC3V33V3

EEPROM I2C 位址

位址為 7-bit 規則 , A0 ~ A2 均接地。 所以位址為 0x50

 

寫入資料

Ameba,I2C

我們要先確認 WP 是否接入 GND。首先送出 EEPROM 的設備位址,0x50 ~ 0x57 之間。根據接線需送出 0x50 (若設備得到正確位址會有 NACK/ACK 反饋)。接著送出數據位址,再送出資料,最後發出 STOP 訊號 endTransmission() 告知 EEPROM 不再繼續。

程式碼


void WriteByte(uint8_t data_addr, uint8_t data)
{
 
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  Wire.write(data);
  Wire.endTransmission();
}

讀取資料

Ameba,I2C

首先要先送出 EEPROM 設備位址 及 數據位址。接下來再送出 設備位址,EEPROM 會反饋 1 組(Byte)資料。

程式碼


uint8_t ReadByte(uint8_t data_addr)
{
  uint8_t data;
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  Wire.endTransmission();
  Wire.requestFrom(EEPROM_ADDRESS,1);


  if(Wire.available())
  {
    data = Wire.read(); 
  }
  Wire.endTransmission();
 
  return data;
}

綜合以上,組成


  WriteByte(1,0x5A);
  delay(10);
  
  Serial.println(ReadByte(1),HEX);

輸出結果

進階

以 AT24C02 來說, 它是由 8 bytes 組成 一個 page, 以這個型號有 32 page。它可以一次寫入讀取最多 8 bytes 的資料, 我們將改寫程式

寫入資料



void WriteBytes(uint8_t data_addr, uint8_t *data,uint8_t len)
{


  uint8_t x;
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  for(x = 0; x < len; x++)
  {
    Wire.write(data[x]);  
  }
  
  Wire.endTransmission();
}

讀取資料


void ReadBytes(uint8_t data_addr,uint8_t *data, int len)
{
  uint8_t x;
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  Wire.endTransmission();
  Wire.requestFrom(EEPROM_ADDRESS,len);


  if(Wire.available())
  {
    for(x = 0; x < len;x++)
    {
      data[x] = Wire.read();    
    }
    
  }
  Wire.endTransmission();
  
}

輸出結果

Ameba,I2C

 

 

GitHub 完整程式碼

連結 ( https://github.com/cold63/Arduino_Code/tree/main/I2C_EEPROM )

其他參考

TI 應用手冊 Understanding the I2C Bus (SLVA704 )
連結 ( https://www.ti.com/lit/an/slva704/slva704.pdf )

 

2022年6月8日星期三

[STM32] 通過 I2C 控制 LCD1602

PCF8574 是擴展 I/O 的晶片並透過 I2C 協議通訊。主控端可以通過 PCF8574 暫存器進行 I/O 端的讀取狀態或是做為輸出端口。

datasheet 連結 (https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf)

STM32,1602

PCF8574 Address 定義

STM32,1602

若要調整 Address , 則短接接地即可。


LCD1602

4 bit 初始流程

STM32,LCD1602

指令集

STM32,LCD1602

連接表格

PINDEFINEPCF8574 PIN
1VSS 
2VCC 
3VEE 
4RSP0
5R/WP1
6ENP2
7DB0 
8DB1 
9DB2 
10DB3 
11DB4P4
12DB5P5
13DB6P6
14DB7P7
15LED+123
16LED-123

程式碼


void lcd_send_cmd(char cmd)
{
    char data_h,data_l;
    uint8_t frame_data[4];
    data_h = (cmd&0xf0);
    data_l = ((cmd <<4)&0xf0);
    frame_data[0] = data_h | 0x0C;    //en=1, rs=0
    frame_data[1] = data_h | 0x08;    //en=0, rs=0
    frame_data[2] = data_l | 0x0C;    //en=1, rs=0
    frame_data[3] = data_l | 0x08;    //en=0, rs=0

    HAL_I2C_Master_Transmit(&hi2c1,LCD_ADDRESS,(uint8_t *)frame_data,4,0x100);

    HAL_Delay(1);
}


void lcd_send_data(char data)
{
    char data_h,data_l;
    uint8_t frame_data[4];
    data_h = (data&0xf0);
    data_l = ((data <<4)&0xf0);
    frame_data[0] = data_h | 0x0D;    //en=1, rs=1
    frame_data[1] = data_h | 0x09;    //en=0, rs=1
    frame_data[2] = data_l | 0x0D;    //en=1, rs=1
    frame_data[3] = data_l | 0x09;    //en=0, rs=1

    HAL_I2C_Master_Transmit(&hi2c1,LCD_ADDRESS,(uint8_t *)frame_data,4,0x100);
    HAL_Delay(1);
}


void lcd_clear()
{
    lcd_send_cmd(0x01);
    HAL_Delay(1);
}


void lcd_Init()
{
    HAL_Delay(50);
    lcd_send_cmd(0x30);
    HAL_Delay(5);
    lcd_send_cmd(0x30);
    HAL_Delay(1);
    lcd_send_cmd(0x30);
    HAL_Delay(10);
    lcd_send_cmd(0x20);
    HAL_Delay(10);


    lcd_send_cmd(0x28);        //function set
    HAL_Delay(1);
    lcd_send_cmd(0x08);        //Display on/off
    HAL_Delay(1);
    lcd_send_cmd(0x01);        //clear display
    HAL_Delay(1);
    lcd_send_cmd(0x06);        //Enter mode
    HAL_Delay(1);
    lcd_send_cmd(0x0C);        //Display on/off
    HAL_Delay(1);


}


void lcd_send_string (char *str)
{
    while(*str)
    {
        lcd_send_data(*str++);
    }
    HAL_Delay(1);
}


void lcd_put_cur(uint8_t row,uint8_t col)
{
    lcd_send_cmd(0x80 | (col + (0x40 * row)));
}

主控程式段



lcd_Init();


  /* USER CODE END 2 */


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
      lcd_put_cur(0,2);
      lcd_send_string("Hello World!");
      lcd_put_cur(1,1);
      lcd_send_string("www.makdev.net");
      HAL_Delay(1000);
      lcd_clear();
      HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }

顯示輸出

STM32,LCD1602

原始碼連結

https://github.com/cold63/STM32_Code/tree/master/L476G-LCD

 

2022年5月3日星期二

[STM32] 透過 ADC 數值控制 PWM 及 伺服馬達 Servo

最近在使用 Arduino AmebaIot 控制 SG90 Servo, 心想也有一段時間沒在寫 STM32 的 Code了,想要練練手感所以發起這個小實驗。想要目的結果是透過 VR可變電阻改變 ADC 值,確認比例之後。間接改變 Servo 的 0度 ~ 180度。 總結來說,會用到的功能環節是 ADC 讀值 , PWM 空占比控制。

 

MCU 設定

這次使用自製的開發板,MCU 為 K051。除了基本設定外,個別加入 ADC IN 及 Time PWM Out 設定
ADC -> ADC_IN8
TIMER -> TIM3_CH2

STM32 PWM

Time 設定 ,使用 Tim3 的 Channel2 。

STM32 PWM

ADC 輸入

使用 Polling 方式輸入 , 請參考 ADC 轉換器 - 使用 Polling 多通道輪詢模式 (連結)
這裡是透過 可變電阻 VR 影響 ADC IN 的輸入值,進而計算出當時的比例值
提示 : STM32 預設解析度為 12 bit = 4096

可變電阻 VR 電路

STM32 PWM ADC

例如:
ADC_in = 1024
比例值 = 1024 /4096 = 25%

Servo 控制

SG-90 可控制角度為 0度 ~ 180 度之間。控制方式需要輸入50Hz 的 PWM 訊號,由訊號寬度來判別控制角度。寬度範圍是 0.5ms ~ 2.5ms 間。

0.5ms 寬度 -> -90 度
1.5ms 寬度 -> 0 度
2.5ms 寬度 -> 90 度

頻率 50Hz = 1/50 = 0.02s = 20ms,所以SG-90 的控制範圍是

0.5ms = 0.5 / 20 = 2.5%
1.5ms = 1.5 / 20 = 7.5%
2.5ms = 2.5 / 20 = 12.5%

STM32 Timer / PWM 設定

MCU CLOCK = 48000000

目標 50 Hz

所以,48000000 / 50 = 960000 ,如果 Period 設定為 1000 ,
則 Prescaler 可以設定為 960000 / 1000 = 960

因此要調整 PWM 空佔比的範圍是 0 ~ 1000
假設需要 1.5ms 的 PWM 寬度 = (1.5ms / 20 ) x 1000 = 75

綜合以上, 導出以下公式


PWMValue = ((2.5*val)/20)*TimePeriod;

val 為 ADC 計算出的比例。

在 STM32 的 HAL 庫, 設定空佔比。可用


__HAL_TIM_SET_COMPARE()

主要控制程式碼


  while (1)
  {
    /* USER CODE END WHILE */
      HAL_ADC_Start(&hadc);


      if(HAL_ADC_PollForConversion(&hadc,100) == HAL_OK)
      {
          ADCValue = HAL_ADC_GetValue(&hadc);
      }
      val = (float)ADCValue/pow(2,12);
      PWMValue = ((2.5*val)/20)*TimePeriod;
      printf("Count[%ld],Value= [%d] ,VR[%d]\%%,PWM value[%d]\r\n",x,(uint16_t)ADCValue ,(uint8_t)((val) * 100),PWMValue);


      if(PWMValue < 25)
      {
          __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,25);
      }
      else
      {
          __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,PWMValue);
      }




      HAL_Delay(250);
      x++;
    /* USER CODE BEGIN 3 */
  }

實際上在示波器測試結果

2.5ms

STM32,PWM,ADC

0.5ms

STM32,PWM,ADC

實體測試電路

原始碼連結

https://github.com/cold63/STM32_Code/tree/master/K051KRunPWM

2022年4月18日星期一

[Ameba] A1 Gyro / RTL8720DN (BW16) 開發板

 

關於 A1 Gyro

為了實現基於 RTL8720DN (BW16 Module) 可以使用在其他不同的 ESP32 shield 上直接使用,所設計的開發板。A1 Gyro 具有 16ch +2 ch的 PWM 信號輸出。您可以透過 A1 Gyro 設計在任何需要 PWM輸出的應用,不論您要設計 小車,坦克車,機械手臂,還是 機械狗。只要 1 片A1 Gyro ,PWM輸出數量已足夠讓您使用。

A1 Gyro 特色

  • 內建 USB/Ext 5V 可自復式保險絲。
  • I2C 介面預裝提升電阻。
  • 使用 CP2102N UART 晶片
  • 支援 Auto flash 功能。
  • 內建 PCA9685 晶片, 有額外的 16 通道 PWM 輸出 (12-bit PWM),可設定晶片的 I2C Address。並有串接 220 ohm 電阻保護晶片輸出,可以直接驅動 伺服器 驅動單顆 LED。
  • 腳位符合 ESP32 38 pin 定義順序,支援 EPS32 擴展板

腳位定義圖

Arduino BW16 ESP32

電路圖

Arduino BW16 ESP32

JUMP 定義說明

定義說明預設
A0 ,A1,A2,A3,A4,A5PCA9685 的 I2C 位址設定0x40
JP1BLINK LED Close
JP2 與 5 (RX )短接Close
JP3與 4 (TX)短接Close


Arduino 安裝

請參考 A1 Lite / RTL8720DN (BW16) 開發板 與 Arduino IDE (連結)

目前已完整驗證過的擴展板

ESP Gyro 擴充板

連結 (https://sites.google.com/view/esp-gyro/ )

Arduino BW16 ESP32

Arduino BW16 ESP32

小車示範影片


[STM32] STM32 核心測試板 / Cortex-M0 & RS485 版

測試板用途

平常在執行各 Device 測試時,一開始都會先使用 ST 開發板先行測試。而目前工作領域時常會用到 I2C , UART , SPI , RS485 等通訊協定。為了能儘早順利接線直接上線測試,因此設計了專門做測試用的 ST Contex-M0 測試板, 及另外的用途是用來做測試製具主板使用。

關於 STM32F051K8T6

測試板核心使用的型號是 STM32F051K8T6 / Cortex-M0 , 運作頻率為 48Mhz。板子使用內建 Internal 8 MHz RC 震盪器 內存 64 kByte / SRAM 8 kByte, 並搭配 RS485 轉換晶片。

STM051K8T6 規格書

原廠連結 ( https://www.st.com/resource/en/datasheet/stm32f051c4.pdf )

測試板佈局

  • 電源 5V 輸入且具有電源反接功能。
  • 3.3V 電壓輸出。
  • GPIO x 11
  • ADC x 3
  • DAC x 1
  • TIME x 9 
  • UART x 1
  • I2C x 1  (預接 2.7K Pull 電阻)
  • SPI x 1
  • USR Key x 1
  • 內建 RS485 (MAX485ESA+) 輸出

在一般做 Device 測試應該已足夠用了。

USR Key

RS485 輸出

腳位定義

電路圖

STM32Cube 設定

STM32Cube 測試板參考設計

GitHub 連結 ( https://github.com/cold63/STM32_Code/tree/master/K051K8TMCUConfig )

購買開發板

7-11 賣貨便 (Only Taiwan)

 

2022年2月20日星期日

[RS485] USB 轉 RS485 轉換器設計

關於 RS485

在產品研發工作中,時常遇到 RS485 的功能要求。在研發初期確實也需要類似於 Monitor 的監看工具,以方便了解傳輸過程是否有錯誤及了解客戶端的裝置是否有正確反饋資料。這時候就會需要 USB RS485 這類轉換工具,當然這也不限定於開發環境中,因為 RS485 通訊協定在工控領域中,是非常常見的。

RS485 是利用差動訊號來辨別 0 與 1 ,重點特性是能抗雜訊及通訊實體線路長距離傳輸。RS485 是 multi-drop network (多點網路),相同接線可以同時連接不同的 RS485 裝置。在於有多點網路特性及 RS485 為半雙工通訊模式,所以實際傳輸上通常會使用 Master-slave 架構,較為常見的軟體協議是 MODBUS。不過更多的情境是各家系統自訂通訊協議,因此需要有工具才能好好的做除錯的工作,更多延伸資訊可參考 RS485 wiki(中文)RS485 wiki(English)

收發器 ( Transceivers )

在單晶片場域中如果要用 RS485 協議,就必須要使用 RS485 收發器 ( Transceivers ),單晶片是 TTL 準位並不適合直接對接,必須要用 收發器 這點就有點像 CAN bus。(恩,這是題外話),我目前手上的是 Maxim 的 MAX485ESA+ 。 Maxim 已被併入 ANALOG DEVICES 旗下了,更顯得我手上的 MAX485ESA+ 是個珍品阿。剛看 Mouser 上的售價單價是 NT$128 元,我是不是應該要繼續珍藏 ?

RS485
(圖片來自 Maxim spec.)

上圖是 RS485 收發器的內部等效圖,分別是 2 各三態閘分別負責 TX 與 RX 。RO 負責接收,由 /RE 做接收控制。 DI 負責傳送,由 DE 做訊息發控制。A與 B 就是 RS485輸出端了。 與裝置連接通常是使用雙絞線方式連接。而連接器沒有特別指定。這類的的收發器有很多廠家都有,Pin out 基本上都相同,也可以交互使用。 這裡就不推薦了,之後有機會再介紹。



USB 轉 UART

來到 USB 這個環節了,在設計上是使用 FTDI FT230XQ 這個型號。是個 USB 轉 UART TTL 準位的晶片,在很多的場域都會看到 FTDI 這個廠牌。

UART
(圖片來自 FTDI spec.)

這是 FT230XQ 接腳圖,就是個 USB 轉 UART 常用輸出腳位。 有 TXD , RXD , RTS , CTS,但重點是它有 4 個 可自定義的腳位,就是這篇 RS485 的主題要使用的部分。剛提到 RS485 收發器 有 /RE 及 DE 腳做收發控制,在這自定義就發揮這個功能。

CBUS0 可以定義為 TXDEN 為專屬於 RS485 使用,當 USB Host 端發出傳送資料需求時,TXDEN 會轉態為 High,資料就會透過 TXD 跟著傳至 RS485 收發器的 DI 腳 完成資料發出的任務。
CBUS3 可以定義為 PWREN。 這是 USB 處於 suspend mode 模式時會被轉態成 Low。

利用這個特性連接 RS485 收發器的 /RE 腳,使UART待機時隨時是接收模式狀態。所以會有個缺點,若是在做 TXD 傳輸時也會同時收到自己傳輸的資料。不過還好,這問題並不大可以透過軟體來解決。

定義功能可透過 FTDI 的軟體工具設定

UART
(圖片來自 FTDI FT_Prog 軟體)

電路圖

RS485

線路是按照 FTDI 標準線路設計,除了,RS485 連接器。也保留 UART 輸出,可以兩用的形式不浪費,但 CBUS3 最好設回 SLEEP 模式。USB 連接器使用 USB B type,我想工具類的環節最好用 B Type 會比較穩固點。

製作完成

RS485

USB Host 應用

這類的軟體應用很多,但因為工作關係。通常我會自行開發 Host 端的部分,因為比較符合客戶需求及實際使用情況,或是大家有甚麼可推薦的軟體? 可以在底下留言哦!

2022年1月25日星期二

[Ameba] A1 Lite / RTL8720DN (BW16) 開發板 與 Arduino IDE

關於 A1 Lite

A1 Lite 是基於 RTL8720DN (BW16 Module) 所設計的開發板,而 RTL8720DN 具有 WIFI 4G/5G 及低功耗 BLE 5 的無線功能。與前版本 A1 Pico (點這裡)所使用的 BW16 Module 相同

A1 Lite 設計特色

  • 內建 USB/Ext 5V 可自復式保險絲。
  • I2C 介面預裝提升電阻。
  • 使用 CP2102N UART 晶片。
  • 支援 Auto flash 功能。
  • 簡化腳位,並使用單排半圓孔,可使用排針 或配合電路直接焊接 PCB 上

電路圖

Arduino BW16

腳位連接圖

Arduino BW16

孔位尺寸圖

單位:mm

RTL8720DN BW16

背面 JUMP 說明

NUM用途預設
JP1USER LEDON
JP2I2C 提升電阻OFF
JP3I2C 提升電阻OFF

準備

先安裝 CP2102N 的驅動程式。

連結在這裡
https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers

Windows 系統請下載 CP210x Windows Drivers,會得到一個壓縮檔,依據您的電腦系統 選擇 x64 或是 x86 安裝執行檔。 安裝步驟這裡就不贅述。

RTL8720DN 加入 Arduino
首先將這個網址複製起來 https://github.com/ambiot/ambd_arduino/raw/master/Arduino_package/package_realtek.com_amebad_index.json

打開 Arduino IDE , 點開 File / Preferences

BW16 Arduno

將網址貼上 紅框 處 , 然後點 OK 儲存。

接著在 Tools / Board: / Boards Manager...

在 搜尋列直接輸入" ameba " 就會出現開發板資訊 , 在右側會有 Install 的 按鈕。 因為我的 Arduino IDE 安裝完成,所以出現不一樣字樣。 點 " Install " 開始安裝 會需要等待一些時間, 可以先去泡一杯咖啡再回來。

BW16 Arduino

稍待片刻後,系統就會自動安裝完成。
在 Tools / Board: / Amaba ARM (32bit) Boards 裡, 應該會找到 RTL8720DN (BW16) 這個選項。
到這裡 安裝 RTL8720DN(BW16) 到 Arduino IDE 的部分已經做完了。

置換 upload_image_tool_windows.exe

預設安裝是沒有支援 Auto Flash 功能的,必須手動更新

首先 到 Ameba 的 Github https://github.com/ambiot/ambd_arduino/blob/dev/Ameba_misc/Autoflash_patch/ameba_d_tools_windows/upload_image_tool_windows.exe

BW16

右下角 Download , 就可以下載。如果您是不同於 Windows 系統,則回到上一層選擇適合的平台

置換的方法

開啟檔案總管, 到這個位置。

C:\Users\%USER%\AppData\Local\Arduino15\packages\realtek\tools\ameba_d_tools\1.0.7

您會看到很多檔案在其中 , 一定會有 upload_image_tool_windows.exe 這個檔案

可以先行 備份 再將 剛剛下載的 upload_image_tool_windows.exe 做覆蓋置換過去就可以。

測試 Blink 程式

將開發板連接電腦 USB 並開啟 Arduino IDE 並選好 開發板名稱 及 COM Port 位置

Arduino BW16

程式碼


int YelloLED = 9; //PA15

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(YelloLED, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(YelloLED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(YelloLED, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

然後點選上傳 , 在訊息欄出現以下。自動上傳並自動 RESET。完成



實際測試結果



技術連結

購買 A1 Lite 開發板

7-11 賣貨便 (Only Taiwan)

官方程式範例

https://bit.ly/bw16_example

官方論壇

https://bit.ly/amebaiot

Ameba Iot Facebook 開發社群

https://bit.ly/amebaiot_groups