STM32で遊ぶ (9) - I2Cマスター
新型コロナウィルスの影響で柔術の練習に全く行けていません。
早く平穏な日常に戻って欲しいと願うと同時に、ついこの前までの何事もなかった日常を懐かしむ毎日です。
持て余している時間は、Switchのどうぶつの森かSTM32ボードをいじって遊んでいます(笑)
さて今回は、前回と前々回の記事を組み合わせて照度センサーから読み取った結果をOLEDへ表示するようにしました。
また、秋月電子でArduino用シールド基板を購入したのでNUCLEO-F446REに取り付けてみました。
Aruduino互換コネクタなのでピッタリでした。
シールド基板の上にミニブレッドボードを乗せることでジャンパ線の取り回しも楽になりました。
ピンソケットはリード長10mmにしたのですが、プッシュスイッチの高さとギリギリでした。
プログラムはこちらです。(少々長いです・・)
#include "stm32f4xx.h" #include "stm32f4xx_tim.h" #include "stm32f4xx_i2c.h" void disp_oled(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char*); #define BH1750_W ((0x23 << 1) | 0x0) // 0100 0110 #define BH1750_R ((0x23 << 1) | 0x1) // 0100 0111 #define OLED_W ((0x3c << 1) | 0x0) // 0111 1000 #define ONE_TIME_H2 0x21 #define ONE_TIME_H 0x20 #define ONE_TIME_L 0x23 unsigned char dec_dat[10][64] = { {0x00, 0xf0, 0xe4, 0xcc, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0xcc, 0xe4, 0xf0, 0x00, 0x00, 0xff, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0xfe, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x1f, 0x4f, 0x67, 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x70, 0x67, 0x4f, 0x1f, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x1f, 0x00}, {0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0xcc, 0xe4, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0xfe, 0xfc, 0xf8, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x4f, 0x67, 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x70, 0x60, 0x40, 0x00, 0x00}, {0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0xcc, 0xe4, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x70, 0x67, 0x4f, 0x1f, 0x00}, {0x00, 0xf0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf0, 0x00, 0x00, 0xff, 0x7f, 0x3f, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x1f, 0x00}, {0x00, 0xf0, 0xe4, 0xcc, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0x0c, 0x04, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x3f, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x70, 0x67, 0x4f, 0x1f, 0x00}, {0x00, 0xf0, 0xe4, 0xcc, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0x0c, 0x04, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x3f, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfc, 0xf8, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x1f, 0x4f, 0x67, 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x70, 0x67, 0x4f, 0x1f, 0x00}, {0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0xcc, 0xe4, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x1f, 0x00}, {0x00, 0xf0, 0xe4, 0xcc, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0xcc, 0xe4, 0xf0, 0x00, 0x00, 0xff, 0x7f, 0x3f, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0xfe, 0xfc, 0xf8, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x1f, 0x4f, 0x67, 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x70, 0x67, 0x4f, 0x1f, 0x00}, {0x00, 0xf0, 0xe4, 0xcc, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0xcc, 0xe4, 0xf0, 0x00, 0x00, 0xff, 0x7f, 0x3f, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x3f, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0xf8, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x70, 0x67, 0x4f, 0x1f, 0x00} }; unsigned char lux_dat[96] = { 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x38, 0xf0, 0xc0, 0xc0, 0xf0, 0x38, 0x08, 0x00, 0x00, 0x00, 0x3f, 0x7f, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7f, 0x60, 0x60, 0x60, 0x30, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x40, 0x60, 0x78, 0x1e, 0x07, 0x07, 0x1e, 0x78, 0x60, 0x40, 0x00 }; int main(void){ unsigned short rd; unsigned char dec[5]; float lux_f; unsigned short lux_s; // 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->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); // OLED Clear - 初期設定 I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_SendData(I2C1, OLED_W); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, 0x00); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // コマンドライト I2C_SendData(I2C1, 0xa0); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // 表示モード設定 左右 - 通常:0xa0 / 逆転:0xa1 I2C_SendData(I2C1, 0xc0); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // 表示モード設定 上下 - 通常:0xc0 / 逆転:0xc8 I2C_SendData(I2C1, 0x20); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // アドレッシングモード指定 I2C_SendData(I2C1, 0x00); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → Horizontalモード I2C_SendData(I2C1, 0x21); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // カラム指定 I2C_SendData(I2C1, 0x00); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → 開始位置(0) I2C_SendData(I2C1, 0x7f); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → 終了位置(127) I2C_SendData(I2C1, 0x22); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // ページ指定 I2C_SendData(I2C1, 0x00); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → 開始ページ(0) I2C_SendData(I2C1, 0x07); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → 終了ページ(7) I2C_SendData(I2C1, 0x8d); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // チャージポンプ設定 I2C_SendData(I2C1, 0x14); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → On I2C_SendData(I2C1, 0xaf); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // 画面表示 On I2C_GenerateSTOP(I2C1, ENABLE); // OLED Clear - data zero I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_SendData(I2C1, OLED_W); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, 0x40); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // デ-タライト for(int i=0; i<1023; i++){ I2C_SendData(I2C1, 0x00); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); } I2C_SendData(I2C1, 0x00); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); // 'lux'表示 disp_oled(86, 32, 2, 3, &lux_dat[0]); while(1){ // H-Resolution Mode 計測開始 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)); // 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)); rd = (I2C_ReceiveData(I2C1) << 8); I2C_AcknowledgeConfig(I2C1, DISABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); rd |= I2C_ReceiveData(I2C1); I2C_GenerateSTOP(I2C1, ENABLE); lux_f = rd * 0.83; // lux変換 lux_s = (unsigned short)lux_f; // 整数へ変換 // 5桁の数値を1桁毎に分解 dec[0] = lux_s / 10000; lux_s %= 10000; dec[1] = lux_s / 1000; lux_s %= 1000; dec[2] = lux_s / 100; lux_s %= 100; dec[3] = lux_s / 10; dec[4] = lux_s % 10; for(int i=0; i<5; i++){ // 1桁毎に表示 disp_oled(i * 16, 16, 1, 4, &dec_dat[dec[i]][0]); } } return(0); } void disp_oled( unsigned char pos_x, // 開始カラム unsigned char width, // 幅ドット数 unsigned char pos_y, // 開始ページ unsigned char height, // 高ページ数 unsigned char* dat // 先頭データ ){ unsigned char pos_xs; unsigned char pos_xe; unsigned char pos_ys; unsigned char pos_ye; int dat_length; // カラム/ページの開始位置/終了位置を算出 pos_xs = pos_x; pos_xe = pos_xs + width - 1; pos_ys = pos_y; pos_ye = pos_ys + height - 1; dat_length = width * height; I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_SendData(I2C1, OLED_W); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, 0x00); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // コマンドライト I2C_SendData(I2C1, 0x21); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // カラム指定 I2C_SendData(I2C1, pos_xs); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → 開始位置 I2C_SendData(I2C1, pos_xe); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → 終了位置 I2C_SendData(I2C1, 0x22); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // ページ指定 I2C_SendData(I2C1, pos_ys); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); // → 開始ページ I2C_SendData(I2C1, pos_ye); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // → 終了ページ I2C_GenerateSTOP(I2C1, ENABLE); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_SendData(I2C1, OLED_W); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, 0x40); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // データライト for(int i=0; i<(dat_length - 1); i++){ I2C_SendData(I2C1, *(dat + i)); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); } I2C_SendData(I2C1, *(dat + dat_length - 1)); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); }
以前Amazonで購入した2,400円の照度計と比較してみたところ、まぁ・・だいたい同じくらいの値でした(笑)
(明るいところだと差が大きい・・)
OLEDに表示している数字のフォントはドット絵を自作しました。
1文字16x32ドットの64Byteで構成しており、プログラム中の
unsigned char dec_dat[10][64] = { ....... };
に展開しています。
こんな感じのドット絵になっています。
[参考記事]