| Up | polling vs interrupt | 作成: 2026-10-19 更新: 2026-10-19 |
main() { // ハードウェア定義・初期設定 INIT() // 着信監視を設定 HAL_I2C_EnableListen_IT( &hi2c1 ); // motor_store_buffer を // 着信データを受けるバッファに設定 HAL_I2C_Slave_Receive_IT( &hi2c1, motor_store_buffer, 24 ); // PI 制御ループ PI_Loop(); } プログラムは,main() から PI_Loop() に入って,無限ループする。 PI_Loop() は,目標電流値 I_cmd が固定なら,つぎのようなる: PI_Loop() { while(1) { // ADC 処理 (実電流値 I-meas の取得) I_MEAS_Get(); // PI 処理 PI_Calc(); // PWM, DIR 処理 // (モータドライバIC のモータ電圧生成へ) PWM_DIR_Send(); } } しかし I_cmd は更新されるので,つぎの処理が要る: 2. PI 処理での目標電流値を更新 polling 方式だと,PI_Loop() をつぎのようにつくることになる: PI_Loop() { while(1) { // 着信処理 I_CMD_Get(); I_MEAS_Get(); PI_Calc(); PWM_DIR_Send(); } } そして I_CMD_Get() は,例えばつぎのよう: // 受信バッファ // (2byte電流値が 12モータ分) uint8_t motor_store_buffer[24]; // 新着チェック用 uint8_t last_value[24] = 0; I_cmd_Get() { // 更新されていない if(memcmp( last_value, motor_store_buffer, 24 ) == 0) { return; } // last_value に motor_store_buffer をコピー memcpy( last_value, motor_store_buffer, 24 ); <目標電流値 I_cmd 復元処理> } ここで <目標電流値 I_cmd 復元処理>は: for(i = 0 ; i < 12 ; i++) { //符号なし8bit整数型 uint8_t high; uint8_t low; high = motor_store_buffer[i * 2]; low = motor_store_buffer[i * 2 + 1]; i_cmd[i] = (int16_t)( (high << 8) | low ); } ところで,HAL にはつぎの関数がある: I2C_HandleTypeDef hi2c1; void HAL_I2C_SlaveRxCpltCallback( I2C_HandleTypeDef *hi2c) { (着信があったときの処理) } polling 方式はそのままにしてこれの利用しようとすると,つぎのようになる: // 新着フラグ volatile bool cmd_arrived = false; void HAL_I2C_SlaveRxCpltCallback( I2C_HandleTypeDef *hi2c) { cmd_arrived = true; // HAL_I2C_Slave_Receive_IT() は // 1回受信したら終了 // →再登録が必要 HAL_I2C_Slave_Receive_IT( &hi2c1, motor_store_buffer, 24 ); } I_cmd_Get() { if( memcmp( last_value, motor_store_buffer ) == 0 ) { return; } last_value = motor_store_buffer; <目標電流値 I_cmd 復元処理> } 着信チェック処理が,memcmp( last_value, motor_store_buffer を使うやり方と比べて,軽くなった。 しかしこれは,HAL_I2C_SlaveRxCpltCallback() の<割り込み>機能の使い方が中途半端である。 そして中途半端なのは,polling 方式にとらわれているため。 実際,つぎのようにすれば,PI_Loop() の while(1) ループから,I_CMD_Get() をまるごと無くせる: void HAL_I2C_SlaveRxCpltCallback( I2C_HandleTypeDef *hi2c) { <目標電流値 I_cmd 復元処理> HAL_I2C_Slave_Receive_IT( &hi2c1, motor_store_buffer, 24 ); } ────────────────────────── 以上まとめて,つぎのようになる: I2C_HandleTypeDef hi2c1; uint8_t motor_store_buffer[24]; volatile int16_t i_cmd[12]; void HAL_I2C_SlaveRxCpltCallback( I2C_HandleTypeDef *hi2c) { int i; for(i = 0 ; i < 12 ; i++) { uint8_t high; uint8_t low; high = motor_store_buffer[i * 2]; low = motor_store_buffer[i * 2 + 1]; i_cmd[i] = (int16_t)( (high << 8) | low ); } HAL_I2C_Slave_Receive_IT( &hi2c1, motor_store_buffer, 24 ); } PI_Loop() { while(1) { I_MEAS_Get(); PI_Calc(); PWM_DIR_Send(); } } main() { INIT() HAL_I2C_EnableListen_IT( &hi2c1 ); HAL_I2C_Slave_Receive_IT( &hi2c1, motor_store_buffer, 24 ); PI_Loop(); } |