前回STM32G031J6をArduino IDEでLチカをしましたが、今回も同じ構成ですが、i2c接続で液晶表示と温湿度センサを同時に動かしててみることにしました。
でもいきなり全部つなぐと、
「どこが原因で動かないのか分からない…」
という状態になりがちです。
そこで今回は、
① まずはLCDだけ動かす
② 次にセンサだけ確認する
③ 最後に組み合わせる
という3段階で進めます。
初心者の方でも確実に動作確認できる構成です。
使用部品
【図①:部品一覧】
STM32G031(8ピン)(数年前に秋月電子で120円で購入したものです)
AQM1602(I2C液晶)
DHT20(I2C温湿度センサ)
470Ω前後の抵抗
3.3V電源 (St-Link) (nucleo-Stlink)(アマゾンの安いものでも書き込めるようです)
ブレッドボード ジャンパーワイヤー
配線
配線図

- PB6(ピン8)── 470Ω ── SCL(SWCLKとSCLを同時有効にす為470Ωの抵抗を入れます)
- PB7(ピン1)──────── SDA
- 3.3V → VDD
- GND → GND
- I2Cは2本の線で複数機器を接続できます。
- NRST は接続しなくても書き込めます。
I2Cは2本の線で複数機器を接続できます。
注意:必ずSCLとSDAラインに10KΩ程度のプルアップ抵抗を入れてください私はAQM16022内のプルアップ抵抗を有効にしてありますので省略してあります。
まずはAQM1602だけ動かす
いきなり全部を動かすのではなく、まずはLCD単体で動作確認します。
ArduinoIDEの設定の仕方についてはこちらの私の記事で確認してくだ。
プログラム(LCD単体)
#include <Wire.h>
#define AQM_ADDR 0x3E
void cmd(uint8_t c){
Wire.beginTransmission(AQM_ADDR);
Wire.write(0x00);
Wire.write(c);
Wire.endTransmission();
}
void data(uint8_t d){
Wire.beginTransmission(AQM_ADDR);
Wire.write(0x40);
Wire.write(d);
Wire.endTransmission();
}
void init_lcd(){
delay(40);
cmd(0x38);
cmd(0x39);
cmd(0x14);
cmd(0x70);
cmd(0x56);
cmd(0x6C);
delay(200);
cmd(0x38);
cmd(0x0C);
cmd(0x01);
delay(2);
}
void print_str(const char *s){
while(*s) data(*s++);
}
void setup(){
Wire.setSCL(PB6);
Wire.setSDA(PB7);
Wire.begin();
init_lcd();
print_str("Hello STM32");
}
void loop(){}LCDに文字が表示されれば成功です。
表示されない場合:
- 電源は3.3Vか?
- SCL/SDAは正しいか?
- 抵抗は正しく接続されているか?
DHT20測定開始するプログラム
ここではまだLCDに表示しません。
プログラム
#include <Wire.h>
#define DHT20_ADDR 0x38
void setup(){ //こちらの部分はAQM1602と共通のセットアップ項目です
Wire.setSCL(PB6);
Wire.setSDA(PB7);
Wire.begin();
}
void loop(){
Wire.beginTransmission(DHT20_ADDR);
Wire.write(0xAC);
Wire.write(0x33);
Wire.write(0x00);
Wire.endTransmission();
delay(80);
}LCD+DHT20を組み合わせる
いよいよ完成形です。
やることはシンプル:
- センサから値を取得
- LCDに表示
最終プログラム
#include <Wire.h>
#define AQM_ADDR 0x3E
#define DHT20_ADDR 0x38
//--------------------------------
// AQM1602 基本関数
//--------------------------------
void aqm_cmd(uint8_t cmd)
{
Wire.beginTransmission(AQM_ADDR);
Wire.write(0x00);
Wire.write(cmd);
Wire.endTransmission();
}
void aqm_data(uint8_t data)
{
Wire.beginTransmission(AQM_ADDR);
Wire.write(0x40);
Wire.write(data);
Wire.endTransmission();
}
void aqm_init()
{
delay(40);
uint8_t initComs[] = {0x38, 0x39, 0x14, 0x70, 0x56, 0x6C, 0x38, 0x0C, 0x01}; //初期化コマンドを配列にまとめる場合
uint16_t delays[] = {2, 2, 2, 2, 2, 150, 2, 2, 2};
for (uint8_t i = 0; i < sizeof(initComs); i++) {
aqm_cmd(initComs[i]);
delay(delays[i]);
}
}
void aqm_setCursor(uint8_t col, uint8_t row)
{
uint8_t addr = (row == 0) ? 0x00 : 0x40;
aqm_cmd(0x80 | (addr + col));
}
void aqm_print(const char *str)
{
while (*str) {
aqm_data(*str++);
}
}
//--------------------------------
// DHT20 読み取り
//--------------------------------
bool dht20_read(float &temp, float &hum)
{
uint8_t buf[7];
// 測定開始
Wire.beginTransmission(DHT20_ADDR);
Wire.write(0xAC);
Wire.write(0x33);
Wire.write(0x00);
if (Wire.endTransmission() != 0) return false;
delay(80);
// データ取得
Wire.requestFrom(DHT20_ADDR, 7);
for (int i = 0; i < 7; i++) {
if (Wire.available()) buf[i] = Wire.read();
else return false;
}
// 生データ変換
uint32_t h_raw =
((uint32_t)buf[1] << 12) |
((uint32_t)buf[2] << 4) |
(buf[3] >> 4);
uint32_t t_raw =
((uint32_t)(buf[3] & 0x0F) << 16) |
((uint32_t)buf[4] << 8) |
buf[5];
hum = (h_raw * 100.0f) / 1048576.0f;
temp = (t_raw * 200.0f) / 1048576.0f - 50.0f;
return true;
}
//--------------------------------
// 数値を簡単表示(軽量版)
//--------------------------------
void print_float(float v)
{
char buf[8];
int i = (int)v;
int d = (int)((v - i) * 10);
if (d < 0) d = -d;
snprintf(buf, sizeof(buf), "%d.%d", i, d);
aqm_print(buf);
}
//--------------------------------
// setup
//--------------------------------
void setup()
{
Wire.setSCL(PB6);
Wire.setSDA(PB7);
Wire.begin();
Wire.setClock(100000);
aqm_init();
aqm_setCursor(0,0);
aqm_print("STM32 + DHT20");
}
//--------------------------------
// loop
//--------------------------------
void loop()
{
float t, h;
if (dht20_read(t, h)) {
aqm_setCursor(0,1);
aqm_print("T:");
print_float(t);
aqm_print(" H:");
print_float(h);
}
delay(2000);
}コンパイルした時のメモリーは下記ようになりました。
最大32768バイトのフラッシュメモリのうち、スケッチが27832バイト(84%)を使っています。
最大8192バイトのRAMのうち、グローバル変数が1504バイト(18%)を使っていて、ローカル変数で6688バイト使うことができます。
出力結果
LCDに2秒間隔で

のように表示されれば成功です。
実際にやってみた感想
8ピンという制限の中でも、
I2Cを使えば複数デバイスを扱えます。
最初は不安でしたが、
動いた瞬間の達成感は大きいです。
まとめ
小型STM32でも、
✔ LCD表示できる
✔ 温湿度を取得できる
✔ I2Cで拡張できる
ということが分かりました。
初心者の方はぜひ
「まずはSTEP1から」試してみてください。
また秋月電子で販売されているこのチップSTM32F303K8T6もメモリー64k vscode pltformIOにも対応していますので魅力的です。


