本篇文章主要讲解在使用软件IIC和硬件IIC时遇到的问题,并简单讲解实现的过程。在程序中使用条件编译的方式实现软件IIC和硬件IIC。
实现的过程,硬件IIC需要在头文件中定义地址,而软件IIC需要在头文件中对引脚的高低电平进行宏定义
- #ifndef __OLED_H
- #define __OLED_H
- #include "gd32vf103.h"
- #include "gd32vf103_gpio.h"
- #include "stdlib.h"
- #define hardware_iic 0
- #define software_iic 1
- #if software_iic
- #define OLED_SCLK_Clr() GPIO_BC(GPIOB) = GPIO_PIN_6
- #define OLED_SCLK_Set() GPIO_BOP(GPIOB) = GPIO_PIN_6//SCL
- #define OLED_SDIN_Clr() GPIO_BC(GPIOB) = GPIO_PIN_7//DIN
- #define OLED_SDIN_Set() GPIO_BOP(GPIOB) = GPIO_PIN_7
- #endif
- #if hardware_iic
- #define I2C0_OWN_ADDRESS7 0x72
- #define I2C0_SLAVE_ADDRESS7 0x78
- #endif
- #define OLED_CMD 0 //写命令
- #define OLED_DATA 1 //写数据
- #define u8 unsigned char
- #define u32 unsigned int
初始化,使用的是
开发板的IIC0,在程序中将IIC0时钟和硬件初始化以及IIC的初始化放在硬件IIC的条件编译语句中
- //OLED的初始化
- void OLED_Init(void)
- {
- rcu_periph_clock_enable(RCU_GPIOB);
- #if hardware_iic
- rcu_periph_clock_enable(RCU_I2C0);
- gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
- i2c_clock_config(I2C0,400000,I2C_DTCY_2);
- i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C0_SLAVE_ADDRESS7);
- i2c_enable(I2C0);
- i2c_ack_config(I2C0,I2C_ACK_ENABLE);
- #endif
- #if software_iic
- gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6|GPIO_PIN_7);
- GPIO_BC(GPIOB) = GPIO_PIN_6;
- GPIO_BC(GPIOB) = GPIO_PIN_7;
- #endif
- delay_ms(500);
- 接下的都是初始化发送命令,没有上传。
接下来就是字节发送函数这部分,这里需要进行一个条件语句的使用,在硬件IIC中需要进行数据发送和命令发送,这里只需使用if语句即可
- if(mode){ i2c_data_transmit(I2C0, 0x40);}
- else { i2c_data_transmit(I2C0, 0x00);}
- //发送一个字节
- //向SSD1306写入一个字节。
- //mode:数据/命令标志 0,表示命令;1,表示数据;
- void OLED_WR_Byte(u8 dat,u8 mode)
- {
- #if software_iic
- I2C_Start();
- Send_Byte(0x78);
- I2C_WaitAck();
- if(mode){Send_Byte(0x40);}
- else{Send_Byte(0x00);}
- I2C_WaitAck();
- Send_Byte(dat);
- I2C_WaitAck();
- I2C_Stop();
- #endif
- #if hardware_iic
- /* wait until I2C bus is idle */
- while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
- /* send a start condition to I2C0 bus */
- i2c_start_on_bus(I2C0);
- /* wait until SBSEND bit is set */
- while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
- /* send slave address to I2C bus */
- i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
- /* wait until ADDSEND bit is set */
- while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
- /* clear ADDSEND bit */
- i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
- /* wait until the transmit data buffer is empty */
- if(mode){ i2c_data_transmit(I2C0, 0x40);}
- else { i2c_data_transmit(I2C0, 0x00);}
- while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
- /* data transmission */
- i2c_data_transmit(I2C0, dat);
- /* wait until the TBE bit is set */
- while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
- /* send a stop condition to I2C bus */
- i2c_stop_on_bus(I2C0);
- /* wait until stop condition generate */
- while(I2C_CTL0(I2C0) & 0x0200);
- #endif
- }
完成了硬件IIC的数据发送,接下来就是软件IIC发送数据,软件IIC就需要进行起始信号、终止信号、应答信号的时序模拟,所以需要将这部分放在条件编译里面
- #if software_iic
- //起始信号
- void I2C_Start(void)
- {
- OLED_SDIN_Set();
- delay_us(8);
- OLED_SCLK_Set();
- delay_us(8);
- OLED_SDIN_Clr();
- delay_us(8);
- OLED_SCLK_Clr();
- delay_us(8);
- }
- //结束信号
- void I2C_Stop(void)
- {
- OLED_SCLK_Set();
- delay_us(8);
- OLED_SDIN_Clr();
- delay_us(8);
- OLED_SDIN_Set();
- delay_us(8);
- }
- //等待信号响应
- void I2C_WaitAck(void) //测数据信号的电平
- {
- OLED_SCLK_Set();
- delay_us(8);
- OLED_SCLK_Clr();
- delay_us(8);
- }
- //写入一个字节
- void Send_Byte(u8 dat)
- {
- u8 i;
- for(i=0;i<8;i++)
- {
- OLED_SCLK_Clr();//将时钟信号设置为低电平
- delay_us(8);
- if(dat&0x80)//将dat的8位从最高位依次写入
- {
- OLED_SDIN_Set();
- delay_us(8);
- }
- else
- {
- OLED_SDIN_Clr();
- delay_us(8);
- }
- OLED_SCLK_Set();//将时钟信号设置为高电平
- delay_us(8);
- OLED_SCLK_Clr();//将时钟信号设置为低电平
- delay_us(8);
- dat<<=1;
- }
- }
- #endif
软件IIC实现结果图:
硬件IIC实现结果图:
其他部分程序则完全相同,值得注意的是在使用软件IIC和硬件IIC都遇到了问题,在这里做个记录。
1.硬件IIC
问题:
出现的问题,即可以显示,但是只能显示一次OLED屏立马就熄灭了,按复位得按两次才能闪现一次。
原因:
原因是因为在开发板的排针焊接时造成了虚焊导致电压不稳。
解决办法:
将排针重新进行焊接。
2.软件IIC
问题:
出现的问题,程序能运行但是就是不能显示,将显示程序和流水灯程序放在程序中,流水灯正常。
原因:
由于这款开发板的主频是108MHZ,在程序中设置的也是108MHZ,所以由于时钟过快模拟IIC没有正常运行
解决方法:
在模拟IIC和数据发送函数中进行一个延时
- //起始信号
- void I2C_Start(void)
- {
- OLED_SDIN_Set();
- delay_us(8);
- OLED_SCLK_Set();
- delay_us(8);
- OLED_SDIN_Clr();
- delay_us(8);
- OLED_SCLK_Clr();
- delay_us(8);
- }
- //写入一个字节
- void Send_Byte(u8 dat)
- {
- u8 i;
- for(i=0;i<8;i++)
- {
- OLED_SCLK_Clr();//将时钟信号设置为低电平
- delay_us(8);
- if(dat&0x80)//将dat的8位从最高位依次写入
- {
- OLED_SDIN_Set();
- delay_us(8);
- }
- else
- {
- OLED_SDIN_Clr();
- delay_us(8);
- }
- OLED_SCLK_Set();//将时钟信号设置为高电平
- delay_us(8);
- OLED_SCLK_Clr();//将时钟信号设置为低电平
- delay_us(8);
- dat<<=1;
- }
- }
我将程序上传至这里,有需要用到的可以参考,使用的是沁恒的开发软件,只需双击工程文件即可打开。
LED1.zip
(733.61 KB)
(下载次数: 5, 2022-5-19 08:52 上传)