照度センサーを接続してI2Cリードの確認を行いました。
使用したモジュールはこちらです。
aitendoで購入しました。
www.aitendo.com
搭載しているフォトダイオードはロームのBH1750と言う型番でした。
上のaitendoの商品ページにデータシートがリンクされています。
I2Cライトと同様にSPLに用意されている関数を使うことで簡単にI2Cリードを行えました。
使用した関数は
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState); uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx); void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState); void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);
の4つです。
I2C_AcknowledgeConfigの第2引数にENABLEを設定するとAck送信、DISABLEを設定するとNack送信となるようですので、リードの最終バイト時にはDISABLEを設定するようにします。
BH1750の使い方としては、0x01をライトしてPower On状態にしてから計測モードをライトすることで計測開始となるようです。
計測モードはスタンダードの「H-Resolution Mode」を使用しました。
計測時間に120msecかかるので、TIM6を使って133msec待ってから16bitの測定結果をリードすることにしました。
MTregの値がデフォルトの69(0x45)だと測定結果を0.83倍することでLuxに変換できるようです。
プログラムはこのような感じで組みました。
#include <stdio.h> #include "stm32f4xx.h" #include "stm32f4xx_tim.h" #include "stm32f4xx_i2c.h" void __auto_semihosting(void) __attribute__((alias("main"))); extern void initialise_monitor_handles(void); #define BH1750_W ((0x23 << 1) | 0x0) // 0100 0110 #define BH1750_R ((0x23 << 1) | 0x1) // 0100 0111 #define ONE_TIME_H2 0x21 #define ONE_TIME_H 0x20 #define ONE_TIME_L 0x23 int main(void){ unsigned short result; float lux; initialise_monitor_handles(); // Clock Enable RCC->APB1ENR |= (RCC_APB1ENR_I2C1EN | RCC_APB1ENR_TIM6EN); RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; // PB8 - I2C1_SCL // PB9 - I2C1_SDA GPIOB->MODER |= ((0x2 << 18) | (0x2 << 16)); // Alternate function mode GPIOB->PUPDR |= ((0x1 << 18) | (0x1 << 16)); // Pull-up GPIOB->OTYPER |= ((0x1 << 9) | (0x1 << 8)); // Output open-drain GPIOB->AFR[1] |= ((0x4 << 4) | (0x4 << 0)); // AF4 // TIM6 TIM6->PSC = 9999; // 11.111nsec(90MHz) * 10,000 = 111.111usec TIM6->ARR = 1200; // 111.111usec * 1200 = 133.333msec TIM6->CNT = 0; TIM6->CR1 = 1; // I2C1 Reset I2C1->CR1 = (0x1 << 15); for(int i=0; i<1000; i++){ asm("NOP"); }; I2C1->CR1 = (0x0 << 15); I2C1->CR2 = 45; I2C1->CCR = ((0 << 15) | (0 << 14) | 226); // 22.222nsec(45MHz) * 226 * 2 = 10usec(100KHz) I2C1->TRISE = 46; // I2C1 Enable I2C1->CR1 |= 1; // BH1750 Power ON I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_SendData(I2C1, BH1750_W); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, 0x01); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); while(1){ // BH1750 Measurement start I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_SendData(I2C1, BH1750_W); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, ONE_TIME_H); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); // Wait 133msec TIM6->SR = 0x0; TIM6->CNT = 0x0; while(!(TIM6->SR)); // BH1750 Result read I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_SendData(I2C1, BH1750_R); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); I2C_AcknowledgeConfig(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); result = I2C_ReceiveData(I2C1); // High Byte result <<= 8; I2C_AcknowledgeConfig(I2C1, DISABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); result |= I2C_ReceiveData(I2C1); // Low Byte I2C_GenerateSTOP(I2C1, ENABLE); lux = result * 0.83; printf("0x%04x : %d -- %f lux\n", result, result, lux); } return(0); }
計測結果をprintfで表示します。
この際、0.83倍したfloatを表示できるようにするためにプロジェクトのプロパティからリンカオプションへ
-u _printf_float
を追加します。
測定結果のリード値とLuxへ変換した値が表示できました。
以前Amazonで購入した照度計がどこかにしまってあるので、今度探し出して値を比べてみたいと思います。
[参考記事]