今回はI2Cによる通信について書いてみます。
投稿時の開発環境を記しておきます。
PC:Windows10 OS
IDE: STM32CubeIDE Version1.3.0
Configurator: STM32CubeMX Version5.5.0
Board: STM32Nucleo-F401RE
I2C通信の概要
・フィリップス(現NXP)セミコンダクターズが開発した通信方式
・SCLとSDAの2本の通信ラインを使って双方向で通信が可能
・通信速度は100k, 1Mbits/secなどいくつか選択肢がある
・マスタとスレーブが存在し、マルチマスタでの構築も可能
I2Cの詳しい仕様については こちら を見て頂ければと思います。
スレーブとなるターゲット
STM32(をマスタ)で制御し、スレーブのデバイスは以下のものを使ってみました。
価格は600円でネットを使って購入しました。
メーカーはSTマイクロです。デバイスのデータシートは こちら です。
SCL, SDAラインにプルアップ抵抗をつけるための半田づけジャンパー2箇所を半田づけしておきます。
接続
下表のとおりに接続します。
このモジュールは I2C か SPI のどちらで接続するのか5番ピンでインターフェースを選択することができます。
今回はI2Cで接続するので5番ピンを H (3.3V) につなぎます。
4番ピンはデバイスアドレスの最下位ビットです。これで同じデバイスを2つつなぐことができるわけですが、今回は1つなので L (GND) につないでおきます。
割り込みは使わないのでINT端子は接続していません。
プロジェクトを作成する
IDEを起動し、File- New – STM32 Project を選択し、Target Selection ウィンドウが出たら Board Selector タブを選択し Boards List から NUCLEO-F401RE を選択し Next ボタンを押します。
Project 名に F401I2cHAL と入力し、Finishボタンを押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yesを押します。
This kind of project is associated with the STM32CubeMx perspective. Do you want to open this perspective now ? と聞いてくるので Yesを押します。
コードジェネレーターでI2Cインターフェースを追加する
今回使うI2Cの端子はPB8とPB9です。(画像の左上付近の赤枠で囲った部分)
PB8を右クリックして選択し、I2C1_SCL を選択します。
PB9を右クリックして選択し、I2C1_SDA を選択します。
端子の色がグレーから黄色にかわることを確認します。
そして Pinout & Configuration – Categories – Connectivity – I2C1 を選択し、
I2C1 Mode and Configuration – Mode の I2C のリストから I2C を選択します。
Project Explorer で F401I2cHAL を選択し、Project – Build Project でビルドします。
端子の色が黄色から緑色にかわります。
また、main.cに MX_I2C1_Init()が生成されていることを確認します。
コードを追加する
MX_I2C1_Init()関数内で完結するコードを書いてみました。
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
#define WHO_AM_I 0x0f
#define CTRL_REG1 0x20
#define WAKE_UP 0x90
#define P_ADRS 0x28
HAL_StatusTypeDef s;
uint8_t err;
uint8_t buf[16];
uint32_t press;
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
buf[0] = WHO_AM_I; // Who am I ?
s = HAL_I2C_Master_Transmit(&hi2c1, 0xb8, buf, 2, 3000);
s = HAL_I2C_Master_Receive(&hi2c1, 0xb9, buf, 1, 3000);
if (HAL_OK == s)
{
if (0xbd == buf[0])
{
err = 0;
}
else
{
err = 1;
}
}
else
{
err = 1;
}
buf[0] = CTRL_REG1; // Control Register1
buf[1] = WAKE_UP;
s = HAL_I2C_Master_Transmit(&hi2c1, 0xb8, buf, 2, 3000);
HAL_Delay(1000);
buf[0] = P_ADRS | 0x80;
s = HAL_I2C_Master_Transmit(&hi2c1, 0xb8, buf, 1, 3000);
s = HAL_I2C_Master_Receive(&hi2c1, 0xb9, buf, 3, 3000);
press = buf[2] << 16 | buf[1] << 8 | buf[0];
press /= 4096;
/* USER CODE END I2C1_Init 2 */
}
コードの解説
WHO_AM_I というレジスタの値を読んで、 0xbdであればデバイスを認識できているとのことです。
コントロールレジスタ1に WAKE_UP(0x90) を書いてパワーダウンモードを解除します。
気圧の計測値は 0x28 (P_ADRS), 0x29, 0x2a のレジスタから読み込みます。
P_ADRS | 0x80 とすることでアドレスをオートインクリメントして次々と読むことができます。
読んだ値を 4096 で割ることで単位 [hPa]の気圧を得ることができます。
読んで計算した気圧は 1009 とか 1010 [hPa] でした。
よろしければI2Cに関する記事の HALを使ってI2Cでメモリーにアクセスする もご覧ください。
コメントを書く