嵌入式协议应用:STM32硬件IIC驱动OLED屏幕显示

目录

OLED介绍

实验所用屏幕参数

OLED与开发板接线

显存与页寻址模式

软件设计

IIC驱动代码

OLED驱动代码

16*16汉字点阵生成工具

显示效果

完整代码资源


OLED介绍

OLED即有机发光管(Organic Light-Emitting Diode,OLED)。OLED显示技术具有自发光、广视角、几乎无穷高的对比度、较低功耗、极高反应速度、可用于绕曲性面板、使用温度范围广、构造及制程简单等有点,被认为是下一代的平面显示屏新兴应用技术。
OLED显示和传统的LCD显示不同,其可以自发光,所以不需要背光灯,这使得OLED显示屏相对于LCD显示屏尺寸更薄,同时显示效果更优。
常用的OLED屏幕有蓝色、黄色、白色等几种。屏的大小为0.96寸,像素点为128*64,所以我们称为0.96oled屏或者12864屏。

实验所用屏幕参数

  1. 模块尺寸:23.7 *23.8mm
  2. 电源电压:3.3-5.5V
  3. 驱动芯片:SSD1306
  4. 像素点阵规模:128x64(128列,64行,共8192颗LED

OLED与开发板接线

OLED引脚
正点原子stm32f4探索者开发板
引脚
引脚说明
GND
GND
电源地
VCC
3.3V/5V
电源正
SCL
PB8(I2C1_SCL)
IIC时钟线
SDA
PB9(I2C1_SDA)
IIC数据线

显存与页寻址模式

驱动芯片SSD1306带有一个128x64 bit大小的GDDRAM,用于存放显示数据,也就是所谓的显存。显存中的数据与显示内容是息息相关的,具体来说,显存中的每一个bit对应一颗像素点,如果显存中的某个bit为1,则它对应的那颗像素LED被点亮,否则是熄灭的。
GDDRAM支持3种内存寻址模式,可以通过指令选择为:
①页寻址模式
②水平寻址模式
③垂直寻址模式。
这里讲解一下最常用的页寻址模式。 在页寻址模式下,每次写入一个字节的显示数据,列地址自动增1。当列地址超过127时,会自动回归到0。但是页指针不会改变,除非使用指令重新设置指向其他的页。

软件设计

IIC驱动代码

这里参考正点原子的IIC驱动代码,使用软件模拟IIC协议。如果对IIC还不是很了解可以参考这一篇:
使用正点原子stm32f4探索者开发板的IIC1接口(PB8和PB9),初始化PB8和PB9,IIC_SCL=1和IIC_SDA=1分别代表将时钟线、数据线拉高。
//初始化SSD1306                        
void OLED_Init(void)
{     
 
      
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

    //GPIOB8,B9初始化设置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    IIC_SCL=1;
    IIC_SDA=1;
/******oled初始化部分放至后续讲解********/
}

接下来需要实现IIC的开始信号、结束信号、写字节函数,由于对OLED屏幕的操作主要是写数据,所以这里没有实现读函数。

IIC_Start()函数模拟了IIC传输数据的开始信号,即在时钟线高时将数据线拉低。

/**********************************************
//IIC Start
**********************************************/
void IIC_Start()
{
    SDA_OUT();     //sda线输出
    IIC_SDA=1;            
    IIC_SCL=1;
    delay_us(4);
     IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
    delay_us(4);
    IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}

IIC_Stop()函数模拟了IIC传输数据的结束信号,即在时钟线高时将数据线从低拉高。

/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop()
{
    SDA_OUT();//sda线输出
    IIC_SCL=0;
    IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
     delay_us(4);
    IIC_SCL=1; 
    IIC_SDA=1;//发送I2C总线结束信号
    delay_us(4);    
    
}

IIC_Wait_Ack()函数模拟了IIC传输过程中的ACK信号,主机发送一个字节的数据后,若从机没有及时返回ACK响应,将停止数据传输。

void IIC_Wait_Ack()
{
    u8 ucErrTime=0;
    SDA_IN();      //SDA设置为输入  
    IIC_SDA=1;delay_us(1);       
    IIC_SCL=1;delay_us(1);     
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
        }
    }
    IIC_SCL=0;//时钟输出0        
}

Write_IIC_Byte()函数模拟了从主机发送一个字节数据到从机,高位在前,低位在后。

void Write_IIC_Byte(unsigned char txd)
{
    u8 t;   
    SDA_OUT();         
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;       
        delay_us(2);   
        IIC_SCL=1;
        delay_us(2); 
        IIC_SCL=0;    
        delay_us(2);
    }
}

OLED驱动代码

oled初始化代码
//初始化SSD1306                        
void OLED_Init(void)
{
 /******oled初始化部分********/    


    delay_ms(200);
    OLED_WR_Byte(0xAE,OLED_CMD);//关闭显示
    
    OLED_WR_Byte(0x40,OLED_CMD);//---set low column address
    OLED_WR_Byte(0xB0,OLED_CMD);//---set high column address

    OLED_WR_Byte(0xC8,OLED_CMD);//-not offset

    OLED_WR_Byte(0x81,OLED_CMD);//设置对比度
    OLED_WR_Byte(0xff,OLED_CMD);

    OLED_WR_Byte(0xa1,OLED_CMD);//段重定向设置

    OLED_WR_Byte(0xa6,OLED_CMD);//设置显示模式,设置为0xa6,显存里的1表示对应led亮,0表示对应led熄灭
    
    OLED_WR_Byte(0xa8,OLED_CMD);//设置驱动路数
    OLED_WR_Byte(0x1f,OLED_CMD);
    
    OLED_WR_Byte(0xd3,OLED_CMD);//设置显示偏移量
    OLED_WR_Byte(0x00,OLED_CMD);
    
    OLED_WR_Byte(0xd5,OLED_CMD);//设置时钟分频数和fosc
    OLED_WR_Byte(0xf0,OLED_CMD);
    
    OLED_WR_Byte(0xd9,OLED_CMD);//设置预充期
    OLED_WR_Byte(0x22,OLED_CMD);
    
    OLED_WR_Byte(0xda,OLED_CMD);//设置com脚硬件配置
    OLED_WR_Byte(0x02,OLED_CMD);
    
    OLED_WR_Byte(0xdb,OLED_CMD);//设置Vcomh deselect level
    OLED_WR_Byte(0x49,OLED_CMD);
    
    OLED_WR_Byte(0x8d,OLED_CMD);//电荷泵设置
    OLED_WR_Byte(0x14,OLED_CMD);
    
    OLED_WR_Byte(0xaf,OLED_CMD);//开启显示
    OLED_Clear();
}

oled显示汉字的程序如下,这里使用的是页寻址模式(本文前面已经介绍过),所以16*16的点阵分为两部分显示,首先显示上半部分的8*16,然后页指针+1,继续显示剩下的8*16。

//显示汉字,显示的汉字为16*16点阵
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{                      
    u8 t,adder=0;
    OLED_Set_Pos(x,y);    
    for(t=0;t<16;t++)//显示上半部分8*16点阵
    {
        OLED_WR_Byte(CHN[2*no][t],OLED_DATA);
        adder+=1;
    }    
    OLED_Set_Pos(x,y+1);    
    for(t=0;t<16;t++)//页指针+1后,显示上半部分8*16点阵
    {    
        OLED_WR_Byte(CHN[2*no+1][t],OLED_DATA);
        adder+=1;
     }                    
}

//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y) 
{     
    OLED_WR_Byte(0xb0+y,OLED_CMD);
    OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
    OLED_WR_Byte((x&0x0f),OLED_CMD); 
}  

//cmd为1(OLED_DATA)时代表写显示数据,cmd为0(OLED_CMD)时代表写操作指令
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
    if(cmd)
    {
        Write_IIC_Data(dat);
    }
    else {
        Write_IIC_Command(dat);
    }
}

/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
    IIC_Start();
    Write_IIC_Byte(0x78);            //D/C#=0; R/W#=0
    IIC_Wait_Ack();    
    Write_IIC_Byte(0x40);            //write data
    IIC_Wait_Ack();    
    Write_IIC_Byte(IIC_Data);
    IIC_Wait_Ack();    
    IIC_Stop();
}

/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
    IIC_Start();
    Write_IIC_Byte(0x78);            //Slave address,SA0=0
    IIC_Wait_Ack();    
    Write_IIC_Byte(0x00);            //write command
    IIC_Wait_Ack();    
    Write_IIC_Byte(IIC_Command); 
    IIC_Wait_Ack();    
    IIC_Stop();
}

16*16汉字点阵生成工具

  1. 设置字宽和字高;
  2. 点击“选项”,在字模选项界面中设置“点阵格式”为阴码,设置“取模方式”为列行式,设置“自定义格式”为C51格式;
  3. 返回软件主界面,输入想要生成的汉字,然后点击“生成自模”;
  4. 把生成的字模复制到keil中使用。

显示效果

完整代码资源

如果需要完整的工程文件可以看这里
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值