1.stm32f103上电后默认GPIO的每个IO是浮空输入模式(GPIO_Mode_IN_FLOATING)。
以常用的模拟I2C接口为例,原理图如下:
模拟I2C的接口通常需外接上拉电阻,图中R21,R23。
2.以下结合代码讲述
#define I2C_SCLSetHigh GPIO_SetBits(GPIOB, GPIO_Pin_8)
#define I2C_SCLSetLow GPIO_ResetBits(GPIOB, GPIO_Pin_8)
#define I2C_SDASetHigh GPIO_SetBits(GPIOB, GPIO_Pin_9)
#define I2C_SDASetLow GPIO_ResetBits(GPIOB, GPIO_Pin_9)
void I2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//////在进行下面的操作之前一定要打开RCC的时钟,否则下面的操作无效。
//////注意此时,I2C_SDA和I2C_SCL均为浮空输入(GPIO_Mode_IN_FLOATING),由于外接上拉电阻。
//////故此时I2C_SDA和I2C_SCL均为高电平。
I2C_SDASetLow;
I2C_SCLSetLow;
//////执行完上两步之后,虽然改变了GPIOB_ODR(端口数据输出寄存器)中的值,但此时I2C_SDA和I2C_SCL的模式仍为浮空输入(GPIO_Mode_IN_FLOATING),故此时I2C_SDA和I2C_SCL还是高电平。
GPIO_InitTypeDef GPIO_InitStructure;
//PB8为I2C_SCL,PB9为I2C_SDA
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//////执行完以上5步之后,I2C_SDA和I2C_SCL模式遍为开漏输出(GPIO_Mode_Out_OD),此时GPIOB_ODR(端口数据输出寄存器)和IO模式的结合,使得I2C_SDA和I2C_SCL输出为低电平。
}
//////下面是改变I2C_SDA和I2C_SCL的输入输出模式的函数,在浮空输入(GPIO_Mode_IN_FLOATING)和开漏输出
//////(GPIO_Mode_Out_OD)之间改变。
void I2C_SCLModeOut(void)
{
/*定义I2C_SCL的方向为输出*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;//开漏输出
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void I2C_SCLModeIn(void)
{
/*定义I2C_SCL的方向为输入*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//PCB有上拉
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void I2C_SDAModeOut(void)
{
/*定义I2C_SDA的方向为输出*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;//开漏输出
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void I2C_SDAModeIn(void)
{
/*定义I2C_SDA的方向为输入*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//PCB有上拉
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
////////改变I2C_SDA和I2C_SCL的输入和输出模式,来进行调试观察。
I2C_SDAModeOut();
I2C_SCLModeOut();
//执行完上两步之后,此时I2C_SDA和I2C_SCL输出的电平取决于GPIOB_ODR(端口数据输出寄存器)中的值。
I2C_SDASetHigh;//拉高数据线,
I2C_SCLSetHigh;
//执行完上两步后,I2C_SDA和I2C_SCL输出高电平。
I2C_SDAModeIn();
I2C_SCLModeIn();
//执行完上两步后,I2C_SDA和I2C_SCL是高电平,但是此时I2C_SDA和I2C_SCL口的电平是只由其外部电路决定
//,与GPIOB_ODR(端口数据输出寄存器)无关。
I2C_SDAModeOut();
I2C_SCLModeOut();
I2C_SDASetLow;//拉低数据线
I2C_SCLSetLow;//拉低时钟线
//执行完以上四步后,I2C_SDA和I2C_SCL输出低电平。
I2C_SDAModeIn();
I2C_SCLModeIn();
//执行完以上两步后,I2C_SDA和I2C_SCL还是高电平,因为I2C_SDA和I2C_SCL口的电平是只由其外部电路决定
//,与GPIOB_ODR(端口数据输出寄存器)无关。
3.总结,当I2C_SDA和I2C_SCL为浮空输入(GPIO_Mode_IN_FLOATING)时,其引脚电平只由其外部电路决定。
当I2C_SDA和I2C_SCL为开漏输出(GPIO_Mode_Out_OD)时,其引脚输出电平由GPIOB_ODR(端口数据输出寄存器)
中的值决定。(有时候用示波器观察波形会出现一个极短低脉冲或者高脉冲,就是因为把先IO口由输入切换为输出模式,然后再改变端口输出寄存器的值的原因。比如原来端口寄存器的值为0,这时想要改变IO为开漏输出并且置高。先改变输入为开漏输出模式,此时IO口的电平为从原来的外部上拉,被强制拉低,产生一个下降沿。这时候再往端口输出寄存器写1,就会出现IO口电平又被强制拉高,产生一个上升沿。从波形上看就是一个极短的低脉冲。在实际代码中,应根据情况考虑改变IO口的输入输出模式和写端口输出寄存器的顺序,避免产生极短的低脉冲或者高脉冲。)
4.至于在其他模式之间的切换,可继续尝试。
|