【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的寄存器是什么

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

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

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

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

需要的头文件

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

学过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_SMBHOSTSMBus主机头(从模式)
I2C_FLAG_SMBDEFAULTSMBus默认报头(从模式)
I2C_FLAG_GENCAL通用调用头标志(从模式)
I2C_FLAG_TRA发射机/接收机的标志
I2C_FLAG_BUSY总线繁忙的标志
I2C_FLAG_MSL主从标志
I2C_FLAG_SMBALERTSMBus警告标志
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_ADD1010位头发送标志(主模式)
I2C_FLAG_BTF字节传输完成标志
I2C_FLAG_ADDR地址发送标志(主模式)
I2C_FLAG_SB开始位标志(主模式)

清除I2Cx的挂起标志。

void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG))
缩写标志
I2C_FLAG_SMBALERTSMBus警告标志
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_SMBALERTSMBus警告标志
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_ADD1010位头发送标志(主模式)
I2C_IT_BTF字节传输完成标志
I2C_IT_ADDR地址发送标志(主模式)“ADSL” 地址匹配标志(从模式)“ENDAD”
I2C_IT_SB开始位标志(主模式)

清除中断标志位

void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT)
标志位含义
I2C_IT_SMBALERTSMBus警报中断
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. 部分文章内容来源于手册和网络,如有侵权请联系我删除。
  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值