库函数-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
———————————————————————人家是有底线的!!!!!—————————————————————————
算了,贴在这里吧
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显示字符数组(字符串)
}
学习了!! 感谢大佬,下午学习试试
页:
[1]