STM32模拟IIC驱动OLED屏 原理+源码

处理器和芯片间的通信可以形象的比喻成两个人讲话:1、你说的别人得能听懂:双方约定信号的协议。2、你的语速别人得能接受:双方满足时序要求。
一、IIC总线的信号类型
开始和停止信号
1、开始信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由高变低就表示一个开始信号。同时IIC总线上的设备检测到这个开始信号它就知道处理器要发送数据了。

2、停止信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由低变高就表示一个停止信号。同时IIC总线上的设备检测到这个停止信号它就知道处理器已经结束了数据传输,我们就可以各忙各个的了,如休眠等。
二、IIC数据传输过程
IIC数据传输
1、在数据传输时,SDA的数据在SCL为高电平时,必须保持稳定,SCL高电平器件完成数据的传输。在SCL低电平器件,可以任意改变SDA的数据。数据写入过程是从最好为开始,高位在前,低位在后,即MSB。
2、响应信号(ACK):接收器在接收到8位数据后,在第9个时钟周期,拉低SDA电平。即接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
三、数据写入的过程
写入数据过程
首先发送一个开始信号,接着发送从机地址,OLED的从机地址前7位为地址,最后一位表示读(1)或者写(0)。应答ACK信号表示有这个从设备存在。在接收到应答信号后,发送控制位,来区分之后所发送的数据是控制命令还是显示相关的数据。在发送控制位后,等待应答信号。然后发送相应的控制命令或者数据。最后发送停止信号,表示数据传输完成。

基本的时序就是以上内容,接下来是源码:

#include "stm32f10x.h"

#include "iic.h"
#include "delay.h"
#include "codetab.h"

/**
**  初始化IIC接口
**/
void IIC_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructer;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitStructer.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7; //6--SCL   7--SDA
    GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;

    GPIO_Init(GPIOB, &GPIO_InitStructer);
}

/**
**  设置SDA为输出
**/
void SDA_OUT(void)
{
    GPIO_InitTypeDef GPIO_InitStructer;
    GPIO_InitStructer.GPIO_Pin= GPIO_Pin_7;
    GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructer);
}


/**
**  设置SDA为输入
**/
void SDA_IN(void)
{
    GPIO_InitTypeDef GPIO_InitStructer;
    GPIO_InitStructer.GPIO_Pin= GPIO_Pin_7;
    GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructer);
}

//开始信号
void IIC_Start(void)
{
    SDA_OUT();
    IIC_SDA=1;
    IIC_SCL=1;
    delay_us(2);
    IIC_SDA=0;
    delay_us(2);
    IIC_SCL=0;
    delay_us(2);
}

void IIC_Stop(void)
{
    IIC_SCL=1;
    IIC_SDA=0;
    delay_us(2);
    IIC_SDA=1;
    delay_us(2);
}


/*
*   返回1--应答出错
*   放回0--应答正确
*/
u8 IIC_Wait_Ask(void)
{
    int count=0;
    SDA_IN();
    IIC_SCL=1;
    delay_us(2);
    while(READ_SDA)
    {
        count++;
        if(count>250)
        {
            IIC_Stop();
            return 1;
        }   
    }
    IIC_SCL=0;
    delay_us(2);
    return 0;
}

//写一个字节
void IIC_WriteByte(u8 data)
{
    u8 i;
    SDA_OUT();
    for(i=0;i<8;i++)
    {
        IIC_SCL=0;
        delay_us(2);
        if(data & 0x80)     //MSB,从高位开始一位一位传输
            IIC_SDA=1;
        else
            IIC_SDA=0;
        IIC_SCL=1;
        delay_us(2);
        IIC_SCL=0;
        data<<=1;

    }
}


u8 IIC_ReadByte(void)
{
    u8 data,i;
    IIC_SDA=1;
    delay_us(2);
    for(i=0;i<8;i++)
    {
        data<<=1;
        IIC_SCL=0;
        delay_us(2);
        IIC_SCL=1;
        delay_us(2);
        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7))
            data=data | 0x01;
        else 
            data=data & 0xFE;

    }
    IIC_SCL=0;
    delay_us(2);
    return data;

}


void WriteCmd(u8 command)
{
    IIC_Start();
    IIC_WriteByte(0x78);//OLED地址
    IIC_Wait_Ask();
    IIC_WriteByte(0x00);//寄存器地址
    IIC_Wait_Ask();
    IIC_WriteByte(command);
    IIC_Wait_Ask();
    IIC_Stop();
}


void WriteDat(u8 data)
{
    IIC_Start();
    IIC_WriteByte(0x78);//OLED地址
    IIC_Wait_Ask();
    IIC_WriteByte(0x40);//寄存器地址
    IIC_Wait_Ask();
    IIC_WriteByte(data);
    IIC_Wait_Ask();
    IIC_Stop();
}

void OLED_Init(void)
{
    delay_ms(100); //这里的延时很重要

    WriteCmd(0xAE); //display off
    WriteCmd(0x20); //Set Memory Addressing Mode    
    WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
    WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
    WriteCmd(0xc8); //Set COM Output Scan Direction
    WriteCmd(0x00); //---set low column address
    WriteCmd(0x10); //---set high column address
    WriteCmd(0x40); //--set start line address
    WriteCmd(0x81); //--set contrast control register
    WriteCmd(0xff); //亮度调节 0x00~0xff
    WriteCmd(0xa1); //--set segment re-map 0 to 127
    WriteCmd(0xa6); //--set normal display
    WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
    WriteCmd(0x3F); //
    WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
    WriteCmd(0xd3); //-set display offset
    WriteCmd(0x00); //-not offset
    WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
    WriteCmd(0xf0); //--set divide ratio
    WriteCmd(0xd9); //--set pre-charge period
    WriteCmd(0x22); //
    WriteCmd(0xda); //--set com pins hardware configuration
    WriteCmd(0x12);
    WriteCmd(0xdb); //--set vcomh
    WriteCmd(0x20); //0x20,0.77xVcc
    WriteCmd(0x8d); //--set DC-DC enable
    WriteCmd(0x14); //
    WriteCmd(0xaf); //--turn on oled panel
}


 /**
  * @brief  OLED_ON,将OLED从休眠中唤醒
  * @param  无
    * @retval 无
  */
void OLED_ON(void)
{
    WriteCmd(0X8D);  //设置电荷泵
    WriteCmd(0X14);  //开启电荷泵
    WriteCmd(0XAF);  //OLED唤醒
}


 /**
  * @brief  OLED_SetPos,设置光标
  * @param  x,光标x位置
    *                   y,光标y位置
  * @retval 无
  */
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{ 
    WriteCmd(0xb0+y);
    WriteCmd(((x&0xf0)>>4)|0x10);
    WriteCmd((x&0x0f)|0x01);
}

 /**
  * @brief  OLED_Fill,填充整个屏幕
  * @param  fill_Data:要填充的数据
    * @retval 无
  */
void OLED_Fill(unsigned char fill_Data)//全屏填充
{
    unsigned char m,n;
    for(m=0;m<8;m++)
    {
        WriteCmd(0xb0+m);       //page0-page1
        WriteCmd(0x00);     //low column start address
        WriteCmd(0x10);     //high column start address
        for(n=0;n<128;n++)
            {
                WriteDat(fill_Data);
            }
    }
}

void OLED_CLS(void)//清屏
{
    OLED_Fill(0x00);
}

/**
  * @brief  OLED_ShowStr,显示codetab.h中的ASCII字符,有6*8和8*16可选择
  * @param  x,y : 起始点坐标(x:0~127, y:0~7);
    *                   ch[] :- 要显示的字符串; 
    *                   TextSize : 字符大小(1:6*8 ; 2:8*16)
    * @retval 无
  */
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
    unsigned char c = 0,i = 0,j = 0;
    switch(TextSize)
    {
        case 1:
        {
            while(ch[j] != '\0')
            {
                c = ch[j] - 32;
                if(x > 126)
                {
                    x = 0;
                    y++;
                }
                OLED_SetPos(x,y);
                for(i=0;i<6;i++)
                    WriteDat(F6x8[c][i]);
                x += 6;
                j++;
            }
        }break;
        case 2:
        {
            while(ch[j] != '\0')
            {
                c = ch[j] - 32;
                if(x > 120)
                {
                    x = 0;
                    y++;
                }
                OLED_SetPos(x,y);
                for(i=0;i<8;i++)
                    WriteDat(F8X16[c*16+i]);
                OLED_SetPos(x,y+1);
                for(i=0;i<8;i++)
                    WriteDat(F8X16[c*16+i+8]);
                x += 8;
                j++;
            }
        }break;
    }
}






  • 77
    点赞
  • 496
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
以下是使用STM32 HAL库驱动OLED幕的代码。请注意,这只是一个基本的示例,可能需要根据您的硬件和要求进行修改。 ``` #include "stm32xxxx.h" #include "stm32xxxx_hal.h" #define OLED_ADDR 0x78 I2C_HandleTypeDef hi2c; void OLED_Init(void) { uint8_t init_cmds[] = {0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0x8D, 0x14, 0x20, 0x00, 0xA0, 0xC8, 0xDA, 0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6, 0xAF}; uint8_t i; for (i = 0; i < sizeof(init_cmds); i++) { HAL_I2C_Mem_Write(&hi2c, OLED_ADDR, 0x00, 1, &init_cmds[i], 1, 10); } } void OLED_SetPos(uint8_t x, uint8_t y) { HAL_I2C_Mem_Write(&hi2c, OLED_ADDR, 0x00, 1, &x, 1, 10); HAL_I2C_Mem_Write(&hi2c, OLED_ADDR, 0x00, 1, &y, 1, 10); } void OLED_WriteCmd(uint8_t cmd) { uint8_t buf[2] = {0x00, cmd}; HAL_I2C_Master_Transmit(&hi2c, OLED_ADDR, buf, 2, 10); } void OLED_WriteData(uint8_t data) { uint8_t buf[2] = {0x40, data}; HAL_I2C_Master_Transmit(&hi2c, OLED_ADDR, buf, 2, 10); } void OLED_Clear(void) { uint8_t i, j; for (i = 0; i < 8; i++) { OLED_SetPos(i, 0); for (j = 0; j < 128; j++) { OLED_WriteData(0x00); } } } void OLED_PutChar(uint8_t x, uint8_t y, uint8_t c) { uint8_t i, j, tmp; tmp = c - ' '; for (i = 0; i < 8; i++) { OLED_SetPos(x, y + i); for (j = 0; j < 6; j++) { if ((Font6x8[tmp][j] >> i) & 0x01) { OLED_WriteData(0xff); } else { OLED_WriteData(0x00); } } } } void OLED_PutString(uint8_t x, uint8_t y, uint8_t *str) { while (*str != '\0') { OLED_PutChar(x, y, *str++); x += 6; } } int main(void) { uint8_t buffer[2]; HAL_Init(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_I2C1_CLK_ENABLE(); GPIO_InitTypeDef gpio_init; gpio_init.Pin = GPIO_PIN_6 | GPIO_PIN_7; gpio_init.Mode = GPIO_MODE_AF_OD; gpio_init.Pull = GPIO_PULLUP; gpio_init.Speed = GPIO_SPEED_FREQ_HIGH; gpio_init.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &gpio_init); hi2c.Instance = I2C1; hi2c.Init.Timing = 0x10909CEC; hi2c.Init.OwnAddress1 = 0; hi2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c.Init.OwnAddress2 = 0; hi2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c) != HAL_OK) { Error_Handler(); } OLED_Init(); OLED_Clear(); OLED_PutString(0, 0, "Hello, World!"); while (1) { } } ``` 请注意,此示例假定您的OLED幕使用I2C接口,并且连接到STM32的I2C1端口。您需要根据您的硬件和要求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值