一、使用STM32CubeMx新建Keil工程
这个不详细介绍,网上一搜一大把,需要把PB8,PB9配置为开漏输出,初始电平为高电平
二、移植OLED驱动程序
我使用的是江协科技的OLED驱动程序,下载地址:0.96寸OLED显示屏_免费高速下载|百度网盘-分享无限制。
下载程序源码后,选择一个版本解压
根据需要选择GB2312/UTF-8
进入Hardware目录,复制里面的四个文件,将其粘贴到自己的工程中
打开Keil工程,将这四个文件添加到工程中
添加头文件路径
需要注意的是:江协的程序是基于标准库的,要将其移植到HAL库中,只需要改动一些代码就行了
#include "stm32f1xx_hal.h" //将"stm32f10x.h" 替换为"stm32f1xx_hal.h"
void OLED_W_SCL(uint8_t BitValue)
{
/*根据BitValue的值,将SCL置高电平或者低电平*/
//GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)BitValue);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, (GPIO_PinState)BitValue); //把标准库的函数替换为HAL库的函数
/*如果单片机速度过快,可在此添加适量延时,以避免超出I2C通信的最大速度*/
//...
}
void OLED_W_SDA(uint8_t BitValue)
{
/*根据BitValue的值,将SDA置高电平或者低电平*/
//GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)BitValue);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, (GPIO_PinState)BitValue); //把标准库的函数替换为HAL库的函数
/*如果单片机速度过快,可在此添加适量延时,以避免超出I2C通信的最大速度*/
//...
}
void OLED_GPIO_Init(void)
{
uint32_t i, j;
/*在初始化前,加入适量延时,待OLED供电稳定*/
for (i = 0; i < 1000; i ++)
{
for (j = 0; j < 1000; j ++);
}
/*可以注释掉引脚配置,在STM32CubeMX中配置PB8,PB9*/
/*将SCL和SDA引脚初始化为开漏模式*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//
// GPIO_InitTypeDef GPIO_InitStructure;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
// GPIO_Init(GPIOB, &GPIO_InitStructure);
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
// GPIO_Init(GPIOB, &GPIO_InitStructure);
/*释放SCL和SDA*/
OLED_W_SCL(1);
OLED_W_SDA(1);
}
打开OLED.Data.h文件,检查宏定义OLED_CHN_CHAR_WIDTH的值是否正确
编译程序,如果出现这样的报错,那么就点击魔术棒→C/C++→在Misc Controls中填入--no-multibyte-chars
编译无错误
如果OLED显示中文逗号,或者,一个方框里面问号的图形,检查编码是否正确
如果还不能显示正确的文字,勾选Use MicroLIB
三、OLED显示汉字
先使用OLED显示一下你好,世界!
将程序下载到开发板中,可以看到,!的位置上显示了一个方框,内部一个问号的图形
打开OLED_Data.c文件,找到365行,发现是因为没有定义!的字模数据,所以显示了这个默认图形
打开取模软件,点击字模生成和液晶面板选项,点阵格式选择阴码,取模方式选择列行式,取模走向选择逆向,输出数制为十六进制,自定义格式选择C51格式,去掉行前缀和行后缀的花括号。
完成设置后,输入!,点击生成字模即可
把生成的字模数据复制到OLED_CF16x16数组中
可以看到,添加了!的字模数据后,!就可以显示出来了
如果想显示其他大小的汉字,比如32X32大小的汉字,可以这样做:
首先,打开取模软件,把字宽和字高设置为32,输入汉字,生成字模
然后,在OLED_Data.h文件中定义字模基本单元(结构体)
typedef struct
{
char Index[OLED_CHN_CHAR_WIDTH + 1]; //汉字索引
uint8_t Data[128]; //字模数据
} ChineseCell32X32_t;
在OLED_Data.c中定义一个数组来存储汉字字模数据
不要忘记在OLED_Data.h中声明这个数组
在OLED.h中,定义两个宏,表示16X16和32X32的汉字大小
然后参考OLED_ShowChinese函数,编写OLED_ShowChinese2函数,尝试将16X16大小的汉字和32X32大小的汉字用一个函数显示出来
void OLED_ShowChinese2(int16_t X, int16_t Y, uint8_t CF_Size,char *Chinese)
{
uint8_t pChinese = 0;
uint8_t pIndex;
uint8_t i;
char SingleChinese[OLED_CHN_CHAR_WIDTH + 1] = {0};
for (i = 0; Chinese[i] != '\0'; i ++) //遍历汉字串
{
SingleChinese[pChinese] = Chinese[i]; //提取汉字串数据到单个汉字数组
pChinese ++; //计次自增
/*当提取次数到达OLED_CHN_CHAR_WIDTH时,即代表提取到了一个完整的汉字*/
if (pChinese >= OLED_CHN_CHAR_WIDTH)
{
pChinese = 0; //计次归零
/*遍历整个汉字字模库,寻找匹配的汉字*/
/*如果找到最后一个汉字(定义为空字符串),则表示汉字未在字模库定义,停止寻找*/
if(CF_Size == OLED_CF16X16)
{
for (pIndex = 0; strcmp(OLED_CF16x16[pIndex].Index, "") != 0; pIndex ++)
{
/*找到匹配的汉字*/
if (strcmp(OLED_CF16x16[pIndex].Index, SingleChinese) == 0)
{
break; //跳出循环,此时pIndex的值为指定汉字的索引
}
}
/*将汉字字模库OLED_CF16x16的指定数据以16*16的图像格式显示*/
OLED_ShowImage(X + ((i + 1) / OLED_CHN_CHAR_WIDTH - 1) * 16, Y, 16, 16, OLED_CF16x16[pIndex].Data);
}
else if(CF_Size == OLED_CF32X32)
{
for (pIndex = 0; strcmp(OLED_CF32x32[pIndex].Index, "") != 0; pIndex ++)
{
/*找到匹配的汉字*/
if (strcmp(OLED_CF32x32[pIndex].Index, SingleChinese) == 0)
{
break; //跳出循环,此时pIndex的值为指定汉字的索引
}
}
/*将汉字字模库OLED_CF16x16的指定数据以32*32的图像格式显示*/
OLED_ShowImage(X + ((i + 1) / OLED_CHN_CHAR_WIDTH - 1) * 32, Y, 32, 32, OLED_CF32x32[pIndex].Data);
}
}
}
}
在OLED.h中声明这个函数
用OLED分别显示16X16大小的汉字:你好世界,32X32大小的汉字:世界你好
把程序下载到开发板上,现象如下
如果要显示其他大小的汉字也可以参照上面的方法
四、OLED显示图像
打开取模软件,点击模式→图形模式,新建图像,宽:16,高:16
绘制图像,点击鼠标左键绘制,鼠标右键取消
在OLED_Data.c中定义数组
在OLED_Data.h中声明数组
调用OLED_ShowImage函数显示图像
接下来是显示图片,我们可以用Matlab对图片进行一些处理
I = imread('OIP-C.bmp');
subplot(1,2,1);
imshow(I) % 显示原图
title('原图');
thresh1 = graythresh(I);
I1 = im2bw(I,thresh1); % 对图像直接进行二值化
I2 = imresize(I1,[64,64]);%调整图片大小,调整为宽64,高64
subplot(1,2,2);
imshow(I2);
title('最终图像');
imwrite(I2,'最终图像.bmp','bmp');
处理结果如下:
点击打开一个bmp图像,这样取模软件就能自动绘制出图像
点击生成字模,重复上述定义数组等步骤,最后结果如下: