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

发布者:beup001最新更新时间:2019-08-10 来源: eefocus关键字: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] != '')

            {

                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] != '')

            {

                c = ch[j] - 32;

                if(x > 120)

                {

                    x = 0;

                    y++;

                }

[1] [2]
关键字:STM32  模拟IIC  驱动OLED屏 引用地址:STM32模拟IIC驱动OLED屏 原理+源码

上一篇:STM32模拟IIC读取PCF8563
下一篇:【STM32】IIC基本原理(实例:普通IO口模拟IIC时序读取24C02)

推荐阅读最新更新时间:2024-11-07 00:27

STM32开发笔记39: Keil打开时提示”Warning #440“警告的解决方法
单片机型号:STM32F070F6P6 首先指明的是此问题是升级keil以后造成的,keil版本升级到V5.26.2.0后,打开原先的程序提示”Warning #440“警告,如下图所示。 此问题的解决方法,在Keil的官方网站中,有详细的描述,网址如下:http://www.keil.com/support/docs/4028.htm。 具体解决的方法,就是打开”Options for Target“对话框,找到”Device“选项页,选择其它芯片类型,然后再选回来,点击”OK“按钮,就解决了。
[单片机]
<font color='red'>STM32</font>开发笔记39: Keil打开时提示”Warning #440“警告的解决方法
STM32中断设置相关寄存器的分析
1.中断设置使能和清除寄存器器的分析 地址 名称 描述 0xE000 E100 SETENA 设置使能中断0到31,写1将位置1,写0无作用 0xE000 E180 CLRENA 写1将位置0,禁能中断,写0无作用 __ASM void SET_CLEAR_IRQ(void) { LDR R0, =0xE000E100 MOVS R1, #0x4 STR R1, LDR R0, =0xE000E180 MOVS R1, #0x4 STR R1,
[单片机]
STM32+0.91寸oled滚动显示bme680测得的数据
#include bme680.h uint8_t bme680_data ={0}; uint8_t aqi_accuracy; int16_t temperature,altitude; uint16_t humidity,aqi; uint32_t pressure,gas; void Bme680_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1Perip
[单片机]
STM32学习笔记(三) STM32的GPIO的深入学习
STM32的开发学习主要涉及软硬件两个部分的实现,包含众多外设和总线的理解配置。STM32的整个学习曲线并不陡峭,但入门却相当困难,因此在学习之初,多动手实验和测试相当重要,GPIO作为整个STM32与外部连接的端口,难度不高,却十分重要。从深入解析GPIO外设开始,一步步熟悉掌握STM32各个模块,就是STM32的整个学习流程。 GPIO模块回顾 在嵌入式软件开发中,几乎所有功能的实现都需要GPIO端口输出才能发挥作用。GPIO端口的操作包括时钟使能,寄存器配置,端口信息修改。这些基础的东西上一章已经讲过,我这里就不在细说,我这里主要讲GPIO涉及到的其它库函数。 1. 读取GPIO端口数据函数 GPIO_ReadInp
[单片机]
<font color='red'>STM32</font>学习笔记(三) <font color='red'>STM32</font>的GPIO的深入学习
STM32定时器中断
STM32中一共有11个定时器,其中2个高级控制定时器,4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。 TIM1和TIM8是能够产生3对PWM互补输出的高级定时器,常用于三相电机的驱动,时钟由APB2的输出产生;TIM2-TIM5是普通定时器,TIM6和TIM7是基本定时器,其时钟由APB1输出产生。 通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。 通用TIMx定时器特性包括: ●16位向上,向下,向上/向下自动装载计数器 ● 16位可编程预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值 ●4个独立通道:(定时器通道是什么意思?在PWM一节中有提到...)
[单片机]
<font color='red'>STM32</font>定时器中断
配置STM32系统时钟经验分享
不知道大家学习STM32时候有没有遇到过这样一种情况,在大神那里拿到了一个工程来学习,然后迫不及待的想烧录到自己板子跑一下看看什么效果,但是当打开工程说明的时候发现大神用的板子是25M的外部晶振,自己的板子是8M的外部晶振,如果直接下载程序的话,那么程序相关的时序就会被破坏,模块之间就没办法正常通信,这时候该怎么办?换外部晶振吗?还是再买一个新板子? 本着有事问度娘的原则,于是各种百度各种找资料,最后发现我的运气确实很差,别人分享的内容都没有我想要的知识,于是本着求人不如求己打破砂锅问到底的精神,找原子、野火相关教程来看,发现在时钟树配置的时候可以配置PLL系数,配置外部晶振分频系数,从而根据外部晶振的频率配置系统时钟。 有思路之
[单片机]
配置<font color='red'>STM32</font>系统时钟经验分享
STM32一键下载电路导致的单片机不能正常运行
使用的正点原子精英版的电路,直接使用那种4线的stlink给单片机供电+下载程序,发现能够正常下载,但死活不运行程序。 一键下载电路如图~ 当时没有使用USB串口功能,所以没有接入5V供电,导致了RTS和DTR引脚悬空,测量电压均为2.69V,即BOOT0被拉高,单片机的启动模式变成了从ISP下载。 插上5V供电一切正常~
[单片机]
<font color='red'>STM32</font>一键下载电路导致的单片机不能正常运行
STM32 PWM问题
本文不提供完整程序,仅点出要点 1:时钟配置。因为PWM输出属于复用功能,所以时钟使能必须使能RCC_APB2Periph_AFIO ; 2:IO口使能。因为PWM属于复用功能,所以IO输出设置要配置成GPIO_Mode_AF_PP;而不能配置成普通输出IO的GPIO_Mode_OUT_PP模式; 3:PWM初始化代码如下,本程序只用通道3输出,所以pwm输出只配置了通道3,TIM_OC3Init(TIM3, &TIM_OCInitStructure);需要多通道输出PWM则需要配置多个PWM输出通道,通过改变TIM_Pulse 的值可以改变pwm的占空比(可以通过直接操作寄存器TIM3- CCR3=2400来实现)。 /* Ti
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved