四汐 发表于 2024-3-23 23:37:35

库函数-OLED12864-IIC/SPI-索引字库-显示GBK2312-OLEDPrintf-画点线面-OLED中英文显示

本帖最后由 四汐 于 2024-3-23 23:42 编辑

库函数-OLED12864-IIC/SPI-索引字库-显示GBK2312-OLEDPrintf-画点线面-OLED中英文显示-自动换行显示-兼容0.96/1.3寸屏

近期,无意间看到官网上的库函数(有时候缘分就是这么巧妙),于是便下载下来看了一下。不看不知道,一看吓一跳!!!

简言之就是,原本写代码需要配置寄存器的时候,得不断地翻用户手册,看看各种配置需要怎么设置,才可以开始写代码。
看了库函数之后,发现直接可以使用结构体配置,各种参数配置也是一目了然,实在不理解再翻手册也可以很容易看明白,而且还配有示例程序,结合则看,很快就可以入手。
看了库函数,对我这种小白而言,真的有很多值得学习的地方,推荐大家也可以看看学习学习。话不多说,贴完我要搞毕设找工作去咯,不然就完蛋了。


言归正传,我曾经在论坛上分享过一篇关于使用IIC/SPI协议驱动OLED12864屏幕的文章。(懒得贴了,时代在进步!)
现在,我使用库函数重写了一遍驱动函数,伴随着ISP工具新增取模工具,我也更新一些新的显示函数。
这里以IIC的版本展示吧,留言下载,有问题请留言喔!!


旧版本演示视频:
https://www.douyin.com/user/self?modal_id=7321033906550000923&showTab=post
新增函数演示视频:
https://www.douyin.com/user/self?modal_id=7345036745228045568&showTab=post

(本来想试试上传本地视频,结果视频太大了哈哈哈,还是贴连接叭)


代码附件在这里:




主函数贴上:
//ISP下载时需将工作频率设置在"config.h"文件中
#include "config.h"
#include "sys.h"
//#include "stc32_stc8_usb.h"

#include "gpio_init.h"
#include "oled12864_iic.h"

// char *USER_DEVICEDESC = NULL;
// char *USER_PRODUCTDESC = NULL;
// char *USER_STCISPCMD = "@STCISP#";       //不停电自动ISP下载命令



void main()
{
//—————————————————主程序参数定义———————————————————————————//




//—————————————————主程序参数初始化—————————————————————————//

sys_init(); // 使能USB功能,IO口初始化
// usb_init(); // USB初始化   //调用USB CDC初始化库函数
// EUSB = 1;   // 使能USB中断
EA = 1;   // 总中断开


//while (DeviceState != DEVSTATE_CONFIGURED); // 等待USB完成配置
//delay_ms(1000);

GPIO_config();
OLED_Init();

// —————————————————主程序循环开始———————————————————//


while (1)
{
   
    // —————————————————以下为USB_CDC串口代码———————————————————//
    // delay_ms(2);      //延时等待USB稳定
    // // 当硬件接收完成上位机通过串口助手发送数据后,会自动将bUsbOutReady置1
    // // 接收的数据字节数保存在OutNumber变量中,接收的数据保存在UsbOutBuffer缓冲区
    // if (bUsbOutReady)
    // {
    //   // 使用USB_SendData库函数可向上位机发送数据,这里的测试代码为将接收数据原样返回
    //   USB_SendData(UsbOutBuffer,OutNumber);
    //   //处理完成接收的数据后,调用usb_OUT_done准备接收下一笔数据
      //         usb_OUT_done();

    //   // ——————在这里写代码,单片机USB_CDC接受到数据后才会执行———————//
      
    // }

    // —————————————————此处开始写代码———————————————————//

    // —————————————————OLED_IIC代码测试———————————————————//
      OLED_Printf(0,0,16,"Welcome to my OLED display program!!!");
    delay_ms(5000);
    OLED_Test_Show();


}
}

iic.c(部分)贴上:
#include "iic.h"


//------------------------------变量定义------------------------------





//------------------------------函数定义------------------------------

#ifdef Hardware_IIC
/**
* @name IIC_config
* @brief 硬件IIC配置
* @version 版本:v1.0
* @date 日期:2024-3-23
* @author 作者:
* @note 注释:
*/
void IIC_Hardware_config()
{
    I2C_InitTypeDef I2C_InitStructure;

    // 作主机设置
    I2C_InitStructure.I2C_Mode      = I2C_Mode_Master;            //主从选择   I2C_Mode_Master, I2C_Mode_Slave
      I2C_InitStructure.I2C_Enable    = ENABLE;                            //I2C功能使能,   ENABLE, DISABLE
      I2C_InitStructure.I2C_MS_WDTA   = DISABLE;                            //主机使能自动发送,ENABLE, DISABLE
      I2C_InitStructure.I2C_Speed   = 63;                                    //总线速度=Fosc/2/(Speed*2+4),      0~63
      I2C_Init(&I2C_InitStructure);
      NVIC_I2C_Init(I2C_Mode_Master,DISABLE,Priority_0);                //主从模式, I2C_Mode_Master, I2C_Mode_Slave; 中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

    // 作从机设置
    // I2C_InitStructure.I2C_Mode      = I2C_Mode_Slave;                //主从选择   I2C_Mode_Master, I2C_Mode_Slave
      // I2C_InitStructure.I2C_Enable    = ENABLE;                              //I2C功能使能,   ENABLE, DISABLE
      // I2C_InitStructure.I2C_SL_MA   = ENABLE;                              //使能从机地址比较功能,   ENABLE, DISABLE
      // I2C_InitStructure.I2C_SL_ADR    = 0x2d;                                        //从机设备地址,0~127(0x2d<<1 = 0x5a)
      // I2C_Init(&I2C_InitStructure);
      // NVIC_I2C_Init(I2C_Mode_Slave,I2C_ESTAI|I2C_ERXI|I2C_ETXI|I2C_ESTOI,Priority_0);      //主从模式, I2C_Mode_Master, I2C_Mode_Slave; 中断使能, I2C_ESTAI/I2C_ERXI/I2C_ETXI/I2C_ESTOI/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

      I2C_SW(I2C_P24_P25);                                        //I2C_P14_P15,I2C_P24_P25,I2C_P76_P77,I2C_P33_P32

}

/**
* @name Wait
* @brief 等待主机模式I2C控制器执行完成I2CMSCR
* @version 版本:v1.0
* @date 日期:2024
* @author 作者:
* @note 注释:
*/
void Wait(void)
{
      while (!(I2CMSST & 0x40));
      I2CMSST &= ~0x40;
}

。。。。。。(中间有点长,省略了)

//---------------------功能函数---------------------

/**
* @name IIC_WriteNbyte
* @brief IIC写入连续的几个字节
* @param slave: 选择哪一个从机的地址
* @param mem_addr: 数据的地址
* @param p: 数据内容,写入数据存储位置
* @param number: 写入几个数据
* @return 无
* @version 版本:v1.0
* @date 日期:2024-3-23
* @author 作者:汐
* @note 注释:DeviceAddress,WordAddress,First Data Address,Byte lenth
*/
void IIC_WriteNbyte_Hard(u8 slave, u8 mem_addr, u8 *p, u8 number)
{
      Start();                              //发送起始命令
      SendData(slave);                     //发送设备地址+写命令
      RecvACK();
      SendData(mem_addr);                     //发送存储地址
      RecvACK();
      do
      {
                SendData(*p++);
                RecvACK();
      }
      while(--number);
      Stop();   
}

/**
* @name IIC_ReadNbyte
* @brief IIC读取连续的几个字节
* @param slave: 选择哪一个从机的地址
* @param mem_addr: 要读的数据的地址
* @param p: 数据,取数据存储位置
* @param number: 写入几个数据
* @return
* @version 版本:v1.0
* @date 日期:2024-3-23
* @author 作者:汐
* @note 注释:发送开始命令->发送器件地址(写)->发送数据地址->发送开始命令->发送器件地址(读)->读数据
* DeviceAddress,WordAddress,First Data Address,Byte lenth
*/
void IIC_ReadNbyte_Hard(u8 slave, u8 mem_addr, u8 *p, u8 number)
{
      Start();                              //发送起始命令
      SendData(slave);                     //发送设备地址+写命令
      RecvACK();
      SendData(mem_addr);                     //发送存储地址
      RecvACK();
      Start();                              //发送起始命令
      SendData(slave|1);                   //发送设备地址+读命令
      RecvACK();
      do
      {
                *p = RecvData();
                p++;
                if(number != 1) SendACK();          //send ACK
      }
      while(--number);
      SendNAK();                              //send no ACK      
      Stop();                                 //发送停止命令
}

#endif

#ifdef Software_IIC

/**
* @name IIC_Software_config
* @brief 软件IIC设置配置
* @version 版本:v1.0
* @date 日期:2024
* @author 作者:
* @note 注释:
*/
void IIC_Software_config()
{
      #if   IIC_PIN == 0      //4P
    SCL = 1;
    SDA = 1;
    #elif   IIC_PIN == 1      //7P
    SCL = 1;
    SDA = 1;
    RES = 1;
    DC = 0;
    CS = 0;
    #endif
}

iic.h贴上:
#ifndef __IIC_H_
#define __IIC_H_


#include "config.h"
#include "STC32G_I2C.h"
#include "STC32G_NVIC.h"
#include "STC32G_Switch.h"

#define IIC_MODE 0          // 0: 软件IIC 1:硬件IIC
#define IIC_PIN0          // 0:四针IIC1:七针IIC(OLED)
//#define Hardware_IIC      // 硬件IIC开关
#define Software_IIC      // 软件IIC开关

//------------------------------引脚定义------------------------------
#ifdef Software_IIC
#if   IIC_PIN == 0
#define SCL P25         //时钟线
#define SDA P24         //数据线

#elif   IIC_PIN == 1
#define SCL P25
#define SDA P24
#define RES P23
#define DCP34
#define CSP11
#endif
#endif
//------------------------------变量声明------------------------------


// typedef struct
// {
//         u8      IIC_SDA;                              // IIC数据线
//         u8      IIC_SCL;                              // IIC时钟线
// } IIC_Soft_InitTypeDef;

//------------------------------函数声明------------------------------

#ifdef Hardware_IIC
void IIC_Hardware_config();
void IIC_WriteNbyte_Hard(u8 slave, u8 mem_addr, u8 *p, u8 number);
void IIC_ReadNbyte_Hard(u8 slave, u8 mem_addr, u8 *p, u8 number);
#endif

#ifdef Software_IIC
void IIC_Software_config();
void IIC_WriteNbyte_Soft(u8 dev_addr, u8 mem_addr, u8 *p, u8 number);
void IIC_ReadNbyte_Soft(u8 dev_addr, u8 mem_addr, u8 *p, u8 number);
#endif
#endif

oled12864_iic.c贴上:
额。。。算了这个真的超级长,就贴新增的函数吧。不知道为什么贴不上来,这样子贴试试

oled12864_iic.h贴上:
#ifndef __OLED12864_IIC_H_
#define __OLED12864_IIC_H_


#include "config.h"
#include "iic.h"

/*选择OLED的尺寸
    0:0.96寸4P/7P
    1:1.30寸4P
*/
#define OLED_SIZE   1               

#define OLED_GRAM_Mode 1            //0:8*128级缓存 1:1024级缓存 2:指令模式


//------------------------------变量声明------------------------------

#define SLAVE_OLED_12864    0X78    //128*64_OLED屏幕IIC地址
#define OLED_WriteCom_Addr      0x00      //从机写指令地址
#define OLED_WriteData_Addr      0x40      //从机写数据地址

#define OLED_CMD0      //写命令
#define OLED_DATA 1      //写数据

#define Max_Column                        128
#define Max_Row                              64
#define      Brightness                        0xFF    //亮度0~255

extern char xdata WaveData;

#if   OLED_GRAM_Mode == 0             //0:8*128级缓存
    extern u8 OLED_GRAM;         // OLED全局缓存

#elif   OLED_GRAM_Mode == 1             //1:1024级缓存
    extern u8 OLED_GRAM;         // OLED全局缓存

#else                                 //2:指令模式

#endif



//------------------------------引脚定义------------------------------






//------------------------------函数声明------------------------------

void OLED_Write_Byte(u8 dat, u8 cmd);               // 写入一个字节
void OLED_Init(void);                               // 初始化OLED
void OLED_Set_Pos(u8 x, u8 y);                      // OLED设置显示位置
void OLED_Display_On(void);                         // 开启OLED显示
void OLED_Display_Off(void);                        // 关闭OLED显示
void OLED_LightSet(u8 num);                         // 亮度设置
void OLED_Clear(bit mode);                        // 清屏函数

#if   OLED_GRAM_Mode == 0 || OLED_GRAM_Mode == 1         //0:8*128级缓存//1:1024级缓存

// #elif   OLED_GRAM_Mode == 1            

    void OLED_GRAM_Clear(bit mode);                                       // 通过缓冲数组,OLED屏幕全亮全灭
    void OLED_Refresh_Gram(void);                                           // OLED刷新显示
    void OLED_RefreshPart_Gram(u8 xstart, u8 ystart, u8 width, u8 height);// OLED局部刷新显示

    void OLED_DrawPoint(u8 x, u8 y, bit mode);                              // OLED画一个点,0:熄灭 1:点亮
    void OLED_FourPoints(u8 x0, u8 y0, bit mode);                           // 4个像素点为一组,控制亮灭
    void OLED_Mask_Gray(u8 x0, u8 y0, u8 BMP[], bit mode);                  // 蒙版函数,衍生于OLED_FourPoints函数
    // void OLED_DrawLineG(u8 x1, u8 y1, u8 x2, u8 y2, bit mode);            // OLED画一条线,0:熄灭 1:点亮
    void OLED_DrawLineG_Dot(u8 x1, u8 y1, u8 x2, u8 y2, bit mode, u8 dot);// OLED画一条虚实线,0:熄灭 1:点亮
    // void OLED_DrawRectangleG(u8 x1, u8 y1, u8 x2, u8 y2, bit mode);         // OLED画一个矩形
    void OLED_DrawFrameG(u8 x0, u8 y0, u8 x1, u8 y1, bit mode);             // OLED画一个方框
    void OLED_DrawBlockG(u8 x0, u8 y0, u8 x1, u8 y1, bit mode);             // OLED画一个实心框
    void OLED_DrawBox(u8 x0, u8 y0, u8 x1, u8 y1, u8 fill, bit mode);       // OLED画空实心矩形
    void OLED_DrawCircleG(u8 x, u8 y, u8 r, bit mode);                      // OLED画一个圆形
    void OLED_DrawEllipticG(u8 x0, u8 y0, u8 R1, u8 R2, bit mode);          // OLED画一个椭圆形
    void OLED_DrawCircleG_Distance(u8 x0, u8 y0, u8 R, bit mode);         // OLED画一个圆形(勾股定理法)
    void OLED_DrawBlockCircleG_Distance(u8 x0, u8 y0, u8 R, bit mode);      // OLED画一个实心圆形(勾股定理法)
    void OLED_DrawCircleG_Bresenham(u8 x, u8 y, u8 r, bit mode);            // OLED画一个圆形(Bresenham法)
    void OLED_DrawBlockCircleG_Bresenham(u8 x, u8 y, u8 r, bit mode);       // OLED画一个实心圆形(Bresenham法)
    void OLED_DrawRoundRectangleG(u8 x0, u8 y0, u8 x1, u8 y1, u8 R, u8 fill, bit mode);       // OLED画一个圆角矩形(Bresenham法)
    void OLED_DrawWidthRoundRectangleG(u8 x0, u8 y0, u8 x1, u8 y1, u8 R, u8 width, bit mode); // OLED画一个宽边圆角矩形(Bresenham法)

    void OLED_DrawSin();                                                      // 画正弦函数
    void ButtonWave();                                                          // 按键控制显示方波

    void OLED_ShowCharG(u8 x, u8 y, u8 chr, u8 charSize, u8 Is_Reverse);      // 缓存显示一个字符
    void OLED_ShowStringG(u8 x, u8 y, char *chr, u8 charSize, u8 Is_Reverse);   // 缓存显示一个字符号串
    void OLED_ShowNumG(u8 x, u8 y, u32 num, u8 len, u8 Size, u8 Is_Reverse);    // 缓存显示一串数字
    void OLED_ShowChineseG(u8 x, u8 y, u8 no, u8 Is_Reverse);                   // 缓存显示汉字
    void OLED_ShowBMPG(u8 x0, u8 y0, u8 x1, u8 y1, u8 BMP[], u8 Is_Reverse);    // 缓存显示BMP图片

#else                                 //2:指令模式
#endif

    void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 charSize, u8 Is_Reverse);         // 早指定位置显示一个字符
    void OLED_ShowString(u8 x, u8 y, char *chr, u8 charSize, u8 Is_Reverse);    // 显示一个字符号串
    u32OLED_Index(u8 m, u8 n);                                                // m^n函数
    void OLED_ShowNum(u8 x, u8 y, u32 num, u8 len, u8 Size, u8 Is_Reverse);   // 显示一串数字
    void OLED_ShowChinese(u8 x, u8 y, u8 no, u8 Is_Reverse);                  // 显示汉字
    void OLED_ShowBMP(u8 x0, u8 y0, u8 x1, u8 y1, u8 BMP[], u8 Is_Reverse);   // 显示BMP图片

    void OLED_ShowGBK2312(u8 x, u8 y, char *GBK, u8 Is_Reverse);                  // 显示一个汉字
    void OLED_Showstr_CN_EN(u8 x, u8 y, char *str, u8 Is_Reverse);                // 显示一串中英文
    void OLED_Printf(u8 x, u8 y, u8 Size, char *format, ...);



void OLED_Test_Show();

#endif

———————————————————————人家是有底线的!!!!!—————————————————————————

四汐 发表于 2024-3-23 23:43:04

算了,贴在这里吧

void OLED_Showstr_CN_EN(u8 x, u8 y, char *str, u8 Is_Reverse)    //显示一串中英文
{
    u8 pGBK = 0;
    u8 pIndex;
    u8 xdata i, j, k = 0;
    u8 SingleChinese = {0};
    u8 px = x + k;

    for (i = 0; str != '\0'; i++)
    {
      if ( (str < 127) && (str >= ' ') )
      {
            OLED_ShowChar(px, y, str, 16, Is_Reverse);
            px += 8;
            // 自动换行
            if (px > 120)
            {
                px = 0;
                y = y + 2;
                delay_oled_ms(500);
                if (y > 7)
                {
                  y = 0;
                }
            }
      }
      else
      {
            SingleChinese = str;         // 提取汉字串数据到单个汉字数组
            pGBK++;                                 // 计次自增

            /*当提取次数到达汉字长度时,即代表提取到了一个完整的汉字*/
            if (pGBK >= OLED_CHN_CHAR_WIDTH)
            {
                pGBK = 0;       // 计次归零

                /*遍历整个汉字字模库,寻找匹配的汉字*/
                /*如果找到最后一个汉字(定义为空字符串),则表示汉字未在字模库定义,停止寻找*/
                for ( pIndex = 0; strcmp(Font_Data.txt, "") != 0; pIndex++)
                {
                  /*找到匹配的汉字*/
                  if (strcmp(Font_Data.txt, SingleChinese) == 0)
                  {
                        break;                //跳出循环,此时pIndex的值为指定汉字的索引
                  }
                }

                /*将汉字字模库OLED_CF16x16的指定数据以16*16的图像格式显示*/
                OLED_Set_Pos((u8)(px), y); // 汉字上半部分坐标(第x列,第y行)
                for (j = 0; j < 16; j++)
                {
                  OLED_Write_Byte(Is_Reverse == 0 ? Font_Data.dat : ~Font_Data.dat, OLED_DATA);
                }
                OLED_Set_Pos((u8)(px), (u8)(y + 1));   // 汉字下半部分坐标(第x列,第y+1行)
                for (j = 0; j < 16; j++)
                {
                  OLED_Write_Byte(Is_Reverse == 0 ? Font_Data.dat : ~Font_Data.dat, OLED_DATA);
                }

                // 自动换行
                px += 16;
                if ( (px) > 112)   
                {
                  px = 0;
                  y = y + 2;
                  delay_oled_ms(500);
                  if (y > 7)
                  {
                        y = 0;
                  }
                }
            }
      }
    }
}

void OLED_Printf(u8 x, u8 y, u8 Size, char *format, ...)
{
    char String;                                                //定义字符数组
        va_list arg;                                                        //定义可变参数列表数据类型的变量arg
        va_start(arg, format);                                        //从format开始,接收参数列表到arg变量
        vsprintf(String, format, arg);                        //使用vsprintf打印格式化字符串和参数列表到字符数组中
        va_end(arg);                                                        //结束变量arg
        OLED_ShowString(x, y, String, Size , 0);//OLED显示字符数组(字符串)
}

小知青 发表于 2025-4-24 22:04:50

学习了!!

原点AC 发表于 3 天前

感谢大佬,下午学习试试
页: [1]
查看完整版本: 库函数-OLED12864-IIC/SPI-索引字库-显示GBK2312-OLEDPrintf-画点线面-OLED中英文显示