ARM9 處理器作為 I2C 主機,STM32 單晶片作為 I2C 從機。這屬於非典型應用(CPU 間通常用 UART/CAN/RS485),但完全可行。關鍵在於從機視為一個具備固定位址的 I2C 裝置,主機完全控制讀寫時序。
I2C_Mode_I2C,自有位址(7-bit,如 0x50)STM32 I2C 從機透過事件中斷處理以下狀態:
void I2C1_EV_IRQHandler(void)
{
uint32_t event = I2C_GetLastEvent(I2C1);
switch (event)
{
case I2C_EVENT_SLAVE_RECEIVER_MATCHED:
// 主機要寫資料給從機:準備接收
rxIndex = 0;
break;
case I2C_EVENT_SLAVE_BYTE_RECEIVED:
// 接收一個位元組(可能是命令碼或參數)
rxBuffer[rxIndex++] = I2C_ReceiveData(I2C1);
break;
case I2C_EVENT_SLAVE_TRANSMITTER_MATCHED:
// 主機要讀資料:準備發送
txIndex = 0;
// 根據先前收到的命令碼決定回應內容
PrepareTxBuffer(rxBuffer[0]);
I2C_SendData(I2C1, txBuffer[txIndex++]);
break;
case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
// 主機要求下一個位元組
if (txIndex < txLength)
I2C_SendData(I2C1, txBuffer[txIndex++]);
break;
case I2C_EVENT_SLAVE_STOP_DETECTED:
// 主機發送 STOP,結束一次傳輸
I2C1->CR1 |= 0x0001; // 讀 SR1 再讀 SR2 清除 STOPF
ProcessCommand(); // 處理完整命令
break;
}
}
參考 RS485/Modbus 風格,定義簡單帧格式:
| 位元組 | 說明 |
|---|---|
| 0 | 從機位址 (含 R/W bit,由硬體自動處理) |
| 1 | 命令碼 (CMD) |
| 2..N | 參數/資料 |
| 最後 | CRC/Checksum (可選) |
範例命令:
0x01:讀取 ADC 數值 → 從機回應 2 位元組0x02:設定 PWM 占空比 → 參數 2 位元組,無回應0x10:讀取裝置版本 → 回應字串在 Linux 使用 i2c-dev 介面:
int file = open("/dev/i2c-1", O_RDWR);
ioctl(file, I2C_SLAVE, 0x50); // 從機 7-bit 位址
// 寫命令:設定 PWM = 50%
uint8_t buf[3] = {0x02, 0x7F, 0x00}; // CMD, 高位元組, 低位元組
write(file, buf, 3);
// 讀取 ADC
uint8_t cmd = 0x01;
write(file, &cmd, 1);
uint8_t resp[2];
read(file, resp, 2);
uint16_t adc = (resp[0] << 8) | resp[1];
| 現象 | 原因 | 解決 |
|---|---|---|
| 主機讀取全 0xFF | 從機未在 TXE 中斷填入資料 | 確保 I2C_EVENT_SLAVE_TRANSMITTER_MATCHED 時預載第一個位元組 |
| 從機收不到資料 | GPIO 未設開漏或上拉電阻缺失 | 檢查原理圖,SCL/SDA 必須外接 4.7kΩ 上拉至 VDD |
| 位址衝突 | 7-bit 位址與總線上其他裝置重複 | 修改從機位址,掃描總線確認唯一 |
| 通訊隨機失敗 | 時鐘延展未處理或中斷優先級過低 | 提高 I2C 中斷優先級;必要時在主機端加入重試機制 |
替代方案:UART (RS232/RS485)、CAN、SPI (短距離)、Ethernet。若必須用 I2C,參考 RS485 協定設計應用層帧格式與重傳機制。
STM32Cube_FW_F1/I2C/I2C_TwoBoards_ComSlavei2cdetect -y 1 掃描從機位址STM32 做 I2C 從機核心在於事件中斷狀態機與自訂應用層協定。將從機視為一個智慧型 EEPROM,主機發「命令+參數」,從機回「資料/ACK」。建議優先評估 UART/CAN 等更適合 CPU 間通訊的介面。