文章目录
- 链接
- 需求分析
- 取模
-
- pr操作
-
- 修改大小
- python操作
- 显示动画
-
- 前期准备
- 动画帧发送
- 动画实现
- 成品
本系列以SSD1306是主控芯片I2C接口的0.96寸OLED以屏幕为例 内容较多,分节进行
链接
基本命令和寻址方法 IIC(I2C)协议
- OLED软件初始化I2C实现,发送基本数据
- 全屏图像显示
- 全屏动画显示
- 显示字母和数字,汉字
- 画指定的点
- 指定两点画线段
- 指定圆心和半径画圆
- 指定圆心半径角度画圆弧
需求分析
在这一节中,我们制作了一个动画
动画的本质是把图片间隔指定的时间放在屏幕上,利用视觉暂留效应看流畅的动画
- 取模
- 显示图片
- 定时刷新
取模
因为网上没有可以批量取模的软件(几秒钟动画就有几十几百张图片),所以我用了python编写一个批量取模的程序
没有python可直接使用基础
import cv2 as cv import numpy as np sl=50#数量 h=64#行数 l=128#列数 yz=140#阈值 sl=sl 1 def threshold_image(image,a): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) #cv.imshow('origin', gray) ret, binary = cv.threshold(gray, yz, 255, cv.THRESH_BINARY)#
自定义阈值为150,白色大于150 小于黑色 #cv.imwrite("./1/" str(a) ".bmp",binary)#输出 #cv.imshow('origin',binary)#调试用 #cv.waitKey(0) return binary for a in range(1,sl): src = cv.imread(r"C:\Users\HZ1213825\Desktop\1\ (" str(a) ").jpg") zj=threshold_image(src,str(a)) tst=np.asarray(zj) np.set_printoptions(threshold=np.inf) js=0 txt="\nconst uint8_t t"+str(a)+"[128][8]=\n{" # 取反用 # for i in range(h): # for j in range(l): # if tst[i][j] == 255: # tst[i][j]=0 # elif tst[i][j]==0: # tst[i][j]=1 # 不取反用 for i in range(h): for j in range(l): if tst[i][j] == 255: tst[i][j]=1 elif tst[i][j]==0: tst[i][j]=0 t=0 for i in range(0,h,8): for j in range(l): js=0 for z in range(0,8): js=js*2+tst[i+7-z][j] txt+=str(hex(js))+"," t+=1 if t==16: txt+="\n" t=0 txt=txt.rstrip(",") txt+="};" #print(tst) with open("1.txt","a") as fp: fp.write(txt) print("t"+str(a)+',',end="")
需要做一些前期准备,请使用pr将视频剪裁为128 * 64像素,并导出为JPG格式
pr操作
修改大小
导入媒体,双击或拖入都行
拖入工作区创建序列
进入序列设置
更改视频大小
更改视频位置和缩放
加入黑白效果(在效果的视频效果的图形设置里)(将这个黑白拖到视频上就行了)
导出
设置为导出Jpe序列
python操作
将导出的图片批量重命名(全选,重命名)
然后把名字删除,之后回车即可(别删后缀名)
打开python,将代码复制进去 设置图片序列的地址和名字
修改数量和阈值
可以将这两行代码前的#删除(取消注释),来观察阈值是否正确
这是测试(调阈值)的效果
在控制台将取模的数组名打印了出来,方便后续操作
在程序的同级目录有输出文件(1.txt)
已经将前缀和后缀写入了,直接复制到Keil工程中即可
这是软件链接: CSDN
链接:百度网盘 提取码:c95i
显示动画
上文说过,动画就是一帧帧的图片间隔一段时间播放做成的
前期准备
为了更方便的将动画刷新,我建立一个结构体
其内部的参数是二维数组指针
头文件(OLED.H)
typedef struct
{
uc8 (*TDArray)[128];
} OLED_Animation_Array;
在后面可以申请一个结构体数组
uc8 t1[8][128]={
};
uc8 t2[8][128]={
};
uc8 t3[8][128]={
};
OLED_Animation_Array a[3]={
t1,t2,t3};
调用时就可以将其作为数组调用,可以进入循环中使用了,就像这样
for(int i=0;i<3;i++)
a[i].TDArray[2][2]=0;
动画帧发送
发送一张图片的函数只需要稍作修改即可移植过来
C文件(OLED.C)
//动画实现函数 Array:含每帧数据的结构体
void OLED_Animation_Ation(OLED_Animation_Array Array)
{
//使用水平寻址模式模式
OLED_Write_Ctrl_Start();
I2C_SendByte(0x20); //设置寻址模式 (0x00水平/0x01垂直/0x02页)
I2C_SendByte(0x00); //水平寻址模式
I2C_SendByte(0x21); //设置列地址
I2C_SendByte(0x00);
I2C_SendByte(0x7f);
I2C_SendByte(0x22); //设置页地址
I2C_SendByte(0x00);
I2C_SendByte(0x07);
I2C_End();
OLED_Write_Data_Start();
for (int i = 0; i < 8; i++) //扫描页
{
for (int j = 0; j < 128; j++) //扫描列
I2C_SendByte(Array.TDArray[i][j]);
}
I2C_End();
}
动画实现
只需要间隔时间调用上文提到的动画帧发送函数即可,封装为函数
C文件(OLED.C)
//动画刷新函数(有需要修改的值) Time:间隔时间单位ms Num:帧的数量
void OLED_Animation(int Time, int Num)
{
//这个需要修改,修改数组大小和内部值 将uc8 [128][8]的名字按顺序放入
OLED_Animation_Array ac[50] = {
t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24, t25, t26, t27, t28, t29, t30, t31, t32, t33, t34, t35, t36, t37, t38, t39, t40, t41, t42, t43, t44, t45, t46, t47, t48, t49, t50};
OLED_Clear();
for (int i = 1; i <= Num; i++)
{
OLED_Animation_Ation(ac[i - 1]);
Delay_ms(Time);
}
}
输入间隔时间和帧数量即可
成品
stm32控制OLED屏幕显示动画演示
CSDN
链接:百度网盘 提取码:ierk