这篇文章将来测评HC32F448的硬件I2C和用I2C驱动OLED。
我选用的OLED是市面上常见的0.96寸OLED,它支持I2C和SPI接口,常见的驱动方式是使用软件I2C或者SPI,这里我将用HC32的硬件I2C将其驱动。
首先,因为市面上用0.96寸的OLED的人很多,所以一些开发者或商家就编写其的通用驱动,为了提高开发效率,避免重复造轮子,我选用某园的驱动,它提供了非常多的例程,我就在其基础上修改。
首先,在Hardware文件夹中新建I2C.c、0_96_OLED.c等C文件及其对应的h头文件。然后在Drivers中添加对应组件如下图所示
第二步,配置HC32F448的硬件I2C,这里参考官方提供的HC32F448_DDL_Rev1.0.0\HC32F448_DDL_Rev1.0.0\projects\ev_hc32f448_lqfp80\examples\i2c\i2c_master_polling
首先是MY_I2C_Init(void),包含对I2C的GPIO的选择和复用功能初始化、使能I2C的时钟、配置I2C的分频系数、传输速率等。
然后就是I2C_Master_Transmit(),该函数负责发送数据,输入参数包括从机地址、待传输数据地址、数据数量、超时时间。
然后就是I2C_Master_Receive(),该函数负责接收数据,输入参数包括从机地址、待接收数据地址、数据接收数量、超时时间。
第三步,将某园的OLED的I2C驱动复制到0_96_OLED.c,面对不同的MCU,只需要移植驱动层,包括OLED指令发送函数和OLED数据发送函数,应用层脱离于具体硬件,不需要移植。
OLED指令发送函数Write_IIC_Command()和OLED数据发送函数Write_IIC_Data()类似,首先发送第一个8位数据:7位从机地址+读写位,因为都是向OLED发送的,所以读写位为0;第二个8位数据为控制字节,如果接下来发送为指令,那么为0x00,如果是数据,那么为0x40;第三个8位数据就是具体的指令或者数据。具体如下。
这里一定一定要注意从机的地址,原来用模拟I2C的时候比如Write_IIC_Command()是下面这样子的:
我想当然是从机地址为0x78,可实际是这个0x78是包含了最后一位的读写位0,实际的地址应该是0x78>>1,而使用I2C_Master_Transmit()填入的从机地址需要真实的地址0x3C(0x78>>1),因为其会调用I2C_TransAddr()来发送地址,I2C_TransData()来发送数据,而I2C_TransAddr()内部是通过下面的语句发送地址,可以看到其会自动将从机地址右移一位并加上读写位,经过它处理才是0x78,所以你填入的从机地址一定要是真实的从机地址,这里纪念一下我踩了几天的坑,呜呜呜呜!!!
I2C_WriteData(I2Cx, (uint8_t)(u16Addr << 1U) | u8Dir);
移植好这两个核心函数后,其他基本就没什么问题了。然后在主函数屏蔽掉BSP_IO_Init()和BSP_LED_Init(),因为这两个函数会使用I2C1驱动IO口扩展芯片TCA9539,而我OLED使用的正是I2C1,要防止冲突。
最后写入对应的API,就能显示对应的效果了。
UI设计还是很优雅的,i2c的地址,还真要的读一下协议才能知道正确的写地址,就是地址后面增加写数据与写指令的位。
引用: lugl4313820 发表于 2023-8-20 07:05 UI设计还是很优雅的,i2c的地址,还真要的读一下协议才能知道正确的写地址,就是地址后面增加写数据与写指 ...
主要之前都是软件I2C 直接参考别人的 改GPIO就好了 用硬件I2C就要适配其库函数 下次就会注意了