为什么写本章节
经过了对于STM32的学习,但是大多数时候都还是以移植别人的历程然后修修改改为主。为了更好的巩固自己的学习能力。
所以此篇文章将会以记录我个人学习硬件IIC为案例,学习驱动IIC总线设备的能力。
首先第一步(准备)
1.《STM32F10x-中文参考手册》
2.《SSD1306芯片手册》
了解 硬件IIC 的工作原理
《STM32F10x-中文参考手册》—书签第24章
IIC的基本参数本章节暂时不做过多的描述,参考手册的24.1-24.3都有详细的讲解。
其中我们需要了解的是
-
●I2C主设备功能 ─ 产生时钟 ─ 产生起始和停止信号
-
●I2C从设备功能 ─ 可编程的I2C地址检测 ─ 可响应2个从地址的双地址能力 ─ 停止位检测
-
●支持不同的通讯速度 ─ 标准速度(高达100 kHz) ─ 快速(高达400 kHz)
-
●2个中断向量 ─ 1个中断用于地址/数据通讯成功 ─ 1个中断用于错误
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的运行的状态。
库函数的状态访问函数主要为三种,主要为文章来源:https://www.toymoban.com/news/detail-427366.html
-
基本状态监视 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 | 主机模式地址 |
-
高级状态监视 Advanced state monitoring uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx); //获取IIC总线的上一个事件
-
标志位状态监视 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);
}
备注:文章来源地址https://www.toymoban.com/news/detail-427366.html
- 本文章是学习记录,如有不足之处或者错误之处欢迎各位指正批评😀;
- 部分文章内容来源于手册和网络,如有侵权请联系我删除。
到了这里,关于【STM32】 硬件IIC 驱动SSD1306(0.96 OLED模块) -- 1/4 库函数 学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!