[G32R] 【G32R501 Micro-EVB测评】3、驱动OLED屏

[复制链接]
84|2
sujingliang 发表于 2026-1-3 15:48 | 显示全部楼层 |阅读模式
一、0.96英寸OLED显示模块参数
驱动芯片:SSD1315(或 SSD1306)
屏幕尺寸:0.96 英寸
分辨率:128x64
颜色:黄蓝双色(顶部128x16像素为黄色,下方128x48像素为蓝色
接口:通常模块会通过跳线帽允许用户选择 I2C 或 SPI 模式。
I2C 地址:默认为 0x3C 或 0x3D。

二、I2C驱动
3.png
根据device.h定义,选择I2C引脚:
  1. // I2C
  2. //
  3. #define DEVICE_GPIO_PIN_SDAA        35U  // GPIO number for I2C SDAA
  4. #define DEVICE_GPIO_PIN_SCLA        37U  // GPIO number for I2C SCLA
  5. #define DEVICE_GPIO_CFG_SDAA        GPIO_35_I2CA_SDA  // "pinConfig" for I2C SDAA
  6. #define DEVICE_GPIO_CFG_SCLA        GPIO_37_I2CA_SCL  // "pinConfig" for I2C SCLA

1、参数定义

  1. // OLED配置
  2. #define OLED_I2C_ADDRESS         0x3c    // OLED I2C地址
  3. #define OLED_WIDTH               128
  4. #define OLED_HEIGHT              64
  5. #define OLED_PAGES               (OLED_HEIGHT / 8)

  6. // I2C配置
  7. #define I2C_BASE                I2CA_BASE
  8. #define I2C_CLK_FREQ            100000   // 400kHz
  9. #define I2C_FIFO_SIZE           16       // FIFO深度

  10. // OLED命令定义
  11. #define OLED_SET_CONTRAST       0x81
  12. #define OLED_DISPLAY_ON         0xAF
  13. #define OLED_DISPLAY_OFF        0xAE
  14. #define OLED_SET_DISPLAY_CLOCK  0xD5
  15. #define OLED_SET_MULTIPLEX      0xA8
  16. #define OLED_SET_DISPLAY_OFFSET 0xD3
  17. #define OLED_SET_START_LINE     0x40
  18. #define OLED_CHARGE_PUMP        0x8D
  19. #define OLED_MEMORY_MODE        0x20
  20. #define OLED_SEG_REMAP          0xA0
  21. #define OLED_COM_SCAN_INC       0xC0
  22. #define OLED_COM_SCAN_DEC       0xC8
  23. #define OLED_SET_COM_PINS       0xDA
  24. #define OLED_SET_PRECHARGE      0xD9
  25. #define OLED_SET_VCOM_DETECT    0xDB
  26. #define OLED_DEACTIVATE_SCROLL  0x2E

2、GPIO初始化
  1. void I2C_GPIO_init(void)
  2. {
  3.     // I2CA pins (SDAA / SCLA)
  4.        
  5.     GPIO_setPinConfig(DEVICE_GPIO_CFG_SDAA);
  6.     GPIO_setDrivingCapability(DEVICE_GPIO_PIN_SDAA,GPIO_DRIVE_LEVEL_VERY_HIGH);
  7.     GPIO_setPadConfig(DEVICE_GPIO_PIN_SDAA, GPIO_PIN_TYPE_PULLUP);
  8.     GPIO_setQualificationMode(DEVICE_GPIO_PIN_SDAA, GPIO_QUAL_ASYNC);

  9.     GPIO_setPinConfig(DEVICE_GPIO_CFG_SCLA);
  10.     GPIO_setDrivingCapability(DEVICE_GPIO_PIN_SCLA,GPIO_DRIVE_LEVEL_VERY_HIGH);
  11.     GPIO_setPadConfig(DEVICE_GPIO_PIN_SCLA, GPIO_PIN_TYPE_PULLUP);
  12.     GPIO_setQualificationMode(DEVICE_GPIO_PIN_SCLA, GPIO_QUAL_ASYNC);
  13. }
SDA和SCL需要上拉,

3、I2C初始化
  1. void I2Cinit(void)
  2. {
  3.     printf("=== I2C OLED初始化 ===\n");
  4.    
  5.     // 1. 禁用模块
  6.     I2C_disableModule(I2C_BASE);
  7.    
  8.     // 2. 基础配置
  9.     I2C_initMaster(I2C_BASE, DEVICE_APBCLK_FREQ, 400000, I2C_DUTYCYCLE_50);
  10.     I2C_setAddressMode(I2C_BASE, I2C_ADDR_MODE_7BITS);
  11.     I2C_setBitCount(I2C_BASE, I2C_BITCOUNT_8);
  12.    
  13.     // 3. FIFO配置(先配置,后使能)
  14.     I2C_setFIFOInterruptLevel(I2C_BASE, I2C_FIFO_TX4, I2C_FIFO_RX4);
  15.     I2C_enableFIFO(I2C_BASE);
  16.    
  17.     // 4. 使能模块
  18.     I2C_enableModule(I2C_BASE);
  19. }

4、I2C FIFO发送函数
  1. // 发送函数
  2. bool I2C_FIFO_Send(uint8_t slaveAddr, uint8_t *buffer, uint16_t length, bool is_command)
  3. {
  4.     uint32_t base = I2C_BASE;
  5.     uint8_t control_byte = is_command ? 0x00 : 0x40;
  6.    
  7.     // 等待总线空闲
  8.                  uint32_t timeout = 10000;
  9.                 while (I2C_isBusBusy(base) && timeout--) ;
  10.     if (timeout == 0) return false;
  11.    
  12.     // 配置I2C
  13.     I2C_setSlaveAddress(base, slaveAddr);
  14.        
  15.        
  16.     I2C_setDataCount(base, length + 1);
  17.     I2C_setConfig(base, I2C_MASTER_SEND_MODE);
  18.    
  19.     // 清除状态
  20.     I2C_clearInterruptStatus(base, I2C_INT_STOP_CONDITION);
  21.    
  22.     // 开始传输
  23.     I2C_sendStartCondition(base);
  24.    
  25.     // 发送控制字节
  26.     I2C_putData(base, control_byte);
  27.    
  28.     // 批量发送数据
  29.     uint16_t sent = 0;
  30.     while (sent < length)
  31.     {
  32.         // 检查FIFO空间
  33.         uint8_t space = I2C_FIFO_SIZE - I2C_getTxFIFOStatus(base);
  34.         
  35.         if (space > 0)
  36.         {
  37.             // 一次尽可能多发送
  38.             uint8_t chunk = (length - sent < space) ? (length - sent) : space;
  39.             
  40.             // 使用循环展开提高效率
  41.             uint8_t i = 0;
  42.             while (i < chunk)
  43.             {
  44.                 I2C_putData(base, buffer[sent + i]);
  45.                 i++;
  46.             }
  47.             sent += chunk;
  48.         }
  49.     }
  50.    
  51.     // 等待传输完成
  52.                 timeout = 100;
  53.     while (I2C_isBusBusy(base) && timeout--) ;
  54.    
  55.     if (timeout == 0)
  56.     {
  57.         I2C_sendStopCondition(base);
  58.         return false;
  59.     }
  60.     // 发送STOP
  61.     I2C_sendStopCondition(base);
  62.    
  63.     // 等待STOP完成
  64.     timeout = 100;
  65.     while (!(I2C_getInterruptStatus(base) & I2C_INT_STOP_CONDITION) && timeout--) ;
  66.    
  67.     if (timeout == 0) return false;
  68.    
  69.     I2C_clearInterruptStatus(base, I2C_INT_STOP_CONDITION);
  70.     return true;
  71. }

5、OLED发送命令和数据函数
  1. // 发送命令
  2. static void OLED_SendCommand(uint8_t cmd)
  3. {
  4.     I2C_FIFO_Send(OLED_I2C_ADDRESS, &cmd, 1, true);
  5. }

  6. // 发送数据
  7. static void OLED_SendData(uint8_t *data, uint16_t length)
  8. {
  9.     // 分片发送(每次最多发送I2C_FIFO_SIZE字节)
  10.     uint16_t offset = 0;
  11.     while (offset < length)
  12.     {
  13.         uint16_t chunkSize = (length - offset > I2C_FIFO_SIZE) ?
  14.                             I2C_FIFO_SIZE : (length - offset);
  15.         I2C_FIFO_Send(OLED_I2C_ADDRESS, &data[offset], chunkSize, false);
  16.         offset += chunkSize;
  17.     }
  18. }


6、OLED初始化
缓存及初始化参数
  1. // 显示缓冲区
  2. uint8_t oled_buffer[OLED_WIDTH * OLED_PAGES] = {0};

  3. // 初始化序列
  4. static const uint8_t oled_init_seq[] = {
  5.     OLED_DISPLAY_OFF,          // 关闭显示
  6.     OLED_SET_DISPLAY_CLOCK,    // 设置时钟分频
  7.     0x80,                      // 建议值
  8.     OLED_SET_MULTIPLEX,        // 设置复用率
  9.     0x3F,                      // 64行
  10.     OLED_SET_DISPLAY_OFFSET,   // 设置显示偏移
  11.     0x00,                      // 无偏移
  12.     OLED_SET_START_LINE | 0x00,// 设置起始行
  13.     OLED_CHARGE_PUMP,          // 电荷泵设置
  14.     0x14,                      // 启用电荷泵
  15.     OLED_MEMORY_MODE,          // 内存模式
  16.     0x00,                      // 水平地址模式
  17.     OLED_SEG_REMAP | 0x01,     // 段重映射
  18.     OLED_COM_SCAN_DEC,         // 扫描方向
  19.     OLED_SET_COM_PINS,         // COM引脚配置
  20.     0x12,                      // 序列配置
  21.     OLED_SET_CONTRAST,         // 设置对比度
  22.     0xCF,                      // 对比度值
  23.     OLED_SET_PRECHARGE,        // 预充电周期
  24.     0xF1,                      // 建议值
  25.     OLED_SET_VCOM_DETECT,      // VCOMH检测器
  26.     0x40,                      // 建议值
  27.     OLED_DISPLAY_ON,           // 开启显示
  28.     OLED_DEACTIVATE_SCROLL     // 关闭滚动
  29. };
初始化函数
  1. // 初始化OLED
  2. void OLED_Init(void)
  3. {
  4.     // 初始化I2C
  5.                
  6.     I2C_FIFO_Init();
  7.     printf("I2C_FIFO_Init\r\n");
  8.     // 发送初始化序列
  9.     for (uint8_t i = 0; i < sizeof(oled_init_seq); i++)
  10.     {
  11.         OLED_SendCommand(oled_init_seq[i]);
  12.       
  13.                                 DEVICE_DELAY_US(600);
  14.     }
  15.     printf("OLED_Init\r\n");
  16.     // 清屏
  17.     OLED_Clear();
  18.     OLED_Display();
  19. }
7、OLED显示相关函数
清屏
  1. // 清屏
  2. void OLED_Clear(void)
  3. {
  4.     memset(oled_buffer, 0, sizeof(oled_buffer));
  5. }
更新显示
  1. // 更新显示
  2. void OLED_Display(void)
  3. {
  4.        
  5.                 uint8_t i,n;
  6.                 for(i=0;i<8;i++)
  7.                 {
  8.                          OLED_SendCommand(0xb0+i); //设置行起始地址
  9.                          OLED_SendCommand(0x00);   //设置低列起始地址
  10.                          OLED_SendCommand(0x10);   //设置高列起始地址
  11.                          OLED_SendData(oled_buffer+i*128, 128);
  12.                 }
  13.    
  14. }
画点
  1. // 设置像素点
  2. void OLED_SetPixel(uint8_t x, uint8_t y, bool on)
  3. {
  4.     if (x >= OLED_WIDTH || y >= OLED_HEIGHT)
  5.         return;
  6.    
  7.     uint16_t page = y / 8;
  8.     uint8_t bit = y % 8;
  9.    
  10.     if (on)
  11.     {
  12.         oled_buffer[x + page * OLED_WIDTH] |= (1 << bit);
  13.     }
  14.     else
  15.     {
  16.         oled_buffer[x + page * OLED_WIDTH] &= ~(1 << bit);
  17.     }
  18. }
绘制字符和字符串
  1. // 绘制字符(6x8字体)
  2. void OLED_DrawChar(uint8_t x, uint8_t y, char ch)
  3. {
  4.     // 简单的字体数据(6x8)
  5.     // 6x8 ASCII 字体数据(每个字符6字节)
  6. static const uint8_t font6x8[95][6] = {
  7.     // 空格 (ASCII 32)
  8.     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  9.     // ! (33)
  10.     {0x00, 0x00, 0x5F, 0x00, 0x00, 0x00},
  11.     // " (34)
  12.     {0x00, 0x07, 0x00, 0x07, 0x00, 0x00},
  13.     // # (35)
  14.     {0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00},
  15.     // $ (36)
  16.     {0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00},
  17.     // % (37)
  18.     {0x23, 0x13, 0x08, 0x64, 0x62, 0x00},
  19.     // & (38)
  20.     {0x36, 0x49, 0x55, 0x22, 0x50, 0x00},
  21.     // ' (39)
  22.     {0x00, 0x05, 0x03, 0x00, 0x00, 0x00},
  23.     // ( (40)
  24.     {0x00, 0x1C, 0x22, 0x41, 0x00, 0x00},
  25.     // ) (41)
  26.     {0x00, 0x41, 0x22, 0x1C, 0x00, 0x00},
  27.     // * (42)
  28.     {0x14, 0x08, 0x3E, 0x08, 0x14, 0x00},
  29.     // + (43)
  30.     {0x08, 0x08, 0x3E, 0x08, 0x08, 0x00},
  31.     // , (44)
  32.     {0x00, 0x50, 0x30, 0x00, 0x00, 0x00},
  33.     // - (45)
  34.     {0x08, 0x08, 0x08, 0x08, 0x08, 0x00},
  35.     // . (46)
  36.     {0x00, 0x60, 0x60, 0x00, 0x00, 0x00},
  37.     // / (47)
  38.     {0x20, 0x10, 0x08, 0x04, 0x02, 0x00},
  39.     // 0 (48)
  40.     {0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00},
  41.     // 1 (49)
  42.     {0x00, 0x42, 0x7F, 0x40, 0x00, 0x00},
  43.     // 2 (50)
  44.     {0x42, 0x61, 0x51, 0x49, 0x46, 0x00},
  45.     // 3 (51)
  46.     {0x21, 0x41, 0x45, 0x4B, 0x31, 0x00},
  47.     // 4 (52)
  48.     {0x18, 0x14, 0x12, 0x7F, 0x10, 0x00},
  49.     // 5 (53)
  50.     {0x27, 0x45, 0x45, 0x45, 0x39, 0x00},
  51.     // 6 (54)
  52.     {0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00},
  53.     // 7 (55)
  54.     {0x01, 0x71, 0x09, 0x05, 0x03, 0x00},
  55.     // 8 (56)
  56.     {0x36, 0x49, 0x49, 0x49, 0x36, 0x00},
  57.     // 9 (57)
  58.     {0x06, 0x49, 0x49, 0x29, 0x1E, 0x00},
  59.     // : (58)
  60.     {0x00, 0x36, 0x36, 0x00, 0x00, 0x00},
  61.     // ; (59)
  62.     {0x00, 0x56, 0x36, 0x00, 0x00, 0x00},
  63.     // < (60)
  64.     {0x08, 0x14, 0x22, 0x41, 0x00, 0x00},
  65.     // = (61)
  66.     {0x14, 0x14, 0x14, 0x14, 0x14, 0x00},
  67.     // > (62)
  68.     {0x00, 0x41, 0x22, 0x14, 0x08, 0x00},
  69.     // ? (63)
  70.     {0x02, 0x01, 0x51, 0x09, 0x06, 0x00},
  71.     // [url=/u/]@[/url] (64)
  72.     {0x32, 0x49, 0x79, 0x41, 0x3E, 0x00},
  73.     // A (65)
  74.     {0x7E, 0x11, 0x11, 0x11, 0x7E, 0x00},
  75.     // B (66)
  76.     {0x7F, 0x49, 0x49, 0x49, 0x36, 0x00},
  77.     // C (67)
  78.     {0x3E, 0x41, 0x41, 0x41, 0x22, 0x00},
  79.     // D (68)
  80.     {0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00},
  81.     // E (69)
  82.     {0x7F, 0x49, 0x49, 0x49, 0x41, 0x00},
  83.     // F (70)
  84.     {0x7F, 0x09, 0x09, 0x09, 0x01, 0x00},
  85.     // G (71)
  86.     {0x3E, 0x41, 0x49, 0x49, 0x7A, 0x00},
  87.     // H (72)
  88.     {0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00},
  89.     // I (73)
  90.     {0x00, 0x41, 0x7F, 0x41, 0x00, 0x00},
  91.     // J (74)
  92.     {0x20, 0x40, 0x41, 0x3F, 0x01, 0x00},
  93.     // K (75)
  94.     {0x7F, 0x08, 0x14, 0x22, 0x41, 0x00},
  95.     // L (76)
  96.     {0x7F, 0x40, 0x40, 0x40, 0x40, 0x00},
  97.     // M (77)
  98.     {0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x00},
  99.     // N (78)
  100.     {0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00},
  101.     // O (79)
  102.     {0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00},
  103.     // P (80)
  104.     {0x7F, 0x09, 0x09, 0x09, 0x06, 0x00},
  105.     // Q (81)
  106.     {0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00},
  107.     // R (82)
  108.     {0x7F, 0x09, 0x19, 0x29, 0x46, 0x00},
  109.     // S (83)
  110.     {0x46, 0x49, 0x49, 0x49, 0x31, 0x00},
  111.     // T (84)
  112.     {0x01, 0x01, 0x7F, 0x01, 0x01, 0x00},
  113.     // U (85)
  114.     {0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00},
  115.     // V (86)
  116.     {0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00},
  117.     // W (87)
  118.     {0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00},
  119.     // X (88)
  120.     {0x63, 0x14, 0x08, 0x14, 0x63, 0x00},
  121.     // Y (89)
  122.     {0x07, 0x08, 0x70, 0x08, 0x07, 0x00},
  123.     // Z (90)
  124.     {0x61, 0x51, 0x49, 0x45, 0x43, 0x00},
  125.     // [ (91)
  126.     {0x00, 0x7F, 0x41, 0x41, 0x00, 0x00},
  127.     // \ (92)
  128.     {0x02, 0x04, 0x08, 0x10, 0x20, 0x00},
  129.     // ] (93)
  130.     {0x00, 0x41, 0x41, 0x7F, 0x00, 0x00},
  131.     // ^ (94)
  132.     {0x04, 0x02, 0x01, 0x02, 0x04, 0x00},
  133.     // _ (95)
  134.     {0x40, 0x40, 0x40, 0x40, 0x40, 0x00},
  135.     // ` (96)
  136.     {0x00, 0x01, 0x02, 0x04, 0x00, 0x00},
  137.     // a (97)
  138.     {0x20, 0x54, 0x54, 0x54, 0x78, 0x00},
  139.     // b (98)
  140.     {0x7F, 0x48, 0x44, 0x44, 0x38, 0x00},
  141.     // c (99)
  142.     {0x38, 0x44, 0x44, 0x44, 0x20, 0x00},
  143.     // d (100)
  144.     {0x38, 0x44, 0x44, 0x48, 0x7F, 0x00},
  145.     // e (101)
  146.     {0x38, 0x54, 0x54, 0x54, 0x18, 0x00},
  147.     // f (102)
  148.     {0x08, 0x7E, 0x09, 0x01, 0x02, 0x00},
  149.     // g (103)
  150.     {0x0C, 0x52, 0x52, 0x52, 0x3E, 0x00},
  151.     // h (104)
  152.     {0x7F, 0x08, 0x04, 0x04, 0x78, 0x00},
  153.     // i (105)
  154.     {0x00, 0x44, 0x7D, 0x40, 0x00, 0x00},
  155.     // j (106)
  156.     {0x20, 0x40, 0x44, 0x3D, 0x00, 0x00},
  157.     // k (107)
  158.     {0x7F, 0x10, 0x28, 0x44, 0x00, 0x00},
  159.     // l (108)
  160.     {0x00, 0x41, 0x7F, 0x40, 0x00, 0x00},
  161.     // m (109)
  162.     {0x7C, 0x04, 0x18, 0x04, 0x78, 0x00},
  163.     // n (110)
  164.     {0x7C, 0x08, 0x04, 0x04, 0x78, 0x00},
  165.     // o (111)
  166.     {0x38, 0x44, 0x44, 0x44, 0x38, 0x00},
  167.     // p (112)
  168.     {0x7C, 0x14, 0x14, 0x14, 0x08, 0x00},
  169.     // q (113)
  170.     {0x08, 0x14, 0x14, 0x18, 0x7C, 0x00},
  171.     // r (114)
  172.     {0x7C, 0x08, 0x04, 0x04, 0x08, 0x00},
  173.     // s (115)
  174.     {0x48, 0x54, 0x54, 0x54, 0x20, 0x00},
  175.     // t (116)
  176.     {0x04, 0x3F, 0x44, 0x40, 0x20, 0x00},
  177.     // u (117)
  178.     {0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00},
  179.     // v (118)
  180.     {0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00},
  181.     // w (119)
  182.     {0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00},
  183.     // x (120)
  184.     {0x44, 0x28, 0x10, 0x28, 0x44, 0x00},
  185.     // y (121)
  186.     {0x0C, 0x50, 0x50, 0x50, 0x3C, 0x00},
  187.     // z (122)
  188.     {0x44, 0x64, 0x54, 0x4C, 0x44, 0x00},
  189.     // { (123)
  190.     {0x00, 0x08, 0x36, 0x41, 0x00, 0x00},
  191.     // | (124)
  192.     {0x00, 0x00, 0x7F, 0x00, 0x00, 0x00},
  193.     // } (125)
  194.     {0x00, 0x41, 0x36, 0x08, 0x00, 0x00},
  195.     // ~ (126)
  196.     {0x10, 0x08, 0x08, 0x10, 0x08, 0x00}
  197. };
  198.    
  199.     if (ch < 32 || ch > 126) return;
  200.    
  201.     const uint8_t *charData = font6x8[ch - 32];
  202.    
  203.     for (uint8_t i = 0; i < 6; i++)
  204.     {
  205.         if (x + i < OLED_WIDTH)
  206.         {
  207.             oled_buffer[(x + i) + (y / 8) * OLED_WIDTH] = charData[i];
  208.         }
  209.     }
  210. }

  211. // 绘制字符串
  212. void OLED_DrawString(uint8_t x, uint8_t y, const char *str)
  213. {
  214.     uint8_t currentX = x;
  215.     while (*str)
  216.     {
  217.         OLED_DrawChar(currentX, y, *str++);
  218.         currentX += 6;  // 字符宽度+间距
  219.         if (currentX >= OLED_WIDTH - 6)
  220.             break;
  221.     }
  222. }

三、运行验证
  1. OLED_DrawString(0, 0, "Hello G32R501!");
  2.                 OLED_DrawString(0, 16, "FIFO I2C Demo");
  3.                 OLED_DrawString(0, 32, "128x64 Display");
  4.                 OLED_Display();

10.jpg



HeartbeatEcho 发表于 2026-1-4 23:39 | 显示全部楼层
FIFO的使用应该会加速显示吧?!
SpiritSong 发表于 2026-1-6 10:20 | 显示全部楼层
咦?这个MCU的I2C引脚配置需要配置为上拉模式吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

179

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部
0