STM32+字库
“高通”字库芯片的使用方法前言
本文应用了这位大神的指导链接:https://blog.csdn.net/qq_40102829/article/details/105622434 再通过自己实践来的结果
测试平台:STM32F103C8T6
字库芯片型号:GT21L16S2W SPI协议
显示方式:0.96寸的OLED SPI协议
通常在小显示屏上显示中文字体需要一个专用的软件对其汉字进行取模,而且需要大量的工作一个一个取出对应汉字的数据,如果是大量的汉字要显示实在不方便,不如直接买一个别人已经将字库弄好的直接调用爽快多了。本次第一次购买掉进了一个坑,在此提醒下,注意购买的时候你要根据你的显示屏扫描的方式 如0.96寸的OLED扫描方式是从先从 下到上 后 左到右 的顺序规律扫描出来的,那些汉字取模软件也有类似的选项给你选择,所以购买时选择好点阵排列方式是竖置横排的还是横
在高通官网站查找不到芯片手册,只能通过百度文库中查找或在立创商城中找到。手册中也坑,在最新版本中要么不给出字体的地址或者是指定的汉字详细计算方法。所以只能在百度文库中找最早出现的A版本查询信息
说实话,我最终还是跟现实低下头,直接买别人现成的,真香。程序部分别人已经写好了有SPI和IIC注释也好看,而我合并了SPI和IIC的功能下次调用直接使能哪一个通讯方式就行。
改为:
测试平台:STM32F407系列
字库芯片型号:GT30L32S4W SPI协议
显示方式:2.08寸的OLED SPI协议
链接: “高通”字库芯片的使用方法
一、电路设计
电路设计:字库芯片跟SPI FLASH 存储器连接方式一样,注意MOSI和MISO与单片机连接对调就行了,没啥好说的
二、程序设计
先看看手册中的指令有哪些
这款芯片比较简单只有两个指令 Read Data Bytes(一般读取)和 Read Data Bytes at Higher Speed(快速读取点阵数据)
以最简单的方式 Read Data Bytes(一般读取) 来讲解
1个字节的命令字(03H)和 3个字节的地址(通过给出的公式计算出来传递给其)
1个字节 = 8位 —> 0000 0000 一共要发送24位数据给到字库芯片中去
从图象中可以看出高位先进去(MSB),发送完24位数据后 字库芯片会发送数据出来 (Data Out1)
代码如下:
//******************************************************************************
// 函数说明:向字库芯片发送指令
// 入口数据:AddrHigh 写地址高字节
// AddrMid 写地址中字节
// AddrLow 写地址低字节
// *pBuff 读到的数据
// DataLen 读取的长度
// 返回值: 无
//******************************************************************************
void get_n_bytes_data_from_ROM(u8 AddrHigh,u8 AddrMid,u8 AddrLow,u8 *pBuff,u8 DataLen )
{
u8 i;
ZK_CS_Clr(); //字库片选
ZK_command(0x03);//写指令
ZK_command(AddrHigh);//写地址高字节
ZK_command(AddrMid);//写地址中字节
ZK_command(AddrLow);//写地址低字节
for(i = 0; i < DataLen; i++ )
{
*(pBuff+i) =get_data_from_ROM();//读一个字节数据
}
ZK_CS_Set();//取消字库片选
}
整体代码部分
1.字库初始化
OLED_IIC_MODE 和 LED_SPI_MODE 该定义即可更改为SPI模式或IIC模式通讯
代码如下(示例):
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"
#include "stm32f4xx_spi.h"
//************************************硬件连接线********************************
// GND 电源地
// VCC 3.3v电源
// D0 PB3(SCL)
// D1 PB5(SDA)
// RES PD6
// DC PD7
// CS1 PF9
// FS0 PB4
// CS2 PF10
//******************************************************************************
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHB1PeriphClockCmd(OLED_GPIO_ClockCmd, ENABLE);//使能GPIO时钟
#if OLED_IIC_MODE
//RES、DC
GPIO_InitStructure.GPIO_Pin = OLED_GPIO_RES_PIN|OLED_GPIO_DC_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(OLED_GPIO_RES_PORT, &GPIO_InitStructure); //初始化
GPIO_Init(OLED_GPIO_DC_PORT, &GPIO_InitStructure); //初始化
//CS1、CS2
GPIO_InitStructure.GPIO_Pin = OLED_GPIO_CS_PIN|ZK_GPIO_CS_PIN;
GPIO_Init(OLED_GPIO_CS_PORT, &GPIO_InitStructure); //初始化
GPIO_Init(ZK_GPIO_CS_PORT, &GPIO_InitStructure); //初始化
//SCL、SDA
GPIO_InitStructure.GPIO_Pin = OLED_GPIO_SCL_PIN|OLED_GPIO_SDA_PIN;
GPIO_Init(OLED_GPIO_SCL_PORT, &GPIO_InitStructure); //初始化
GPIO_Init(OLED_GPIO_SDA_PORT, &GPIO_InitStructure); //初始化
//FS0
GPIO_InitStructure.GPIO_Pin = ZK_GPIO_FS0_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //普通输入模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOE8
GPIO_SetBits(ZK_GPIO_FS0_PORT,ZK_GPIO_CS_PIN);
#endif
#if OLED_SPI_MODE
RCC_APB2PeriphClockCmd(ZK_SPI_CLK, ENABLE); //使能SPI1时钟
//RES、DC
GPIO_InitStructure.GPIO_Pin = OLED_GPIO_RES_PIN|OLED_GPIO_DC_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(OLED_GPIO_RES_PORT, &GPIO_InitStructure); //初始化
GPIO_Init(OLED_GPIO_DC_PORT, &GPIO_InitStructure); //初始化
//CS1、CS2
GPIO_InitStructure.GPIO_Pin = OLED_GPIO_CS_PIN|ZK_GPIO_CS_PIN;
GPIO_Init(OLED_GPIO_CS_PORT, &GPIO_InitStructure); //初始化
GPIO_Init(ZK_GPIO_CS_PORT, &GPIO_InitStructure); //初始化
//MOSI、MISO、SCK
GPIO_InitStructure.GPIO_Pin = OLED_GPIO_SCL_PIN|OLED_GPIO_SDA_PIN|ZK_GPIO_FS0_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(ZK_GPIO_FS0_PORT, &GPIO_InitStructure);
GPIO_Init(OLED_GPIO_SCL_PORT, &GPIO_InitStructure);
GPIO_Init(OLED_GPIO_SDA_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(ZK_GPIO_FS0_PORT,ZK_GPIO_PinSource_SCL,ZK_SPI_GPIO_AF); //PB3复用为 SPI1
GPIO_PinAFConfig(ZK_GPIO_FS0_PORT,ZK_GPIO_PinSource_FS0,ZK_SPI_GPIO_AF); //PB4复用为 SPI1
GPIO_PinAFConfig(ZK_GPIO_FS0_PORT,ZK_GPIO_PinSource_SDA,ZK_SPI_GPIO_AF); //PB5复用为 SPI1
//这里只针对SPI口初始化
RCC_APB2PeriphResetCmd(ZK_SPI_CLK,ENABLE); //复位SPI1
RCC_APB2PeriphResetCmd(ZK_SPI_CLK,DISABLE); //停止复位SPI1
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(ZK_SPIx, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(ZK_SPIx, ENABLE); //使能SPI外设
SPI1_ReadWriteByte(0xff);//启动传输
#endif
OLED_RES_Clr(); //复位
delay_ms(10);
OLED_RES_Set();
OLED_WR_REG(0xAE);//Set display off
OLED_WR_REG(0xB0); //Row address Mode Setting
OLED_WR_REG(0x00);
OLED_WR_REG(0x10); //Set Higher Column Address of display RAM
OLED_WR_REG(0x00); //Set Lower Column Address of display RAM
OLED_WR_REG(0xD5); //Set Display Clock Divide Ratio/Oscillator Frequency
OLED_WR_REG(0x50); //50 125hz
OLED_WR_REG(0xD9); //Set Discharge/Precharge Period
OLED_WR_REG(0x22);
OLED_WR_REG(0x40); //Set Display Start Line
OLED_WR_REG(0x81); //The Contrast Control Mode Set
OLED_WR_REG(0xFF);
if(USE_HORIZONTAL)
{
OLED_WR_REG(0xA1); //Set Segment Re-map
OLED_WR_REG(0xC8); //Set Common Output Scan Direction
OLED_WR_REG(0xD3); //Set Display Offset
OLED_WR_REG(0x20);
}else
{
OLED_WR_REG(0xA0); //Set Segment Re-map
OLED_WR_REG(0xC0); //Set Common Output Scan Direction
OLED_WR_REG(0xD3); //Set Display Offset
OLED_WR_REG(0x00);
}
OLED_WR_REG(0xA4); //Set Entire Display OFF/ON
OLED_WR_REG(0xA6); //Set Normal/Reverse Display
OLED_WR_REG(0xA8); //Set Multiplex Ration
OLED_WR_REG(0x3F);
OLED_WR_REG(0xAD); //DC-DC Setting
OLED_WR_REG(0x80); //DC-DC is disable
OLED_WR_REG(0xDB); //Set VCOM Deselect Level
OLED_WR_REG(0x30);
OLED_WR_REG(0xDC); //Set VSEGM Level
OLED_WR_REG(0x30);
OLED_WR_REG(0x33); //Set Discharge VSL Level 1.8V
OLED_Clear();
OLED_WR_REG(0xAF); //Set Display On
}
//******************************************************************************
// 函数说明:硬件SPI读写一个字节
// 入口数据:要写入的字节
// 返回值: 读取到的字节
//******************************************************************************
#if OLED_SPI_MODE
u8 SPI1_ReadWriteByte(u8 TxData)
{
while (SPI_I2S_GetFlagStatus(ZK_SPIx, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空
SPI_I2S_SendData(ZK_SPIx, TxData); //通过外设SPIx发送一个byte 数据
while (SPI_I2S_GetFlagStatus(ZK_SPIx, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte
return SPI_I2S_ReceiveData(ZK_SPIx); //返回通过SPIx最近接收的数据
}
#endif
//******************************************************************************
// 函数说明:OLED写入一个指令
// 入口数据:dat 数据
// 返回值: 无
//******************************************************************************
void OLED_WR_Bus(u8 dat)
{
u8 i;
OLED_CS_Clr();
#if OLED_IIC_MODE
for(i=0;i<8;i++)
{
OLED_SCL_Clr();
if(dat&0x80)
{
OLED_SDA_Set();
}
else
{
OLED_SDA_Clr();
}
OLED_SCL_Set();
dat<<=1;
}
// printf("IIC\r");
#endif
#if OLED_SPI_MODE
SPI1_ReadWriteByte(dat);
// printf("SPI\r");
#endif
OLED_CS_Set();
}
//******************************************************************************
// 函数说明:OLED写入一个指令
// 入口数据:reg 指令
// 返回值: 无
//******************************************************************************
void OLED_WR_REG(u8 reg)
{
OLED_DC_Clr();
OLED_WR_Bus(reg);
OLED_DC_Set();
}
//******************************************************************************
// 函数说明:OLED写入一个数据
// 入口数据:dat 数据
// 返回值: 无
//******************************************************************************
void OLED_WR_Byte(u8 dat)
{
OLED_WR_Bus(dat);
}
//******************************************************************************
// 函数说明:OLED显示列的起始终止地址
// 入口数据:a 列的起始地址
// b 列的终止地址
// 返回值: 无
//******************************************************************************
void OLED_AddressSet(u8 x,u8 y)
{
OLED_WR_REG(0xB0);
OLED_WR_REG(y);
OLED_WR_REG(((x&0xf0)>>4)|0x10);
OLED_WR_REG((x&0x0f));
}
//******************************************************************************
// 函数说明:OLED清屏显示
// 入口数据:无
// 返回值: 无
//******************************************************************************
void OLED_Clear(void)
{
u16 j,i;
OLED_AddressSet(0,0);
OLED_CS_Clr();
for(i=0;i<64;i++)
{
#if OLED_IIC_MODE
OLED_AddressSet(0,i);
#endif
for(j=0;j<128;j++)
{
#if OLED_IIC_MODE
OLED_WR_Byte(0x00);
#endif
#if OLED_SPI_MODE
SPI1_ReadWriteByte(0x00);
#endif
}
}
OLED_CS_Set();
}
//******************************************************************************
// 函数说明:OLED清屏显示
// 入口数据:x1,y1 起点坐标
// x2,y2 结束坐标
// color 填充的颜色值
// 返回值: 无
//******************************************************************************
void OLED_Fill(u16 x1,u8 y1,u16 x2,u8 y2,u8 color)
{
u16 j,i;
x1/=2;
x2/=2;
for(i=y1;i<y2;i++)
{
OLED_AddressSet(x1,i);
for(j=x1;j<x2;j++)
{
OLED_WR_Byte(color);
}
}
}
//******************************************************************************
// 函数说明:OLED显示汉字
// 入口数据:x,y :起点坐标
// *s :要显示的汉字串
// sizey 字符高度
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_ShowChinese(u8 x,u8 y,u8 *s,u8 sizey,u8 mode)
{
while(*s!=0)
{
if(sizey==16) OLED_ShowChinese16x16(x,y,s,sizey,mode);
else if(sizey==24) OLED_ShowChinese24x24(x,y,s,sizey,mode);
else if(sizey==32) OLED_ShowChinese32x32(x,y,s,sizey,mode);
else return;
s+=2;
x+=sizey;
}
}
//******************************************************************************
// 函数说明:OLED显示汉字
// 入口数据:x,y :起点坐标
// *s :要显示的汉字
// sizey 字符高度
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_ShowChinese16x16(u8 x,u8 y,u8 *s,u8 sizey,u8 mode)
{
u8 i,j,k,t,DATA=0,HZnum;
u16 TypefaceNum;
x/=2;
TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;//字符所占字节数
HZnum=sizeof(tfont16)/sizeof(typFNT_GB16); //统计汉字库数目
t=sizey/8;
for(k=0;k<HZnum;k++)
{
if ((tfont16[k].Index[0]==*(s))&&(tfont16[k].Index[1]==*(s+1)))
{
for(i=0;i<TypefaceNum;i++)
{
if(i%t==0)
{
OLED_AddressSet(x,y);
y++;
}
for(j=0;j<4;j++)
{
if(tfont16[k].Msk[i]&(0x01<<(j*2+0)))
{
DATA=0xf0;
}
if(tfont16[k].Msk[i]&(0x01<<(j*2+1)))
{
DATA|=0x0f;
}
if(mode)
{
OLED_WR_Byte(~DATA);
}else
{
OLED_WR_Byte(DATA);
}
DATA=0;
}
}
}
continue; //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
}
//******************************************************************************
// 函数说明:OLED显示汉字
// 入口数据:x,y :起点坐标
// *s :要显示的汉字
// sizey 字符高度
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_ShowChinese24x24(u8 x,u8 y,u8 *s,u8 sizey,u8 mode)
{
u8 i,j,k,t,DATA=0,HZnum;
u16 TypefaceNum;
x/=2;
TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;//字符所占字节数
HZnum=sizeof(tfont24)/sizeof(typFNT_GB24); //统计汉字库数目
t=sizey/8;
for(k=0;k<HZnum;k++)
{
if ((tfont24[k].Index[0]==*(s))&&(tfont24[k].Index[1]==*(s+1)))
{
for(i=0;i<TypefaceNum;i++)
{
if(i%t==0)
{
OLED_AddressSet(x,y);
y++;
}
for(j=0;j<4;j++)
{
if(tfont24[k].Msk[i]&(0x01<<(j*2+0)))
{
DATA=0xf0;
}
if(tfont24[k].Msk[i]&(0x01<<(j*2+1)))
{
DATA|=0x0f;
}
if(mode)
{
OLED_WR_Byte(~DATA);
}else
{
OLED_WR_Byte(DATA);
}
DATA=0;
}
}
}
continue; //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
}
//******************************************************************************
// 函数说明:OLED显示汉字
// 入口数据:x,y :起点坐标
// *s :要显示的汉字
// sizey 字符高度
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_ShowChinese32x32(u8 x,u8 y,u8 *s,u8 sizey,u8 mode)
{
u8 i,j,k,t,DATA=0,HZnum;
u16 TypefaceNum;
x/=2;
TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;//字符所占字节数
HZnum=sizeof(tfont32)/sizeof(typFNT_GB32); //统计汉字库数目
t=sizey/8;
for(k=0;k<HZnum;k++)
{
if ((tfont32[k].Index[0]==*(s))&&(tfont32[k].Index[1]==*(s+1)))
{
for(i=0;i<TypefaceNum;i++)
{
if(i%t==0)
{
OLED_AddressSet(x,y);
y++;
}
for(j=0;j<4;j++)
{
if(tfont32[k].Msk[i]&(0x01<<(j*2+0)))
{
DATA=0xf0;
}
if(tfont32[k].Msk[i]&(0x01<<(j*2+1)))
{
DATA|=0x0f;
}
if(mode)
{
OLED_WR_Byte(~DATA);
}else
{
OLED_WR_Byte(DATA);
}
DATA=0;
}
}
}
continue; //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
}
//******************************************************************************
// 函数说明:OLED显示字符函数
// 此函数适用范围:字符宽度是2的倍数 字符高度是宽度的2倍
// 入口数据:x,y 起始坐标
// chr 要写入的字符
// sizey 字符高度
// 返回值: 无
//******************************************************************************
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey,u8 mode)
{
u8 i,j,c,k,t=4,temp,DATA=0;
u16 num;
x/=2;
c=chr-' ';
num=(sizey/16+((sizey%16)?1:0))*sizey;
k=sizey/16;
for(i=0;i<num;i++)
{
if(sizey==16)temp=ascii_1608[c][i];//调用8x16字符
else if(sizey==24)temp=ascii_2412[c][i];//调用12x24字符
else if(sizey==32)temp=ascii_3216[c][i];//调用16x32字符
// else if(sizey==48)temp=ascii_4824[c][i];//调用24x48字符
else return;
if(sizey%16)
{
k=sizey/16+1;
if(i%k) t=2;
else t=4;
}
if(i%k==0)
{
OLED_AddressSet(x,y);
y++;
}
for(j=0;j<t;j++)
{
if(temp&(0x01<<(j*2+0)))
{
DATA=0xf0;
}
if(temp&(0x01<<(j*2+1)))
{
DATA|=0x0f;
}
if(mode)
{
OLED_WR_Byte(~DATA);
}else
{
OLED_WR_Byte(DATA);
}
DATA=0;
}
}
}
//******************************************************************************
// 函数说明:OLED显示字符串
// 入口数据:x,y 起始坐标
// *dp 要写入的字符
// sizey 字符高度
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_ShowString(u8 x,u8 y,u8 *dp,u8 sizey,u8 mode)
{
while(*dp!='\0')
{
OLED_ShowChar(x,y,*dp,sizey,mode);
dp++;
x+=sizey/2;
}
}
//******************************************************************************
// 函数说明:m^n
// 入口数据:m:底数 n:指数
// 返回值: result
//******************************************************************************
u32 oled_pow(u16 m,u16 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//******************************************************************************
// 函数说明:OLED显示变量
// 入口数据:x,y :起点坐标
// num :要显示的变量
// len :数字的位数
// sizey 字符高度
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_ShowNum(u8 x,u8 y,u32 num,u16 len,u8 sizey,u8 mode)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(sizey/2)*t,y,' ',sizey,mode);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(sizey/2)*t,y,temp+'0',sizey,mode);
}
}
//******************************************************************************
// 函数说明:显示灰度图片
// 入口数据:x,y :起点坐标
// length 图片长度
// width 图片宽度
// BMP[] :要显示图片
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_DrawBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode)
{
u8 i,j;
u16 k=0;
x/=2;
length=length/2+((length%2)?1:0);
for(i=0;i<width;i++)
{
OLED_AddressSet(x,y+i);
for(j=0;j<length;j++)
{
if(mode)
{
OLED_WR_Byte(~BMP[k++]);
}else
{
OLED_WR_Byte(BMP[k++]);
}
}
}
}
//******************************************************************************
// 函数说明:显示灰度图片
// 入口数据:x,y :起点坐标
// length 图片长度
// width 图片宽度
// BMP[] :要显示图片
// mode 0:正常显示;1:反色显示
// 返回值: 无
//******************************************************************************
void OLED_DrawSingleBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode)
{
u8 i,j,k,DATA=0;
u16 m=0;
length=length/8+((length%8)?1:0);
x/=2;
for(i=0;i<width;i++)
{
OLED_AddressSet(x,y+i);
for(j=0;j<length;j++)
{
for(k=0;k<4;k++)
{
if(BMP[m]&(0x01<<(k*2+0)))
{
DATA=0xf0;
}
if(BMP[m]&(0x01<<(k*2+1)))
{
DATA|=0x0f;
}
if(mode)
{
OLED_WR_Byte(~DATA);
}else
{
OLED_WR_Byte(DATA);
}
DATA=0;
}
m++;
}
}
}
以上SPI用到的是STM32的SPI2当中,时钟挂接在36M的PCLK1分频得到,预分频设置为最大值256(36M/256 = 0.14M)
SCLK的频率为140KHz,Tsclk:14.0us
2.字库头文件
代码如下(示例):
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
#define USE_HORIZONTAL 0 //设置显示方向 0:正向显示;1:旋转180度显示
#define OLED_SPI_MODE 0 //设置硬件SPI或软件IIC 0:硬件SPI; 1:软件IIC
#define OLED_IIC_MODE 1 //设置硬件SPI或软件IIC 0:硬件SPI; 1:软件IIC
//SCL=SCLK
//SDA=MOSI
//RES=RES
//DC=DC
//CS=CS1
//FS0=MOSI
//CS2=CS2
//-----------------OLED端口定义----------------
#define OLED_GPIO_ClockCmd RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB
#define OLED_GPIO_SCL_PORT GPIOA
#define OLED_GPIO_SCL_PIN GPIO_Pin_8
#define OLED_GPIO_SCL_CLK RCC_AHB1Periph_GPIOA
#define OLED_GPIO_SDA_PORT GPIOA
#define OLED_GPIO_SDA_PIN GPIO_Pin_5
#define OLED_GPIO_SDA_CLK RCC_AHB1Periph_GPIOA
#define OLED_GPIO_RES_PORT GPIOA
#define OLED_GPIO_RES_PIN GPIO_Pin_15
#define OLED_GPIO_RES_CLK RCC_APB1Periph_GPIOA
#define OLED_GPIO_DC_PORT GPIOB
#define OLED_GPIO_DC_PIN GPIO_Pin_6
#define OLED_GPIO_DC_CLK RCC_APB1Periph_GPIOB
#define OLED_GPIO_CS_PORT GPIOB
#define OLED_GPIO_CS_PIN GPIO_Pin_7
#define OLED_GPIO_CS_CLK RCC_APB1Periph_GPIOB
#define ZK_GPIO_CS_PORT GPIOA
#define ZK_GPIO_CS_PIN GPIO_Pin_0
#define ZK_GPIO_CS_CLK RCC_APB1Periph_GPIOA
#define ZK_GPIO_FS0_PORT GPIOA
#define ZK_GPIO_FS0_PIN GPIO_Pin_4
#define ZK_GPIO_FS0_CLK RCC_APB1Periph_GPIOA
#define ZK_SPIx SPI1
#define ZK_SPI_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ZK_SPI_CLK RCC_APB2Periph_SPI1
#define ZK_SPI_GPIO_AF GPIO_AF_SPI1
#define ZK_GPIO_PinSource_SCL GPIO_PinSource3
#define ZK_GPIO_PinSource_SDA GPIO_PinSource5
#define ZK_GPIO_PinSource_FS0 GPIO_PinSource4
#define OLED_SCL_Clr() GPIO_ResetBits(OLED_GPIO_SCL_PORT,OLED_GPIO_SCL_PIN)//SCL
#define OLED_SCL_Set() GPIO_SetBits(OLED_GPIO_SCL_PORT,OLED_GPIO_SCL_PIN)
#define OLED_SDA_Clr() GPIO_ResetBits(OLED_GPIO_SDA_PORT,OLED_GPIO_SDA_PIN)//SDA
#define OLED_SDA_Set() GPIO_SetBits(OLED_GPIO_SDA_PORT,OLED_GPIO_SDA_PIN)
#define OLED_RES_Clr() GPIO_ResetBits(OLED_GPIO_RES_PORT,OLED_GPIO_RES_PIN)//RES
#define OLED_RES_Set() GPIO_SetBits(OLED_GPIO_RES_PORT,OLED_GPIO_RES_PIN)
#define OLED_DC_Clr() GPIO_ResetBits(OLED_GPIO_DC_PORT,OLED_GPIO_DC_PIN)//DC
#define OLED_DC_Set() GPIO_SetBits(OLED_GPIO_DC_PORT,OLED_GPIO_DC_PIN)
#define OLED_CS_Clr() GPIO_ResetBits(OLED_GPIO_CS_PORT,OLED_GPIO_CS_PIN)//CS1
#define OLED_CS_Set() GPIO_SetBits(OLED_GPIO_CS_PORT,OLED_GPIO_CS_PIN)
#define ZK_CS_Clr() GPIO_ResetBits(ZK_GPIO_CS_PORT,ZK_GPIO_CS_PIN)//CS2
#define ZK_CS_Set() GPIO_SetBits(ZK_GPIO_CS_PORT,ZK_GPIO_CS_PIN)
#define ZK_READ_FS0() GPIO_ReadInputDataBit(ZK_GPIO_FS0_PORT,ZK_GPIO_FS0_PIN)//FS0
u8 SPI1_ReadWriteByte(u8 TxData);
//显示屏功能函数
void OLED_WR_REG(u8 reg); //写入一个指令
void OLED_WR_Byte(u8 dat); //写入一个数据
void OLED_AddressSet(u8 x,u8 y); //设置起始坐标函数
void OLED_Clear(void); //清平函数
void OLED_Fill(u16 x1,u8 y1,u16 x2,u8 y2,u8 color); //填充函数
void OLED_ShowChinese(u8 x,u8 y,u8 *s,u8 sizey,u8 mode); //显示汉字串
void OLED_ShowChinese16x16(u8 x,u8 y,u8 *s,u8 sizey,u8 mode);//显示16x16汉字
void OLED_ShowChinese24x24(u8 x,u8 y,u8 *s,u8 sizey,u8 mode);//显示24x24汉字
void OLED_ShowChinese32x32(u8 x,u8 y,u8 *s,u8 sizey,u8 mode);//显示32x32汉字
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey,u8 mode); //显示单个字符
void OLED_ShowString(u8 x,u8 y,u8 *dp,u8 sizey,u8 mode); //显示字符串
void OLED_ShowNum(u8 x,u8 y,u32 num,u16 len,u8 sizey,u8 mode);//显示整数变量
void OLED_DrawBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode); //显示灰度图片
void OLED_DrawSingleBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode);//显示单色图片
void OLED_Init(void);
//字库函数
void ZK_command(u8 dat); //向字库发送命令
u8 get_data_from_ROM(void); //从字库度一个数据
void get_n_bytes_data_from_ROM(u8 AddrHigh,u8 AddrMid,u8 AddrLow,u8 *pBuff,u8 DataLen );//从字库读DataLen个数据
void Display_GB2312_String(u16 x,u8 y,u8 text[],u8 zk_num,u8 mode); //显示汉字字符串
void Display_GB2312(u16 x,u8 y,u8 zk_num,u8 mode); //显示汉字
void Display_Asc_String(u16 x,u8 y,u8 text[],u8 zk_num,u8 mode); //显示ASCII 字符串
void Display_Asc(u16 x,u8 y,u8 zk_num,u8 mode); //显示ASCII
void Display_GBasc_String(u16 x,u8 y,u8 text[],u8 zk_num,u8 mode); //显示GB2312 ascii 字符串
void Display_GBasc(u16 x,u8 y,u8 zk_num,u8 mode); //显示GB2312 ascii
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler);
u8 SPI1_ReadWriteByte(u8 TxData);
void SPI1_Init(void);
void OLED1_Init(void);
#endif
3.主函数
// GND 电源地
// VCC 3.3v电源
// D0 PB3(SCL)
// D1 PB5(SDA)
// RES PD6
// DC PD7
// CS1 PF9
// FS0 PB4
// CS2 PF10
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "oled.h"
#include "bmp.h"
int main(void)
{
delay_init(168);
// uart_init(115200); //初始化USART
OLED_Init();
while(1)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_15);
delay_ms(1000);
GPIO_SetBits(GPIOA, GPIO_Pin_15);
delay_ms(1000);
OLED_DrawBMP(0,0,256,64,gImage_1,0);//灰度图片显示
delay_ms(1000);
OLED_Clear();
OLED_DrawSingleBMP(0,0,256,64,gImage_2,0);//单色图片显示
delay_ms(1000);
OLED_Clear();
Display_GB2312_String(0,26,"中",12,0);//GB2312_12*12
Display_GB2312_String(12,24,"景",16,0);//GB2312_15*16
Display_GB2312_String(28,20,"园",24,0);//GB2312_24*24
Display_GB2312_String(52,16,"电",32,0);//GB2312_32*32
Display_GB2312_String(84,16,"子",32,0);//GB2312_32*32
Display_GB2312_String(128,16,"中",32,1);//GB2312_12*12
Display_GB2312_String(160,16,"景",32,1);//GB2312_15*16
Display_GB2312_String(192,20,"园",24,1);//GB2312_24*24
Display_GB2312_String(216,24,"电",16,1);//GB2312_32*32
Display_GB2312_String(232,26,"子",12,1);//GB2312_32*32
delay_ms(1000);
OLED_Clear();
Display_Asc_String(0,0,"ASCII:5x7",7,0);//5x7 ASCII
Display_Asc_String(0,13,"ASCII:7x8",8,0);//7x8 ASCII
Display_Asc_String(0,26,"ASCII:6x12",12,0);//6x12 ASCII
Display_Asc_String(0,43,"ASCII:8x16",16,0);//8x16 ASCII
delay_ms(1000);
OLED_Clear();
Display_Asc_String(0,0,"ASCII:5x7",7,1);//5x7 ASCII
Display_Asc_String(0,13,"ASCII:7x8",8,1);//7x8 ASCII
Display_Asc_String(0,26,"ASCII:6x12",12,1);//6x12 ASCII
Display_Asc_String(0,43,"ASCII:8x16",16,1);//8x16 ASCII
delay_ms(1000);
OLED_Clear();
Display_Asc_String(0,0,"ASC12x24",24,0);//12x24 ASCII
Display_Asc_String(0,30,"ASC16x32",32,0);//16x32 ASCII
delay_ms(1000);
OLED_Clear();
Display_Asc_String(0,0,"ASC12x24",24,1);//12x24 ASCII
Display_Asc_String(0,30,"ASC16x32",32,1);//16x32 ASCII
delay_ms(1000);
// Display_GB2312_String(16*0,0,"当",16,0);//GB2312_32*32
// Display_GB2312_String(16*1,0,"前",16,0);//GB2312_32*32
// Display_GB2312_String(16*2,0,"距",16,0);//GB2312_32*32
// Display_GB2312_String(16*3,0,"离",16,0);//GB2312_32*32
// Display_GB2312_String(16*4,0,":",16,0);//GB2312_32*32
// Display_Asc_String(16*5,0,"32",16,0);//16x32 ASCII
// Display_GB2312_String(16*0,16,"设",16,0);//GB2312_32*32
// Display_GB2312_String(16*1,16,"置",16,0);//GB2312_32*32
// Display_GB2312_String(16*2,16,"距",16,0);//GB2312_32*32
// Display_GB2312_String(16*3,16,"离",16,0);//GB2312_32*32
// Display_GB2312_String(16*4,16,":",16,0);//GB2312_32*32
// Display_Asc_String(16*5,16,"32",16,0);//16x32 ASCII
// Display_GB2312_String((12*0)+34,52,"设",12,0);//GB2312_32*32
// Display_GB2312_String((12*1)+34,52,"置",12,0);//GB2312_32*32
// Display_GB2312_String((12*2)+34,52,"距",12,0);//GB2312_32*32
// Display_GB2312_String((12*3)+34,52,"离",12,0);//GB2312_32*32
// Display_GB2312_String((12*4)+34,52,":",12,0);//GB2312_32*32
// Display_GB2312_String((12*0)+34,52,"设置",12,0);//GB2312_32*32
// delay_ms(2000);
OLED_Clear();
}
}