在沁恒家32位机(CH56x,CH57X,CH58X)中,我们发现GPIO似乎并没有一个单独的输出模式叫开漏(OD,open-drian)
在CH57x,CH58x只有下面几种模式:
/**
* @brief Configuration GPIO Mode
*/
typedef enum{
GPIO_ModeIN_Floating, //浮空输入
GPIO_ModeIN_PU, //上拉输入
GPIO_ModeIN_PD, //下拉输入
GPIO_ModeOut_PP_5mA, //推挽输出最大5mA
GPIO_ModeOut_PP_20mA, //推挽输出最大20mA
}GPIOModeTypeDef;
那么怎么实现开漏呢?
开漏的特性:
- 输出高的时候: 悬空/ 弱上拉
- 输出低的时候: 强吸入电流
沁恒的的GPIO模式配置函数:
这里我们只拿GPIOA来做说明
/*******************************************************************************
* Function Name : GPIOA_ModeCfg
* Description : GPIOA端口引脚模式配置
* Input : pin:
PA0-PA15
GPIO_Pin_0 - GPIO_Pin_15
mode:
GPIO_ModeIN_Floating - 浮空输入
GPIO_ModeIN_PU - 上拉输入
GPIO_ModeIN_PD - 下拉输入
GPIO_ModeOut_PP_5mA - 推挽输出最大5mA
GPIO_ModeOut_PP_20mA - 推挽输出最大20mA
* Return : None
*******************************************************************************/
void GPIOA_ModeCfg( uint32_t pin, GPIOModeTypeDef mode ) {
switch(mode){
case GPIO_ModeIN_Floating:
R32_PA_PD_DRV &= ~pin;
R32_PA_PU &= ~pin;
R32_PA_DIR &= ~pin;
break;
case GPIO_ModeIN_PU:
R32_PA_PD_DRV &= ~pin;
R32_PA_PU |= pin;
R32_PA_DIR &= ~pin;
break;
case GPIO_ModeIN_PD:
R32_PA_PD_DRV |= pin;
R32_PA_PU &= ~pin;
R32_PA_DIR &= ~pin;
break;
case GPIO_ModeOut_PP_5mA:
R32_PA_PD_DRV &= ~pin;
R32_PA_DIR |= pin;
break;
case GPIO_ModeOut_PP_20mA:
R32_PA_PD_DRV |= pin;
R32_PA_DIR |= pin;
break;
default:
break;
}
}
所以,我们只需要按照下面的方式即可实现,开漏
下面使用PB5/PB4 模拟iic 的初始化代码
初始化:
把要设置为开漏输出的IO, 初始化为输入模式,然后输出设置为低电平就行了,
#define IIC_CKL_PIN GPIO_Pin_5
#define IIC_SDA_PIN GPIO_Pin_4
#define ch57x_i2c_clk_init() { GPIOB_ModeCfg(IIC_CKL_PIN,GPIO_ModeIN_PU );\
GPIOB_ResetBits(IIC_CKL_PIN);}
#define ch57x_i2c_sda_init() { GPIOB_ModeCfg(IIC_SDA_PIN,GPIO_ModeIN_PU );\
GPIOB_ResetBits(IIC_SDA_PIN);}
使用:
通过设置IO的方向寄存器,来实现开漏的高低电平控制
#define GPIOB_PinOutput(pin) (R32_PB_DIR |= pin)
#define GPIOB_PinInput(pin) (R32_PB_DIR &= ~pin)
#define ch57x_i2c_clk_set() { GPIOB_PinInput(IIC_CKL_PIN); }
#define ch57x_i2c_clk_clr() { GPIOB_PinOutput(IIC_CKL_PIN); }
#define ch57x_i2c_clk_get() ( GPIOB_ReadPortPin(IIC_CKL_PIN) )
#define ch57x_i2c_sda_set() { GPIOB_PinInput(IIC_SDA_PIN); }
#define ch57x_i2c_sda_clr() { GPIOB_PinOutput(IIC_SDA_PIN); }
#define ch57x_i2c_sda_get() ( GPIOB_ReadPortPin(IIC_SDA_PIN))
注意事项:
- 除了耐受5v输入的IO外,其他IO处于输入模式时,不能高于芯片的供电电压,所以如果对接5v系统的iic,尽量用耐受5v输入的IO.
- CH57x,CH58x 系列芯片的内部上拉/下拉是50K,如果速度比较快,通常是需要挂外部上拉的.
扩展
- 使用原子指令操作GPIO:https://www.cnblogs.com/iot-fan/p/17254827.html