本文主要是介绍和STM32的I2C接口搏击道路1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
- 一直使用STM32进行开发,对项目进行开发的过程中对I2C接口很常用到。平常在使用I2C过程中基本都是使用IO口直接模拟I2C。不过在使用软件I2C过程中可能会面临着达不到400k的速率。因此想趁着使用I2C器件的过程中使用硬件I2C。在调试的过程中,终于明白了大家为什么直接使用软件模拟I2C。因为硬件在使用过程中确实有点麻烦。
- 平常在对STM32的片内外设进行初始化的时候喜欢直接操作寄存器,主要原因是觉得对寄存器操作能够对该资源的运转有个质的把控。在使用库函数或者HAL库的时候总觉得隔着一层面纱不能真正对资源进行把控。因此,在对I2C进行调试的时候,依旧采用了寄存器操作来初始化硬件。
- 通过查看STM32F103RCT6的原理图,看到I2C的功能是复用在PB6,PB7上。因此在初始化的时候需要先对PB6,PB7进行复用初始化。这里要注意一点,I2C的管脚复用时为开漏推挽输出。因为I2C协议支持多个主设备与多个从设备在一条总线上,如果不用开漏输出,而采用推挽输出,会出现主设备之间短路的情况,因此要为开漏输出。而且I2C的片外器件要接上拉电阻。这里采用的I2C器件为MAX30101,如图1所示。该小开发板在板子上已经接了上拉电阻。
- 硬件准备好后就需要进行软件的编写,这时候需要根据操作手册进行时序的编写。首先是关于I2C的初始化。在《STM32中文参考手册》中对I2C在主模式的操作顺序如图2所示。
- 按照说明进行操作时,内想到初始化后一直不成功,进行断点调试发现在初始化后I2C的SR2寄存器的BUSY位一直是1,这说明总线一直被占用。但是这明显是不对的,没有数据“住在”总线的时候,总线竟然呈现着“被占用”的状态。刚开始逐行查找初始化的语句并没有发现错误。代码如下所示:
/*
*Description :I2C初始化,这里配置为100khz的普通模式
*Param :None
*Return Code :None
*/
void I2C_Init(void)
{ RCC->APB2ENR|=1<<3; //PORTB是专用使能RCC->APB1ENR|=1<<21; //I2C1时钟使能GPIOB->CRL|=0X00FFFFFF; //GPIOB6,7复用为开漏输出GPIOB->CRL|=0XFF000000; //GPIOB6,7复用为开漏输出
// GPIOB->CRL|=0XFF000000; //GPIOB6,7复用为开漏输出GPIOB->ODR|=1<<6;GPIOB->ODR|=1<<7;I2C1->CR2|=0X24; //0X02 2MHZ-0X24 36MHZ, 0X14 20MHZ,0X08I2C1->CCR|=0XB4;I2C1->TRISE&=0X0000;I2C1->TRISE|=0X25;I2C1->OAR1|=1<<14; //在这里将该位用软件设置为1I2C1->OAR1|=0X0A; //写入从机地址I2C1->CR1|=1<<10; //使能I2C模式I2C1->CR1|=1<<0; //使能I2C模式
}
- 单步调试如图3所示
- 从代码分析刚开始确实没查找出错误,首先对PB6,PB7的操作来看,最终确实是配置成了开漏复用输出,对I2C的寄存器操作确实是都写进去了,但是SR2的BUSY位还是为1.表示总线处在繁忙的状态。查找无果。
- 既然寄存器一直走不通,何不采用库函数来配置一下。对I2C进行配置。然后查看SR2状态寄存器是否依旧是busy状态。采用库函数的配置程序如下
/*
*Description:MAX30101初始化
*Param :None
*Return Code:None
*/
void max30102_init(void)
{ /*对端口进行初始化*/GPIO_InitTypeDef GPIO_InitStructure;I2C_InitTypeDef I2C_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //打开PORTB口的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); //打开I2C1的端口GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD; //开漏复用输出GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6; //SCLGPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7; //SDAGPIO_Init(GPIOB,&GPIO_InitStructure);/*对I2C进行初始化*/I2C_InitStructure.I2C_Mode=I2C_Mode_I2C; //设置为I2C模式I2C_InitStructure.I2C_OwnAddress1=0X0A; //自己的地址I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_InitStructure.I2C_ClockSpeed = 100000;I2C_Init(I2C1,&I2C_InitStructure);I2C_Cmd(I2C1,ENABLE); //使能I2C1
}
- 使用库函数对I2C配置如图4所示。
- 可以看出采用库函数初始化I2C的SR2状态位不是处于BUSY状态,这说明配置步骤没有问题。问题应该还是出在寄存器配置端口这里。重新返回事故现场进行调试。发现在执行第14行代码的时候。SR2寄存器的BUSY位就会进入置1的状态。结果如图5所示。因为学习的板子一直是参考正点原子的例程,因此习惯了先&后|对GPIO的寄存器进行操作。当然也不是说正点原子的例程有错误,只是在这时候执行第14行代码再执行第15行代码确实将PB6,PB7配置成了开漏输出,但是这个过程是先配置为模拟输入然后再配置成了开漏输出。这样实质是没有对PB6,PB7完成开漏配置。
- 跳过GPIO->CRL&=0X00FFFFFF;这个步骤,直接执行GPIO->CRL|=0XFF000000,在进行调试,发现事故不在发生。结果如图6所示。从结果中可以看出,I2C的SR2寄存器没有处在BUSY状态,对PB6,PB7的配置也是开漏输出。
- 至此,刚走过初始化的部分。初始化中唯一一个坑就是对PB6,PB7的推挽输出复用功能时的寄存器配置。
这篇关于和STM32的I2C接口搏击道路1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!