文章目錄
- 軟件模擬I2C
- 硬件的實現方式
最近在研究I2C的屏幕使用。
有兩種使用方式,軟件模擬I2C、硬件HAL使用I2C。
軟件模擬I2C
發送數據是通過設置引腳的高低電平實現的。
/*引腳配置*/
#define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(x))
#define OLED_W_SDA(x) GPIO_WriteBit(GPIOB, GPIO_Pin_7, (BitAction)(x))/*引腳初始化*/
void OLED_I2C_Init(void)
{// 先關閉 I2C1 避免 PB6/PB7 被干擾// RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_Init(GPIOB, &GPIO_InitStructure);OLED_W_SCL(1);OLED_W_SDA(1);
}/*** @brief I2C發送一個字節* @param Byte 要發送的一個字節* @retval 無*/
void OLED_I2C_SendByte(uint8_t Byte)
{uint8_t i;for (i = 0; i < 8; i++){OLED_W_SDA(Byte & (0x80 >> i));OLED_W_SCL(1);OLED_W_SCL(0);}OLED_W_SCL(1); //額外的一個時鐘,不處理應答信號OLED_W_SCL(0);
}
硬件的實現方式
/*** @brief 向OLED發送指令*/
void OLED_SendCmd(uint8_t cmd) {static uint8_t sendBuffer[2] = {0};sendBuffer[1] = cmd;OLED_Send(sendBuffer, 2);
}/*** @brief 向OLED發送數據的函數* @param data 要發送的數據* @param len 要發送的數據長度* @return None* @note 此函數是移植本驅動時的重要函數 將本驅動庫移植到其他平臺時應根據實際情況修改此函數*/#define I2C_TIMEOUT 100 // 超時時間(單位:ms)
uint8_t OLED_Send(uint8_t *data, uint8_t len) {
// HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, data, len, HAL_MAX_DELAY);HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, data, len, I2C_TIMEOUT);if (status != HAL_OK) {// 打印錯誤(如果你有串口)// printf("I2C Error: %d\n", status);// 重置 I2CI2C_Reset(&hi2c1);// 嘗試重發一次status = HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, data, len, I2C_TIMEOUT);// 如果還是不行,返回失敗if (status != HAL_OK) {return 0; // 失敗}}return 1; // 成功}
HAL_I2C_Master_Transmit 會引起卡死的操作,所以要設置一下超時時間為100ms。
也不知道底層是怎么配置的。
驅動 IC 為 SSD1306,程序重啟的時候需要重新配置一下I2C,不然對應的硬件端口會卡死。