#更新通知:2023-09-06 STM32L151 固件库 使用I2C 太难了,又宕机了,建议不要在固件库版本上尝试硬件IIC 了,一般人真用不了,直接使用软件模拟的,或者不要使用固件库了,用HAL 库吧,据说HAL 库没这么多问题,不死心的我还是死心了,等有空再研究吧
// stm32l151c8t6 as master, oled control ic (CH1116G) as slave, and communicate by master iic2
void STM32L151C8T6_IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // GPIO_OType_OD, GPIO_OType_PP
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_400KHz;
GPIO_Init(GPIOB, &GPIO_InitStruct); // IIC2 SCL - PB10, SDA - PB11
GPIO_ResetBits(GPIOB, GPIO_Pin_11);
delay_xms(20);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2); // set PB10 as IIC2 SCL
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2); // set PB11 as IIC2 SDA
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_ClockSpeed = iic_clockSpeed_400Khz; // must be less than 100 Khz
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStruct.I2C_Mode = I2C_Mode_SMBusHost; // 这里很重要
I2C_InitStruct.I2C_OwnAddress1 = IIC2_NOT_USE_OWN_ADDR; // do not use own address
I2C_Init(I2C2, &I2C_InitStruct);
I2C_Cmd(I2C2, ENABLE);
I2C_AcknowledgeConfig(I2C2, ENABLE);
}
// master (STM32L151C8T6) send cmd instruction to oled screen control ic (CH1116G)
void OLED_SendCmd(uint8_t cmd)
{
WaitFor_IIC_ReadyToWorking();
I2C_GenerateSTART(I2C2, ENABLE); // iic start signal
IIC_SendStartSignal_CheckEvent();
I2C_Send7bitAddress(I2C2, OLED_ADDRESS, I2C_Direction_Transmitter); // send device addr and write bit
I2C_SendDeviceAddrWaitAck();
IIC_SendByteToOLED(iic_transmitType_Cmd);
IIC_Delay(IIC_TIMEOUT_COUNTER);
I2C_SendData(I2C2, cmd);
I2C_SendByteDataWaitAck();
I2C_GenerateSTOP(I2C2, ENABLE);
IIC_Delay(IIC_TIMEOUT_COUNTER);
}
static void WaitFor_IIC_ReadyToWorking(void)
{
while (I2C2->SR2 & 0x02)
{
INFO_LOG("[WaitFor_IIC_ReadyToWorking] i2c2 is busy\r\n");
}
}
static void IIC_SendStartSignal_CheckEvent(void)
{
while (!((uint16_t)(I2C2->SR1) & (uint16_t)(0x0001)))
{
printf("[IIC_SendStartSignal_CheckEvent][] I2C_SR1=0x%04x, I2C2_SR2=0x%04x\r\n", I2C2->SR1, I2C2->SR2);
}
while (!((uint16_t)(I2C2->SR2) & (uint16_t)(0x0003)) == 0x0003)
{
printf("[IIC_SendStartSignal_CheckEvent][] I2C_SR1=0x%04x, I2C2_SR2=0x%04x\r\n", I2C2->SR1, I2C2->SR2);
}
}
static void I2C_SendDeviceAddrWaitAck(void)
{
while (!((uint16_t)(I2C2->SR1) & (uint16_t)(0x0082)) == 0x0082)
{
}
while (!((uint16_t)(I2C2->SR2) & (uint16_t)(0x0007)) == 0x0007)
{
}
}
static void IIC_SendByteToOLED(uint8_t mode)
{
IIC_Delay(IIC_TIMEOUT_COUNTER);
I2C_SendData(I2C2, mode); // 0x00, high 8-bits, cmd code, iic_transmitType_Cmd
I2C_SendByteDataWaitAck();
IIC_Delay(IIC_TIMEOUT_COUNTER);
I2C_SendData(I2C2, mode); // 0x00, low 8-bits, cmd code
I2C_SendByteDataWaitAck();
}
static void I2C_SendByteDataWaitAck(void)
{
while (!((uint16_t)(I2C2->SR1) & (uint16_t)(0x0080)) == 0x0080)
{
}
while (!((uint16_t)(I2C2->SR2) & (uint16_t)(0x0007)) == 0x0007)
{
}
}
void OLED_Init(void)
{
delay_xms(20); // oled startup slowly than stm32l151c8t6
INFO_LOG("[OLED_Init] init start\r\n");
OLED_SendCmd(0xAE); // display off
OLED_SendCmd(0x02); // set colum start address
OLED_SendCmd(0x10); // set colum end address
OLED_SendCmd(0x40); // set start line (first row)
OLED_SendCmd(0xB0); // set page address
OLED_SendCmd(0x81); // set contrast ratio
OLED_SendCmd(0xCF); // 128
OLED_SendCmd(0xA1); // set segment remapping, from right to left
OLED_SendCmd(0xA6); // forward display, normal or reverse
OLED_SendCmd(0xA8); // multiple reuse rate, multiple ratio
OLED_SendCmd(0x3F); // duty = 1 / 64
OLED_SendCmd(0xAD); // set charge pump enable
OLED_SendCmd(0x8B); // enable DC-DC
OLED_SendCmd(0x33); // set VPP = 10V
OLED_SendCmd(0xC8); // set output scan direction, COM[N - 1] to COM[0], COM scan direction
OLED_SendCmd(0xD3); // set display offset
OLED_SendCmd(0x00); // 0x00
OLED_SendCmd(0xD5); // set internal clock frequence, set osc frequency
OLED_SendCmd(0xC0);
OLED_SendCmd(0xD9); // set pre-charge period
OLED_SendCmd(0x1F); // 0x22
OLED_SendCmd(0xDA); // set COM pins, pin layout
OLED_SendCmd(0x12);
OLED_SendCmd(0xDB); // set electrical level, set VCOMH
OLED_SendCmd(0x40);
OLED_SendCmd(0xAF); // enable display, display on
INFO_LOG("[OLED_Init] init complete\r\n");
}
void OLED_Test(void)
{
OLED_SendCmd(0xB0); // page 0
OLED_SendCmd(0x00); // colume 0 low 4-bits
OLED_SendCmd(0x10); // colume 0 high 8-bits
OLED_SendCmd(0x40);
OLED_SendCmd(0xAA);
}
int main(void)
{
delay_xms(1000);
OLED_Init();
OLED_Test();
}
#define IIC_TIMEOUT_COUNTER 0x1000 // iic transmit timeout
static void IIC_Delay(uint32_t delay_time)
{
uint32_t delayTime;
for (delayTime = 0; delayTime < delay_time; delayTime++)
{
}
}