• STM32 软件IIC 控制OLED 显示屏


    1. 硬件IIC 实在是太难用了,各种卡死,各种发不出来数据,没那么多时间折腾了,还是用软件IIC 先吧,初始化

    void OLED_Software_IIC_Init(void)
    {
        GPIO_InitTypeDef GPIO_InitStruct;
    
        RCC_AHBPeriphClockCmd(OLED_SOFTWARE_IIC_PORT_B | OLED_SOFTWARE_IIC_AF_CLOCK, ENABLE);
    
        GPIO_InitStruct.GPIO_Pin = OLED_IIC_SDA_PIN_B11 | OLED_IIC_SCL_PIN_B10;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
        GPIO_Init(GPIOB, &GPIO_InitStruct); // PB11 - SDA, PB10 - SCL
    
        GPIO_SetBits(GPIOB, OLED_IIC_SDA_PIN_B11 | OLED_IIC_SCL_PIN_B10);
    
        OLED_IIC_Stop();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2. 一些宏定义,带FreeRTOS 实时操作系统,系统节拍设置为1ms,系统主频设置为32Mhz

    #define OLED_USE_SOFTWARE_IIC
    
    #define OLED_SOFTWARE_IIC_PORT_B    RCC_AHBPeriph_GPIOB // SCL - PB10, SDA -PB11
    #define OLED_SOFTWARE_IIC_AF_CLOCK    RCC_APB1Periph_I2C2
    
    #define IIC_TIMEOUT_COUNTER    0x2000 // iic transmit timeout
    
    #define OLED_IIC_SCL_PIN_B10    GPIO_Pin_10
    #define OLED_IIC_SDA_PIN_B11    GPIO_Pin_11
    #define OLED_SCL_H()    GPIO_SetBits(GPIOB, OLED_IIC_SCL_PIN_B10)
    #define OLED_SCL_L()    GPIO_ResetBits(GPIOB, OLED_IIC_SCL_PIN_B10)
    
    #define OLED_ADDRESS    0x78 // 0x78: device address + write, 0x79 - device address + read
    #define IIC_CMD_LEN    2
    
    #define OLED_SDA_H()    GPIO_SetBits(GPIOB, OLED_IIC_SDA_PIN_B11)
    #define OLED_SDA_L()    GPIO_ResetBits(GPIOB, OLED_IIC_SDA_PIN_B11)
    
    #define OLED_SDA_READ()    GPIO_ReadInputDataBit(GPIOB, OLED_IIC_SDA_PIN_B11)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3. 延时函数,CPU 阻塞,空转

    static void IIC_Delay(void)
    {
       uint8_t temp;
    
       for (temp = 0; temp < 10; temp++)
       {
           // do nothing
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4. 起始信号

    static void OLED_IIC_Start(void)
    {
        OLED_SDA_H();
        OLED_SCL_H();
    
        IIC_Delay();
        OLED_SDA_L();
        IIC_Delay();
        OLED_SCL_L();
        IIC_Delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5. 停止信号

    static void OLED_IIC_Stop(void)
    {
       OLED_SDA_L();
       OLED_SCL_H();
       IIC_Delay();
       OLED_SDA_H();
       IIC_Delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6. 发送一个字节的数据

    static void OLED_IIC_SendByte(uint8_t data)
    {
       uint8_t index;
       GPIO_InitTypeDef GPIO_InitStruct;
    
       for (index = 0; index < 8; index++) // send one byte data, first send MSB (bit[7]), send LSB at the last (bit[0])
       {
           if (data & 0x80)
           {
               OLED_SDA_H(); // send 1
           }
           else
           {
               OLED_SDA_L(); // send 0
           }
           IIC_Delay();
           OLED_SCL_H();
           IIC_Delay();
           OLED_SCL_L();
           data <<= 1; // send next bit (MSB -> LSB)
           IIC_Delay();
       }
    //    OLED_SDA_H();
       GPIO_InitStruct.GPIO_Pin = OLED_IIC_SDA_PIN_B11;
       GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
       GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    
       GPIO_Init(GPIOB, &GPIO_InitStruct);
    
       IIC_Delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    7. 发送一个字节数据后等待从机回复一个ACK 信号

    uint8_t OLED_IIC_WaitAck(void)
    {
       uint8_t ret;
    
       OLED_SCL_H();
       if (OLED_SDA_READ())
       {
           ret = 1; // not received ACK signal, wait fail
       }
       else
       {
           ret = 0; // received ACK signal, wait success
       }
       IIC_Delay();
       OLED_SCL_L();
       IIC_Delay();
    
       return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    8. GPIO 重新初始化

    static void OLED_SoftwareIIC_SDA_Resume(void)
    {
        GPIO_InitTypeDef GPIO_InitStruct;
    
        GPIO_InitStruct.GPIO_Pin = OLED_IIC_SDA_PIN_B11;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
        GPIO_Init(GPIOB, &GPIO_InitStruct); // PB11 - SDA
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    9. 模仿HAL库写的一个自己的函数,实现功能,发送设备地址+读写控制,再发送0x00,表示发的是命令,再发一个字节数据,具体的内容,数据,共发了三个字节的数据,加了超时退出机制

    /*
     * imitate the stm32 HAL library, achieve myself's software i2c send function
     * deviceAddr: 0x78 - device address and write operation, 0x79 - device address and read operation
     */
    static void HAL_I2C_Master_Transmit(I2C_TypeDef *I2Cx, uint8_t deviceAddr, uint8_t buff[], uint16_t buffLen, uint32_t timeout)
    {
        uint32_t temp;
        uint16_t index;
    
        temp = timeout;
    
        OLED_IIC_Start();
    
        IIC_Delay();
        OLED_IIC_SendByte(deviceAddr); // device address and write bit
    
        while (OLED_IIC_WaitAck())
        {
            temp--;
            if (0 == temp)
            {
                return;
            }
            IIC_Delay();
        }
    
        OLED_SoftwareIIC_SDA_Resume();
        for (index = 0; index < buffLen; index++)
        {
            OLED_IIC_SendByte(buff[index]);
            IIC_Delay();
            while (OLED_IIC_WaitAck())
            {
                temp--;
                if (0 == temp)
                {
                    return;
                }
                IIC_Delay();
            }
            OLED_SoftwareIIC_SDA_Resume();
            IIC_Delay();
        }
    
        OLED_IIC_Stop();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    10. 向OLED 发送指令函数

    static void OLED_SendCmd(uint8_t cmd)
    {
        uint8_t sendBuff[2];
    
        sendBuff[0] = 0x00;
        sendBuff[1] = cmd;
    
        HAL_I2C_Master_Transmit(I2C2, OLED_ADDRESS, sendBuff, IIC_CMD_LEN, IIC_TIMEOUT_COUNTER);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    11. OLED 初始化函数,OLED 用的龙科显示公式的产品,控制IC 用的是CH1116G,他们给我发是资料却是SH1106的

    void OLED_Init(void)
    {
        delay_xms(200); // 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, low 4-bits
        OLED_SendCmd(0x10); // set colum end address, high 4-bits
    
        OLED_SendCmd(0x40); // set start line (first row)
        OLED_SendCmd(0xB0); // set page address
    
        delay_xms(5);
        OLED_SendCmd(0x81); // set contrast ratio (对比度)
        delay_xms(5);
        OLED_SendCmd(0xCF); // 128
        delay_xms(5);
    
        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][alfred01] init complete\r\n");
        INFO_LOG("[OLED_Init] init complete\r\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    12. OLED 测试函数

    void OLED_Test(void)
    {
        OLED_SendCmd(0xB0); // page 0
        OLED_SendCmd(0x02); // colume 0, low 4-bits
        OLED_SendCmd(0x10); // colume 0, high 4-bits
    
        uint8_t sendBuff[] = {0x40, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
        HAL_I2C_Master_Transmit(I2C2, OLED_ADDRESS, sendBuff, sizeof(sendBuff), IIC_TIMEOUT_COUNTER);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    13. OLED 初步显示效果,表示控制驱动是OK的了,其它的就是慢慢细调了

    在这里插入图片描述

    14. OLED 规格书,控制芯片用的CH1116G,这是硬件发给我,和厂家给的不一致,厂家说是兼容的,那我就直接上手调了

    在这里插入图片描述

    15. 看这三个引脚接的是高电平还是低电平,怎么组合的,就知道用的什么接口,需要看原理图

    在这里插入图片描述
    需要看原理图了
    在这里插入图片描述
    在这里插入图片描述

    16. 逻分仪抓的OLED 初始化时序图

    在这里插入图片描述

  • 相关阅读:
    python+flask计算机毕业设计农村住宅房屋信息管理应用系统(程序+开题+论文)
    昨天
    C语言 | Leetcode C语言接雨水II
    HTML如何制作音乐网站(如何搭建个人音乐网页)
    1334. 阈值距离内邻居最少的城市
    大数据技术学习笔记(五)—— MapReduce(2)
    linux优点和缺点有哪些?
    Spring Boot+微信小程序_保存微信登录者的个人信息
    【Git】Git基础命令操作速记
    工作一年半,我终于明白了这些|1024有感
  • 原文地址:https://blog.csdn.net/weixin_50212044/article/details/132720719