【STM32】 硬件IIC 驱动SSD1306(0.96 OLED模块) — 1/4 库函数 学习

为什么写本章节

经过了对于STM32的学习,但是大多数时候都还是以移植别人的历程然后修修改改为主。为了更好的巩固自己的学习能力。

所以此篇文章将会以记录我个人学习硬件IIC为案例,学习驱动IIC总线设备的能力。

首先第一步(准备)

1.《STM32F10x-中文参考手册》
2.《SSD1306芯片手册》

了解 硬件IIC 的工作原理

《STM32F10x-中文参考手册》—书签第24章
IIC的基本参数本章节暂时不做过多的描述,参考手册的24.1-24.3都有详细的讲解。
其中我们需要了解的是

  1.  ●I2C主设备功能
     ─ 产生时钟
     ─ 产生起始和停止信号
    
  2.  ●I2C从设备功能
     ─ 可编程的I2C地址检测
     ─ 可响应2个从地址的双地址能力
     ─ 停止位检测
    
  3.  ●支持不同的通讯速度
     ─ 标准速度(高达100 kHz)
     ─ 快速(高达400 kHz)
    
  4.  ●2个中断向量
     ─ 1个中断用于地址/数据通讯成功
     ─ 1个中断用于错误
    

IIC通讯的基本框图

IIC的功能框图
IIC默认是工作在从模式的。从从模式切换到主模式,需要产生一个其实条件,为了产生正确的时序必须在I2C_CR2寄存器中设定该模块的输入时钟

  • 标准模式下为:2MHz
  • 快速模式下为:4MHz
  • 一旦检测到起始条件,在SDA线上接收到的地址被送到移位寄存器

    讲了这么多,那么STM32的标准库函数需要怎样写呢?

    首先就是认识硬件IIC在STM32的寄存器是什么

    寄存器 名称 寄存器的缩写
    控制寄存器1 I2C_CR1
    控制寄存器2 I2C_CE2
    自身地址寄存器1 I2C_OAR1
    自身地址寄存器2 I2C_OAR2
    数据寄存器 I2C_DR
    状态寄存器1 I2C_SR1
    状态寄存器2 I2C_SR2
    时钟控制寄存器 I2C_CCR
    TRISE寄存器 I2C_TRISE


    小贴士:就是寄存器的保留地址是不需要我们去理会的,每个寄存器的位,就相当于一个功能开关,我们需要什么功能。通过位操作打开/关闭就可以了

    接下来就是在KEIL软件上的操作了

    因为文章篇幅问题,创建工程、创建文件夹就忽略啦!需要的可以网络搜索教程/移植一个空白工程就可以了。

    需要的头文件

    头文件 名称
    stm32f10x.h 标准库函数
    stm32f10x_i2c.h 标准库函数
    delay.h SysTick定时器编写的延时函数

    学过STM32库函数工程,我们肯定是需要向初始化GPIO、时钟总线什么的。那我们此时应该先创建一个初始化的函数

    Void I2C_Configuration(void)
    {
    		//创建GPIO,I2C1的结构体
    		GPIO_InitTypeDef GPIO_InitStructure;				
    		I2C_InitTypeDef I2C_InitStructure;				
    		
    		//使能挂载时钟总线
    		RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    		
    		//PB6——SCL PB7——SDA
    		//配置GPIO的引脚模式、引脚脚位、引脚速度
    		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_OD;
    		GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;
    		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    		//初始化GPIO的结构体
    		GPIO_Init(GPIOB, &GPIO_InitStructure);
    		
    		//初始化I2C1的寄存器默认数值
    		I2C_DeInit(I2C1);
    		//使能 I2C_Ack
    		//指定地址位数为7bit/10bit
    		//I2C的时钟速度
    		//I2C的时钟占空比,一般为1/2 或者 9/16
    		//IIC的模式
    		//IIC设备自身地址,用于当从机的时候的访问地址
    		I2C_InitStructure.I2C_Ack                 = I2C_Ack_Enable;
    		I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    		I2C_InitStructure.I2C_ClockSpeed          = 400000;
    		I2C_InitStructure.I2C_DutyCycle           = I2C_DutyCycle_2;
    		I2C_InitStructure.I2C_Mode                = I2C_Mode_I2C;
    		I2C_InitStructure.I2C_OwnAddress1         = 0x30;
    		
    		//初始化I2C1结构体
    		I2C_Init(I2C1, &I2C_InitStructure);
    		//使能I2C1
    		I2C_Cmd(I2C1, ENABLE);
    }
    

    至此,I2C1的初始化函数就写好了。那么我们要怎样通过IIC来和写数据呢?
    因为OLED主要为显示输出,所以本章节以写入数据为案例;

    在写IIC写函数的时候,我们需要先了解 stm32f10x_i2c.h的库函数里面有什么函数!

    stm32f10x_i2c.h 函数表

    函数名称 函数作用
    void I2C_DeInit(I2C_TypeDef* I2Cx); 初始化I2C寄存器的默认值
    void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct); 初始化I2C的GPIO结构体
    void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct) 用默认值填充I2Cx的结构体
    void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用/禁用I2Cx
    void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用/禁用I2Cx的DMA通道
    void I2C_DMALastTransferCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 指定下一个DMA传输是否为最后一个
    void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState); 生成I2Cx通讯开始条件
    void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState); 生成I2Cx通讯停止条件
    void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState); 开启/关闭I2C的应答特性
    void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint8_t Address); 配置I2C的自身地址2
    void I2C_DualAddressCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用/禁止I2Cx双寻址模式
    void I2C_GeneralCallCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用/禁止I2Cx通用呼叫模式
    void I2C_ITConfig(I2C_TypeDef* I2Cx, uint16_t I2C_IT, FunctionalState NewState); 启用/禁止指定I2C中断
    void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data); 通过I2Cx外设发送1字节的数据
    uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx); 返回I2Cx外设最近接收到的数据
    void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction); 传输地址字节以选择从设备
    uint16_t I2C_ReadRegister(I2C_TypeDef* I2Cx, uint8_t I2C_Register); 读取指定的I2C寄存器并返回它的值
    void I2C_SoftwareResetCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 指定I2C软件复位开关
    void I2C_NACKPositionConfig(I2C_TypeDef* I2Cx, uint16_t I2C_NACKPosition); 选择主接收模式下指定的I2C NACK位置。*此功能在I2C主接收模式下有用
    void I2C_SMBusAlertConfig(I2C_TypeDef* I2Cx, uint16_t I2C_SMBusAlert); 驱动SMBusAlert引脚为指定的I2C高或低
    void I2C_TransmitPEC(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用或禁用指定的I2C PEC传输
    void I2C_PECPositionConfig(I2C_TypeDef* I2Cx, uint16_t I2C_PECPosition); 选择指定的I2C PEC位置
    void I2C_CalculatePEC(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用或禁用传输字节的PEC值计算
    uint8_t I2C_GetPEC(I2C_TypeDef* I2Cx); 返回指定I2C的PEC值
    void I2C_ARPCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用/禁用指定I2C ARP
    void I2C_StretchClockCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); 启用或禁用指定的I2C时钟拉伸功能
    void I2C_FastModeDutyCycleConfig(I2C_TypeDef* I2Cx, uint16_t I2C_DutyCycle); 选择指定的I2C快模式占空比

    当然,这些函数并不是需要全部应用在硬件IIC写函数上的,更重要的是

    I2C State Monitoring Functions
    只有知道I2C的状态,我们才能掌握I2C的运行的状态。
    库函数的状态访问函数主要为三种,主要为

    1.  基本状态监视 Basic state monitoring
       ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);					//	检查事件标志位
      
    事件缩写 事件名称
    I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED 从机发射地址匹配
    I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED 从机接收地址匹配
    I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED 从机发射第二地址匹配
    I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED 从机接收第二地址匹配
    I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED 从机通用呼叫匹配
    I2C_EVENT_SLAVE_BYTE_RECEIVED 从机字节数据接收
    I2C_EVENT_SLAVE_BYTE_RECEIVE 、I2C_FLAG_DUALF 从机字节数据接收 DUAL
    I2C_EVENT_SLAVE_BYTE_RECEIVED 、I2C_FLAG_GENCALL 从机字节数据接收通用传呼标志位
    I2C_EVENT_SLAVE_BYTE_TRANSMITTED 从机发送字节
    I2C_EVENT_SLAVE_BYTE_TRANSMITTED 、 I2C_FLAG_DUALF 从机发送字节 DUAL
    I2C_EVENT_SLAVE_BYTE_TRANSMITTED 、I2C_FLAG_GENCALL 从机字节发送 通用传呼
    I2C_EVENT_SLAVE_ACK_FAILURE 从机应答失败
    I2C_EVENT_SLAVE_STOP_DETECTED 从机停止信号检测
    I2C_EVENT_MASTER_MODE_SELECT 主机模式选择
    I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED 主机发送模式选择
    I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED 主机接收模式选择
    I2C_EVENT_MASTER_BYTE_RECEIVED 主机字节接收
    I2C_EVENT_MASTER_BYTE_TRANSMITTING 主机字节数据发送时
    I2C_EVENT_MASTER_BYTE_TRANSMITTED 主机字节数据发送以后
    I2C_EVENT_MASTER_MODE_ADDRESS10 主机模式地址
    1.  高级状态监视 Advanced state monitoring
       uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx); 								 //获取IIC总线的上一个事件
      
    2.   标志位状态监视 Flag-based state monitoring
       FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);		//获取状态标志位
      

    检查指定的I2C标志位是否设置。

    FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG)
    
    标志位 含义
    I2C_FLAG_DUALF 双标志(从模式)
    I2C_FLAG_SMBHOST SMBus主机头(从模式)
    I2C_FLAG_SMBDEFAULT SMBus默认报头(从模式)
    I2C_FLAG_GENCAL 通用调用头标志(从模式)
    I2C_FLAG_TRA 发射机/接收机的标志
    I2C_FLAG_BUSY 总线繁忙的标志
    I2C_FLAG_MSL 主从标志
    I2C_FLAG_SMBALERT SMBus警告标志
    I2C_FLAG_TIMEOUT 超时或Tlow错误标志
    I2C_FLAG_PECERR 接收标志中的PEC错误
    I2C_FLAG_OVR 过载/不足标志(从模式)
    I2C_FLAG_AF 应答错误警告
    I2C_FLAG_ARLO 仲裁丢失标志(主模式)
    I2C_FLAG_BERR 总线错误标志
    I2C_FLAG_TXE 数据寄存器空标志(发射机)
    I2C_FLAG_RXNE 数据寄存器不为空(接收器)标志
    I2C_FLAG_STOPF 停止检测标志(从模式)
    I2C_FLAG_ADD10 10位头发送标志(主模式)
    I2C_FLAG_BTF 字节传输完成标志
    I2C_FLAG_ADDR 地址发送标志(主模式)
    I2C_FLAG_SB 开始位标志(主模式)

    清除I2Cx的挂起标志。

    void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG))
    
    缩写 标志
    I2C_FLAG_SMBALERT SMBus警告标志
    I2C_FLAG_TIMEOUT 超时或Tlow错误标志
    I2C_FLAG_PECERR 接收标志中的PEC错误
    I2C_FLAG_OVR 过载/不足标志(从模式)
    I2C_FLAG_AF 应答失败标志
    I2C_FLAG_ARLO 仲裁丢失标志(主模式)
    I2C_FLAG_BERR 总线错误标志

    获取中断源

    ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT)
    
    中断源 含义
    I2C_IT_SMBALERT SMBus警告标志
    I2C_IT_TIMEOUT 超时或Tlow错误标志
    I2C_IT_PECERR 接收标志中的PEC错误
    I2C_IT_OVR 过载/不足标志(从模式)
    I2C_IT_AF 应答失败的标志
    I2C_IT_ARLO 仲裁丢失标志(主模式)
    I2C_IT_BERR 总线错误标志
    I2C_IT_TXE 数据寄存器空标志(发射机)
    I2C_IT_RXNE 数据寄存器不为空(接收器)标志
    I2C_IT_STOPF 停止检测标志(从模式)
    I2C_IT_ADD10 10位头发送标志(主模式)
    I2C_IT_BTF 字节传输完成标志
    I2C_IT_ADDR 地址发送标志(主模式)“ADSL” 地址匹配标志(从模式)“ENDAD”
    I2C_IT_SB 开始位标志(主模式)

    清除中断标志位

    void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT)
    
    标志位 含义
    I2C_IT_SMBALERT SMBus警报中断
    I2C_IT_TIMEOUT 超时或Tlow错误中断
    I2C_IT_PECERR 接收中断中的PEC错误
    I2C_IT_OVR 溢出/不足运行中断(从模式)
    I2C_IT_AF 应答失败中断
    I2C_IT_ARLO 仲裁丢失中断(主模式)
    I2C_IT_BERR 总线错误中断
    IIC发送数据8步曲
    
    1.判断IIC总线是否忙
    	👇
    2.产生IIC的开始信号
    	👇
    3.判断主机\从机模式
    	👇
    4.发送地址
    	👇
    5.判断地址数据是否传输完成
    	👇
    6.发送数据
    	👇
    7.判断发送数据是否完成
    	👇
    8.发送停止信号
    
    void I2C_WriteByte(uint8_t addr,uint8_t data)
    {
    	//检测IIC的总线忙,如果忙则阻止程序运行
    	while( I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) );
    	//产生IIC启动信号
        I2C_GenerateSTART(I2C1, ENABLE);
    	//检查主机模式是否选择完成
    	while( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) );
    	//发送8位数据, 向I2C1发送oled地址,主从模式
        I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);	
    	 //检查主机发送字节是否结束
    	while( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) );
    	//发送addr 寄存器的地址
    	I2C_SendData(I2C1, addr);													
    	//检查主机字节发送是否结束
    	while( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING) );		
    	//通过IICx发送数据	
    	I2C_SendData(I2C1, data);													
    	//检查字节发送是否结束
    	while( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) );
    	//停止信号结束		
    	I2C_GenerateSTOP(I2C1, ENABLE);												
    }
    

    备注

    1. 本文章是学习记录,如有不足之处或者错误之处欢迎各位指正批评😀;
    2. 部分文章内容来源于手册和网络,如有侵权请联系我删除。
    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32】 硬件IIC 驱动SSD1306(0.96 OLED模块) — 1/4 库函数 学习

    发表评论