RISC-V技术论坛
直播中

jf_15811252

3年用户 249经验值
擅长:嵌入式技术
私信 关注
[经验]

【兆易创新GD32VF103R-START开发板试用体验】软件和硬件IIC驱动OLED

本篇文章主要讲解在使用软件IIC和硬件IIC时遇到的问题,并简单讲解实现的过程。在程序中使用条件编译的方式实现软件IIC和硬件IIC。

实现的过程,硬件IIC需要在头文件中定义地址,而软件IIC需要在头文件中对引脚的高低电平进行宏定义
  1. #ifndef __OLED_H
  2. #define __OLED_H
  3. #include "gd32vf103.h"
  4. #include "gd32vf103_gpio.h"
  5. #include "stdlib.h"       

  6. #define  hardware_iic   0
  7. #define  software_iic   1

  8. #if software_iic
  9. #define OLED_SCLK_Clr()  GPIO_BC(GPIOB) = GPIO_PIN_6
  10. #define OLED_SCLK_Set()  GPIO_BOP(GPIOB) = GPIO_PIN_6//SCL

  11. #define OLED_SDIN_Clr()  GPIO_BC(GPIOB) = GPIO_PIN_7//DIN
  12. #define OLED_SDIN_Set()  GPIO_BOP(GPIOB) = GPIO_PIN_7

  13. #endif

  14. #if hardware_iic

  15. #define I2C0_OWN_ADDRESS7   0x72
  16. #define I2C0_SLAVE_ADDRESS7 0x78

  17. #endif


  18. #define OLED_CMD  0        //写命令
  19. #define OLED_DATA 1        //写数据

  20. #define u8 unsigned char
  21. #define u32 unsigned int

初始化,使用的是开发板的IIC0,在程序中将IIC0时钟和硬件初始化以及IIC的初始化放在硬件IIC的条件编译语句中
  1. //OLED的初始化
  2. void OLED_Init(void)
  3. {
  4.     rcu_periph_clock_enable(RCU_GPIOB);
  5. #if hardware_iic
  6.     rcu_periph_clock_enable(RCU_I2C0);

  7.     gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
  8.     i2c_clock_config(I2C0,400000,I2C_DTCY_2);
  9.     i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C0_SLAVE_ADDRESS7);
  10.     i2c_enable(I2C0);
  11.     i2c_ack_config(I2C0,I2C_ACK_ENABLE);
  12. #endif

  13. #if software_iic
  14.     gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6|GPIO_PIN_7);
  15.     GPIO_BC(GPIOB) = GPIO_PIN_6;
  16.     GPIO_BC(GPIOB) = GPIO_PIN_7;

  17. #endif
  18.     delay_ms(500);
  19. 接下的都是初始化发送命令,没有上传。

接下来就是字节发送函数这部分,这里需要进行一个条件语句的使用,在硬件IIC中需要进行数据发送和命令发送,这里只需使用if语句即可
  1. if(mode){ i2c_data_transmit(I2C0, 0x40);}
  2. else { i2c_data_transmit(I2C0, 0x00);}
  1. //发送一个字节
  2. //向SSD1306写入一个字节。
  3. //mode:数据/命令标志 0,表示命令;1,表示数据;
  4. void OLED_WR_Byte(u8 dat,u8 mode)

  5. {

  6. #if software_iic
  7.         I2C_Start();
  8.         Send_Byte(0x78);
  9.         I2C_WaitAck();
  10.         if(mode){Send_Byte(0x40);}
  11.     else{Send_Byte(0x00);}
  12.         I2C_WaitAck();
  13.         Send_Byte(dat);
  14.         I2C_WaitAck();
  15.         I2C_Stop();

  16. #endif

  17. #if hardware_iic

  18.     /* wait until I2C bus is idle */
  19.        while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
  20.        /* send a start condition to I2C0 bus */
  21.        i2c_start_on_bus(I2C0);
  22.        /* wait until SBSEND bit is set */
  23.        while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
  24.        /* send slave address to I2C bus */
  25.        i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
  26.        /* wait until ADDSEND bit is set */
  27.        while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
  28.        /* clear ADDSEND bit */
  29.        i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
  30.        /* wait until the transmit data buffer is empty */
  31.        if(mode){ i2c_data_transmit(I2C0, 0x40);}
  32.        else {  i2c_data_transmit(I2C0, 0x00);}
  33.        while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
  34.            /* data transmission */
  35.        i2c_data_transmit(I2C0, dat);
  36.         /* wait until the TBE bit is set */
  37.        while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
  38.        /* send a stop condition to I2C bus */
  39.        i2c_stop_on_bus(I2C0);
  40.        /* wait until stop condition generate */
  41.        while(I2C_CTL0(I2C0) & 0x0200);

  42. #endif
  43. }
完成了硬件IIC的数据发送,接下来就是软件IIC发送数据,软件IIC就需要进行起始信号、终止信号、应答信号的时序模拟,所以需要将这部分放在条件编译里面
  1. #if software_iic
  2. //起始信号
  3. void I2C_Start(void)
  4. {
  5.         OLED_SDIN_Set();
  6.         delay_us(8);
  7.         OLED_SCLK_Set();
  8.         delay_us(8);
  9.         OLED_SDIN_Clr();
  10.         delay_us(8);
  11.         OLED_SCLK_Clr();
  12.         delay_us(8);
  13. }

  14. //结束信号
  15. void I2C_Stop(void)
  16. {
  17.         OLED_SCLK_Set();
  18.         delay_us(8);
  19.         OLED_SDIN_Clr();
  20.         delay_us(8);
  21.         OLED_SDIN_Set();
  22.         delay_us(8);
  23. }

  24. //等待信号响应
  25. void I2C_WaitAck(void) //测数据信号的电平
  26. {
  27.         OLED_SCLK_Set();
  28.         delay_us(8);
  29.         OLED_SCLK_Clr();
  30.         delay_us(8);
  31. }


  32. //写入一个字节
  33. void Send_Byte(u8 dat)
  34. {
  35.         u8 i;
  36.         for(i=0;i<8;i++)
  37.         {
  38.                 OLED_SCLK_Clr();//将时钟信号设置为低电平
  39.                 delay_us(8);
  40.                 if(dat&0x80)//将dat的8位从最高位依次写入
  41.                 {
  42.                         OLED_SDIN_Set();
  43.                         delay_us(8);
  44.     }
  45.                 else
  46.                 {
  47.                         OLED_SDIN_Clr();
  48.                         delay_us(8);
  49.     }
  50.                 OLED_SCLK_Set();//将时钟信号设置为高电平
  51.             delay_us(8);
  52.                 OLED_SCLK_Clr();//将时钟信号设置为低电平
  53.             delay_us(8);
  54.                 dat<<=1;
  55.   }
  56. }

  57. #endif

软件IIC实现结果图:
软iic.jpg
硬件IIC实现结果图:

硬iic.jpg
其他部分程序则完全相同,值得注意的是在使用软件IIC和硬件IIC都遇到了问题,在这里做个记录。
1.硬件IIC
     问题:

出现的问题,即可以显示,但是只能显示一次OLED屏立马就熄灭了,按复位得按两次才能闪现一次。
    原因:

原因是因为在开发板的排针焊接时造成了虚焊导致电压不稳。
    解决办法:
将排针重新进行焊接。


2.软件IIC
    问题:

出现的问题,程序能运行但是就是不能显示,将显示程序和流水灯程序放在程序中,流水灯正常。
   原因:
由于这款开发板的主频是108MHZ,在程序中设置的也是108MHZ,所以由于时钟过快模拟IIC没有正常运行
  解决方法:

在模拟IIC和数据发送函数中进行一个延时
  1. //起始信号
  2. void I2C_Start(void)
  3. {
  4.         OLED_SDIN_Set();
  5.         delay_us(8);
  6.         OLED_SCLK_Set();
  7.         delay_us(8);
  8.         OLED_SDIN_Clr();
  9.         delay_us(8);
  10.         OLED_SCLK_Clr();
  11.         delay_us(8);
  12. }
  1. //写入一个字节
  2. void Send_Byte(u8 dat)
  3. {
  4.         u8 i;
  5.         for(i=0;i<8;i++)
  6.         {
  7.                 OLED_SCLK_Clr();//将时钟信号设置为低电平
  8.                 delay_us(8);
  9.                 if(dat&0x80)//将dat的8位从最高位依次写入
  10.                 {
  11.                         OLED_SDIN_Set();
  12.                         delay_us(8);
  13.     }
  14.                 else
  15.                 {
  16.                         OLED_SDIN_Clr();
  17.                         delay_us(8);
  18.     }
  19.                 OLED_SCLK_Set();//将时钟信号设置为高电平
  20.             delay_us(8);
  21.                 OLED_SCLK_Clr();//将时钟信号设置为低电平
  22.             delay_us(8);
  23.                 dat<<=1;
  24.   }
  25. }
我将程序上传至这里,有需要用到的可以参考,使用的是沁恒的开发软件,只需双击工程文件即可打开。
LED1.zip (733.61 KB)
(下载次数: 5, 2022-5-19 08:52 上传)


更多回帖

发帖
×
20
完善资料,
赚取积分