Giới thiệu về I2C phần cứng:
I2C (Inter-Integrated Circuit) là giao thức truyền thông nối tiếp hai dây được sử dụng rộng rãi để kết nối vi điều khiển với các thiết bị ngoại vi như cảm biến, EEPROM và màn hình OLED. Trên dòng vi điều khiển CH57x, CH582, CH592 của WCH, module I2C phần cứng được tích hợp sẵn, cho phép truyền dữ liệu nhanh chóng mà không cần xử lý bit qua phần mềm.
Quy trình hoạt động của I2C:
Giao thức I2C bao gồm các bước cơ bản sau: khi bus ở trạng thái rảnh, master gửi tín hiệu START để giành quyền điều khiển bus, sau đó gửi địa chỉ của slave cùng với bit đọc/ghi. Slave nhận ra địa chỉ và phản hồi ACK. Dữ liệu được truyền theo từng byte, mỗi byte được xác nhận bởi bit ACK. Cuối cùng, master gửi tín hiệu STOP để giải phóng bus.
Mã nguồn điều khiển OLED:
Dưới đây là các hàm được viết lại để giao tiếp với màn hình OLED qua I2C phần cứng:
/**
* @brief Gửi dữ liệu đến OLED (dạng hex, số dương)
* @param diaChi: Địa chỉ slave
* @param lenh: Lệnh xác định loại dữ liệu
* @param duLieu: Dữ liệu cần gửi
* @retval Không có
*/
void OLED_GuiDuLieu(uint8_t diaChi, uint8_t lenh, uint8_t duLieu)
{
while(I2C_GetFlagStatus(I2C_FLAG_BUSY) != RESET);
I2C_GenerateSTART(ENABLE);
while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(diaChi, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
if(I2C_GetFlagStatus(I2C_FLAG_TXE) != RESET)
I2C_SendData(lenh);
I2C_SendData(duLieu);
while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(ENABLE);
}
void OLED_DatConTro(uint8_t hang, uint8_t cot)
{
OLED_GuiDuLieu(0x78, 0x00, 0xB0 | hang);
OLED_GuiDuLieu(0x78, 0x00, 0x10 | ((cot & 0xF0) >> 4));
OLED_GuiDuLieu(0x78, 0x00, 0x00 | (cot & 0x0F));
}
void OLED_KhoiTao(void)
{
OLED_GuiDuLieu(0x78, 0x00, 0xAE);
OLED_GuiDuLieu(0x78, 0x00, 0xD5);
OLED_GuiDuLieu(0x78, 0x00, 0x80);
OLED_GuiDuLieu(0x78, 0x00, 0xA8);
OLED_GuiDuLieu(0x78, 0x00, 0x3F);
OLED_GuiDuLieu(0x78, 0x00, 0xD3);
OLED_GuiDuLieu(0x78, 0x00, 0x00);
OLED_GuiDuLieu(0x78, 0x00, 0x40);
OLED_GuiDuLieu(0x78, 0x00, 0xA1);
OLED_GuiDuLieu(0x78, 0x00, 0xC8);
OLED_GuiDuLieu(0x78, 0x00, 0xDA);
OLED_GuiDuLieu(0x78, 0x00, 0x12);
OLED_GuiDuLieu(0x78, 0x00, 0x81);
OLED_GuiDuLieu(0x78, 0x00, 0xCF);
OLED_GuiDuLieu(0x78, 0x00, 0xD9);
OLED_GuiDuLieu(0x78, 0x00, 0xF1);
OLED_GuiDuLieu(0x78, 0x00, 0xDB);
OLED_GuiDuLieu(0x78, 0x00, 0x30);
OLED_GuiDuLieu(0x78, 0x00, 0xA4);
OLED_GuiDuLieu(0x78, 0x00, 0xA6);
OLED_GuiDuLieu(0x78, 0x00, 0x8D);
OLED_GuiDuLieu(0x78, 0x00, 0x14);
OLED_GuiDuLieu(0x78, 0x00, 0xAF);
OLED_XoaManHinh();
}
Lưu ý quan trọng:
Khi sử dụng I2C phần cứng trên các chân chuyên dụng, vi điều khiển tự động cấu hình chế độ open-drain (mở thuần). Chỉ có các chân hỗ trợ I2C mới có thể sử dụng cho chức năng này. Người dùng cần tham khảo datasheet để xác định đúng các chân I2C trên thiết cụ thể.
Ví dụ chương trình hoàn chỉnh:
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit();
PRINT("Che do I2C Master\r\n");
GPIOB_ModeCfg(GPIO_Pin_13 | GPIO_Pin_12, GPIO_ModeIN_PU);
I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, 0x42);
OLED_KhoiTao();
char kiTu = '!';
for(uint8_t i = 1; i < 5; i++)
{
for(uint8_t j = 1; j < 17; j++)
{
OLED_HienThiKiTu(i, j, kiTu);
kiTu++;
}
}
while(1);
}
Giải thích cấu hình:
Trong ví dụ trên, chân SCL được kết nối với GPIO12 và chân SDA với GPIO13 của port B. Tốc độ truyền được đặt là 400Kbit/s theo chế độ Fast Mode. Địa chỉ slave của màn hình OLED 0.96 inch thường là 0x78. Hàm khởi tạo gửi một chuỗi các lệnh cấu hình để thiết lập các thông số hiển thị như tỷ lệ phân chia, dòng bắt đầu, hướng hiển thị và bộ kích charge pump.
Sau khi khởi tạo, chương trình hiển thị các ký tự từ '!' đến '~' trên 4 hàng và 16 cột của màn hình OLED để kiểm tra hoạt động.