介紹
本文介紹在51單片機上,使用OLED12864(SSD1306)播放視頻,并且使用蜂鳴器播放音樂,
(因為是gif的原因,看著會比較卡,實際上是不會有卡頓的,實際效果可以看文末的視頻鏈接)
最終的效果如下:
播放bad apple的效果:

播放數碼寶貝的效果:

使用到的主要元器件如下:
-
國產51單片機:STC15F2K60S2
-
OLED顯示屏:SSD1306,解析度為128*64
-
無源蜂鳴器,8550三極管等
原理圖如下:

具體方案
由于視頻檔案比較大(MB級別),而51單片機的flash一般都比較小(KB級別),因此把視頻檔案直接存盤在單片機內部顯然是不行的,可以把視頻檔案存盤在SD卡里面,然后單片機讀取SD卡里面的內容;或者視頻檔案直接存盤在電腦上,然后電腦通過串口實時發送視頻資料給單片機,單片機實時顯示視頻畫面,文本采用后者的方案,
OLED12864繪圖
我們購買OLED12864(SSD1306)顯示屏時,一般賣家都會提供51單片機的示例代碼,或者網上也能找到很多相關的代碼,
使用這些代碼在整個螢屏上繪圖時,發現重繪率比較低,在11.0592M時鐘頻率的情況下,實測大概只有8.6fps,測驗方法如下:
void main() { for(;;) { p27 = ~p27; oled_drawbmp(pic); } }
oled_drawbmp為賣家提供的繪圖的函式,每次螢屏重繪一次,p27 IO口翻轉一次,使用邏輯分析儀測驗p27的電平變化如下,可以看到頻率約為4.3Hz,那么螢屏的重繪率大概為8.6Hz(fps),

因為我們的目的是使用單片機在這款顯示屏上播放視頻,而一般視頻的幀率需要大于25fps,幀率過低就會有卡頓的感覺,顯然,上面提到螢屏8.6Hz的重繪率是比較低的,因此我們需要做一些優化,
比較直觀且容易的優化方式之一,就是提高時鐘頻率,把11.0592M提高到24M或者27M的時鐘頻率,
第二個優化方法就是優化繪圖函式,
先來看看iic的開始信號和結束信號的代碼:
void iic_start() //開始iic { scl = 1; sda = 1; delay_5us(); sda = 0; delay_5us(); scl = 0; } void iic_stop() //停止iic { scl = 0; sda = 0; scl = 1; delay_5us(); sda = 1; delay_5us(); }
可以看到,里面有一些延時5微妙(delay_5us),其實這個不是必須的,去掉這個延時,iic同樣可以正常通信,因此,去掉這個延時,可以加快顯示屏的重繪速率,
其次,我們再看看賣家提供繪圖部分的函式:
/***********功能描述:顯示顯示BMP圖片128×64起始點坐標(x,y)*****************/ void oled_drawbmp(unsigned char bmp[]) //畫圖 { unsigned int j = 0; unsigned char x, y; for (y = 0; y < 8; y++) { oled_set_pos(0, y); for (x = 0; x < 128; x++) { iic_writedata(bmp[j++]); } } }
而iic_writedata的實作如下:
void iic_writedata(unsigned char iic_data) //寫資料 { iic_start(); write_byte(0x78); write_byte(0x40); write_byte(iic_data); iic_stop(); }
可以看到,每寫一次影像資料bmp[j],都會有一次iic開始與結束動作,也都會先發送兩個控制指令(0x78, 0x40),這其實沒有必要,優化后的函式如下:
// 快速繪制影像 void oled_drawbmp_fast(unsigned char BMP[]) { unsigned int j = 0; unsigned char x, y; for (y = 0; y < 8; y++) { oled_set_pos(0, y); iic_start(); write_byte(0x78); write_byte(0x40); for (x = 0; x < 128; x++) { write_byte(BMP[j++]); } iic_stop(); } }
可以看到,上面的函式減少了啟動iic、結束iic,減少了寫控制命令(0x78, 0x40),使用跟之前同樣的測驗方法,經過上述的優化,最終螢屏的重繪率如下:

上述的結果為,使用27M時鐘頻率,加上上面提到的幾點優化,可以看出最終螢屏的重繪率約為34.5*2=69Hz(fps),這已經滿足我們播放視頻所需的螢屏重繪率了,
另外,再提一點,其實還可以進一步優化,使得螢屏重繪率達到100fps以上,測驗結果如下,在這里賣個關子,感興趣可以去B站看下,視頻地址為:51單片機播放視頻-原理介紹,

視頻轉碼成十六進制格式
單片機播放視頻,我們需要將視頻轉碼為單片機可以讀取的十六進制資料,
首先我們需要將視頻分解為一幀一幀的影像,然后可以用如下的取模軟體獲得影像的十六進制字模,

但是,由于視頻的幀數比較多,我們一幀一幀手動的使用取模軟體獲取字模,顯然是一個比較累的活,因此,我們可以寫個python代碼,批量生成每幀畫面的十六進制資料,python代碼如下:
import cv2 def bit2num(pixcels): output_val = 0 for i, pix in enumerate(pixcels): if pix > 128: # 白色 output_val += pow(2, i) return output_val def main(): video_path = 'BadApple.flv' cap = cv2.VideoCapture(video_path) # 打開視頻 cnt = 0 fout = open('bad_apple_data.txt', 'w') # while True: ret, frame = cap.read() # 一幀一幀的讀取 if not ret: break cnt += 1 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 轉換為灰度的畫面 frame = cv2.resize(frame, (128, 64)) # 影像尺寸調整到128*64大小 convert_val = [] for row in range(0, 8): # page0 ~ page7 for col in range(0, 128): # seg0 ~ seg127 cur_data = https://www.cnblogs.com/hejunlin1992/archive/2022/05/03/frame[row*8: row*8+8, col] # 取出對應的8個像素點 convert_val.append(str(bit2num(cur_data))) # 轉換成8位的資料 fout.write("%s\n"%(','.join(convert_val))) # cv2.imshow("capture", frame) #顯示畫面 # if cv2.waitKey(30) & 0xff == ord('q'): #按q退出 # break main()
代碼比較簡單,其中會呼叫OpenCV的庫,用來讀取視頻以及視頻畫面對應的像素值,
串口發送
視頻資料準備好之后,我們需要把視頻資料通過串口發送給單片機,單片機接收到完整的一幀資料(一幀畫面)之后,就可以開始顯示畫面,我們同樣可以寫個python代碼來將視頻資料發送給單片機,代碼如下:
import serial # 匯入串口相關的庫 from time import sleep def get_bmp_data(): filepath = 'bad_apple_data.txt' f = open(filepath) bmp_data = [] for line in f: val = line.strip().split(',') if len(val) == 0: continue bmp_data.append([int(x) for x in val]) f.close() return bmp_data def main(): com = serial.Serial('com10', 345600, timeout=10) # 設定埠號,波特率,超時時間 if not com.isOpen(): # 判斷埠是否打開成功 raise "埠打開失敗" bmp_data = get_bmp_data() # 讀取剛剛生成的TXT檔案 for frame in bmp_data: # 一幀一幀的發送資料 ret = com.write(bytes(frame)) # 將資料轉換成二進制后發送 sleep(0.03) # 延時適當時間 main()
代碼比較簡單,其中會呼叫串口相關的serial庫,然后每次回圈發送一幀資料,直至全部發送完成,
小結
最后,總結一下 在51單片機播放視頻的大致流程:
-
視頻解碼成一幀幀的影像,然后再轉碼成顯示屏可以顯示的十六進制格式(這一步可以提前完成)
-
電腦通過串口把十六進制格式的視頻資料發送給單片機
-
單片機接收到完整的一幀資料(一幅影像)后,顯示屏開始顯示畫面
-
同時,蜂鳴器播放音樂(可選)
注:
想進一步了解細節的朋友,可以去B站看下我上傳的視頻,里面的介紹更加詳細一點,也有最終的效果演示,
51單片機播放視頻-原理介紹
51單片機之超級簡易視頻播放器
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/469566.html
標籤:其他
