01
【米爾MYD-YA15XC-T評(píng)測(cè)】+開箱上電測(cè)試
STM32MP1 是意法半導(dǎo)體推出的首款 MPU,其內(nèi)部集成了 1-2 顆主頻 650MHz 的 Arm Cortex-A7 應(yīng)用處理器內(nèi)核和 1 顆運(yùn)行頻率 209MHz 的高性能 Arm Cortex-M4 微 控制器內(nèi)核。兩種內(nèi)核之間分工明確、配合默契,Cortex-A7 內(nèi)核專用于開源操作系統(tǒng), Cortex-M4 內(nèi)核則專用于實(shí)時(shí)及低功耗任務(wù)處理。這一靈活的異構(gòu)計(jì)算架構(gòu)在單一芯片 上執(zhí)行快速數(shù)據(jù)處理和實(shí)時(shí)任務(wù),可以實(shí)現(xiàn)最高的能效。MYC-YA15XC-T 核心板基于 STM32MP1 系列處理器研制,完美繼承了該處理器高 性能、低功耗的優(yōu)點(diǎn),且擁有良好的軟件開發(fā)環(huán)境,Cortex-A7 內(nèi)核支持開源操作系統(tǒng) Linux,Cortex-M4 內(nèi)核完美沿用現(xiàn)有的 STM32 MCU 生態(tài)系統(tǒng),有助于開發(fā)者輕松實(shí) 現(xiàn)各類開發(fā)應(yīng)用。
這次的板卡包裝比米爾以往的板卡包裝大得多。
包裝很用心:含有指導(dǎo)手冊(cè)
電源適配器贈(zèng)送了不同國家的插口適配器:
一如既往的黑色沉金
板卡背面
贈(zèng)送了塑料螺柱
上電效果
接下來就需要下載資料進(jìn)行交叉編譯器和SDK環(huán)境的安裝了。
02
【米爾MYD-YA15XC-T評(píng)測(cè)】+ USB UVC攝像頭測(cè)試
UVC全稱為USB Video Class,即:USB視頻類,是一種為USB視頻捕獲設(shè)備定義的協(xié)議標(biāo)準(zhǔn)。是Microsoft與另外幾家設(shè)備廠商聯(lián)合推出的為USB視頻捕獲設(shè)備定義的協(xié)議標(biāo)準(zhǔn),已成為USB org標(biāo)準(zhǔn)之一。米爾MYD-YA15XC-T開發(fā)板內(nèi)核已經(jīng)開啟了UVC驅(qū)動(dòng),因此插入U(xiǎn)SB UVC攝像頭后可以看到識(shí)別信息:
V4L2是Video for linux2的簡(jiǎn)稱,為linux中關(guān)于視頻設(shè)備的內(nèi)核驅(qū)動(dòng)。在Linux中,視頻設(shè)備是設(shè)備文件,可以像訪問普通文件一樣對(duì)其進(jìn)行讀寫,攝像頭在/dev/video*下,如果只有一個(gè)視頻設(shè)備,通常為/dev/video0。v4l2-ctl是用戶空間一組用于測(cè)試,配置和使用整個(gè)相機(jī)子系統(tǒng)的工具,包括外部相機(jī)傳感器和相機(jī)接口。v4l2-ctl 是最有用的實(shí)用工具。
v4l2-ctl基本常用的命令如下:
-
使用--list-devices選項(xiàng)列出所有可用的視頻設(shè)備
-
v4l2-ctl --list-devices
-
獲得有關(guān)特定設(shè)備的信息,加上-D 選項(xiàng):
-
v4l2-ctl -d /dev/video1 -D
-
v4l2-ctl -L -d /dev/video1
其中可以通過 --set-ctrl 選項(xiàng)更改控制值,如:
-
v4l2-ctl --set-ctrl test_pattern=1
控制值可以動(dòng)態(tài)更改。
-
設(shè)置像素格式,分辨率和幀率,使用 --list-formats-ext 選項(xiàng)可獲取受支持的像素格式、分辨率和幀速率:
-
v4l2-ctl --list-formats-ext -d /dev/video1
-
查看當(dāng)前攝像頭支持的視頻壓縮格式
-
v4l2-ctl -d /dev/video1 --list-formats
-
查看攝像頭所有參數(shù)
-
v4l2-ctl -d /dev/video1 --all
-
查看攝像頭所支持的分辨率
-
v4l2-ctl --list-framesizes=MJPG -d /dev/video1
GStreamer是用于創(chuàng)建流媒體應(yīng)用程序的框架,開發(fā)板集成了gstreamer系列命令。
-
單次拍照
-
gst-launch-1.0 v4l2src device=/dev/video1 num-buffers=1 ! image/jpeg,width=1920,height=1080 ! filesink location=/tmp/capture.jpg
使用 gst-typefind 命令檢查圖片分辨率
-
gst-typefind-1.0 /tmp/capture.jpg
初步完成了usb攝像頭圖像的采集,后續(xù)將研究簡(jiǎn)單的圖像處理,視頻采集,體驗(yàn)米爾MYD-YA15XC-T開發(fā)板的多媒體處理性能。
03
【米爾MYD-YA15XC-T評(píng)測(cè)】+使用mjpg-streamer搭建網(wǎng)絡(luò)攝像頭
0、mjpg-streamer介紹
mjpg-streamer是一款免費(fèi)基于IP地址的視頻流服務(wù)器,它的輸入插件從攝像頭讀取視頻數(shù)據(jù),這個(gè)輸入插件產(chǎn)生視頻數(shù)據(jù)并將視頻數(shù)據(jù)復(fù)制到內(nèi)存中,它有多個(gè)輸出插件將這些視頻數(shù)據(jù)經(jīng)過處理,其中最重要的輸出插件是網(wǎng)站服務(wù)器插件,它將視頻數(shù)據(jù)傳送到用戶瀏覽器中,mjpg-streamer的工作就是將其中的一個(gè)輸入插件和多個(gè)輸出插件綁定在一起,所有的工作都是通過它的各個(gè)插件完成的。mjpg-streamer各個(gè)文件如下:
(1)input_testpicture.so。這是一個(gè)圖像測(cè)試插件,它將預(yù)設(shè)好的圖像編譯成一個(gè)頭文件,可以在沒有攝像頭的情況下傳輸圖像,從而方便調(diào)試程序。
(2)input_uvc.so。此文件調(diào)用USB攝像頭驅(qū)動(dòng)程序V4L2,從攝像頭讀取視頻數(shù)據(jù)。
(3)input_control.so。這個(gè)文件實(shí)現(xiàn)對(duì)攝像頭轉(zhuǎn)動(dòng)的控制接口。
(4)output_http.so。這是一個(gè)功能齊全的網(wǎng)站服務(wù)器,它不僅可以從單一文件夾中處理文件,還可以執(zhí)行一定的命令,它可以從輸入插件中處理一幅圖像,也可以將輸入插件的視頻文件根據(jù)現(xiàn)有M-JPEG標(biāo)準(zhǔn)以HTTP視頻數(shù)據(jù)服務(wù)流形式輸出。
(5)output_file.so。這個(gè)插件的功能是將輸入插件的JPEG圖像存儲(chǔ)到特定的文件夾下,它可以用來抓取圖像。
mjpg-streamer優(yōu)點(diǎn)是對(duì)RAM和CPU的消耗比較少,可以快速的傳輸jpeg流。
一、米爾SDK安裝
在終端執(zhí)行命令:
-
. /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
將設(shè)置好交叉編譯工具鏈,常用的環(huán)境變量如CC。
二、libjpeg交叉編譯
有些UVC攝像頭只支持輸出YUV原始圖像,此時(shí)mjpg-streamer會(huì)將其轉(zhuǎn)碼為mjpeg,然后進(jìn)行傳輸,此時(shí)會(huì)對(duì)CPU的消耗以及實(shí)時(shí)流的流暢度有影響,特別是分辨率比較大的時(shí)候。
因此mjpg-streamer 依賴 libjpeg, libjpeg下載地址:
http://www.ijg.org/
目前最新版本是v9d。libjpeg交叉編譯命令:
-
make clean
-
. /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
-
./configure --host=arm-ostl-linux-musl --prefix=$HOME/stm32mp1/build_jpegsrc.v9d
-
make -j6
-
make install
寫成編譯腳本:
編譯成功后得到動(dòng)態(tài)庫:
米爾MYD-YA15XC-T內(nèi)核已經(jīng)配置好了UVC和USB 驅(qū)動(dòng),因此無需重新配置編譯內(nèi)核。
三、mjpg-streamer交叉編譯
mjpeg-streamer下載
https://sourceforge.net/p/mjpg-streamer/code/HEAD/tree/
目前最新版本為r182,本次測(cè)試使用版本r63。
在ubuntu可通過2種命令下載代碼:
-
svn checkout svn://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-code
或者
-
svn checkout https://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-code
在編譯前需要對(duì)源碼的Makefile做以下修改:
將源碼的所有Makefile(包含其子目錄)中的編譯工具鏈修改為米爾開發(fā)板的編譯工具鏈,由于在終端執(zhí)行命令. /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi會(huì)設(shè)置好交叉編譯相關(guān)的環(huán)境變量,因此去掉Makefile文件中的CC 即可。
本次測(cè)試只需要 input_uvc.so 和 output_http.so,在主目錄中的Makefile里面只選擇這兩個(gè),其它的去掉。
插件input_uvc依賴jpeg,因此修改plugins/input_uvc/Makefile文件,指定jpeg庫頭文件路徑:
-
CFLAGS += -I$HOME/stm32mp1/build_jpegsrc.v9d/include
指定鏈接jpeg動(dòng)態(tài)庫路徑:
-
-ljpeg -L$HOME/stm32mp1/build_jpegsrc.v9d/lib
編譯成功之后,在lib目錄會(huì)生成如下輸入、輸出動(dòng)態(tài)庫文件:
在mjpg-streamer-r63目錄生成mjpg-streamer可執(zhí)行文件:
查看一下mjpg-streamer文件信息,ARM 32位可執(zhí)行程序:
將上面生成的動(dòng)態(tài)庫文件都復(fù)制到lib目錄:
然后將lib目錄里面的文件和mjpg-streamer可執(zhí)行文件一起打包為app_and_lib.tar.xz,使用SCP命令將它復(fù)制到開發(fā)板home目錄:
解壓:
得到如下文件,使用chmod +x mjpg-streamer命令為mjpg-streamer添加可執(zhí)行權(quán)限:
四、測(cè)試
插入U(xiǎn)SB UVC攝像頭,正確識(shí)別到了視頻設(shè)備:
手動(dòng)指定一下庫路徑:
-
export LD_LIBRARY_PATH=./
執(zhí)行下列命令啟動(dòng)mjpg-streamer:
-
./mjpg_streamer -i "input_uvc.so -r 1920x1080" -o "output_http.so -w ./www"
如果是輸出YUV格式的UVC攝像頭,則執(zhí)行命令:
-
./mjpg_streamer -i "input_uvc.so -y -r 1920x1080" -o "output_http.so -w ./www
查看圖片,在瀏覽器輸入:
http://192.168.1.136:8080/?action=snapshot
查看視頻,在瀏覽器輸入:
http://192.168.1.136:8080/?action=stream
其中192.168.1.136為開發(fā)板IP地址。
附錄:
MJPG簡(jiǎn)介:MJPEG全名為 "Motion Joint Photographic Experts Group",是一種視頻編碼格式,Motion JPEG技術(shù)常用于閉合電路的電視攝像機(jī)的模擬視頻信號(hào)“翻譯”成視頻流,并存儲(chǔ)在硬盤上。典型的應(yīng)用如數(shù)字視頻記錄器等。MJPEG不像MPEG,不使用幀間編碼,因此用一個(gè)非線性編輯器就很容易編輯。MJPEG的壓縮算法與MPEG一脈相承,功能很強(qiáng)大,能發(fā)送高質(zhì)圖片,生成完全動(dòng)畫視頻等;從另一個(gè)角度說,在某些條件下,MJPEG也許是效率最低的編碼/解碼器之一。MJPEG與MJPG的區(qū)別:mjpeg是視頻,就是由系列jpg圖片組成的視頻。
還有一款MJPG視頻流服務(wù)開源軟件uStreamer:
μStreamer is a lightweight and very quick server to streamMJPGvideo from any V4L2 device to the net.
https://github.com/pikvm/ustreamer
04
【米爾MYD-YA15XC-T評(píng)測(cè)】+ 使用ffmpeg音視頻處理軟件處理多媒體文件(上)
在多媒體音視頻處理應(yīng)用中一個(gè)常見的需求就是給視頻或者圖像疊加水印文字、圖片logo等。以下是ffmpeg的介紹:
FFmpeg是一套可以用來記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開源計(jì)算機(jī)程序。采用LGPL或GPL許可證。它提供了錄制、轉(zhuǎn)換以及流化音視頻的完整解決方案。它包含了非常先進(jìn)的音頻/視頻編解碼庫libavcodec,為了保證高可移植性和編解碼質(zhì)量,libavcodec里很多code都是從頭開發(fā)的。
FFmpeg在Linux平臺(tái)下開發(fā),但它同樣也可以在其它操作系統(tǒng)環(huán)境中編譯運(yùn)行,包括Windows、Mac OS X等。這個(gè)項(xiàng)目最早由Fabrice Bellard發(fā)起,2004年至2015年間由Michael Niedermayer主要負(fù)責(zé)維護(hù)。許多FFmpeg的開發(fā)人員都來自MPlayer項(xiàng)目,而且當(dāng)前FFmpeg也是放在MPlayer項(xiàng)目組的服務(wù)器上。項(xiàng)目的名稱來自MPEG視頻編碼標(biāo)準(zhǔn),前面的"FF"代表"Fast Forward"。[1] FFmpeg編碼庫可以使用GPU加速。
FFmpeg是一套可以用來記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開源計(jì)算機(jī)程序。它包括了領(lǐng)先的音/視頻編碼庫libavcodec等。
libavformat:用于各種音視頻封裝格式的生成和解析,包括獲取解碼所需信息以生成解碼上下文結(jié)構(gòu)
和讀取音視頻幀等功能;
libavcodec:用于各種類型聲音/圖像編解碼;
libavutil:包含一些公共的工具函數(shù);
libswscale:用于視頻場(chǎng)景比例縮放、色彩映射轉(zhuǎn)換;
libpostproc:用于后期效果處理;
ffmpeg:該項(xiàng)目提供的一個(gè)工具,可用于格式轉(zhuǎn)換、解碼或電視卡即時(shí)編碼等;
ffsever:一個(gè) HTTP 多媒體即時(shí)廣播串流服務(wù)器;
ffplay:是一個(gè)簡(jiǎn)單的播放器,使用ffmpeg 庫解析和解碼,通過SDL顯示;
本次就打算使用ffmpeg進(jìn)行中英文特殊字符水印、圖片水印的疊加測(cè)試,首先在電腦端實(shí)現(xiàn)功能,然后交叉編譯移植到米爾MYD-YA15XC-T平臺(tái),順便定性對(duì)比下電腦和米爾MYD-YA15XC-T的多媒體處理性能。
在編譯ffmpeg前需要先編譯字體處理軟件freetype,這里使用了freetype-2.10.2版本。
編譯命令如下:
-
make clean
-
./configure --prefix=/opt/nrjd/nrjd-olms-0201/apps/aaa/comm/pc/freetype --with-zlib=no --with-png=no --enable-static=no
-
make -j12
-
make install
-
make clean
然后編譯ffmpeg,指定freetype庫和頭文件路徑:
-
make clean
-
./configure --enable-shared --disable-static --target-os=linux --enable-libx264 --enable-gpl --enable-libfreetype --enable-filter=drawtext --extra-cflags="-I/home/qldeng/ffmpeg_watermark_test/ffmpeg_test_pc/comm/pc/freetype/include/freetype2" --extra-ldflags="-L/home/qldeng/ffmpeg_watermark_test/ffmpeg_test_pc/comm/pc/freetype/lib" --prefix=/home/qldeng/ffmpeg_watermark_test/ffmpeg_test_pc/comm/pc/ffmpeg
-
make -j12
-
make install
-
make clean
項(xiàng)目文件夾內(nèi)容如下:
-
qldeng@ubuntu:~/ffmpeg_watermark_test/ffmpeg_test_pc$ tree -L 2
-
.
-
├── build
-
├── CMakeLists.txt
-
├── comm
-
│ ├── ffmpeg-4.4
-
│ ├── freetype-2.10.2
-
│ └── pc
-
├── in.jpg
-
├── logo.png
-
├── main.cpp
-
├── out.jpg
-
├── readme.txt
-
├── SourceHanSansCN-Bold.ttf
-
├── toolchain.cmake
-
└── 捕獲.PNG
-
5 directories, 9 files
測(cè)試項(xiàng)目使用CMake構(gòu)建,CMakeLists.txt內(nèi)容如下:
-
cmake_minimum_required(VERSION 3.17)
-
#輸出可執(zhí)行文件的文件名
-
set(ARTIFACT_NAME myapp)
-
project(${ARTIFACT_NAME})
-
set(CMAKE_CXX_STANDARD 11)
-
set(CMAKE_C_STANDARD 99)
-
set(MYLIBS_PATH /opt/nrjd/nrjd-olms-0201/apps/ffmpeg_test_pc/comm/pc)
-
set(INC_DIR
-
${PROJECT_SOURCE_DIR}
-
${MYLIBS_PATH}/freetype/include/freetype2
-
${MYLIBS_PATH}/ffmpeg/include
-
)
-
set(LINK_DIR
-
${MYLIBS_PATH}/freetype/lib
-
${MYLIBS_PATH}/ffmpeg/lib
-
)
-
include_directories(${INC_DIR})
-
link_directories(${LINK_DIR})
-
aux_source_directory(${PROJECT_SOURCE_DIR} SOURCE_FILES)
-
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
-
link_libraries(
-
freetype
-
avcodec
-
avdevice
-
avfilter
-
avformat
-
avutil
-
postproc
-
swresample
-
swscale
-
)
-
add_executable(${ARTIFACT_NAME} ${SOURCE_FILES})
-
target_link_libraries(${ARTIFACT_NAME}
-
freetype
-
avcodec
-
avdevice
-
avfilter
-
avformat
-
avutil
-
postproc
-
swresample
-
swscale
-
pthread)
main.cpp是測(cè)試代碼,直接使用system函數(shù)調(diào)用ffmpeg即可,需要注意的是特殊符號(hào)需要轉(zhuǎn)義:
-
cmd = "ffmpeg -loglevel quiet -i " + string(dest_path) + " -vf drawtext="fontcolor=white:fontfile=SourceHanSansCN-Bold.ttf:fontsize=40:x=w-tw-th/2:y=h-th-th::alpha=0.65:box=1:boxcolor=0x000000:text='" + string(s5) + "" -y " + string(dest_path);
-
system(cmd.c_str());
-
float battery_voltage = 12.345;
-
float battery_current = 0.678;
-
float device_temperature = 37.2;
-
s1 = "日期\\:" + string(str) + """;
-
memset(str, 0, sizeof(str));
-
sprintf(str, "處理器\\:%0.1f\℃ 電源\\:%0.1fV %0.2fA CSQ\\:%d%%", device_temperature, battery_voltage,battery_current,64);
-
s2 = string(str);
toolchain.cmake內(nèi)容:
-
set(CMAKE_CXX_COMPILER g++)
-
set(CMAKE_C_COMPILER gcc)
進(jìn)入build目錄,打開終端執(zhí)行以下命令進(jìn)行編譯:
-
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake ..
-
make
可以看到圖片上疊加了預(yù)期的水印內(nèi)容,處理時(shí)間183毫秒:
下一步就是眼睛就如何正確交叉編譯ffmpeg到米爾MYD-YA15XC-T平臺(tái)了,周六晚上折騰了半天,雖然編譯出了命令行工具個(gè)庫,但是放到米爾MYD-YA15XC-T里面無法運(yùn)行,總是提示命令找不到,還得仔細(xì)研究下。
05
【米爾MYD-YA15XC-T評(píng)測(cè)】+ 使用STM32CubeProgrammer軟件更新系統(tǒng)固件
米爾提供的資料01_Documents\User_Manual\Chinese\軟件手冊(cè)\MYD-YA15XC-T_Linux軟件開發(fā)指南V1.0.0.pdf第四節(jié)描述了如何更新系統(tǒng)固件。
MYC-YA15XC-T 開發(fā)板采用的是 ST 公司的 STM32MP1 系列微處理器,原生支持使用ST推出的STM32CubeProgrammer軟件更新系統(tǒng)固件,只需要連接一根USB線通信即可完成燒錄固件,快速方便。按照米爾提供的資料,實(shí)際使用中遇到些小問題。
首先選擇啟動(dòng)模式,將撥碼開關(guān)撥到 Download 模式(B2/B1/B0 : 0/0/0)。將開發(fā)板的 J5 USB接口與電腦連接,插入電源適配器。如下圖所示:
這時(shí)候可以在電腦發(fā)現(xiàn)USB DFU設(shè)備了:
打開 STM32CubeProgrammer 軟件,選擇 USB燒錄方式:
點(diǎn)擊 connect按鈕連接,連接正常就會(huì)顯示處理器的信息,如下圖:
根據(jù)本開發(fā)板的處理器選擇的燒錄包位于目錄myir-image-core\256N256D。然后點(diǎn)擊Open File,選擇nand的 TSV 文件myir-image-core\256N256D\myir-image-core\flashlayout_myir-image-core\trusted\FlashLayout_nand-2-256_stm32mp15xc-ya151c-256d-t-trusted.tsv,如下圖所示:
但是按照這個(gè)步驟燒錄出錯(cuò)了:
根據(jù)錯(cuò)誤原因提示,將目錄myir-image-core\256N256D\myir-image-core下的arm-trusted-firmware、bootloader、myir-image-core-openstlinux-eglfs-myir-ya151c-t_nand_2_256_multivolume.ubi復(fù)制到目錄myir-image-core\256N256D\myir-image-core\flashlayout_myir-image-core\trusted下即可:
然后就可以燒錄成功了:
06
【米爾MYD-YA15XC-T評(píng)測(cè)】+ epoll串口通信
串口是嵌入式系統(tǒng)中最常用的接口之一,系統(tǒng)終端通常都是串口。除了終端功能之外,實(shí)際應(yīng)用中,Linux系統(tǒng)也經(jīng)常通過串口與其它設(shè)備進(jìn)行通信和數(shù)據(jù)傳遞,如232、485等接口傳感器通常底層都是串口。在Linux下的串口編程不像微控制器上那么簡(jiǎn)單。本帖以米爾MYD-YA15XC-T為例,實(shí)現(xiàn)串口基本操作、串口屬性設(shè)置、如串口數(shù)據(jù)讀寫。米爾MYD-YA15XC-T開發(fā)板擴(kuò)展排針接口引出了串口3供我們使用。位置如下圖所示:
終端使用ls /dev/tty*命令查看設(shè)備文件:
Linux的串口表現(xiàn)為設(shè)備文件,Linux的串口設(shè)備文件命名一般為/dev/tty*,米爾MYD-YA15XC-T開發(fā)板串口設(shè)備命名為/dev/ttySTM*。
可以看到串口3對(duì)應(yīng)的設(shè)備文件是/dev/ttySTM3,使用一個(gè)TTL串口調(diào)試助手連接到串口3:
首先使用echo命令測(cè)試發(fā)送數(shù)據(jù),可以看到串口3收到了數(shù)據(jù):
接下來通過編寫代碼的方式實(shí)現(xiàn)串口的數(shù)據(jù)收發(fā)。
首先配置網(wǎng)絡(luò),因?yàn)楹竺婵截愇募介_發(fā)板需要用到。
在編寫Linux串口的C程序代碼時(shí),需要包含termios.h頭文件。主要流程為:
打開串口:用open()函數(shù)打開它所對(duì)應(yīng)的設(shè)備文件。
關(guān)閉串口:用close()函數(shù)關(guān)閉串口。
發(fā)送數(shù)據(jù):使用write()函數(shù)可以發(fā)送數(shù)據(jù)。
讀取數(shù)據(jù):使用read()函數(shù)可以讀取接收到的數(shù)據(jù)。
此外,如果對(duì)串口屬性進(jìn)行設(shè)置需要包含頭文件,該文件包含了POSIX終端屬性描述結(jié)構(gòu)struct termios。
完整的代碼如下所示:
-
#include
-
using namespace std;
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
class MySerial
-
{
-
private:
-
int fd = -1;
-
string serial_dev;
-
int serial_baudrate;
-
string serial_parity;
-
int serial_databits;
-
int serial_stopbits;
-
void* (*rx_cb_fun)(void*);
-
int epfd;
-
struct epoll_event event;// 告訴內(nèi)核要監(jiān)聽什么事件
-
struct epoll_event wait_event;
-
public:
-
MySerial(string serial_dev, int serial_baudrate, string serial_parity, int serial_databits, int serial_stopbits,void* (*rx_cb_fun)(void*))
-
{
-
this-> serial_dev= serial_dev;
-
this-> serial_baudrate= serial_baudrate;
-
this-> serial_parity= serial_parity;
-
this-> serial_databits= serial_databits;
-
this-> serial_stopbits= serial_stopbits;
-
this->rx_cb_fun = rx_cb_fun;
-
epfd = epoll_create(10); // 創(chuàng)建一個(gè) epoll 的句柄,參數(shù)要大于 0, 沒有太大意義
-
if( -1 == epfd )
-
{
-
perror ("epoll_create");
-
}
-
};
-
int OpenSerial()
-
{
-
struct termios tios;
-
int speed;
-
fd = open(serial_dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
-
if (fd < 0)
-
{
-
perror("open");
-
}
-
memset(&tios, 0, sizeof(struct termios));
-
switch (serial_baudrate)
-
{
-
case 50:
-
speed = B50;
-
break;
-
case 75:
-
speed = B75;
-
break;
-
case 110:
-
speed = B110;
-
break;
-
case 134:
-
speed = B134;
-
break;
-
case 150:
-
speed = B150;
-
break;
-
case 200:
-
speed = B200;
-
break;
-
case 300:
-
speed = B300;
-
break;
-
case 600:
-
speed = B600;
-
break;
-
case 1200:
-
speed = B1200;
-
break;
-
case 1800:
-
speed = B1800;
-
break;
-
case 2400:
-
speed = B2400;
-
break;
-
case 4800:
-
speed = B4800;
-
break;
-
case 9600:
-
speed = B9600;
-
break;
-
case 19200:
-
speed = B19200;
-
break;
-
case 38400:
-
speed = B38400;
-
break;
-
case 57600:
-
speed = B57600;
-
break;
-
case 115200:
-
speed = B115200;
-
break;
-
case 230400:
-
speed = B230400;
-
break;
-
case 460800:
-
speed = B460800;
-
break;
-
case 500000:
-
speed = B500000;
-
break;
-
case 576000:
-
speed = B576000;
-
break;
-
case 921600:
-
speed = B921600;
-
break;
-
case 1000000:
-
speed = B1000000;
-
break;
-
case 1152000:
-
speed = B1152000;
-
break;
-
case 1500000:
-
speed = B1500000;
-
break;
-
case 2000000:
-
speed = B2000000;
-
break;
-
case 2500000:
-
speed = B2500000;
-
break;
-
case 3000000:
-
speed = B3000000;
-
break;
-
case 3500000:
-
speed = B3500000;
-
break;
-
case 4000000:
-
speed = B4000000;
-
break;
-
default:
-
speed = B9600;
-
break;
-
}
-
if ((cfsetispeed(&tios, speed) < 0) || (cfsetospeed(&tios, speed) < 0))
-
{
-
close(fd);
-
fd = -1;
-
perror("cfsetispeed or cfsetospeed");
-
}
-
tios.c_cflag |= (CREAD | CLOCAL);
-
tios.c_cflag &= ~CSIZE;
-
switch (serial_databits)
-
{
-
case 5:
-
tios.c_cflag |= CS5;
-
break;
-
case 6:
-
tios.c_cflag |= CS6;
-
break;
-
case 7:
-
tios.c_cflag |= CS7;
-
break;
-
case 8:
-
default:
-
tios.c_cflag |= CS8;
-
break;
-
}
-
if (serial_stopbits == 1)
-
{
-
tios.c_cflag &= ~CSTOPB;
-
}
-
else
-
{
-
tios.c_cflag |= CSTOPB;
-
}
-
if (serial_parity == "none")
-
{
-
tios.c_cflag &= ~PARENB;
-
}
-
else if (serial_parity == "even")
-
{
-
tios.c_cflag |= PARENB;
-
tios.c_cflag &= ~PARODD;
-
}
-
else if (serial_parity == "odd")
-
{
-
tios.c_cflag |= PARENB;
-
tios.c_cflag |= PARODD;
-
}
-
tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
-
if (serial_parity == "none")
-
{
-
tios.c_iflag &= ~INPCK;
-
}
-
else
-
{
-
tios.c_iflag |= INPCK;
-
}
-
tios.c_iflag &= ~(IXON | IXOFF | IXANY);
-
tios.c_oflag &= ~OPOST;
-
tios.c_cc[VMIN] = 0;
-
tios.c_cc[VTIME] = 0;
-
if (tcsetattr(fd, TCSANOW, &tios) < 0)
-
{
-
close(fd);
-
fd = -1;
-
perror("tcsetattr");
-
}
-
event.data.fd = fd; // 串口描述符
-
event.events = EPOLLIN; // 表示對(duì)應(yīng)的文件描述符可以讀
-
// 事件注冊(cè)函數(shù),將描述符fd加入監(jiān)聽事件
-
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
-
if(-1 == ret)
-
{
-
perror("epoll_ctl");
-
}
-
return fd;
-
}
-
void loop()
-
{
-
int ret;
-
// 監(jiān)視并等待多文件(串口)描述符的屬性變化(是否可讀)
-
// 沒有屬性變化,這個(gè)函數(shù)會(huì)阻塞,直到有變化才往下執(zhí)行,這里沒有設(shè)置超時(shí)
-
ret = epoll_wait(epfd, &wait_event, 2, -1);
-
if(ret == -1) // 出錯(cuò)
-
{
-
close(epfd);
-
perror("epoll");
-
}
-
else if(ret > 0) // 準(zhǔn)備就緒的文件描述符
-
{
-
//char buf[100] = {0};
-
if((fd == wait_event.data.fd) && (EPOLLIN == wait_event.events & EPOLLIN))
-
{
-
rx_cb_fun(&fd);
-
}
-
}
-
else if(0 == ret)
-
{
-
printf("time out\n");
-
}
-
}
-
~MySerial()
-
{
-
close(fd);
-
close(epfd);
-
}
-
};
-
void *SerialRxCB(void* arg)
-
{
-
int fd = *(int*)arg;
-
char buf;
-
read(fd, &buf, 1);
-
printf("%c\n", buf);
-
return NULL;
-
}
-
void thread_task(void* arg)
-
{
-
int fd = *(int*)arg;
-
while(1)
-
{
-
char tx_buf[]="hello eeworld & mier";
-
this_thread::seconds(1));
-
write (fd, tx_buf, sizeof(tx_buf));
-
}
-
}
-
int main(int argc,char* argv[])
-
{
-
MySerial *ps = new MySerial("/dev/ttySTM3",9600,"none",8,1,SerialRxCB);
-
int ret = ps->OpenSerial();
-
if(ret < 0)
-
{
-
perror("open serial");
-
return -1;
-
}
-
thread t(thread_task,&ret);
-
t.detach();
-
while(1)
-
{
-
ps->loop();
-
}
-
return 0;
-
}
程序中使用到了epoll,類似單片機(jī)里面的中斷,可以實(shí)現(xiàn)異步數(shù)據(jù)的接收,程序中還使用到了c++11的線程庫,米爾提供的交叉編譯器版本很新,完全支持c++11的各種特性。首先在虛擬機(jī)終端執(zhí)行命令,這樣交叉編譯環(huán)境變量就在該終端生效了:
-
. /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
可以看到CXX環(huán)境變量:
然后執(zhí)行命令進(jìn)行程序的編譯:
-
$CXX stm32mp1_uart_test.cpp -o uart_test -lpthread
c++11的線程庫底層使用了pthread實(shí)現(xiàn),因此需要加鏈接參數(shù)-lpthread
交叉編譯完成后,使用scp命令將程序拷貝到開發(fā)板上執(zhí)行:
-
scp qldeng@192.168.1.131:/home/qldeng/stm32mp1_uart_test/uart_test ./
復(fù)制到板子上的效果:
最后看看實(shí)際效果吧:
-
開發(fā)板
+關(guān)注
關(guān)注
25文章
4959瀏覽量
97214
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論