打印
[应用相关]

STM32软件模拟I2C驱动0.96寸OLED屏幕

[复制链接]
681|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-10-16 12:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
0.96寸OLED屏幕
0.96寸:屏幕对角线长0.96英寸

驱动:SSD1306驱动IC,驱动芯片内置128*64的SRAM存储器,用于缓存要显示的数据

分辨率:128*64(横128,竖64)

供电:3.3V(驱动内部内置升压电路,会将3.3升到7),需要与stm32共地(GND接在stm32上)

针脚:4脚(GND、VCC、SCL、SDA)

从机地址:0x78

指令操作前缀:

                       先发0x00表示后面的内容是对SSD1306驱动的控制命令;

                       先发0x40表示后面的内容是要显示的数据

显示流程:

页列显示,每列会以从上到下(上面是低位,下面的高位)的方式显示,显示8bit后自动换到右边的列,重复流程。

超过第127列后自动从本页开头覆盖显示,不自动跳页。1亮,0暗。

显示操作:对目标列进行显示,需要写命令操作。

对页操作:命令高五位是10110时,命令低三位则是页(8行)地址。页地址范围是0~8。

对列操作:  命令高四位为0001时,命令低四位则为x坐标的高四位。命令高四位为0000时,命令低四位则为x坐标的低四位。

软件I2C
        引脚配置:开漏输出

        输出:SDA、SCL

        工作流程:启动->7位地址+读写操作(0写1读)->传输数据...->停止

        数据传输方式:高位先行

         工作原理:

                        启动条件:SCL高时,下拉SDA

                        停止条件:SCL高时,上拉SDA

                        发送数据:在完成启动条件后,在SCL高电平时,会发送SDA的数据(0/1);在SCL低电平时,更改SDA上的数据(0/1)。发送方发送完一位数据(8bit)后,需要接收方发送<接收应答>(0/1,0应答,1不应答),然后发送发接收这个应答位来判断发送的数据是否被读取

细节注意:

                SCL由STM32控制,所以就算是从机要发送应答,也是由STM32改变SCL的电平去加载数据,同时需要STM32去释放对SDA的控制(拉高SDA)

                当STM32是发送方时,STM32在SCL高电平时发送SDA的数据,而从机在这个时候读取SDA的数据;当从机是发送方时,而OLED在SCL高电平时发送的数据,STM32在SCL时接收SDA的数据;

                当STM32是接收方时,STM32发送的应答位(0继续发/1别发了);与从机是接收方是,从机发送的应答位(0收到了/1没收到)的含义不同。

主要代码
软件模拟I2C的GPIO初始化

void GPIO_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_InitTypeDef GPIOBStructure;
    GPIOBStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIOBStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIOBStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIOBStructure);
    GPIO_WriteBit(GPIOB,GPIO_Pin_9,1);//SDA
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//SCL

//SDA和SCL没有进入启动模式前,SCL和SDA都是高电平
}

字节发送

void SendByte(uint8_t Byte)
{
    for(uint8_t i = 0; i < 8; i ++)
    {
        GPIO_WriteBit(GPIOB,GPIO_Pin_9,Byte & (0x80 >> i ));//SDA从高位开始加载数据
         GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//发送SDA上的数据
         GPIO_WriteBit(GPIOB,GPIO_Pin_8,0);//保证下一次SDA可以进行数据更改操作
    }

    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//拉高电平。结束for函数出来后的SCL为低,这里拉高SCL原先是硬件用来等待应答位的,这里直接拉高就是不接收应答位。
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,0);//保证下一次操作时是SCL为低,可以进行SDA的数据更改操作
}

对SSD1306写入命令操作

void OLED_WriteCommand(uint8_t Command)
{

    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//SCL

    GPIO_WriteBit(GPIOB,GPIO_Pin_9,0);//SDA
    SendByte(0x78 );//从机地址
    SendByte(0x00 );//写命令
    SendByte(Command);//发送指令

    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//SCL

    GPIO_WriteBit(GPIOB,GPIO_Pin_9,1);//SDA
}

对OLED屏幕写入要显示的数据
void OLED_WriteData(uint8_t Data)
{
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//SCL

    GPIO_WriteBit(GPIOB,GPIO_Pin_9,0);//SDA
    SendByte(0x78);        //从机地址
    SendByte(0x40);        //写数据
    SendByte(Data);        //数据
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//SCL

    GPIO_WriteBit(GPIOB,GPIO_Pin_9,1);//SDA
}

发送应答

void I2C_SendAck(uint8_t AckBit)//    主机接收时,会选择是否接着接收,所以要能传参
{
    GPIO_WriteBit(GPIOB,GPIO_Pin_9,AckBit);//SDA
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//SCL
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,0);//SCL
}

接收应答
uint8_t I2C_ReceiveAck(void)
{
    uint8_t AckBit;
     GPIO_WriteBit(GPIOB,GPIO_Pin_9,1);//主机释放对SDA的控制
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,1);//发送SCL后,从机会发送一个应答位给Pin9
    AckBit =     GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9);
    GPIO_WriteBit(GPIOB,GPIO_Pin_8,0);
    return AckBit;
}

选定在某页某列开始显示

void OLED_SetCursor(uint8_t pag, uint8_t x)
{
    //命令高五位是10110时,命令低三位则是页地址。页地址范围是0~8
    OLED_WriteCommand(0xB0 | pag);//取出数据低四位

    //命令高四位为0001时,命令低四位则为x坐标的高四位。
    OLED_WriteCommand(0x10 | (x & 0xF0) >> 4);//取出数据高四位
    //命令高四位为0000时,命令低四位则为x坐标的低四位
    OLED_WriteCommand(0x00 | (x & 0x0F));//取出数据低四位

}

OLED初始化(参考自江科大)

//OLED初始化---写入指令
void MyOLED_Init(void)
{   
    uint32_t i, j;
    for (i = 0; i < 1000; i++)  for (j = 0; j < 1000; j++);          //上电延时


    GPIO_Init();            //端口初始化
    OLED_WriteCommand(0xAE);    //关闭显示
    OLED_WriteCommand(0xD5);    //设置显示时钟分频比/振荡器频率
    OLED_WriteCommand(0x80);
    OLED_WriteCommand(0xA8);    //设置多路复用率
    OLED_WriteCommand(0x3F);
    OLED_WriteCommand(0xD3);    //设置显示偏移
    OLED_WriteCommand(0x00);
    OLED_WriteCommand(0x40);    //设置显示开始行
    OLED_WriteCommand(0xA1);    //设置左右方向,0xA1正常 0xA0左右反置
    OLED_WriteCommand(0xC8);    //设置上下方向,0xC8正常 0xC0上下反置

    OLED_WriteCommand(0xDA);    //设置COM引脚硬件配置
    OLED_WriteCommand(0x12);
    OLED_WriteCommand(0x81);    //设置对比度控制
    OLED_WriteCommand(0xCF);

    OLED_WriteCommand(0xD9);    //设置预充电周期
    OLED_WriteCommand(0xF1);

    OLED_WriteCommand(0xDB);    //设置VCOMH取消选择级别
    OLED_WriteCommand(0x30);

    OLED_WriteCommand(0xA4);    //设置整个显示打开/关闭

    OLED_WriteCommand(0xA6);    //设置正常/倒转显示

    OLED_WriteCommand(0x8D);    //设置充电泵
    OLED_WriteCommand(0x14);

    OLED_WriteCommand(0xAF);    //开启显示

        for (i = 0; i < 1000; i++) for (j = 0; j < 1000; j++);           //上电延时
}
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/QL_SD/article/details/142377356

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1931

主题

15650

帖子

12

粉丝