最近在学习STM32F7的片上I2C硬件,看到原子哥的OLED模块可以用I2C来驱动,于是就试了下。现在将试验结果与大家分享,目前还没有毕业经历过的项目比较少,只是为了抛砖引玉,有什么不合理的地方,请大家批评指正,谢谢啦!
首先,将模块后面的BS2改为接地,选择I2C模式。
然后,将模块上的DC引脚与地接到一起,也就是I2C的从地址为0111 100最低位为0,还少一位为读写方向位。再将模块上的D1与D2接到一起,即SDAin与SDAout接到一起为一个完整的SDA信号线。
其次,将模块上的RES引脚通过10K电阻接到电源上、通过104电容接到地上,以产生硬件延时省掉一个GPIO引脚。
最后,程序修改如下:
在oled.c文件中编写I2C初始化函数为:
void I2C3_Init()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN; //使能GPIOH时钟
RCC->APB1ENR |= RCC_APB1ENR_I2C3EN; //使能I2C3时钟
GPIOH->MODER |= GPIO_MODER_MODER7_1
| GPIO_MODER_MODER8_1; //PH7/PH8复用功能模式
GPIOH->OTYPER |= GPIO_OTYPER_OT_7
| GPIO_OTYPER_OT_8; //PH7/PH8开漏输出
GPIOH->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7_1
| GPIO_OSPEEDER_OSPEEDR8_1; //PH7/PH8快速50Hz
GPIOH->PUPDR |= GPIO_PUPDR_PUPDR7_0
| GPIO_PUPDR_PUPDR8_0; //PH7/PH8上拉
GPIOH->AFR[0] |= GPIO_AFRL_AFRL7_2; //PH7复用4
GPIOH->AFR[1] |= GPIO_AFRH_AFRH0_2; //PH8复用4
I2C3->TIMINGR = 0x60201E2B; //I2C时序标准模式100KHz由ST计算工具获得
I2C3->CR1 |= I2C_CR1_PE; //I2C3外设使能
I2C3->CR2 = 0x78 //设置从设备地址为0111 100
| I2C_CR2_AUTOEND; //自动结束
}
将写字节函数修改为:
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 temp;
I2C3->CR2 |= (2U<<16); //只传送两个字节数据
//| I2C_CR2_START; //生成起始位
if(cmd == OLED_CMD)
temp = 0x80;
else
temp = 0xC0;
I2C3->CR2 |= I2C_CR2_START;
while((I2C3->ISR & I2C_ISR_TXIS) == 0); //等待数据发送完成
I2C3->TXDR = temp; //写入发送数据
while((I2C3->ISR & I2C_ISR_TXIS) == 0); //等待数据发送完成
I2C3->TXDR = dat; //写入发送数据
}
将OLED初始化函数修改为:
void OLED_Init()
{
I2C3_Init();
OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率
OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64)
OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
OLED_WR_Byte(0X00,OLED_CMD); //默认为0
OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示
OLED_WR_Byte(0xAF,OLED_CMD); //开启显示
OLED_Clear();
}
至此,就可以用两根信号线点亮OLED了。(注:其他部分都保持原子哥程序原样不变即可。)
另外,感谢原子哥为我们提供的精致的开发板和丰富的精品教程,谢谢!