目录
1.如何写入LCD1602的自定义字符,即如何写入CGRAM?
前言
暑假在学51单片机,了解到了LCD1602内部有8个可自定义字符,当时也没多想,直到在B站看到了两位佬用LCD1602放坏苹果,太有意思了,本着有屏幕的地方就有BadApple!!的原则,我立马想要复刻一遍。对着LCD1602的手册看了半天,总算是会了写入自定义存储区CGRAM的方法,这下基本是没有其他难点了,我当时这么想着,事实证明我还是太年轻了。我用的普中51开发板,存储空间太小,不能把视频文件全保存下来播放了,只能依靠电脑发送数据,用的串口,波特率57600。
我前前后后分三个时间点重做了三次,第一次是暑假刚学完51那会,我用现成的软件取模,由于LCD1602每个字符是5*8像素,取模每个字节只有后五位有效,我无论如何无法找到适用于这种方式的取模软件,于是我换了种思路,先把视频旋转90°这样正好是8位,然后用那什么stc-isp里自带的串口助手把取模的数据包发送给单片机,然后用算法把这种方式取模的数据处理成可以直接写入CGRAM的数据,就成了。效果不错,但是讲道理,感觉这种算法把简单问题复杂化了,给当时我幼小的心灵造成了很大的打击,苦思冥想一下午才写出来。
第二次重做是国庆假期那会,我反思了这个学会51单片机后做的第一个小项目,觉得有点小尴尬。主要是,太不自动化了,单单是视频处理我都得打开ps用宏把每帧提取出来然后旋转、缩放成20*16像素的尺寸,然后送到取模软件里取模,得到的txt文件还要去除空格,最后送到串口助手里发送。感觉很笨啊这种方式,无论是时间效率还是空间效率都特差,显得我很傻。
于是我就学了点python、opencv、numpy什么的,刚好可以用来处理视频!我写了两个py程序,一个是把视频每帧提取出来并缩放、旋转,省去了我ps的操作,还有一个是把取模后的txt文件自动去除空格然后转换成二进制bin文件,没错,中间用软件取模这个操作我还是手动来,还要经两个py程序,还得手动用串口助手发送数据包!省了点事,但是没完全省,倒是显得我更傻了,其实这也是由于我对python还学艺不精,此时我还不会用python写个取模程序...
于是时间就来到了寒假,也就是现在,经过国庆以来在学校的学习,我决定再次重做一遍,一定要足够优雅。这次我用一天时间,用py程序完成了视频处理取模到串口发送到监控帧率播放进度以及自适应调整延时等所有操作,写了两个线程,一个线程进行视频取模处理,一个线程用来串口发送数据包,而单片机的程序则因此大大化简,取模的复杂算法都在电脑实现了,单片机只要乖乖地接收数据包以及更新显示就行,我还用上了双缓冲刷新机制,但是感觉没啥用。最终也是很完美,现在只用点一下运行py脚本即可在LCD1602那虽小但精致的屏幕上播放坏苹果了!!
其他视频也可以,不过这种像素点级别的屏幕,也只有坏苹果这样的影绘剪影视频可以生动演绎了吧,我猜这也是坏苹果的魅力之一,没有坏苹果我不会整这个小项目,没有它我会失去很多快乐。
纵观整个历程,我好像从幼稚变得稍微成熟了一点,我很享受这种成就感,但也会感叹我当时为什么会这么傻,但是这么想显然是不公平的,毕竟当时我还刚接触没多久,编程方面也是菜鸟一只,而且也许再过半年,那时的自己再看到这个小项目、这篇有感而发的文章时,同样会发出这样的感叹:这孩子怎么这么傻!!
但是很幸运的是,这没什么不好的,说明在进步嘛。我想保存做完一个项目时的那份激动感、成就感,因为这是我打心底里面感到的快乐,我爱电子、我爱单片机、我爱我感兴趣的一切。
多年以后,当面对压力山大的生活和工作,这位同志会想起第一次用lcd1602放坏苹果的那个下午。
原理
好好好打住,停止煽情,下面简要记录一下原理和用到的知识,防止日后遗忘,并且方便有想法但是没思路的小伙伴复刻。
1.如何写入LCD1602的自定义字符,即如何写入CGRAM?
这部分有文档详细介绍,末尾网盘里会有。简单来说,8个字符的地址分别是0x00~0x07,单片机发送指令0x40即可定位到CGRAM中第一个字符的第一行地址,再写入取模后的数据,每行一个字节,写入后地址会自动+1跳到下一行,第一个字符的最后一行写完后会跳到第二个字符的第一行,同理最后一个字符的最后一行写完后会跳到第一个字符。
2.如何取模?如何发送?
在LCD1602中这么排列,先将视频二值化,再缩放至20*16大小,然后进行取模。取模数据用串口发送,单片机初始化串口,波特率为57600,每帧数据包包头0xFF包尾0xFE,数据位为一帧画面的数据,用8*8的二维数组存储,表示第i个字符的第j行取模数据。取模的时候横向每五个像素作为一个字节的后五位,黑色为1白色为0,依次填入数组即可。
3.用到的库及主要函数:
1. OpenCV (
cv2
)
cv2.VideoCapture
: 用于打开和读取视频文件。
cv2.CAP_PROP_FPS
: 获取视频的帧率。
cv2.CAP_PROP_FRAME_COUNT
: 获取视频的总帧数。
cv2.cvtColor
: 将图像从 BGR 转换为 RGB。
cv2.resize
: 调整图像大小。
cv2.imshow
: 显示图像。
cv2.waitKey
: 控制图像显示的刷新间隔。2. NumPy (
np
)
np.ones
: 创建指定大小的数组并初始化为指定值。
np.array
: 将输入数据转换为 NumPy 数组。
np.where
: 对数组中的值进行条件判断和替换。3. Python 串口库 (
serial
)
serial.Serial
: 初始化和操作串口通信。
ser.write
: 通过串口发送数据。
ser.close
: 关闭串口通信。4. PIL (
Image
fromPIL
)
Image.fromarray
: 将 NumPy 数组转换为 PIL 图像。
image.convert
: 转换图像模式(如灰度)。
image.resize
: 调整图像尺寸。5. 多线程与队列
threading.Thread
: 创建并管理线程。
threading.Thread.start
: 启动线程。
threading.Thread.join
: 等待线程执行完成。
queue.Queue
: 用于线程间的数据通信。
queue.Queue.put
: 将数据加入队列。
queue.Queue.get
: 从队列中获取数据。6. 标准库
time.sleep
: 控制程序暂停执行的时间。
time.time
: 获取当前时间戳。
exit
: 退出程序。
4.单片机的程序怎么写?
只需要写两个函数,一个是刷新显示,一个是将一帧数据写入CGRAM。建立两个缓冲区,一个用来接收数据,一个用来写入CGRAM,在串口接收中断中,每当接收到包尾(即0xFE)且本帧数据接收满8*8=64字节时就写入缓冲区,并将两个缓冲区对换,写入CGRAM更新显示。在主循环中可以增加其他逻辑。
源文件
简单拍了个视频记录下:
lcd1602放坏苹果https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048https://www.acfun.cn/v/ac46804048 源文件都放在网盘里了,普中的51开发板可以直接用,py程序里把串口号改一改运行就能出效果。
通过网盘分享的文件:lcd1602放坏苹果.zip
链接: https://pan.baidu.com/s/18ouBvC-CsbbZBrHlGIdxqg?pwd=nwky 提取码: nwky
--来自百度网盘超级会员v4的分享