参考中文参考手册
思路:
1)要先打开AHB的APB2使能时钟
2)端口配置CNFO[1:0]和MODE0[1:0]模式,如推挽模式和输出速度,控制GPIOx_IDR寄存器
3)端口输出模式,如拉低电平,控制GPIOx_ODR寄存器
方法:
以GPIOD为例
通过存储映像找到AHB的0x4002 1000,再对应找到APB2ENR时钟的偏移地址: 0x18,即0x40021018
通过GPIOx_CRL寄存器,先找到存储映像GPIOD的0x4001 1400 ,选择低位GPIOx_CRL寄存器的偏移地址: 0x00,即0x40011400

控制GPIOx_ODR 寄存器,先先找到存储映像GPIOD的0x4001 1400,选择GPIOx_ODR 寄存器的地址偏移: 0C,即0x4001140C

总结:
1)置位 |=, 清0 &=~
2) *( unsigned int * )指编译器要把它看做地址,强制的数据类型转换,加*表示指针,括号外加*识别指针操作
3)( (1) << 5 )指1左移5位, &= ~( (0x0f) << (4*2) )指CNFO[1:0]和MODE0[1:0]左移4*2=8位,先变为1,后面取为0,即都置0
int main (void)
{
//PD2亮
// 打开 GPIOD 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 5 ); //打开RCC的APB2
// 配置IO口为输出 低寄存器控制着低八位 16个IO ,CNFO[1:0]和MODE0[1:0]控制着一个IO口
*( unsigned int * )0x40011400 &= ~( (0x0f) << (4*2) ); // CNFO[1:0]和MODE0[1:0]都置0,
*( unsigned int * )0x40011400 |= ( (3) << (4*2) ); //推挽输出模式CNFO[1:0]=00,MODE0[1:0]=01 ,0001代表2的次方,即第0位,以4个为一组
// 控制 ODR 寄存器 1左移0位 ,是到GPIOD的位置
*( unsigned int * )0x4001140C &= ~(1<<2); //端口数据ODR,PD2由ODR2控制,这个位写0
//输出低电平
//GPIOA 时钟 PA8亮
*( unsigned int * )0x40021018 |= ( (1) << 2 );
// 配置IO口为输出 高寄存器控制着高八位
*( unsigned int * )0x40010804 &= ~( (0x0f) << (4*0) ); // 置0
*( unsigned int * )0x40010804 |= ( (1) << (4*0) );
// 控制 ODR 寄存器 GPIOA.8
*( unsigned int * )0x4001080C &= ~(1<<8); //低电平
}
QQ截图20181206185027.png (40.85 KB, *载下**次数: 2)

//IO方向设置
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;} 输入
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;} 输出
//IO操作函数
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
#define READ_SDA PBin(7) //输入SDA
GPIOB->CRL&=0X0FFFFFFF;这句这样写的目的是将28-31的引脚清零,好进行操作赋值
GPIOB->CRL|=(u32)8<<28指将原来的位置CNF0[1:0]和MODE0[1:0]通过左移28位到CNF7[1:0]和MODE7[1:0],8二进制1000代表CNF0[1:0]=10,MODE0[1:0]=00,即输入模式的上拉方式
GPIOB->CRL|=(u32)3<<28指3的二进制0011代表CNF0[1:0]=00,MODE0[1:0]=11对应位29:28的输出模式,最大速度50MHz