OLED12864播放视频

本文介绍如何使用C#编写上位机软件,通过串口将128x64分辨率的图片传送到NodeMCU单片机,配合u8g2库实现在OLED12864屏幕上播放视频。作者分享了代码实现,并提到通过PotPlayer截图获取128x64的图片,按照时间顺序命名以便播放。单片机端的NodeMCU程序接收并显示图片,实现了简单的视频播放功能。
摘要由CSDN通过智能技术生成

OLED12864播放视频

最近看了B站up@会飞的阿卡林做的一个主板小屏幕,可以在一块0.96寸的12864上播放视频,觉得十分不错,up还附上了上位机软件和NodeMCU单片机的代码。不过上位机代码我好像没找到,所以心血来潮自己写了一个。但是我也是临时学的C#,代码写得不太好,勉强能用,等后面学了界面再来改进。先附上这个up的视频地址 视频地址

上位机代码

​ 我们不可能把整个视频放到NodeMCU里,所以要通过串口把一张张分辨率128x64的图片通过串口发到单片机里让它驱动屏幕显示出来。其实之前也试过用WIFI来发,不过不知道为啥贼慢。上位机里要做的就是读取图片、转换成oled12864能用的字节数组再通过串口发送而已。

using System;
using System.IO.Ports;
using System.Threading;
using System.IO;
using System.Drawing;
using System.Collections;

namespace ConsoleApp10
{
    class Program
    {
        public class Comparer : IComparer  //图片序列按照文件名给出的的时间进行比较,确保播放顺序正确
        {
            public int Compare(Object x, Object y)
            {
                string s1 = (string)x;
                string s2 = (string)y;

                string name1 = s1.Substring(0, s1.Length - 4);
                string name2 = s2.Substring(0, s1.Length - 4);

                return Convert.ToDouble(name1) > Convert.ToDouble(name2) ? 1 : -1;
            }
        }
        static bool PicToByte(string path,ref Byte[] temp)  //将图片转换为单片机可用的字节数组
        {
            try
            {
                string bits = "";
                int count = 0;
                int byteCount = 0;
                Bitmap bitmap = new Bitmap(path);
                for (int i = 0; i < bitmap.Height; ++i)
                {
                    for (int j = 0; j < bitmap.Width; ++j)
                    {
                        Color c = bitmap.GetPixel(j,i);
                        int rgb= (int)(c.R * .3 + c.G * .59 + c.B * .11)  ;//灰度公式
                        bits += rgb > 100 ? '1' : '0';                        
                        ++count;                        
                        if (count%8 == 0)
                        {
                            temp[byteCount++] = Convert.ToByte(bits, 2);
                            bits = "";
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
            Array.Reverse(temp); //切换大小端
            return true;
        }
        static void Main(string[] args)
       {
            try
            {
                string[] ports = SerialPort.GetPortNames();
                if (ports.Length == 0)
                {
                    Console.WriteLine("No Avaliable Serial Port...");
                    return;
                }
                SerialPort port = new SerialPort(ports[0], 1000000, Parity.None, 8);//端口的初始化设置
                port.StopBits = StopBits.One;
                port.Open();
                Byte[] test = new byte[1024];
                string path = "F:\\截取";
                DirectoryInfo dInfo = new DirectoryInfo(path);
                FileInfo[] fInfo = dInfo.GetFiles();
                Console.Clear();
                string[] fileName = new string[fInfo.Length];
                int count = 0;
                foreach (FileInfo f in fInfo)
                {
                    fileName[count++] = f.Name;
                }
                Array.Sort(fileName, new Comparer());//按照时间对所有文件名排序

                Console.WriteLine("Pree Any Key to Start");
                Console.ReadKey();
                Console.WriteLine("Playing...");

                int p = 0;
                for (; ; )
                {
                    PicToByte(path + @"\" + fileName[p], ref test);
                    p += 2; //每4张图片播放一张,配合下面的sleep可以达到稍微能看的播放速度
                    if (p >= fileName.Length)
                    {
                        p = 0;  //播放完从头播放
                    }
                    port.Write(test, 0, 1024);
                    Thread.Sleep(45);
                }
            } 
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return;
            }
        }
    }
}

NodeMCU程序

​ 单片机的程序只需要接收发来的图片数组就行。一张图片为128x24=8192bit=1024byte,也就是这个图片数组将有1024个元素。可能是单片机缓冲区的问题还是啥这么多数据不能一次接收完得分多次才行。接收之后直接调用u8g2库的显示图片函数就完成了:

#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned char col[1024] = {};//储存图片数据的数组
unsigned int n = 0;

void setup(void) {
  u8g2.begin();
  u8g2.clearBuffer();

  Serial.begin(1000000);  
  while (Serial.available() > 0)
    Serial.read();
  printStr("Running");
}

void loop(void) {
  if (Serial.available() > 0 && n < 1024) { 
    while (Serial.available() > 0) {
      col[n++] = Serial.read();
    }
    if (n < 1024) { //没有读取1024个数据将进入下一循环继续读取
      return;
    }
	//读取了一整个图片数据,可以显示在屏幕上了
    u8g2.clearBuffer();
    u8g2.drawXBM(0, 0, 128, 64, col);
    u8g2.sendBuffer();
    n = 0;  //重置计数以读取下一帧的数据
  }
}

void printStr(char* str) {
  u8g2.clearBuffer();          // clear the internal memory
  u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
  u8g2.drawStr(10, 10, str); // write something to the internal memory
  u8g2.sendBuffer();
}
关于图片的获取

可以使用PotPlayer的截图功能,根据视频的时长和想要的帧数采集一定数量的图片。注意这些图片尺寸设置为128x64,格式可以是BMP和PNG,用播放的时间命名文件就OK。另外再改一下上位机程序里的图片路径到截图路径。

在这里插入图片描述

效果如下

在这里插入图片描述

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值