硬件i2c

STM32的IIC特性及架构
·通讯引脚
·时钟控制逻辑·数据控制逻辑
在这里插入图片描述

在stm32f103中文参考手册120页i2c重映射引脚

在这里插入图片描述

时钟控制逻辑
SCL线的时钟信号,由IIC接口根据时钟控制寄存器(CCR)控制,控制的参数主要位时钟频率。
·可选择IIC通讯的“标准/快速”模式,这两个模式分别对应100/400Kbits/s的通讯速率。
·在快速模式下可选择SCL时钟的占空比,可选T(low)/T(high) = 2或T(low)/T(high)=16/9模式。
·CCR寄存器中12位的配置因子CCR,它与IIC外设的输入时钟源共用作用,产生SCL时钟。STM32的IIC外设输入时钟源位PCKL1
TPCLK1为36M
在这里插入图片描述
在这里插入图片描述

(1).

计算时钟频率
标准模式  T high = CCR *T pckl1  T low= CCR*Tpclk1
快速模式中 Tlow/Tlow =2时:Thigh = CCR*Tpckl1    T low = 2*low*Tpckl1  
快速模式中 Tlow/Tlow =16/9时:Thigh = 9*CCR*Tpckl1    T low = 16*low*Tpckl1
PCLK1 = 36MHz,想要配置400Kbits/s 方法:
PCLK时钟周期: TPCLK1 = 1/36 000 000
目标SCL时钟周期:  TSCL = 1/400 000
SCL时钟周期内的高电平时间: Thigh = TSCL/3
SCL时钟周期内的低电平时间: Tlow  = 2*TSCL/3
计算CCR的值 :   CCR = THIGH/TPCLK1 = 30
计算出来的值写入到寄存器即可。             

3.数据控制逻辑
IIC的SDA信号主要连接到数据移位寄存器上,数据移位寄存器的数据来源及目标是数据寄存器(DR)、地址寄存器(OAR)、PEC寄存器以及SDA数据线。
·当向外发送数据的时候,数据移位寄存器以“数据寄存器”为数据源,把数据一位一位地通过SDA信号线发送出去。
·当从外部接收数据的时候,数据移位寄存器把SDA信号线采样到的数据一位一位地存储到”数据寄存器”中。
那么从低位还是高位发送,由SMBA控制。

STM32的IIC的通讯过程
1.主发送器
在这里插入图片描述
·控制产生起始信号(S),当发生起始信号后,它产生事件”EV5”,并会对SR1寄存器的 SB 位置1,表示起始信号已经发生。
·发生设备地址并等待应答信号,若有从机应答,则产生时间 EV6 及 EV8 ,这时SR1寄存器的 ADDR位及 TXE位被置1,ADDR位1 表示地址已经发送,TEX表示数据寄存器为空。

·往IIC的数据寄存器DR写入要发送的数据,这时TXE位会被充值0,表示数据寄存器非空,IIC外设通过SDA信号线一位位把数据发送出去后,又会产生EV8事件,即TXE被置1,重复这个过程,可发送多个字节。
·发送数据完成后,控制IIC设备产生一个停止信号P,这个时候产生EV2事件,SR1的TEX位及BTF位被置1,表示通讯结束。

i2c固件库结构体

typedef struct
{
  uint32_t I2C_ClockSpeed;     //设置SCL时钟频率,此值要低于400 000                                              
  uint16_t I2C_Mode;             //指定工作模式,可选IIC模式及SMBUS模式
  uint16_t I2C_DutyCycle;       //时钟占空比,可选low/high = 2:0或16:9
  uint16_t I2C_OwnAddress1;  //自身的IIC设备地址   
  uint16_t I2C_Ack;                //使能或者关闭响应,一般是使能
  uint16_t I2C_AcknowledgedAddress; //指定地址长度,可为7或10
}I2C_InitTypeDef;

·void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint8_t Address);                      //配置自身设备地址2

·void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);  //发送设备地址

·uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);//接收数据

·void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState); //停止接收

·void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState); //IIC外设开始正常工作

配置I2C
配置GPIO去外设找相应的结构体
在这里插入图片描述

在STM32中选用IO模式
(1)GPIO_Mode_AIN 模拟输入---应用ADC模拟输入,或者低功耗下省电
(2)GPIO_Mode_IN_FLOATING 浮空输入---可以做KEY识别
(3)GPIO_Mode_IPD 下拉输入--- IO内部下拉电阻输入
(4)GPIO_Mode_IPU 上拉输入---IO内部上拉电阻输入
(5)GPIO_Mode_Out_OD 开漏输出---IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能。
(6)GPIO_Mode_Out_PP 推挽输出---IO输出0-接GND,IO输出1 -接VCC,读输入值是未知的。
(7)GPIO_Mode_AF_OD 复用开漏输出---片内外设功能(TX1,MOSI,MISO.SCK.SS)。
(8)GPIO_Mode_AF_PP 复用推挽输出---片内外设功能(I2C的SCL,SDA)
void I2C_Configuration(void)
{
	
	GPIO_InitTypeDef GPIO_initStructure;  /* gpio结构体变量声明 */
	I2C_InitTypeDef I2C_InitStructure;     /* l2c结构体变量声明 */
	
	
RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE);  /* APB2总线使能gpio */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);	/* APB1总线使能i2c外设 */

/ *配置gpio结构体 */
GPIO_initStructure.GPIO_Mode= GPIO_Mode_AF_PP;  /* 复用推挽输出 */
GPIO_initStructure.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7;  /*Pin_6-scL,Pin_7-SDA
GPIO_initStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_initStructure);  /* 初始化结构体 */
	
/* 配置硬件结构体 */
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Ack=I2C_Ack_Enable ;  /*应答使能*/
I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; /*数据7位*/
I2C_InitStructure.I2C_ClockSpeed=400000;
I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2  ;/* 2分频*/
I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1=0x30;/* 主机地址随便写*/
I2C_Init(I2C1,&I2C_InitStructure);/* 初始化i2c */
I2C_Cmd(I2C1,ENABLE);
}

在这里插入图片描述

配置完后,封装函数i2c怎么写一个字节
void I2C_WriteByte(uint8_t addr, uint8_t data)  
{
	while( I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) /* 发送之前检查总线是否繁忙 */		I2C_GenerateSTART(I2C1,ENABLE) ;  /* 开启i2c1  */
while( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT ))/* 检查是否有应答标志EV5 */
		
	I2C_Send7bitAddress(I2C1,OLED_address ,I2C_Direction_Transmitter);/* 发送器件地址数据,OLED_address在.h文件中宏定义
*/
    while(  !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED  ))
	/* 	检查是否有应答标志EV6 */
	I2C_SendData(I2C1,addr); /* 发送寄存器地址数据 */
	while(  !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING ))	 检查是否有应答标志EV8 */
I2C_SendData(I2C1,data);/* 发送数据 */
    while(  !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING ))
	
	I2C_GenerateSTOP(I2C1, ENABLE);/* 关闭i2c总线*/

}

//写命令
void WriteCmd(unsigned char I2C_Command)
{
	
	I2C_WriteData(0x00, I2C_Command);

}

//写数据
void WriteDat(unsigned char I2C_data)
{
	I2C_WriteData(0x00, I2C_data);
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴凯你在想啥呢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值