W25Q64保存汉字字库
利用W25Q64保存汉字字库,OLED显示汉字的时候,先通过SPI接口访问W25Q64,先将要显示的汉子字模数据,从SPI FLASH中读取出来,然后再显示到OLED屏幕上。
- 按照原创作者的思路制作SPI flash字库,需要准备一块足够大的字库SPI flash芯片以及flash足够大的MCU才行。这里选择:W25Q64 + STM32F103VET6
/*字库写入*/
/*字库需要分2次写入FLASH,一次写1半,写完上半部分后,把if 1 改为 if 0,再写下半部分*/
/*CNFont.h也需要同步修改,写完注释掉这段代码*/
/*写完注释掉或者删除掉这段代码*/
// #if 0
// W25Q64_WriteData(W25Q64_GBK_ADDR,(uint8_t *)Chinses_16,383041);
// printf("写字库上半部分 OK!\r\n");
// #else
W25Q64_WriteData(W25Q64_GBK_ADDR+383041,(uint8_t *)Chinses_16,383039);
printf("写字库下半部分 OK!\r\n");
// #endif
/*写完注释掉或者删除掉这段代码*/
Chinses_16
字体库BIN文件,是从spi flash中提取出来的。如果自己有SPI flash编程器,可以直接烧录到SPI FLASH当中去。(经过验证,将裁剪后的bin文件烧录到4MB SPI FLASH中,挂载到mcu上,可以正确访问和读取数据。OLED显示正常).链接:https://pan.baidu.com/s/13uU5Uc7yiiHDMtMMNd71ew?pwd=v0l7
提取码:v0l7
链接:https://pan.baidu.com/s/1y8_p0PL-QeTQTkgahKGTXg?pwd=x324
提取码:x324
W25QXX Device ID
读取命令(0x90)
W25Q80的芯片ID为:0XEF13
W25Q16 的芯片ID为:0XEF14
W25Q32 的芯片ID为:0XEF15
W25Q64 的芯片ID为:0XEF16
W25Q128的芯片ID为:0XEF17
W25Q256的芯片ID为:0XEF18
W25Q512的芯片ID为:0XEF19
const unsigned char Chinses_16[766080]={........};//字库数组
int main() {
size_t size = sizeof(Chinses_16[0]);
size_t count = sizeof(Chinses_16) / size;
FILE *fp = fopen("output.bin", "wb");
if (fp == NULL) {
printf("Failed to open file.\n");
return 1;
}
size_t elements_written = fwrite(Chinses_16, size, count, fp);
if (elements_written != count) {
printf("Failed to write data to file.\n");
fclose(fp);
return 1;
}
fclose(fp);
printf("Data written successfully.\n");
return 0;
}
链接:https://pan.baidu.com/s/1oqJ5WeaJKv6LI-p-LUPojA?pwd=0vfh
提取码:0vfh
SPI FLASH ----- STM32F103VET6
CS ---- PB12
MOSI---- PB15
MISO---- PB14
SCK ---- PB13
----------------------------------
OLED I2C SSD1306 --- STM32F103VET6
SCL----- PB8
SDA ---- PB9
/*
引脚接线说明
SPI FLASH ----- STM32F103VET6
CS ---- PB12
MOSI---- PB15
MISO---- PB14
SCK ---- PB13
----------------------------------
OLED I2C SSD1306 --- STM32F103VET6
SCL----- PB8
SDA ---- PB9
*/
#include "main.h"
#include "usart1.h"
#include "systick.h"
#include "oled_i2c.h"
#include "w25q64.h"
#include "cnfont.h"
#include "codetab.h"
static void CLOCK_Config(void);
static void NVIC_Config(void);
int main(void)
{
CLOCK_Config(); //时钟配置
NVIC_Config(); //中断优先级配置
W25Q64_InitConfig();//初始化W25Q64
USART1_Config();
printf("WRITE Start, FLASH ID=%X\r\n",W25Q64_GetID());
/*字库写入*/
/*字库需要分2次写入FLASH,一次写1半,写完上半部分后,把if 1 改为 if 0,再写下半部分*/
/*CNFont.h也需要同步修改,写完注释掉这段代码*/
/*写完注释掉或者删除掉这段代码*/
// #if 1
// W25Q64_WriteData(W25Q64_GBK_ADDR,(uint8_t *)Chinses_16,383041);
// printf("写字库上半部分 OK!\r\n");
// #else
// W25Q64_WriteData(W25Q64_GBK_ADDR+383041,(uint8_t *)Chinses_16,383039);
// printf("写字库下半部分 OK!\r\n");
// #endif
/*写完注释掉或者删除掉这段代码*/
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
I2C_OLED_Cfg();
OLED_Init();
OLED_Fill(0xFF);//全屏点亮
Delay_ms(50);
OLED_Fill(0x00);//全屏灭
Delay_ms(50);
OLED_CLS();//清屏
OLED_ShowStr(0, 0, (uint8_t *)"Loading now 1...", 2);
Delay_ms(500);
OLED_CLS();//清屏
OLED_DrawBMP(0,0,128,8,LOGO_BMP);
Delay_ms(2000);
OLED_CLS();//清屏
OLED_ShowChinese(0,0,"床前明月光,",16);
OLED_ShowChinese(0,2,"疑是地上霜、",16);
OLED_ShowChinese(0,4,"举头望明月?",16);
OLED_ShowChinese(0,6,"疑是地上霜。",16);
while(1)
{
}
}
//外设时钟配置
static void CLOCK_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);
//1.配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_SetBits(GPIOB,GPIO_Pin_1);
}
//中断优先级初始化
static void NVIC_IRQPriority_Init(uint8_t IRQChannel,uint8_t PreemptionPriority, uint8_t SubPriority)
{
NVIC_InitTypeDef NVIC_IRQ_Init;
NVIC_IRQ_Init.NVIC_IRQChannel = IRQChannel;
NVIC_IRQ_Init.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
NVIC_IRQ_Init.NVIC_IRQChannelSubPriority = SubPriority;
NVIC_IRQ_Init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_IRQ_Init);
}
//配置中断优先级
static void NVIC_Config(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断优先级分组
NVIC_IRQPriority_Init(USART1_IRQn,1,1);
}
链接:https://pan.baidu.com/s/1SPauxXcXfs0JZvhfRF6zDw?pwd=hota
提取码:hota
链接:https://pan.baidu.com/s/1sfs3LxUnYwfvZ8iVMaFeHQ?pwd=onky
提取码:onky
链接:https://pan.baidu.com/s/11Y9boVofu7Og9CnbV1_6oQ?pwd=quun
提取码:quun