跳到主要内容

兆易创新-GD32F30X-SPI-OLED移植

-GD32F307E-START开发板评测 SPI-OLED显示模块移植

软硬件平台

  1. GD32F307E-START Board开发板
  2. GCC Makefile

接口说明
GND电源地
VCC电源正(3.3V)
D0串行信号时钟输入
D1串行信号数据输入
RES复位信号输入(低电平有效)
DC数据/命令控制(引脚拉高为数据,引脚拉低为命令)
CS片选输入(只有CS拉低时,芯片才能使能MCU通信)

模块为SPI通信协议的从机,D0为SPI信号线(SCK),D1为SPI输出线(MOSI),CS为SPI片选线(NSS)。

软件SPI移植

  1. 工程模板建立

    在之前的gcc makefile的工程模板上进行添加文件,同时oled部分代码参考梁山派GD32F4开发板资料进行。

    olde_drive.c olde_drive.h // oled底层驱动文件,包括软件spi实现,oled引脚配置,oled初始化

    olde_draw.c olde_draw.h // oled应用层文件,主要是绘图api实现(可以移植到其他开发板,不需要改,仅配置好驱动文件即可)

  2. 配置引脚

    选择引脚,进入工程开始编写屏幕引脚初始化代码。

    为了方便后续移植,我在oled_driver.h处宏定义了每一个引脚,后续根据需要进行修改即可。

    //-----------------OLED端口移植---------------- 
    #define RCU_LCD_D0 RCU_GPIOA//SCK
    #define PORT_LCD_D0 GPIOA
    #define GPIO_LCD_D0 GPIO_PIN_7

    #define RCU_LCD_D1 RCU_GPIOA//MOSI
    #define PORT_LCD_D1 GPIOA
    #define GPIO_LCD_D1 GPIO_PIN_3

    #define RCU_LCD_CS RCU_GPIOC//NSS
    #define PORT_LCD_CS GPIOC
    #define GPIO_LCD_CS GPIO_PIN_0

    #define RCU_LCD_RES RCU_GPIOA//RES
    #define PORT_LCD_RES GPIOA
    #define GPIO_LCD_RES GPIO_PIN_1

    #define RCU_LCD_DC RCU_GPIOC //DC
    #define PORT_LCD_DC GPIOC
    #define GPIO_LCD_DC GPIO_PIN_2
  1. 引脚gpio初始化 (重点1)

    void OLED_Configuare(void)
    {

    //根据GPIO组初始化GPIO时钟 gd32 rcu_periph_clock_enable
    rcu_periph_clock_enable(RCU_LCD_D0);
    rcu_periph_clock_enable(RCU_LCD_D1);
    rcu_periph_clock_enable(RCU_LCD_CS);
    rcu_periph_clock_enable(RCU_LCD_DC);
    rcu_periph_clock_enable(RCU_LCD_RES);
    /* 配置CS */
    gpio_init(PORT_LCD_CS,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_CS);
    gpio_bit_write(PORT_LCD_CS, GPIO_LCD_CS, SET);
    /* 配置D0 */
    gpio_init(PORT_LCD_D0,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_D0);
    gpio_bit_write(PORT_LCD_D0, GPIO_LCD_D0, SET);
    /* 配置D1 */
    gpio_init(PORT_LCD_D1,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_D1);
    gpio_bit_write(PORT_LCD_D1, GPIO_LCD_D1, SET);
    //OLED_DC初始化设置
    gpio_init(PORT_LCD_DC,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_DC);
    gpio_bit_write(PORT_LCD_DC, GPIO_LCD_DC, SET);
    //GPIO_RES初始化设置
    gpio_init(PORT_LCD_RES,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_RES);
    gpio_bit_write(PORT_LCD_RES, GPIO_LCD_RES, SET);

    }
  2. 端口宏定义设置


    #define OLED_SCL_Clr() gpio_bit_write(PORT_LCD_D0, GPIO_LCD_D0, RESET)//SCL=SCLK
    #define OLED_SCL_Set() gpio_bit_write(PORT_LCD_D0, GPIO_LCD_D0, SET)

    #define OLED_SDA_Clr() gpio_bit_write(PORT_LCD_D1, GPIO_LCD_D1, RESET)//SDA=MOSI
    #define OLED_SDA_Set() gpio_bit_write(PORT_LCD_D1, GPIO_LCD_D1, SET)

    #define OLED_RES_Clr() gpio_bit_write(PORT_LCD_RES, GPIO_LCD_RES, RESET)//RES
    #define OLED_RES_Set() gpio_bit_write(PORT_LCD_RES,GPIO_LCD_RES, SET)

    #define OLED_DC_Clr() gpio_bit_write(PORT_LCD_DC, GPIO_LCD_DC, RESET)//DC
    #define OLED_DC_Set() gpio_bit_write(PORT_LCD_DC, GPIO_LCD_DC, SET)

    #define OLED_CS_Clr() gpio_bit_write(PORT_LCD_CS, GPIO_LCD_CS, RESET)//CS
    #define OLED_CS_Set() gpio_bit_write(PORT_LCD_CS, GPIO_LCD_CS, SET)
  3. OLED_WR_Byte函数配置(重点)

    //==================================================================================================
    // 函数功能: OLED外设驱动函数部分
    // 函数标记: OLED_WR_Byte
    // 函数说明: 串行数据写入函数
    // 函数形参:data 要写入的串行数据 cmd 发送命令还是数据控制
    // 函数返回:无
    //-------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_WR_Byte(uint8_t data,uint8_t cmd)
    {
    uint8_t i;
    if(cmd)
    {
    OLED_DC_Set();
    }
    else
    {
    OLED_DC_Clr();
    }

    OLED_CS_Clr();

    for(i=0;i<8;i++)
    {
    OLED_SCL_Clr();

    if(data&0x80)
    {
    OLED_SDA_Set();
    }
    else
    {
    OLED_SDA_Clr();
    }

    OLED_SCL_Set();
    data<<=1;
    }
    OLED_CS_Set();
    OLED_DC_Set();
    }
  1. OLED初始化函数

    void OLED_Init(void)
    {
    OLED_Configuare();

    OLED_RES_Clr();
    delay_1ms(200);
    OLED_RES_Set();

    OLED_WR_Byte(0xAE,OLED_CMD);//--display off
    OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
    OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
    OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
    OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
    OLED_WR_Byte(0x81,OLED_CMD); // contract control
    OLED_WR_Byte(0xFF,OLED_CMD);//--128
    OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
    OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
    OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
    OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
    OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
    OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
    OLED_WR_Byte(0x00,OLED_CMD);//
    OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
    OLED_WR_Byte(0x80,OLED_CMD);//
    OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
    OLED_WR_Byte(0x05,OLED_CMD);//
    OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
    OLED_WR_Byte(0xF1,OLED_CMD);//
    OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
    OLED_WR_Byte(0x12,OLED_CMD);//
    OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
    OLED_WR_Byte(0x30,OLED_CMD);//
    OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
    OLED_WR_Byte(0x14,OLED_CMD);//
    OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel

    }

    综上所述,软件spi oled驱动文件完成,接下来就是应用层文件。

    #include "main.h"
    #include "oledfont.h"

    //--------------------------------------------------------------------------------------------------
    // 自定义变量定义 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //--------------------------------------------------------------------------------------------------
    uint8_t OLED_GRAM[128][8];
    //画图光标
    static int _pointx=0;
    static int _pointy=0;

    //如有需要还可以自己迭代字体颜色 文字背景颜色等
    static Type_color _Draw=pix_white;
    static Type_color _fill=pix_white;
    //==================================================================================================
    // 函数功能: OLED显示函数部分
    // 函数标记: SetDrawColor
    // 函数说明: 划线 线条的颜色
    //-------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void SetDrawColor(Type_color value) //就是划线 线条的颜色
    {
    _Draw=value;
    }
    //==================================================================================================
    // 函数功能: OLED显示函数部分
    // 函数标记: GetDrawColor
    // 函数说明:
    //-------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    Type_color GetDrawColor(void)
    {
    return _Draw;
    }
    //==================================================================================================
    // 函数功能: OLED显示函数部分
    // 函数标记: SetFillcolor
    // 函数说明: 填充 实心图形内的颜色
    //-------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void SetFillcolor(Type_color value) //就是填充 实心图形内的颜色
    {
    _fill=value;
    }
    //==================================================================================================
    // 函数功能: OLED显示函数部分
    // 函数标记: SetDrawColor
    // 函数说明: GetFillColor
    //-------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    Type_color GetFillColor(void)
    {
    return _fill;
    }
    //==================================================================================================
    // 函数功能: OLED外设驱动函数部分
    // 函数标记: OLED_Refresh_Gram
    // 函数说明: 更新显存到LCD
    //-------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_Refresh_Gram(void)
    {
    uint8_t i,n;
    for(i=0;i<8;i++)
    {
    OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
    OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置―列低地址
    OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置―列高地址

    for(n=0;n<128;n++)
    OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
    }
    }
    //==================================================================================================
    // 函数功能: OLED外设驱动函数部分
    // 函数标记: Fill_picture
    // 函数说明: 无
    //-------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void Fill_picture(uint8_t fill_Data)
    {
    uint8_t m,n;
    for(m=0;m<8;m++)
    {
    OLED_WR_Byte(0xb0+m,OLED_CMD); //page0-page1
    OLED_WR_Byte(0x00,OLED_CMD); //low column start address
    OLED_WR_Byte(0x10,OLED_CMD); //high column start address
    for(n=0;n<128;n++)
    {
    OLED_WR_Byte(fill_Data,OLED_DATA);
    }
    }
    }

    //==================================================================================================
    // 实现功能: OLED_Set_Pos 定位光标
    // 函数标记: 外设驱动函数
    // 函数说明: 无
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_Set_Pos(uint8_t X, uint8_t Y)
    {
    OLED_WR_Byte(0xb0+Y,OLED_CMD);
    OLED_WR_Byte(((X&0xf0)>>4)|0x10,OLED_CMD);
    OLED_WR_Byte((X&0x0f),OLED_CMD);
    }

    //==================================================================================================
    // 实现功能: OLED 清除屏幕区域内容
    // 函数标记: 外设驱动函数
    // 函数说明: 无
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // X_Size - X方向尺寸 取值范围 - 1~127
    // Y_Size - Y方向尺寸 取值范围 - 1~ 7
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_AreaClear(uint8_t X, uint8_t Y, uint8_t X_Size, uint8_t Y_Size)
    {
    uint8_t i; // 定义局部变量 用于函数循环计数
    uint8_t j; // 定义局部变量 用于函数循环计数

    for(i=0; i<(Y_Size/8); i++) // 遍历每一行
    {
    OLED_Set_Pos(X, Y+i); // 设置显示坐标
    for(j=0; j<X_Size; j++) // 遍历每一列
    {
    OLED_WR_Byte(0x00,OLED_DATA);
    }
    }
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 显示字符 06x08像素
    // 函数标记: 应用函数 已完成
    // 函数说明: 1. 位置选取不恰当 可能造成字符串显示不完全
    // 2. 如果字库不存在该文字则不显示
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // Char - 待写字符 取值范围 - ASCII字符
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowChar_06x08(uint8_t X, uint8_t Y, uint8_t Char)
    {
    uint8_t i; // 定义局部变量 用于函数循环计数
    uint8_t j; // 定义局部变量 用于函数循环计数
    uint8_t FontCount; // 定义局部变量 用于记录字符字库个数



    FontCount=sizeof(OLED_ASCII_06x08_FontCode)/sizeof(OLED_ASCII_06x08_FontCode[0]);

    for(i=0; i<FontCount; i++) // 遍历每一字库
    {
    if(Char == OLED_ASCII_06x08_FontCode[i].Char)
    {
    OLED_Set_Pos(X,Y); // 设置显示坐标
    for(j=0; j<6; j++) // 遍历每一列
    {
    OLED_WR_Byte(OLED_ASCII_06x08_FontCode[i].Code[j],OLED_DATA);
    }
    break;
    }
    }
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 显示字符串 06x08像素
    // 函数标记: 外设驱动函数
    // 函数说明: 1. 位置选取不恰当 可能造成字符串显示不完全
    // 2. 如果字库不存在该文字则不显示
    // 3. 06x08像素不能显示汉字 只能显示ASCII字符
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // String - 待显示字符串 取值范围 - ASCII字符串
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowString_06x08(uint8_t X, uint8_t Y, uint8_t *String)
    {
    while(*String) // 判断字符串是否为空
    {
    OLED_ShowChar_06x08(X, Y, *String); // 指定位置显示字符
    String++; // 字符串指针移动下一个字节
    X+=6; // X坐标移动下一个位置
    }
    }
    //==================================================================================================
    // 实现功能: OLED 指定位置 显示字符 08x16像素
    // 函数标记: 应用函数 已完成
    // 函数说明: 1. 位置选取不恰当 可能造成字符串显示不完全
    // 2. 如果字库不存在该文字则不显示
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // Char - 待显示字符 取值范围 - ASCII字符
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowChar_08x16(uint8_t X, uint8_t Y, uint8_t Char)
    {
    uint8_t i; // 定义局部变量 用于函数循环计数
    uint8_t j; // 定义局部变量 用于函数循环计数
    uint8_t FontCount; // 定义局部变量 用于记录字符字库个数
    FontCount=sizeof(OLED_ASCII_08x16_FontCode)/sizeof(OLED_ASCII_08x16_FontCode[0]);

    for(i=0; i<FontCount; i++) // 循环查询字符字模位置
    {
    if(Char == OLED_ASCII_08x16_FontCode[i].Char)
    {
    OLED_Set_Pos(X,Y); // 设置显示坐标 用于显示字符
    for(j=0; j<8; j++)
    {
    OLED_WR_Byte(OLED_ASCII_08x16_FontCode[i].Code[j],OLED_DATA);
    }
    OLED_Set_Pos(X,Y+1); // 设置显示坐标 用于显示字符
    for(j=8; j<16; j++)
    {
    OLED_WR_Byte(OLED_ASCII_08x16_FontCode[i].Code[j],OLED_DATA);
    }
    break;
    }
    }
    }
    //==================================================================================================
    // 实现功能: OLED 指定位置 显示中英文混合字符串 08x16像素
    // 函数标记: 外设驱动函数
    // 函数说明: 1. 位置选取不恰当 可能造成字符串显示不完全
    // 2. 目前能显示英文和汉字混合字符串
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // String - 待显示字符串 取值范围 - ASCII和汉字混合字符串
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowString_08x16(uint8_t X, uint8_t Y, uint8_t *String)
    {
    uint8_t Position = 0; // 定义局部变量 用于标记字符串位置

    while(*String)
    {
    // 判断字符串中的某字符的编码值是否小于0x80
    // 如果小于0x80 即为ASCII字符
    // 如果大于0x80 即为汉字字符串
    if(*String < 0x80)
    {
    // 显示ASCII字符
    OLED_ShowChar_08x16(X+Position*8, Y, *String);
    String++; // 字符串指针移动下一个字节
    Position++; // 字符串位置下一个位置
    }
    else
    {
    // 显示汉字
    OLED_ShowCHinese(X+Position*8, Y,*String);
    String+=2; // 字符串指针移动下一个字节
    Position+=2; // 字符串位置下一个位置
    }
    }
    }
    //==================================================================================================
    // 实现功能: OLED 显示汉字
    // 函数标记: 外设驱动函数
    // 函数说明: 无
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // Chinese - 待显示汉字 取值范围 - 单个汉字组成的字符串
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowCHinese(uint8_t X,uint8_t Y,uint8_t Chinese)
    {
    uint8_t count,adder=0;
    OLED_Set_Pos(X,Y);
    for(count=0;count<16;count++)
    {
    OLED_WR_Byte(CHinese[2*Chinese][count],OLED_DATA);
    adder+=1;
    }

    OLED_Set_Pos(X,Y+1);

    for(count=0;count<16;count++)
    {
    OLED_WR_Byte(CHinese[2*Chinese+1][count],OLED_DATA);
    adder+=1;
    }
    }
    //==================================================================================================
    // 实现功能: OLED 显示数组
    // 函数标记: OLED_ShowArray_06x08
    // 函数说明: 无
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // Array 待显示数组
    // Count 待显示整型数字长度
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowArray_06x08(uint8_t X, uint8_t Y, uint8_t *Array, uint8_t Count)
    {
    uint8_t i; // 定义局部变量 用于函数循环计数
    uint8_t j; // 定义局部变量 用于函数循环计数
    uint8_t k; // 定义局部变量 用于函数循环计数
    uint8_t FontCount; // 定义局部变量 用于记录字符字库个数


    FontCount=sizeof(OLED_ASCII_06x08_FontCode)/sizeof(OLED_ASCII_06x08_FontCode[0]);

    for(i=0; i<Count; i++)
    {
    for(j=0; j<FontCount; j++) // 循环查询字符字模位置
    {
    if(*Array == OLED_ASCII_06x08_FontCode[j].Char)
    {
    OLED_Set_Pos(X,Y); // 设置显示坐标 用于显示字符
    for(k=0; k<6; k++)
    {
    OLED_WR_Byte(OLED_ASCII_06x08_FontCode[j].Code[k],OLED_DATA);
    }
    break;
    }
    }
    Array++;
    X += 6; // 数组位置下一个位置
    }
    }
    //==================================================================================================
    // 实现功能: OLED 显示数组
    // 函数标记: OLED_ShowArray_08x16
    // 函数说明: 无
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // Array 待显示数组
    // Count 待显示整型数字长度
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowArray_08x16(uint8_t X, uint8_t Y, uint8_t *Array, uint8_t Count)
    {
    uint8_t i; // 定义局部变量 用于函数循环计数
    uint8_t j; // 定义局部变量 用于函数循环计数
    uint8_t k; // 定义局部变量 用于函数循环计数
    uint8_t FontCount; // 定义局部变量 用于记录字符字库个数

    FontCount=sizeof(OLED_ASCII_08x16_FontCode)/sizeof(OLED_ASCII_08x16_FontCode[0]);

    for(i=0; i<Count; i++)
    {
    for(j=0; j<FontCount; j++) // 循环查询字符字模位置
    {
    if(*Array == OLED_ASCII_08x16_FontCode[j].Char)
    {
    OLED_Set_Pos(X,Y); // 设置显示坐标 用于显示字符
    for(k=0; k<6; k++)
    {
    OLED_WR_Byte(OLED_ASCII_08x16_FontCode[j].Code[k],OLED_DATA);
    }
    break;
    }
    }
    Array++;
    X += 6; // 数组位置下一个位置
    }
    }
    //==================================================================================================
    // 实现功能: OLED 指定位置 显示有符号整形数字
    // 函数标记: 外设驱动函数
    // 函数说明: 1.最大显示5位数字 位置选取不恰当 可能造成数字显示不完全
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // IntegerNumber - 待显示整型数字 取值范围 - -32767~+32768
    // Count - 待显示整型数字长度 取值范围 - 0~5;
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_SignedInteger_06x08(uint8_t X, uint8_t Y, signed short IntegerNumber, uint8_t Count)
    {
    uint8_t IntegerNumber_Array[5]={0}; // 定义局部数组 用于数组数据存储
    // 判断 整型数字正负
    if(IntegerNumber < 0)
    {
    IntegerNumber=0 - IntegerNumber;
    OLED_ShowChar_06x08(X, Y, '-');
    }
    else
    {
    OLED_ShowChar_06x08(X, Y, '+');
    }

    // 计算各位数值的字符
    if(Count>4) IntegerNumber_Array[0] = (IntegerNumber/10000) % 10 + 0x30;
    if(Count>3) IntegerNumber_Array[1] = (IntegerNumber/1000 ) % 10 + 0x30;
    if(Count>2) IntegerNumber_Array[2] = (IntegerNumber/100 ) % 10 + 0x30;
    if(Count>1) IntegerNumber_Array[3] = (IntegerNumber/10 ) % 10 + 0x30;
    if(Count>0) IntegerNumber_Array[4] = (IntegerNumber/1 ) % 10 + 0x30;

    // 执行显示操作
    OLED_ShowArray_06x08(X+6, Y, &IntegerNumber_Array[5-Count], Count);
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 显示有符号整形数字
    // 函数标记: 外设驱动函数
    // 函数说明: 1.最大显示5位数字 位置选取不恰当 可能造成数字显示不完全
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // IntegerNumber - 待显示整型数字 取值范围 - -32767~+32768
    // Count - 待显示整型数字长度 取值范围 - 0~5;
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_SignedInteger_08x16(uint8_t X, uint8_t Y, signed short IntegerNumber, uint8_t Count)
    {
    uint8_t IntegerNumber_Array[5]={0}; // 定义局部数组 用于数组数据存储
    // 判断 整型数字正负
    if(IntegerNumber < 0)
    {
    IntegerNumber=0 - IntegerNumber;
    OLED_ShowChar_08x16(X, Y, '-');
    }
    else
    {
    OLED_ShowChar_08x16(X, Y, '+');
    }

    // 计算各位数值的字符
    if(Count>4) IntegerNumber_Array[0] = (IntegerNumber/10000) % 10 + 0x30;
    if(Count>3) IntegerNumber_Array[1] = (IntegerNumber/1000 ) % 10 + 0x30;
    if(Count>2) IntegerNumber_Array[2] = (IntegerNumber/100 ) % 10 + 0x30;
    if(Count>1) IntegerNumber_Array[3] = (IntegerNumber/10 ) % 10 + 0x30;
    if(Count>0) IntegerNumber_Array[4] = (IntegerNumber/1 ) % 10 + 0x30;

    // 执行显示操作
    OLED_ShowArray_08x16(X+6, Y, &IntegerNumber_Array[5-Count], Count);
    }
    //==================================================================================================
    // 实现功能: OLED 指定位置 显示无符号整形数字
    // 函数标记: 外设驱动函数
    // 函数说明: 1.最大显示5位数字 位置选取不恰当 可能造成数字显示不完全
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // IntegerNumber - 待显示整型数字 取值范围 - -32767~+32768
    // Count - 待显示整型数字长度 取值范围 - 0~5;
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_UnsignedInteger_06x08(uint8_t X, uint8_t Y, uint16_t IntegerNumber, uint8_t Count)
    {
    uint8_t IntegerNumber_Array[5]={0}; // 定义局部数组 用于数组数据存储

    // 计算各位数值的字符
    if(Count>4) IntegerNumber_Array[0] = (IntegerNumber/10000) % 10 + 0x30;
    if(Count>3) IntegerNumber_Array[1] = (IntegerNumber/1000 ) % 10 + 0x30;
    if(Count>2) IntegerNumber_Array[2] = (IntegerNumber/100 ) % 10 + 0x30;
    if(Count>1) IntegerNumber_Array[3] = (IntegerNumber/10 ) % 10 + 0x30;
    if(Count>0) IntegerNumber_Array[4] = (IntegerNumber/1 ) % 10 + 0x30;

    // 执行显示操作
    OLED_ShowArray_06x08(X, Y, &IntegerNumber_Array[5-Count], Count);
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 显示无符号整形数字
    // 函数标记: 外设驱动函数
    // 函数说明: 1.最大显示5位数字 位置选取不恰当 可能造成数字显示不完全
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // IntegerNumber - 待显示整型数字 取值范围 - -32767~+32768
    // Count - 待显示整型数字长度 取值范围 - 0~5;
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_UnsignedInteger_08x16(uint8_t X, uint8_t Y, uint16_t IntegerNumber, uint8_t Count)
    {
    uint8_t IntegerNumber_Array[5]={0}; // 定义局部数组 用于数组数据存储

    // 计算各位数值的字符
    if(Count>4) IntegerNumber_Array[0] = (IntegerNumber/10000) % 10 + 0x30;
    if(Count>3) IntegerNumber_Array[1] = (IntegerNumber/1000 ) % 10 + 0x30;
    if(Count>2) IntegerNumber_Array[2] = (IntegerNumber/100 ) % 10 + 0x30;
    if(Count>1) IntegerNumber_Array[3] = (IntegerNumber/10 ) % 10 + 0x30;
    if(Count>0) IntegerNumber_Array[4] = (IntegerNumber/1 ) % 10 + 0x30;

    // 执行显示操作
    OLED_ShowArray_08x16(X, Y, &IntegerNumber_Array[5-Count], Count);
    }
    //==================================================================================================
    // 实现功能: OLED 指定位置 显示06x08大小的浮点数字
    // 函数标记: 外设驱动函数
    // 函数说明: float型数据有效数字显示7位 double型数据有效数字16位
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // FloatNumber - 待显示浮点型数字 取值范围 - -99999.99999~99999.99999
    // Count1 - 整数显示位数 取值范围 - 0~5
    // Count2 - 小数显示位数 取值范围 - 0~5
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_Float_06x08(uint8_t X, uint8_t Y, float FloatNumber, uint8_t Count1, uint8_t Count2)
    {
    uint8_t Number_Integer_Array[5]; // 定义局部数组 用于存储整数位各位数据
    uint8_t Number_Decimal_Array[5]; // 定义局部数组 用于存储小数位各位数据

    unsigned long Number_Integer = 0; // 定义局部变量 表示浮点数的 整数部分
    unsigned long Number_Decimal = 0; // 定义局部变量 表示浮点数的 小数部分

    if(FloatNumber < 0)
    {
    FloatNumber= 0 - FloatNumber;
    OLED_ShowChar_06x08(X,Y,'-');
    }
    else
    {
    OLED_ShowChar_06x08(X,Y,'+');
    }
    //----------------------------------------------------------------------------------------------
    // 限制 显示字符数
    //----------------------------------------------------------------------------------------------
    // 由于由于float型的有效十进制数值最多为7位 即整数位 + 小数位 数量一定小于等于7
    while((Count1 + Count2 > 7 ))
    {
    if((Count1 > 5) && (Count1 != 0))
    {
    --Count1;
    }
    else
    {
    --Count2;
    }
    }
    Number_Integer = (unsigned long)(FloatNumber); // 取整数部分
    Number_Decimal = (unsigned long)((FloatNumber - Number_Integer + 0.000005) * 1e5); // 取小数部分 1e5科学计数法

    Number_Integer_Array[0] = Number_Integer/10000 % 10 + 0x30; // 计算整数部分
    Number_Integer_Array[1] = Number_Integer/ 1000 % 10 + 0x30;
    Number_Integer_Array[2] = Number_Integer/ 100 % 10 + 0x30;
    Number_Integer_Array[3] = Number_Integer/ 10 % 10 + 0x30;
    Number_Integer_Array[4] = Number_Integer/ 1 % 10 + 0x30;

    Number_Decimal_Array[0] = Number_Decimal/10000 % 10 + 0x30; // 计算小数部分
    Number_Decimal_Array[1] = Number_Decimal/ 1000 % 10 + 0x30;
    Number_Decimal_Array[2] = Number_Decimal/ 100 % 10 + 0x30;
    Number_Decimal_Array[3] = Number_Decimal/ 10 % 10 + 0x30;
    Number_Decimal_Array[4] = Number_Decimal/ 1 % 10 + 0x30;

    OLED_ShowArray_06x08(X+6, Y, &Number_Integer_Array[5-Count1], Count1); // 显示整数位
    OLED_ShowChar_06x08( X+(1+Count1)*6, Y, '.'); // 显示小数点
    OLED_ShowArray_06x08(X+(2+Count1)*6, Y, &Number_Decimal_Array[0], Count2); // 显示小数位
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 显示08x16大小的浮点数字
    // 函数标记: 外设驱动函数
    // 函数说明: float型数据有效数字显示7位 double型数据有效数字16位
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // FloatNumber - 待显示浮点型数字 取值范围 - -99999.99999~99999.99999
    // Count1 - 整数显示位数 取值范围 - 0~5
    // Count2 - 小数显示位数 取值范围 - 0~5
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_Float_08x16(uint8_t X, uint8_t Y, float FloatNumber, uint8_t Count1, uint8_t Count2)
    {
    uint8_t Number_Integer_Array[5]; // 定义局部数组 用于存储整数位各位数据
    uint8_t Number_Decimal_Array[5]; // 定义局部数组 用于存储小数位各位数据

    unsigned long Number_Integer = 0; // 定义局部变量 表示浮点数的 整数部分
    unsigned long Number_Decimal = 0; // 定义局部变量 表示浮点数的 小数部分

    if(FloatNumber < 0)
    {
    FloatNumber= 0 - FloatNumber;
    OLED_ShowChar_08x16(X,Y,'-');
    }
    else
    {
    OLED_ShowChar_08x16(X,Y,'+');
    }
    //----------------------------------------------------------------------------------------------
    // 限制 显示字符数
    //----------------------------------------------------------------------------------------------
    // 由于由于float型的有效十进制数值最多为7位 即整数位 + 小数位 数量一定小于等于7
    while((Count1 + Count2 > 7 ))
    {
    if((Count1 > 5) && (Count1 != 0))
    {
    --Count1;
    }
    else
    {
    --Count2;
    }
    }
    Number_Integer = (unsigned long)(FloatNumber); // 取整数部分
    Number_Decimal = (unsigned long)((FloatNumber - Number_Integer + 0.000005) * 1e5); // 取小数部分 1e5科学计数法

    Number_Integer_Array[0] = Number_Integer/10000 % 10 + 0x30; // 计算整数部分
    Number_Integer_Array[1] = Number_Integer/ 1000 % 10 + 0x30;
    Number_Integer_Array[2] = Number_Integer/ 100 % 10 + 0x30;
    Number_Integer_Array[3] = Number_Integer/ 10 % 10 + 0x30;
    Number_Integer_Array[4] = Number_Integer/ 1 % 10 + 0x30;

    Number_Decimal_Array[0] = Number_Decimal/10000 % 10 + 0x30; // 计算小数部分
    Number_Decimal_Array[1] = Number_Decimal/ 1000 % 10 + 0x30;
    Number_Decimal_Array[2] = Number_Decimal/ 100 % 10 + 0x30;
    Number_Decimal_Array[3] = Number_Decimal/ 10 % 10 + 0x30;
    Number_Decimal_Array[4] = Number_Decimal/ 1 % 10 + 0x30;

    OLED_ShowArray_08x16(X+6, Y, &Number_Integer_Array[5-Count1], Count1); // 显示整数位
    OLED_ShowChar_08x16( X+(1+Count1)*6, Y, '.'); // 显示小数点
    OLED_ShowArray_08x16(X+(2+Count1)*6, Y, &Number_Decimal_Array[0], Count2); // 显示小数位
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 显示06x08大小的二进制数字
    // 函数标记: 外设驱动函数
    // 函数说明: 1. 位置选取不恰当 可能造成字符串显示不完全
    // 2. 显示8位二进制数字 主要作为寄存器数据显示
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // BinaryNumber - 待显示二进制数字 取值范围 - 0~4294967295
    // Count - 二进制显示位数 取值范围 - 1~16
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_Binary_06x08(uint8_t X, uint8_t Y, unsigned long BinaryNumber, uint8_t Count)
    {
    uint8_t i; // 定义局部变量 用于函数循环计数

    for(i=Count; i>0; i--)
    {
    if(BinaryNumber & ( 1 << (Count-1) ))
    {
    OLED_ShowChar_06x08(X, Y, '1'); // 显示二进制字符'1'
    }
    else
    {
    OLED_ShowChar_06x08(X, Y, '0'); // 显示二进制字符'1'
    }
    BinaryNumber <<= 1; // 移位运算
    X += 6; // 数组位置下一个位置
    }
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 显示06x08大小的十六进制数字
    // 函数标记: 外设驱动函数
    // 函数说明: 1. 位置选取不恰当 可能造成字符串显示不完全
    // 2. 显示8位二进制数字 主要作为寄存器数据显示
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // BinaryNumber - 待显示二进制数字 取值范围 - 0~4294967295
    // Count - 二进制显示位数 取值范围 - 1~8
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_ShowNumber_Hex_06x08(uint8_t X, uint8_t Y, unsigned long HexNumber, uint8_t Count)
    {
    uint8_t i; // 定义局部变量 用于函数循环计数
    unsigned long Number; // 定义局部变量 用于装载数据
    for(i=Count; i>0; i--)
    {
    Number = HexNumber>>(4*(i-1)) & 0x0000000F;
    if(Number<10)
    {
    OLED_ShowChar_06x08(X, Y, '0'+Number);
    }
    else
    {
    OLED_ShowChar_06x08(X, Y, 'A'+(Number-10));
    }
    X += 6; // 数组位置下一个位置
    }
    }

    //==================================================================================================
    // 实现功能: OLED 指定位置 画点
    // 函数标记: 外设驱动函数
    // 函数说明:
    //--------------------------------------------------------------------------------------------------
    // 输入参量: //画点
    // //x:0~127
    // //y:0~63
    // //t:1 填充 0,清空
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_DrawDot(uint8_t X,uint8_t Y,uint8_t T)
    {
    uint8_t pos,bx,temp=0;
    if( X>127|| Y>63) return;
    pos=(Y)/8;
    bx=Y%8;
    temp=1<<(bx);
    if(T)
    OLED_GRAM[X][pos]|=temp;
    else
    OLED_GRAM[X][pos]&=~temp;

    OLED_Refresh_Gram();
    }
    //==================================================================================================
    // 实现功能: OLED 指定位置 绘制直线数据
    // 函数标记: 外设驱动函数
    // 函数说明: 该点为8个像素的竖线 并非实际像素点
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X1,X2 - X方向坐标 取值范围 - 0~127
    // Y1,Y2 - Y方向坐标 取值范围 - 0~ 7
    // 输出参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_DrawLine(int X1,int Y1,int X2,int Y2)
    {
    unsigned short us;
    unsigned short usX_Current, usY_Current;

    int lError_X = 0, lError_Y = 0, lDelta_X, lDelta_Y, lDistance;
    int lIncrease_X, lIncrease_Y;

    lDelta_X = X2 - X1; //计算坐标增量
    lDelta_Y = Y2 - Y1;

    usX_Current = X1;
    usY_Current = Y1;

    if ( lDelta_X > 0 )
    lIncrease_X = 1; //设置单步正方向
    else if ( lDelta_X == 0 )
    lIncrease_X = 0; //垂直线
    else
    {
    lIncrease_X = -1; //设置单步反方向
    lDelta_X = - lDelta_X;
    }

    //Y轴的处理方式与上图X轴的处理方式同理
    if ( lDelta_Y > 0 )
    lIncrease_Y = 1;
    else if ( lDelta_Y == 0 )
    lIncrease_Y = 0; //水平线
    else
    {
    lIncrease_Y = -1;
    lDelta_Y = - lDelta_Y;
    }

    //选取不那么陡的方向依次画点
    if ( lDelta_X > lDelta_Y )
    lDistance = lDelta_X;
    else
    lDistance = lDelta_Y;

    //依次画点 进入缓存区 画好后再刷新缓冲区就好啦
    for ( us = 0; us <= lDistance + 1; us ++ ) //画线输出
    {
    OLED_DrawDot(usX_Current,usY_Current,GetDrawColor()); //画点
    lError_X += lDelta_X ;
    lError_Y += lDelta_Y ;

    if ( lError_X > lDistance )
    {
    lError_X -= lDistance;
    usX_Current += lIncrease_X;
    }

    if ( lError_Y > lDistance )
    {
    lError_Y -= lDistance;
    usY_Current += lIncrease_Y;
    }
    }
    }
    void MoveTo(int x,int y)
    {
    _pointx=x;
    _pointy=y;
    }
    void LineTo(int x,int y)
    {
    OLED_DrawLine(_pointx,_pointy,x,y);
    _pointx=x;
    _pointy=y;

    }
    //绘制一个点
    void DrawPixel(int x,int y)
    {
    OLED_DrawDot(x,y,GetDrawColor());
    }
    //功能:快速绘制一条水平线 w为长度
    void DrawFastHLine(int x, int y, unsigned char w)
    {
    int end = x+w;
    int a;

    Type_color color =GetDrawColor();
    for ( a = MAX(0,x); a < MIN(end,SCREEN_COLUMN); a++)
    {
    OLED_DrawDot(a,y,color);
    }
    }
    //功能:快速绘制一条垂直线 h为高度
    void DrawFastVLine(int x, int y, unsigned char h)
    {
    int end = y+h;
    int a;

    Type_color color =GetDrawColor();
    for (a = MAX(0,y); a < MIN(end,SCREEN_ROW); a++)
    {
    OLED_DrawDot(x,a,color);
    }
    }
    //绘制折线 开始和转折点的坐标 总点个数
    void DrawPolyLineTo(const TypeXY *points,int num)
    {
    int i=0;
    MoveTo(points[0].x,points[0].y);
    for(i=1;i<num;i++)
    {
    LineTo(points[i].x,points[i].y);
    }
    }
    //==================================================================================================
    // 实现功能: OLED 指定位置 绘制图像 Draw_BMP
    // 函数标记: 外设驱动函数
    // 函数说明:
    //--------------------------------------------------------------------------------------------------
    // 输入参量: X - X方向坐标 取值范围 - 0~127
    // Y - Y方向坐标 取值范围 - 0~ 7
    // X_Size - X方向尺寸大小 取值范围 - 0~127
    // Y_Size - Y方向尺寸大小 取值范围 - 0~7
    // Image - 图像数据
    // 输出参量: 无
    /*功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void Draw_BMP(uint8_t X0,uint8_t Y0,uint8_t X1,uint8_t Y1,uint8_t BMP[])
    {
    uint32_t j=0;
    uint8_t x,y;

    if(Y1%8==0) y=Y1/8;
    else y=Y1/8+1;
    for(y=Y0;y<Y1;y++)
    {
    OLED_Set_Pos(X0,y);
    for(x=X0;x<X1;x++)
    {
    OLED_WR_Byte(BMP[j++],OLED_DATA);
    }
    }
    }

    //==================================================================================================
    ///**
    // * @brief 在 oled 显示器上使用 Bresenham 算法画圆
    // * @param usX_Center :在特定扫描方向下圆心的X坐标
    // * @param usY_Center :在特定扫描方向下圆心的Y坐标
    // * @param usRadius:圆的半径(单位:像素)
    // * @param ucFilled :选择是否填充该圆
    // * 该参数为以下值之一:
    // * @arg 0 :空心圆
    // * @arg 1 :实心圆
    // * @retval 无
    // */
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_DrawCircle( uint16_t usX_Center, uint16_t usY_Center, uint16_t usRadius, uint8_t ucFilled )
    {
    int16_t sCurrentX, sCurrentY;
    int16_t sError;


    sCurrentX = 0; sCurrentY = usRadius;

    sError = 3 - ( usRadius << 1 ); //判断下个点位置的标志


    while ( sCurrentX <= sCurrentY )
    {
    int16_t sCountY;


    if ( ucFilled )
    for ( sCountY = sCurrentX; sCountY <= sCurrentY; sCountY ++ )
    {
    OLED_DrawDot ( usX_Center + sCurrentX, usY_Center + sCountY,OLED_DATA ); //1,研究对象
    OLED_DrawDot ( usX_Center - sCurrentX, usY_Center + sCountY,OLED_DATA); //2
    OLED_DrawDot ( usX_Center - sCountY, usY_Center + sCurrentX,OLED_DATA); //3
    OLED_DrawDot ( usX_Center - sCountY, usY_Center - sCurrentX,OLED_DATA ); //4
    OLED_DrawDot ( usX_Center - sCurrentX, usY_Center - sCountY,OLED_DATA ); //5
    OLED_DrawDot ( usX_Center + sCurrentX, usY_Center - sCountY,OLED_DATA ); //6
    OLED_DrawDot ( usX_Center + sCountY, usY_Center - sCurrentX,OLED_DATA ); //7
    OLED_DrawDot ( usX_Center + sCountY, usY_Center + sCurrentX,OLED_DATA ); //0
    }
    else
    {
    OLED_DrawDot ( usX_Center + sCurrentX, usY_Center + sCurrentY,OLED_DATA ); //1,研究对象
    OLED_DrawDot ( usX_Center - sCurrentX, usY_Center + sCurrentY,OLED_DATA ); //2
    OLED_DrawDot ( usX_Center - sCurrentY, usY_Center + sCurrentX,OLED_DATA ); //3
    OLED_DrawDot ( usX_Center - sCurrentY, usY_Center - sCurrentX,OLED_DATA ); //4
    OLED_DrawDot ( usX_Center - sCurrentX, usY_Center - sCurrentY,OLED_DATA ); //5
    OLED_DrawDot ( usX_Center + sCurrentX, usY_Center - sCurrentY,OLED_DATA); //6
    OLED_DrawDot ( usX_Center + sCurrentY, usY_Center - sCurrentX,OLED_DATA); //7
    OLED_DrawDot ( usX_Center + sCurrentY, usY_Center + sCurrentX,OLED_DATA ); //0
    }
    sCurrentX ++;
    if ( sError < 0 )
    sError += 4 * sCurrentX + 6;
    else
    {
    sError += 10 + 4 * ( sCurrentX - sCurrentY );
    sCurrentY --;
    }
    }
    }

    //==================================================================================================
    // 实现功能: OLED LCD_DrawRectangle
    // 函数标记: 外设驱动函数
    // 函数说明: 使用对角点填充矩形
    //--------------------------------------------------------------------------------------------------
    // 输入参量: uint32_t X1, 长度 宽度:俩点坐标(x1,y1 ,(x2,y2)
    // uint32_t Y1,
    // uint32_t X2,
    // uint32_t Y2,
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================

    void LCD_DrawRectangle(uint16_t X1, uint16_t Y1, uint16_t X2, uint16_t Y2)
    {
    OLED_DrawLine(X1,Y1,X2,Y1);
    OLED_DrawLine(X1,Y1,X1,Y2);
    OLED_DrawLine(X1,Y2,X2,Y2);
    OLED_DrawLine(X2,Y1,X2,Y2);
    }

    //==================================================================================================
    // 实现功能: OLED OLED_Fill_Draw_circle //画圆填充
    // 函数标记: 外设驱动函数
    // 函数说明:
    //--------------------------------------------------------------------------------------------------
    // 输入参量: //写画实心圆心(x0,y0),半径r,dot=1填充,dot=0不填充
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void OLED_Fill_Draw_circle(uint8_t X0,uint8_t Y0,uint8_t r,uint8_t dot)
    {
    uint8_t x = 0,y = 0,R = 0;
    for(x = X0-r;x <= X0+r;x++)
    {
    for(y = Y0-r; y <= Y0+r ;y++ )
    {
    R = sqrt(pow(r,2)-pow(x-X0,2))+Y0; //圆方程 x,y反置
    if( (y >= Y0 && y <= R) || (y < Y0 && y >= 2*Y0-R )|| dot == 0 )
    { //点限制在 圆方程内
    OLED_DrawDot(y,x,dot);
    }
    }
    }
    }
    //==================================================================================================
    // 实现功能: OLED_RollDisplay
    // 函数标记: 外设驱动函数
    // 函数说明: //水平滚动
    // 函数完成情况:有问题
    //--------------------------------------------------------------------------------------------------
    // 输入参量: 无
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================

    void OLED_RollDisplay(void)
    {
    OLED_WR_Byte(0x2E,OLED_CMD); //关闭滚动
    OLED_WR_Byte(0x29,OLED_CMD); //水平向左或者右滚动 2A/29
    OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节
    OLED_WR_Byte(0x00,OLED_CMD); //起始页 0
    OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔
    OLED_WR_Byte(0x07,OLED_CMD); //终止页 7
    OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节
    OLED_WR_Byte(0xFF,OLED_CMD); //虚拟字节
    OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动
    }

    //显示图片
    /*
    @brief 显示图片
    @param x0:起始列地址
    y0:起始页地址
    x1:终止列地址
    y1:终止页地址
    BMP[]:存放图片代码的数组
    @retval 无
    */
    void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[])
    {
    unsigned int j = 0; //定义变量
    unsigned char x, y; //定义变量

    if(y1 % 8 == 0)
    {
    y = y1 / 8; //判断终止页是否为8的整数倍
    }
    else
    {
    y = y1 / 8 + 1;
    }

    for(y = y0; y < y1; y++) //从起始页开始,画到终止页
    {
    OLED_Set_Pos(x0, y); //在页的起始列开始画

    for(x = x0; x < x1; x++) //画x1 - x0 列
    {
    //OLED_Write_Date(BMP[j++]);
    OLED_WR_Byte(BMP[j++],OLED_DATA); //画图片的点
    }
    }
    }

    //显示动图
    /*
    @brief 显示动图
    @param x0:起始列地址
    y0:起始页地址
    x1:终止列地址
    y1:终止页地址
    k: 帧个数
    m: 单帧数组大小
    BMP[][m]:存放动图代码的数组
    @retval 无
    */
    void OLED_DrawGIF(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char k, int m, const unsigned char GIF[][m])
    {
    unsigned int j = 0; //定义变量
    unsigned char x, y, i; //定义变量

    if(y1 % 8 == 0)
    {
    y = y1 / 8; //判断终止页是否为8的整数倍
    }
    else
    {
    y = y1 / 8 + 1;
    }

    for (i = 0; i < k; i++) //从第一帧开始画
    {
    j = 0;

    for(y = y0; y < y1; y++) //从起始页开始,画到终止页
    {
    OLED_Set_Pos(x0, y); //在页的起始列开始画

    for(x = x0; x < x1; x++) //画x1 - x0 列
    {
    //OLED_Write_Date(GIF[i][j++]); //画图片的点
    OLED_WR_Byte(GIF[i][j++],OLED_DATA);
    }
    }

    //Delay_Ms(80);
    }
    }


测试

  1. 主函数

    //==================================================================================================
    // 实现功能: oled_test测试函数
    // 函数说明: 采用软件IIC 进行配置 SDA PB9 SCL in
    // 函数备注: 测试正常
    //--------------------------------------------------------------------------------------------------
    // | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    //==================================================================================================
    void oled_example(void)
    {
    OLED_ShowString_08x16(0,0,"GD32 SWSPI OLED");
    OLED_ShowNumber_SignedInteger_06x08(16,2,1234,5);
    OLED_ShowNumber_UnsignedInteger_06x08(64,2,1234,4);
    OLED_ShowString_06x08(32,3,"Time:2023.12.03");
    OLED_ShowNumber_Float_06x08(32,4,123.46,3,3);
    OLED_ShowString_06x08(32,5,"By:Endhub");
    OLED_ShowCHinese(32,6,5);
    OLED_ShowCHinese(48,6,6);
    OLED_ShowCHinese(64,6,7);
    OLED_ShowCHinese(80,6,8);
    //OLED_Clear();
    }
    //
    int main(void)
    {
    Hardware_Init();
    printf("Hardware_Init [ok] \r\n");
    printf("GD32307E-START Baord Testing\r\n");
    OLED_Clear();
    while(1)
    {

    HW_LED_Flash();
    oled_example(); //oled软件spi测试
    OLED_Display_scroll();
    printf("gd32f307_spi_oled 20231203! \r\n");

    }
    }
  2. 测试效果