经验——OLED的使用

型号:HS96L01W 4S03

分辨率:120*64

通讯方式:4线SPI 模式00

MCU:MSPM0G3507(只影响SPI的配置)

        原本照着型号搜到了嘉立创的使用文档,但是实际上并不能正常使用,后来寻到了一篇博客教程【常用模块】OLED显示模块(原理讲解、STM32实例操作)_oled介绍-CSDN博客,博客里写的非常详细且通俗易懂。

        借鉴了上面的初始化函数才能正常完成初始化,初始化代码如下:

void OLED_Init(void)
{
    SPI_Init(3,0);//4分频,模式为0,0

    DL_GPIO_initDigitalOutput(GPIO_OLED_RES_IOMUX);
    DL_GPIO_initDigitalOutput(GPIO_OLED_DC_IOMUX);
    DL_GPIO_clearPins(GPIO_OLED_PORT, GPIO_OLED_DC_PIN);
    DL_GPIO_setPins(GPIO_OLED_PORT, GPIO_OLED_RES_PIN);
    DL_GPIO_enableOutput(GPIO_OLED_PORT, GPIO_OLED_RES_PIN | GPIO_OLED_DC_PIN);


    //OLED复位

    OLED_RES_Ctrl();//RES 置0

    delay_ms(200);//延时 200ms

    OLED_RES_Set();//RES 置1

    //OLED初始化

    OLED_WR_Byte(0xAE, OLED_CMD);//关闭显示
    OLED_WR_Byte(0xD5, OLED_CMD);//设置时钟分频因子,震荡频率
    OLED_WR_Byte(80, OLED_CMD);  //[3:0],分频因子;[7:4],震荡频率
    OLED_WR_Byte(0xA8, OLED_CMD);//设置驱动路数
    OLED_WR_Byte(0X3F, OLED_CMD);//默认0X3F(1/64)
    OLED_WR_Byte(0xD3, OLED_CMD);//设置显示偏移
    OLED_WR_Byte(0X00, OLED_CMD);//默认为0

    OLED_WR_Byte(0x40, OLED_CMD);//设置显示开始行 [5:0],行数.

    OLED_WR_Byte(0x8D, OLED_CMD);//电荷泵设置
    OLED_WR_Byte(0x14, OLED_CMD);//bit2,开启/关闭
    OLED_WR_Byte(0x20, OLED_CMD);//设置内存地址模式
    OLED_WR_Byte(0x02, OLED_CMD);//[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
    OLED_WR_Byte(0xA1, OLED_CMD);//段重定义设置,bit0:0,0->0;1,0->127;
    OLED_WR_Byte(0xC0, OLED_CMD);//设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
    OLED_WR_Byte(0xDA, OLED_CMD);//设置COM硬件引脚配置
    OLED_WR_Byte(0x12, OLED_CMD);//[5:4]配置

    OLED_WR_Byte(0x81, OLED_CMD);//对比度设置
    OLED_WR_Byte(0xEF, OLED_CMD);//1~255;默认0X7F (亮度设置,越大越亮)
    OLED_WR_Byte(0xD9, OLED_CMD);//设置预充电周期
    OLED_WR_Byte(0xf1, OLED_CMD);//[3:0],PHASE 1;[7:4],PHASE 2;
    OLED_WR_Byte(0xDB, OLED_CMD);//设置VCOMH 电压倍率
    OLED_WR_Byte(0x30, OLED_CMD);//[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

    OLED_WR_Byte(0xA4, OLED_CMD);//全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
    OLED_WR_Byte(0xA6, OLED_CMD);//设置显示方式;bit0:1,反相显示;0,正常显示
    OLED_WR_Byte(0xAF, OLED_CMD);//开启显示
                                 //这里不能加延迟,否则什么都不显示!!!!!!!!
    OLED_Clear();

    /**下面代码为嘉立创源码,但不能用*/
#if 0
    //
    //    OLED_WR_Byte(0xAE, OLED_CMD);//–turn off oled panel
    //
    //    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(0x81, OLED_CMD);//–set contrast control register
    //
    //    OLED_WR_Byte(0xCF, OLED_CMD);//Set SEG Output Current Brightness
    //
    //    OLED_WR_Byte(0xA1, OLED_CMD);//–Set SEG/Column Mapping 0xa0左右反置 0xa1正常
    //
    //    OLED_WR_Byte(0xC8, OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置  0xc8正常
    //
    //    OLED_WR_Byte(0xA6, OLED_CMD);//–set normal display
    //
    //    OLED_WR_Byte(0xAB, OLED_CMD);//–set multiplex ratio(1 to 64)
    //
    //    OLED_WR_Byte(0x3f, OLED_CMD);//–1/64 duty
    //
    //    OLED_WR_Byte(0xD3, OLED_CMD);//–set display offset Shift Mapping RAM Counter (0x00~0x3F)
    //
    //    OLED_WR_Byte(0x00, OLED_CMD);//–not offset
    //
    //    OLED_WR_Byte(0xd5, OLED_CMD);//–set display dock divide ratio/oscillator frequency
    //
    //    OLED_WR_Byte(0x80, OLED_CMD);//–set divide ratio, Set Clock as 100 Frames/Sec
    //
    //    OLED_WR_Byte(0xD9, OLED_CMD);//–set pre-charge period
    //
    //    OLED_WR_Byte(0xf1, OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1Clock
    //
    //    OLED_WR_Byte(0xDA, OLED_CMD);//–set com pins hardware configuration
    //
    //    OLED_WR_Byte(0x12, OLED_CMD);
    //
    //    OLED_WR_Byte(0xDB, OLED_CMD);//–set vcomh
    //
    //    OLED_WR_Byte(0x30, OLED_CMD);//Set VCOM Deselect Level
    //
    //    OLED_WR_Byte(0x20, OLED_CMD);//–Set Page Addressing Mode (0x00/0x01/0x02)
    //
    //    OLED_WR_Byte(0x02, OLED_CMD);//
    //
    //    OLED_WR_Byte(0x8D, OLED_CMD);//–set Charge Pump enable/disable
    //
    //    OLED_WR_Byte(0x14, OLED_CMD);//–set(0x10) disable
    //
    //    OLED_Clear();
    //
    //    OLED_WR_Byte(0xAF, OLED_CMD);
#endif
}

       

         完整代码如下,为了提高刷新的性能,下面绘画函数没有选择直接更新屏幕,而是只有当所有绘画完成后,再统一调用更新函数。不过关于字体函数的命名有些紊乱

OLED.h

//
// Created by 34753 on 2024/7/22.
//

#ifndef ISB_TI_OLED_H
#define ISB_TI_OLED_H
#include "ZQ_Conf.h"

#include "ti_init.h"
#include "SPI.h"

/* Port definition for Pin Group GPIO_LCD */
#define GPIO_OLED_PORT (GPIOA)

/* Defines for RS: GPIOA.12 with pinCMx 34 on package pin 5 */
#define GPIO_OLED_RES_PIN (DL_GPIO_PIN_12)
#define GPIO_OLED_RES_IOMUX (IOMUX_PINCM34)
/* Defines for RST: GPIOA.13 with pinCMx 35 on package pin 6 */
#define GPIO_OLED_DC_PIN (DL_GPIO_PIN_13)
#define GPIO_OLED_DC_IOMUX (IOMUX_PINCM35)

#define OLED_RES_Ctrl()  DL_GPIO_clearPins(GPIO_OLED_PORT, GPIO_OLED_RES_PIN)
#define OLED_RES_Set()  DL_GPIO_setPins(GPIO_OLED_PORT, GPIO_OLED_RES_PIN)
#define OLED_DC_Ctrl()  DL_GPIO_clearPins(GPIO_OLED_PORT, GPIO_OLED_DC_PIN)
#define OLED_DC_Set()  DL_GPIO_setPins(GPIO_OLED_PORT, GPIO_OLED_DC_PIN)

void OLED_Init(void);
void OLED_Clear();

void OLED_Fill(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t dot);
void OLED_Refresh_Gram(void);
void OLED_ShowChar_1608(uint16_t x, uint16_t y, uint8_t chr);
void OLED_ShowChar_1206(uint16_t x, uint16_t y, char chr);
void OLED_ShowString_1206(uint16_t x, uint16_t y, char *chr, uint16_t length);
void OLED_ShowCustomChar_1616_Fast(uint16_t x, uint16_t y, uint16_t chrNum);
void OLED_ShowCustomString_1616_Fast(uint16_t x, uint16_t y, uint16_t chrNum,uint16_t length);
void OLED_ShowCustomChar_1212_Fast(uint16_t x, uint16_t y, uint16_t chrNum);
void OLED_ShowCustomString_1212_Fast(uint16_t x, uint16_t y, uint16_t chrNum,uint16_t length);
void OLED_Point(uint16_t x, uint16_t y);//只用来画像素点,并不作为其他函数的子函数,若需则用OLED_DrawPoint

void OLED_Rectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t width);//显示矩形框
void OLED_Line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width);//显示线条
void OLED_Circle(uint16_t x, uint16_t y, uint16_t r, uint16_t width);//显示圆



#endif//ISB_TI_OLED_H

OLED.c

//
// Created by 34753 on 2024/7/22.
//

#include "OLED.h"
#include "DATA/FONT.h"
#include "Timer.h"
#include <stdlib.h>

#define OLED_CMD 0 //write command
#define OLED_DATA 1//write data

uint8_t OLED_GRAM[128][8];//缓冲区数组
static const uint8_t lut[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};//用于加速描点计算

/**内联函数*/

//画点
//x:0~127
//y:0~63
//t:1 填充 0,清空
static inline void OLED_WR_Byte(uint8_t data, uint8_t cmd)
{
    if (cmd)
    {
        OLED_DC_Set();
    }
    else
    {
        OLED_DC_Ctrl();
    }

    SPI_WriteByte(data);
    OLED_DC_Set();
}

static inline void OLED_DrawPoint_Inline(uint16_t x, uint16_t y, uint8_t t)
{
#if 0
        uint8_t pos, bx, temp = 0;
        if (x > 127 || y > 63)
            return;//超出范围了.
        pos = 7 - y>>3;// 7-y/8
        bx = y % 8;
        temp = 1 << (7 - bx);
        if (t)
            OLED_GRAM[x][pos] |= temp;
        else
            OLED_GRAM[x][pos] &= ~temp;
#endif

    /**优化后*/
    uint8_t pos = 7 - (y / 8);//计算页数

    if (t)
        OLED_GRAM[x][pos] |= lut[y % 8];
    else
        OLED_GRAM[x][pos] &= ~lut[y % 8];
}

static inline void OLED_DrawPointDefault_Inline(uint8_t x, uint8_t y)
{
#if 0
        uint8_t pos, bx, temp = 0;
        if (x > 127 || y > 63)
            return;//超出范围了.
        pos = 7 - y>>3;// 7-y/8
        bx = y % 8;
        temp = 1 << (7 - bx);
        if (t)
            OLED_GRAM[x][pos] |= temp;
        else
            OLED_GRAM[x][pos] &= ~temp;
#endif

    /**优化后*/
    uint8_t pos = 7 - (y / 8);//计算页数
    OLED_GRAM[x][pos] |= lut[y % 8];
}

//更新显存到LCD
static inline void OLED_Refresh_Gram_Inline(void)
{
    for (uint8_t 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 (uint8_t n = 0; n < 128; n++)
            OLED_WR_Byte(OLED_GRAM[n][i], OLED_DATA);
    }
}
static inline void OLED_FillRect_Inline(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
    // 遍历矩形的宽度和高度,逐行逐列调用OLED_Point
    for (uint16_t row = 0; row < h; row++)
    {
        for (uint16_t col = 0; col < w; col++)
        {
            // 调用OLED_Point在当前位置绘制一个点
            OLED_DrawPoint_Inline(x + col, y + row, 1);
        }
    }
}

void OLED_Line_In(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width)
{
    int deltaX = x2 - x1;
    int deltaY = y2 - y1;
    uint16_t signX = (deltaX > 0) ? 1 : ((deltaX < 0) ? -1 : 0);
    uint16_t signY = (deltaY > 0) ? 1 : ((deltaY < 0) ? -1 : 0);
    deltaX = abs(deltaX);
    deltaY = abs(deltaY);

    if (deltaX > deltaY)
    {
        int fraction = deltaY * 2 - deltaX;
        for (; x1 != x2; x1 += signX)
        {
            OLED_FillRect_Inline(x1, y1, width, width);// Draw a square instead of a point.
            if (fraction >= 0)
            {
                y1 += signY;
                fraction -= deltaX * 2;
            }
            fraction += deltaY * 2;
        }
    }
    else
    {
        int fraction = deltaX * 2 - deltaY;
        for (; y1 != y2; y1 += signY)
        {
            OLED_FillRect_Inline(x1, y1, width, width);// Draw a square instead of a point.
            if (fraction >= 0)
            {
                x1 += signX;
                fraction -= deltaY * 2;
            }
            fraction += deltaX * 2;
        }
    }

    // Draw the last point or adjust if necessary
    OLED_FillRect_Inline(x1, y1, width, width);
}

void drawCircleHelper_In(uint16_t x_center, uint16_t y_center, int x0, int y0, uint16_t width)
{
    for (uint16_t i = 0; i < width; i++)
    {
        for (uint16_t j = 0; j < width; j++)
        {
            if ((i * i + j * j) <= (width * width))
            {
                OLED_DrawPointDefault_Inline(x_center + x0 + i, y_center + y0 + j);
                OLED_DrawPointDefault_Inline(x_center + x0 + i, y_center - (y0 + j));
                OLED_DrawPointDefault_Inline(x_center - (x0 + i), y_center + y0 + j);
                OLED_DrawPointDefault_Inline(x_center - (x0 + i), y_center - (y0 + j));
                OLED_DrawPointDefault_Inline(x_center + (y0 + j), y_center + x0 + i);
                OLED_DrawPointDefault_Inline(x_center + (y0 + j), y_center - (x0 + i));
                OLED_DrawPointDefault_Inline(x_center - (y0 + j), y_center + x0 + i);
                OLED_DrawPointDefault_Inline(x_center - (y0 + j), y_center - (x0 + i));
            }
        }
    }
}


void OLED_Init(void)
{
    SPI_Init(3,0);//模式为1,1

    DL_GPIO_initDigitalOutput(GPIO_OLED_RES_IOMUX);
    DL_GPIO_initDigitalOutput(GPIO_OLED_DC_IOMUX);
    DL_GPIO_clearPins(GPIO_OLED_PORT, GPIO_OLED_DC_PIN);
    DL_GPIO_setPins(GPIO_OLED_PORT, GPIO_OLED_RES_PIN);
    DL_GPIO_enableOutput(GPIO_OLED_PORT, GPIO_OLED_RES_PIN | GPIO_OLED_DC_PIN);


    //OLED复位

    OLED_RES_Ctrl();//RES 置0

    delay_ms(200);//延时 200ms

    OLED_RES_Set();//RES 置1

    //OLED初始化

    OLED_WR_Byte(0xAE, OLED_CMD);//关闭显示
    OLED_WR_Byte(0xD5, OLED_CMD);//设置时钟分频因子,震荡频率
    OLED_WR_Byte(80, OLED_CMD);  //[3:0],分频因子;[7:4],震荡频率
    OLED_WR_Byte(0xA8, OLED_CMD);//设置驱动路数
    OLED_WR_Byte(0X3F, OLED_CMD);//默认0X3F(1/64)
    OLED_WR_Byte(0xD3, OLED_CMD);//设置显示偏移
    OLED_WR_Byte(0X00, OLED_CMD);//默认为0

    OLED_WR_Byte(0x40, OLED_CMD);//设置显示开始行 [5:0],行数.

    OLED_WR_Byte(0x8D, OLED_CMD);//电荷泵设置
    OLED_WR_Byte(0x14, OLED_CMD);//bit2,开启/关闭
    OLED_WR_Byte(0x20, OLED_CMD);//设置内存地址模式
    OLED_WR_Byte(0x02, OLED_CMD);//[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
    OLED_WR_Byte(0xA1, OLED_CMD);//段重定义设置,bit0:0,0->0;1,0->127;
    OLED_WR_Byte(0xC0, OLED_CMD);//设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
    OLED_WR_Byte(0xDA, OLED_CMD);//设置COM硬件引脚配置
    OLED_WR_Byte(0x12, OLED_CMD);//[5:4]配置

    OLED_WR_Byte(0x81, OLED_CMD);//对比度设置
    OLED_WR_Byte(0xEF, OLED_CMD);//1~255;默认0X7F (亮度设置,越大越亮)
    OLED_WR_Byte(0xD9, OLED_CMD);//设置预充电周期
    OLED_WR_Byte(0xf1, OLED_CMD);//[3:0],PHASE 1;[7:4],PHASE 2;
    OLED_WR_Byte(0xDB, OLED_CMD);//设置VCOMH 电压倍率
    OLED_WR_Byte(0x30, OLED_CMD);//[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

    OLED_WR_Byte(0xA4, OLED_CMD);//全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
    OLED_WR_Byte(0xA6, OLED_CMD);//设置显示方式;bit0:1,反相显示;0,正常显示
    OLED_WR_Byte(0xAF, OLED_CMD);//开启显示
                                 //这里不能加延迟,否则什么都不显示!!!!!!!!
    OLED_Clear();

    /**下面代码为嘉立创源码,但不能用*/
#if 0
    //
    //    OLED_WR_Byte(0xAE, OLED_CMD);//–turn off oled panel
    //
    //    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(0x81, OLED_CMD);//–set contrast control register
    //
    //    OLED_WR_Byte(0xCF, OLED_CMD);//Set SEG Output Current Brightness
    //
    //    OLED_WR_Byte(0xA1, OLED_CMD);//–Set SEG/Column Mapping 0xa0左右反置 0xa1正常
    //
    //    OLED_WR_Byte(0xC8, OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置  0xc8正常
    //
    //    OLED_WR_Byte(0xA6, OLED_CMD);//–set normal display
    //
    //    OLED_WR_Byte(0xAB, OLED_CMD);//–set multiplex ratio(1 to 64)
    //
    //    OLED_WR_Byte(0x3f, OLED_CMD);//–1/64 duty
    //
    //    OLED_WR_Byte(0xD3, OLED_CMD);//–set display offset Shift Mapping RAM Counter (0x00~0x3F)
    //
    //    OLED_WR_Byte(0x00, OLED_CMD);//–not offset
    //
    //    OLED_WR_Byte(0xd5, OLED_CMD);//–set display dock divide ratio/oscillator frequency
    //
    //    OLED_WR_Byte(0x80, OLED_CMD);//–set divide ratio, Set Clock as 100 Frames/Sec
    //
    //    OLED_WR_Byte(0xD9, OLED_CMD);//–set pre-charge period
    //
    //    OLED_WR_Byte(0xf1, OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1Clock
    //
    //    OLED_WR_Byte(0xDA, OLED_CMD);//–set com pins hardware configuration
    //
    //    OLED_WR_Byte(0x12, OLED_CMD);
    //
    //    OLED_WR_Byte(0xDB, OLED_CMD);//–set vcomh
    //
    //    OLED_WR_Byte(0x30, OLED_CMD);//Set VCOM Deselect Level
    //
    //    OLED_WR_Byte(0x20, OLED_CMD);//–Set Page Addressing Mode (0x00/0x01/0x02)
    //
    //    OLED_WR_Byte(0x02, OLED_CMD);//
    //
    //    OLED_WR_Byte(0x8D, OLED_CMD);//–set Charge Pump enable/disable
    //
    //    OLED_WR_Byte(0x14, OLED_CMD);//–set(0x10) disable
    //
    //    OLED_Clear();
    //
    //    OLED_WR_Byte(0xAF, OLED_CMD);
#endif
}


void OLED_Clear()
{
    for (uint16_t 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 (uint16_t n = 0; n < 128; n++)
            OLED_WR_Byte(0x00, OLED_DATA);
    }
}

void OLED_Refresh_Gram(void)
{
    OLED_Refresh_Gram_Inline();
}

//开启OLED显示
void OLED_Display_On(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD);//SET DCDC命令
    OLED_WR_Byte(0X14, OLED_CMD);//DCDC ON
    OLED_WR_Byte(0XAF, OLED_CMD);//DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD);//SET DCDC命令
    OLED_WR_Byte(0X10, OLED_CMD);//DCDC OFF
    OLED_WR_Byte(0XAE, OLED_CMD);//DISPLAY OFF
}


//x1,y1,x2,y2 填充区域的对角坐标
//确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63
//dot:0,清空;1,填充
void OLED_Fill(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t dot)
{
    for (uint16_t x = x1; x <= x2; x++)
    {
        for (uint16_t y = y1; y <= y2; y++)
            OLED_DrawPoint_Inline(x, y, dot);
    }
}


void OLED_Point(uint16_t x, uint16_t y)
{
    OLED_DrawPoint_Inline(x, y, 1);
}


/**
 * @brief   使用自定义字库16*16
 * @param   x,y 横纵坐标
 * @param   chrNum 字符在自定义字库里的位置
 * @note    默认亮显,取模方式为逐列式,低位在前
 * */
void OLED_ShowChineseChar_Fast_In(uint16_t x, uint16_t y, uint16_t chrNum, uint8_t size)
{
    uint8_t temp;
    uint16_t y0 = y;
    uint8_t pos;
    chrNum <<= 1;//由于1616字体数组是16为一行,而字体又是16*16,所以每个字体在字体数组中需要两行

    for (uint8_t i = 0; i < 2; ++i)
    {
        for (uint8_t t = 0; t < size; t++)
        {
            switch (size)
            {
                case 12:
                    temp = Character_Custom_1212[chrNum + i][t];
                    break;

                case 16:
                    temp = Character_Custom_1616[chrNum + i][t];
                    break;

                default:
                    return;//报错
            }
            //对一个字节开始解码
            for (uint8_t t1 = 0; t1 < 8; t1++)
            {
                pos = 7 - (y / 8);//计算页数
                if (temp & 0x1)
                {
                    OLED_GRAM[x][pos] |= lut[y % 8];
                }
                else
                {
                    OLED_GRAM[x][pos] &= ~lut[y % 8];
                }
                temp >>= 1;

                y++;
                //从上到下,如果满16字高则换一列
                if ((y - y0) == 16)
                {
                    y = y0;
                    x++;
                    break;
                }
            }
        }
    }
}

/**
 * @brief   使用自定义字库16*16
 * @param   x,y 横纵坐标
 * @param   chrNum 字符在自定义字库里的位置
 * @note    默认亮显,取模方式为逐列式,低位在前
 * */
void OLED_ShowChar_Fast_In(uint16_t x, uint16_t y, char chr, uint8_t size)
{
    uint8_t temp;
    uint16_t y0 = y;
    uint8_t pos;
    chr = chr - ' ';

    for (uint8_t i = 0; i < 2; ++i)
    {
        for (uint8_t t = 0; t < size; t++)
        {
            switch (size)
            {
                case 12:
                    temp = asc_1206[chr + i][t];
                    break;

                case 16:
                    temp = asc_1608[chr + i][t];
                    break;

                default:
                    return;//报错
            }
            //对一个字节开始解码
            for (uint8_t t1 = 0; t1 < 8; t1++)
            {
                pos = 7 - (y / 8);//计算页数
                if (temp & 0x1)
                {
                    OLED_GRAM[x][pos] |= lut[y % 8];
                }
                else
                {
                    OLED_GRAM[x][pos] &= ~lut[y % 8];
                }
                temp >>= 1;

                y++;
                //从上到下,如果满16字高则换一列
                if ((y - y0) == 16)
                {
                    y = y0;
                    x++;
                    break;
                }
            }
        }
    }
}
void OLED_ShowCustomChar_1616_Fast(uint16_t x, uint16_t y, uint16_t chrNum)
{
    OLED_ShowChineseChar_Fast_In(x, y, chrNum, 16);
}

void OLED_ShowCustomString_1616_Fast(uint16_t x, uint16_t y, uint16_t chrNum, uint16_t length)
{
    for (uint16_t i = 0; i < length; i++)
    {
        OLED_ShowChineseChar_Fast_In(x + i * 16, y, chrNum + i, 16);
    }
}

void OLED_ShowCustomChar_1212_Fast(uint16_t x, uint16_t y, uint16_t chrNum)
{
    OLED_ShowChineseChar_Fast_In(x, y, chrNum, 12);
}
void OLED_ShowChar_1206(uint16_t x, uint16_t y, char chr)
{
    OLED_ShowChar_Fast_In(x, y, chr, 12);
}

void OLED_ShowString_1206(uint16_t x, uint16_t y, char *chr, uint16_t length)
{
    for (uint16_t i = 0; i != '\0'; ++i)
    {
        chr[i] = chr[i] - ' ';
        OLED_ShowChar_Fast_In(x + i * 6, y, chr[i],12);
    }
}

void OLED_ShowCustomString_1212_Fast(uint16_t x, uint16_t y, uint16_t chrNum, uint16_t length)
{
    for (uint16_t i = 0; i < length; i++)
    {
        OLED_ShowChineseChar_Fast_In(x + i * 12, y, chrNum + i, 12);
    }
}


//下面为原代码备份,不要做任何改动!!!
#if 0
//void OLED_ShowCustomChar_1616_Fast(uint8_t x, uint8_t y, uint8_t chrNum)
//{
//    static const uint8_t lut[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
//
//    uint8_t temp;
//    uint8_t y0 = y;
//    chrNum <<= 1;//由于字体数组是16为一行,而字体又是16*16,所以每个字体在字体数组中需要两行
//    for (uint8_t i = 0; i < 2; ++i)
//    {
//        for (uint8_t t = 0; t < 16; t++)
//        {
//            temp = Character_Custom[chrNum + i][t];
//
//            //对一个字节开始解码
//            for (uint8_t t1 = 0; t1 < 8; t1++)
//            {
//                if (temp & 0x1)
//                {
//                    uint8_t pos = 7 - (y / 8);//计算页数
//                    OLED_GRAM[x][pos] |= lut[y % 8];
//                }
//                else
//                {
//                    uint8_t pos = 7 - (y / 8);//计算页数
//                    OLED_GRAM[x][pos] &= ~lut[y % 8];
//                }
//                temp >>= 1;
//                y++;
//                //从上到下,如果满16字高则换一列
//                if ((y - y0) == 16)
//                {
//                    y = y0;
//                    x++;
//                    break;
//                }
//            }
//        }
//    }
//    OLED_Refresh_Gram();//更新显示
//}
#endif
void OLED_ShowChar_1608(uint16_t x, uint16_t y, uint8_t chr)
{
    uint8_t temp, pos;
    uint16_t y0 = y;
    chr = chr - ' ';//得到偏移后的值
    for (uint8_t t = 0; t < 16; t++)
    {
        temp = asc_1608[chr][t];//调用1608字体

        //对一个字节开始解码
        for (uint8_t t1 = 0; t1 < 8; t1++)
        {
            pos = 7 - (y / 8);//计算页数
            if (temp & 0x1)
            {
                OLED_GRAM[x][pos] |= lut[y % 8];
            }
            else
            {
                OLED_GRAM[x][pos] &= ~lut[y % 8];
            }
            temp >>= 1;

            y++;
            //从上到下,如果满16字高则换一列
            if ((y - y0) == 16)
            {
                y = y0;
                x++;
                break;
            }
        }
    }
}


//显示字符串
//x,y:起点坐标
//size:字体大小
//*p:字符串起始地址
void OLED_ShowString(uint8_t x, uint8_t y, const uint8_t *p, uint8_t size)
{
    while ((*p <= '~') && (*p >= ' '))//判断是不是非法字符!
    {
        if (x > (128 - (size / 2)))
        {
            x = 0;
            y += size;
        }
        if (y > (64 - size))
        {
            y = x = 0;
        }
        // OLED_ShowChar(x, y, *p, size, 1);
        x += size / 2;
        p++;
    }
}
//显示矩形框
void OLED_Rectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t width)
{
    OLED_Line_In(x, y, x + w, y, width);
    OLED_Line_In(x + w, y, x + w, y + h, width);
    OLED_Line_In(x, y + h, x + w, y + h, width);
    OLED_Line_In(x, y, x, y + h, width);
}
//显示线条
//void OLED_Line_nowidth(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
//{
//    unsigned int t;
//    int xerr=0,yerr=0,delta_x,delta_y,distance;
//    int incx,incy,uRow,uCol;
//
//    delta_x=x2-x1; //计算坐标增量
//    delta_y=y2-y1;
//    uRow=x1;
//    uCol=y1;
//
//    if(delta_x>0)
//        incx=1; //设置单步方向
//    else if(delta_x==0)
//        incx=0;//垂直线
//    else
//    {
//        incx=-1;delta_x=-delta_x;
//    }
//    if(delta_y>0)
//        incy=1;
//    else if(delta_y==0)
//        incy=0;//水平线
//    else
//    {
//        incy=-1;delta_y=-delta_y;
//    }
//    if( delta_x>delta_y)
//        distance=delta_x; //选取基本增量坐标轴
//    else
//        distance=delta_y;
//    for(t=0;t<=distance+1;t++ )//画线输出
//    {
//        OLED_Point(uRow,uCol);//画点
//        xerr+=delta_x ;
//        yerr+=delta_y ;
//        if(xerr>distance)
//        {
//            xerr-=distance;
//            uRow+=incx;
//        }
//        if(yerr>distance)
//        {
//            yerr-=distance;
//            uCol+=incy;
//        }
//    }
//}

void OLED_Line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width)
{
    OLED_Line_In(x1, y1, x2, y2, width);
}
//显示圆
void OLED_Circle(uint16_t x, uint16_t y, uint16_t r, uint16_t width)
{
    int d = 3 - 2 * r;
    int x0 = 0;
    int y0 = r;

    // 绘制外圆
    drawCircleHelper_In(x, y, x0, y0, width);

    while (x0 <= y0)
    {
        if (d < 0)
        {
            d += 4 * x0 + 6;
        }
        else
        {
            d += 4 * (x0 - y0) + 10;
            y0--;
        }
        x0++;

        // 每次迭代都要画圆的所有八分之一
        drawCircleHelper_In(x, y, x0, y0, width);
    }
}

        

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值