【GD32L233C-START评测】12. 硬件IIC驱动OLED
[复制链接]
之前的帖子可以参考:
【GD32L233C-START评测】1.开箱
【GD32L233C-START评测】2.手把手创建新工程
【GD32L233C-START评测】3.移植FreeRTOS到GD32L233
【GD32L233C-START评测】4. 移植RT-Thread到GD32L233
【GD32L233C-START评测】5. IIC驱动OLED
【GD32L233C-START评测】6. 获取RTC时间并通过OLED显示
【GD32L233C-START评测】7. PWM驱动LED
【GD32L233C-START评测】8. TRNG真随机数生成
【GD32L233C-START评测】9. CRC检验
【GD32L233C-START评测】10. ADC读取芯片内部温度
【GD32L233C-START评测】11.DAC输出电压值_ADC读取外部电压值
在我第5篇帖子里,我使用软件IIC完成了OLED的驱动,第6篇帖子里加上了RTC来显示时间,本帖将用硬件IIC来完成OLED的显示以及时间显示。
为什么用硬件IIC呢?第一点硬件IIC实现逻辑相对软件IIC而言少了IIC通信逻辑部分,相对而言要简单很多;第二点就是硬件IIC速度比软件IIC的速度快很多。
一、了解硬件IIC
要成功使用硬件IIC,我们首先需要了解硬件IIC的相关知识,查看数据手册内容,参考是《用户手册》第21章21. 内部集成电路总线接口I2C)。
硬件I2C有四种工作模式:
从机发送
从机接收
主机发送
主机接收
本帖主要是对OLED的操作,不需要读,而且OLED是作为从机被控制的,所以我们的单片机将作为主机发送数据,只工作在这一个模式下。
关于IIC数据通信的有效性以及格式,原理以及通信时序等重要信息等都在《用户手册》中有详细的描述,不懂得小伙伴可以自行阅读。
二、接口信息
查看《用户手册》了解了IIC的通信原理以及相关寄存器之后,我们需要查看《数据手册》了解IIC相关的接口配置,方便程序编写。
GD32L233C开发板引出的IIC接口是PB10以及PB11,我们直接查找《数据手册》中这两个引脚的复用信息即可。
如下图:
复用可选时AF4,其中
PB10 -- AF5 -- I2C1的SCL
PB11 -- AF4 -- I2C1的SDA
三、软件代码
1、初始化GPIO
初始化GPIO主要是设置PB10以及PB11位复用端口,复用IIC功能
void i2c_gpio_config(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* connect PB10 to I2C1_SCL */
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_10);
/* connect PB11 to I2C1_SDA */
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_11);
/* configure GPIO pins of I2C1 */
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
}
2、初始化硬件IIC
初始化硬件IIC,需要设置:
IIC主机的IIC地址,设置位0x72,用宏I2C_OWN_ADDRESS7表示
IIC从机的IIC地址,也就是OLED的地址,位0x78,用宏I2C_SLAVE_OLED_ADDRESS7表示
硬件IIC每次传输的数据个数,OLED有写数据寄存器0x40和写命令寄存器0x00,每次需要想这两个寄存器中写入数据,所以是2个字节,用I2C_DATA_BYTES表示。
void i2c_config(void)
{
/* enable I2C1 clock */
rcu_periph_clock_enable(RCU_I2C1);
/* configure I2C timing */
i2c_timing_config(I2C1, 0, 0x3, 0);
i2c_master_clock_config(I2C1, 0x13, 0x36);
/* configure I2C address */
i2c_address_config(I2C1, I2C_OWN_ADDRESS7, I2C_ADDFORMAT_7BITS);
/* configure slave address */
i2c_master_addressing(I2C1, I2C_SLAVE_OLED_ADDRESS7, I2C_MASTER_TRANSMIT);
/* configure number of bytes to be transferred */
i2c_transfer_byte_number_config(I2C1, I2C_DATA_BYTES);
/* enable I2C1 */
i2c_enable(I2C1);
}
3、OLED写命令与写数据函数实现
因为之前使用的是软件IIC,本次使用硬件IIC,所以我用了一个宏定义对硬件IIC代码和硬件IIC代码进行区分,需要使用硬件IIC或者软件IIC的时候只需要修改一些宏定义即可,如下:
#define OLED_IIC_TYPE_SW 0U /*IIC for software*/
#define OLED_IIC_TYPE_HW 1U /*IIC for hardware*/
#define OLED_IIC_TYPE OLED_IIC_TYPE_HW
写数据函数实现:
void OLED_WrDat(unsigned char IIC_Data)
{
#if(OLED_IIC_TYPE == OLED_IIC_TYPE_HW)
uint8_t i2c_transmitter[2]={0x40, IIC_Data};
uint8_t i;
i2c_transmitter[0] = 0x40;
i2c_transmitter[1] = IIC_Data;
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until the transmit data buffer is empty */
I2C_STAT(I2C1) |= I2C_STAT_TBE;
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
for(i = 0; i < 2; i++) {
/* data transmission */
i2c_data_transmit(I2C1, i2c_transmitter[i]);
/* wait until the TI bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_TI));
}
/* wait for transfer complete flag */
while(!i2c_flag_get(I2C1, I2C_FLAG_TC));
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
/* wait until stop condition generate */
while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
/* clear the STPDET bit */
i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
#elif(OLED_IIC_TYPE == OLED_IIC_TYPE_SW)
IIC_Start();
IIC_Send_Byte(0x78);
IIC_Wait_Ack();
IIC_Send_Byte(0x40); //write data
IIC_Wait_Ack();
IIC_Send_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
#endif
}
写命令函数实现
void OLED_WrCmd(unsigned char IIC_Command)
{
#if(OLED_IIC_TYPE == OLED_IIC_TYPE_HW)
uint8_t i2c_transmitter[2]={0x00, IIC_Command};
uint8_t i;
i2c_transmitter[0] = 0x00;
i2c_transmitter[1] = IIC_Command;
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until the transmit data buffer is empty */
I2C_STAT(I2C1) |= I2C_STAT_TBE;
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
for(i = 0; i < 2; i++) {
/* data transmission */
i2c_data_transmit(I2C1, i2c_transmitter[i]);
/* wait until the TI bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_TI));
}
/* wait for transfer complete flag */
while(!i2c_flag_get(I2C1, I2C_FLAG_TC));
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
/* wait until stop condition generate */
while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
/* clear the STPDET bit */
i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
#elif(OLED_IIC_TYPE == OLED_IIC_TYPE_SW)
IIC_Start();
IIC_Send_Byte(0x78); //Slave address,SA0=0
IIC_Wait_Ack();
IIC_Send_Byte(0x00); //write command
IIC_Wait_Ack();
IIC_Send_Byte(IIC_Command);
IIC_Wait_Ack();
IIC_Stop();
#endif
}
4、OLED显示代码
OLED的显示代码没有变化,直接参考我第6篇帖子即可:【GD32L233C-START评测】6. 获取RTC时间并通过OLED显示
四、效果展示
显示效果如下,视频拍倒了,见谅:
五、源代码
源代码分享如下,有需要的小伙伴可以参考。
GD32L233C_Prj_OLED_HW_IIC.zip
(784.54 KB, 下载次数: 31)
|