基于STM32F4xx利用串口播放视频(OLED)

效果视频 : 基于STM32F11的1.3寸OLED屏_驱动芯片SH1106_哔哩哔哩_bilibili

该屏幕用硬件SPI进行驱动的。买屏幕时商家都会提供驱动源码,显示文字,数字等的应该都没问题。我这次主要讲如何显示视频,我的图片显示和文字数字显示是自己写的(也可以私信我获取,但是显示速度没源码快)。

stm32单片机内存不够大,一个视频可能就几M了,完全放不下。视频其实也就一帧一帧照片组合而成,我们会了一张图片的显示也就会了视频的播放了(循环发送图片信息再刷新屏幕显示)。

接下来 我会把视频播放的步骤说一遍 (工具可以到下面网盘链接下载)

第一步骤:视频的图片捕获

        随便下载一个比较长时间的gif 把它后缀改成.mp4用KMPlayer.exe打开

        打开后如下右键屏幕 高级捕获

 

扫描二维码关注公众号,回复: 14745364 查看本文章

先暂停视频,再点击上图开始按钮,然后点击播放视频。你会发现在你上面的文件夹下面出现一堆bmp图片。

 第二步骤:把bmp图片转换成单片机需要的格式

        打开这个工具Img2Lcd.exe  配置弄成下图

        

 再打开第一张bmp

批量转换

选择是       随后就生产很多.ebm文件

这一步就是生成每个图片的ebm格式的内容了,你可以直接用串口发送这个文件  此时屏幕显示的图片就发生变化了。当然前提是你已经把串口接收写好,我用了dma 接收一张图片信息(大概1000多个字节)到了再中断。

所以单片机DMA中断然后就可以显示一张图片了。

为了连续发送所有的ebm文件我用了python 把文件结合一起,上图end.ebm就是python生成的文件。  下面是python的代码 需要下载python编译器不然运行不起来。

import time
import serial
import os

def gain_datas_true():
    meragefiledir = "C:/KMPlayer/Capture/1/batch"  #文件路径
    docList = os.listdir(meragefiledir)  # 将文件下的 文件名存入到 list 中
    docList.sort()  # 对文件名进行排序
    print(docList)

    fname = open("C:/KMPlayer/Capture/1/batch/end.ebm", "wb")  # 打开end.ebm文件 没有自动创建
    for i in docList:
        x = open('C:/KMPlayer/Capture/1/batch/' + i, "rb")  # 打开列表中的文件,读取文件内容
        fname.write(x.read())  # 写入新建的fname文件中
        x.close()
    fname.close()





def main():
    gain_datas_true()





if __name__ == '__main__':
    main()

生成后就完成了,然后直接串口发送就好了,下面是单片机的串口与DMA代码。标准库函数开发

usart.c

#include "usart.h"
#include <stdio.h>


//------------------------------------------------修改以下宏定义可以配置相应的串口初始化----------------------------------------------------
#define USART_TX GPIO_Pin_9	//串口GPIO发送端口
#define USART_RX GPIO_Pin_10	//串口GPIO接收端口

#define USART_GPIO_TypeDef GPIOA	//串口对应的GPIO位置

#define USART_Pin_TX GPIO_PinSource9	//串口映射发送的GPIO
#define USART_Pin_RX GPIO_PinSource10 //串口映射读取的GPIO

#define USART_RCC RCC_APB2Periph_USART1	// 注意串口1/6 是APB2总线  其它是APB1总线
#define USART_GPIO_RCC RCC_AHB1Periph_GPIOA //串口对应的GPIO总线

#define USART_IRQ USART1_IRQn //串口 中断号
#define USART USART1	//串口号
//------------------------------------------------修改以上宏定义可以配置相应的串口初始化----------------------------------------------------
/*
函数功能:初始化串口1
函数参数:uint32_t USART_BaudRate 
函数返回值:无 
函数描述:无
*/
void Usart1_Init(uint32_t USART_BaudRate)
{
	GPIO_InitTypeDef GPIO_InitStruct;    //串口GPIO结构体定义
	USART_InitTypeDef USART_InitStruct; //串口结构体定义
	
	RCC_APB2PeriphClockCmd(USART_RCC,ENABLE);	//使能串口外设的线   注意串口1/6 是APB2总线  其它是APB1总线
	RCC_AHB1PeriphClockCmd(USART_GPIO_RCC,ENABLE);	//使能串口对应的GPIO线
	
	GPIO_PinAFConfig(USART_GPIO_TypeDef,USART_Pin_TX,GPIO_AF_USART1);	//串口发送复用映射
	GPIO_PinAFConfig(USART_GPIO_TypeDef,USART_Pin_RX,GPIO_AF_USART1);	//串口接收复用映射
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_Pin = USART_TX | USART_RX;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(USART_GPIO_TypeDef,&GPIO_InitStruct);	//串口 发送/接受端口初始化
	
	USART_InitStruct.USART_BaudRate = USART_BaudRate;
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStruct.USART_Parity = USART_Parity_No;
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART,&USART_InitStruct); //串口初始化
	
	USART_ReceiveData(USART);	//初始化时候读取一次避免 一开始就有中断
	
	USART_DMACmd(USART,USART_DMAReq_Rx,ENABLE); //读取中断配置
	
	USART_Cmd(USART,ENABLE);
}


/*
函数功能:printf函数重定向
函数参数:无
函数返回值:无 
函数描述:无
*/
int fputc(int ch, FILE * f)
{
	USART->DR = (unsigned char)ch; //USART是上面宏定义的 哪个串口初始化就打印那个串口
	while((USART->SR & 0x80) == 0);	
	return ch;
}
//------------------------------------------------某个串口初始化和打印完成----------------------------------------------------

usart.h

#ifndef _USART_H_
#define _USART_H_



#include "stm32f4xx.h"

void Usart1_Init(uint32_t USART_BaudRate);














#endif

dma.c

#include "dma.h"



/*
函数功能:DMA2初始化
函数参数:无
函数返回值:无
函数描述:DMA2 通道4 不用缓冲FIFO
*/
void Dma2Init(uint32_t DMA_Memory0BaseAddr,uint32_t DMA_PeripheralBaseAddr,uint32_t DMA_BufferSize)
{
	NVIC_InitTypeDef NVIC_InitStruct;	//总中断结构体定义
	DMA_InitTypeDef DMA_InitStruct;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
	
	DMA_InitStruct.DMA_BufferSize = DMA_BufferSize;
	DMA_InitStruct.DMA_Channel = DMA_Channel_4;
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
	DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
	DMA_InitStruct.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;
	DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStruct.DMA_PeripheralBaseAddr = DMA_PeripheralBaseAddr;
	DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;
	
	DMA_Init(DMA2_Stream2,&DMA_InitStruct);
	
	DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);
	
	NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);	//DMA总中断初始化
	
	DMA_Cmd(DMA2_Stream2,ENABLE);
}





dma.h

#ifndef _DMA_H_
#define _DMA_H_



#include "stm32f4xx.h"


void Dma2Init(uint32_t DMA_Memory0BaseAddr,uint32_t DMA_PeripheralBaseAddr,uint32_t DMA_BufferSize);


#endif

主函数中你需要 以下函数

unsigned char UsartData[1056];

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                                     //中断优先级配置

Usart1_Init(115200);                                                                                      //串口初始化
Dma2Init((uint32_t)&UsartData[0],(uint32_t)&(USART1->DR),1056);   //串口使用DMA   

while循环里面如下

if(UsartFlagAchieve)                  //串口数据接收完成                                
    {
        Dis_Piture_Serial(UsartData);   //屏幕显示一张图片的
        UsartFlagAchieve = 0;                //接收完标志位置0 
    }         

现在是利用电脑端存数据 后续开发可以利用片外存储器。

最后最后确保一点 ,就是ebm文件通过串口发送过去必须要显示到完整的图片,不然ebm里面的数据格式不对,你连起来的数据格式也是不可以的。

由于每个人用到OLED屏幕不一样 我用的是1.3寸OLED屏_驱动芯片SH1106 

如果你用的是也是这种显示照片可以私信我哟。

链接:https://pan.baidu.com/s/1WH4T9Tgl1tpDGHDmD5QDBw 
提取码:0225 
--来自百度网盘超级会员V2的分享

猜你喜欢

转载自blog.csdn.net/longjintao1/article/details/126213451