自己做網(wǎng)站怎么選架構(gòu)專注網(wǎng)絡(luò)營(yíng)銷推廣公司
目錄
- 一. 引言
- 二. 軟件功能
- 2.1 原理
- 2.2 軟件功能
- 2.3 運(yùn)行環(huán)境
- 三. 軟件操作使用
- 3.1 軟件界面
- 3.2 軟件功能使用詳解
- 3.2.1 連接
- 3.2.2 數(shù)據(jù)監(jiān)測(cè)(串口示波器)
- 3.2.3 數(shù)據(jù)修改
- 3.2.4 數(shù)據(jù)保存
- 3.3 軟件的硬件連接
- 四. 通信協(xié)議——STM32移植篇
- 4.1 通信協(xié)議
- 4.2 STM32如何傳輸浮點(diǎn)數(shù)
- 4.3 簡(jiǎn)單移植(只進(jìn)行簡(jiǎn)單數(shù)據(jù)監(jiān)控)
- 4.4 完整移植
- 寫在最后
一. 引言
當(dāng)前,嵌入式系統(tǒng)的運(yùn)用非常普遍。無論是智能家居,還是各類機(jī)器人控制系統(tǒng),都離不開嵌入式硬件和軟件的支撐。而在各類系統(tǒng)的開發(fā)、使用和維護(hù)過程中,數(shù)據(jù)可視化都是一項(xiàng)重要內(nèi)容。通過可視化界面,達(dá)到“測(cè)”與“控”的目的?!皽y(cè)”即監(jiān)測(cè)系統(tǒng)運(yùn)行過程中的各類狀態(tài),以數(shù)字、儀表、曲線等形式進(jìn)行展示。“控”即通過上位機(jī)進(jìn)行指令下發(fā),達(dá)到參數(shù)修改、遠(yuǎn)程指揮的目的。
然而,嵌入式系統(tǒng)(一般稱為下位機(jī))的開發(fā)和可視化界面(一般稱為上位機(jī))的開發(fā)都是有難度的。熟悉嵌入式系統(tǒng)開發(fā)的工程師、學(xué)生并不一定擅長(zhǎng)上位機(jī)的開發(fā)。有時(shí)候做一些小項(xiàng)目,僅僅只需要監(jiān)測(cè)一兩個(gè)數(shù)據(jù),專門去開發(fā)一個(gè)可視化軟件耗時(shí)耗力、并不經(jīng)濟(jì)。本人長(zhǎng)期從事基于單片機(jī)的機(jī)器人控制系統(tǒng)研發(fā),略懂一點(diǎn)可視化軟件開發(fā),經(jīng)常是一個(gè)嵌入式系統(tǒng)就要配套一個(gè)上位機(jī),開發(fā)周期長(zhǎng)、維護(hù)難度大。另外經(jīng)常收到各類關(guān)于上位機(jī)開發(fā)的咨詢,深知這方面需求巨大。
因此,基于快速開發(fā)的需求,本軟件開發(fā)了一款通用的上位機(jī)軟件。使用者只需按照本軟件提供的通信協(xié)議進(jìn)行工程移植,即可使用本軟件進(jìn)行嵌入式系統(tǒng)遠(yuǎn)程“測(cè)”“控”。
本軟件非常適合對(duì)上位機(jī)開發(fā)不熟悉的工程師、學(xué)生使用,可以快速構(gòu)建自己的遠(yuǎn)程數(shù)據(jù)采集系統(tǒng),大大縮短開發(fā)周期。尤其對(duì)學(xué)生而言、可快速構(gòu)建測(cè)控系統(tǒng),方便采集數(shù)據(jù),加速論文寫作。
軟件和配套STM32工程、說明文檔的下載地址:嵌入式系統(tǒng)遠(yuǎn)程測(cè)控軟件-串口示波器-遠(yuǎn)程修改參數(shù)
二. 軟件功能
2.1 原理
如何實(shí)現(xiàn)上位機(jī)和下位機(jī)通信,熟悉單片機(jī)開發(fā)的對(duì)串口調(diào)試助手肯定不陌生。串口調(diào)試助手就是一個(gè)上位機(jī),它可收可發(fā),只是它只能以文本顯示原始數(shù)據(jù)幀。當(dāng)我們定義好通信協(xié)議,下位機(jī)和上位機(jī)都按照協(xié)議進(jìn)行數(shù)據(jù)發(fā)與收,自然就能解析出我們想要的數(shù)據(jù)。本軟件也是基于串口通信的,使用的是自定義通信協(xié)議。
2.2 軟件功能
(1) 數(shù)據(jù)監(jiān)測(cè)。以文本數(shù)據(jù)和曲線形式顯示下位機(jī)上傳的數(shù)據(jù)。
(2) 數(shù)據(jù)修改。對(duì)下位機(jī)的數(shù)據(jù)進(jìn)行修改
(3) 歷史數(shù)據(jù)保存。以日志文件形式保存部分監(jiān)測(cè)的數(shù)據(jù),供后期進(jìn)行數(shù)據(jù)處理。
2.3 運(yùn)行環(huán)境
電腦環(huán)境:本軟件基于Qt5.14開發(fā),發(fā)行版為綠色免安裝版本,無需安裝開發(fā)環(huán)境。電腦上安裝CH340、CP2102等串口驅(qū)動(dòng)即可。
單片機(jī)環(huán)境:任意單片機(jī),只要能進(jìn)行串口通信。
三. 軟件操作使用
3.1 軟件界面
直接雙擊exe文件即可打開主界面。啟動(dòng)后主界面如圖所示,界面由多個(gè)區(qū)域組成。其中左側(cè)兩個(gè)區(qū)域,“端口”框內(nèi)為設(shè)備連接操作部分,下方是快速設(shè)置寄存器值。右側(cè)區(qū)域?yàn)闃?biāo)簽頁(yè)區(qū)域,有四個(gè)標(biāo)簽頁(yè),“數(shù)據(jù)曲線”標(biāo)簽頁(yè)是進(jìn)行數(shù)據(jù)顯示(上行數(shù)據(jù)),“更改參數(shù)”標(biāo)簽頁(yè)是進(jìn)行數(shù)據(jù)修改(下發(fā)數(shù)據(jù)),“串口數(shù)據(jù)”標(biāo)簽頁(yè)顯示串口原始16進(jìn)制數(shù)據(jù)。“ReadMe”標(biāo)簽頁(yè)里面是一些版本信息和說明文字。
其中,“數(shù)據(jù)曲線”標(biāo)簽頁(yè)又分成了多個(gè)標(biāo)簽頁(yè)?!皵?shù)據(jù)曲線00”是地址為0x00的數(shù)據(jù),“數(shù)據(jù)曲線01”是地址為0x02的數(shù)據(jù),依次類推?!白远x曲線1”和“自定義曲線2”兩個(gè)標(biāo)簽頁(yè)可以任意選擇地址進(jìn)行數(shù)據(jù)顯示,可以分別最多顯示4條曲線。
3.2 軟件功能使用詳解
3.2.1 連接
(1)通過下拉框設(shè)置串口號(hào)、波特率、數(shù)據(jù)位、停止位、校驗(yàn)位等串口參數(shù),其中默認(rèn)參數(shù)為波特率115200、數(shù)據(jù)位8、停止位1、校驗(yàn)位無。串口號(hào)在軟件啟動(dòng)時(shí)自動(dòng)搜索計(jì)算機(jī)當(dāng)前可用串口并可以通過下拉框選取,當(dāng)沒有設(shè)備連接時(shí)下拉框?yàn)榭?#xff0c;不可選擇。
(2)點(diǎn)擊“打開串口”按鈕,即可與下位機(jī)連接。
(3)當(dāng)需要斷開連接時(shí)點(diǎn)擊“關(guān)閉串口”按鈕,即可與控制板斷開連接。
(4)當(dāng)軟件運(yùn)行過程中出現(xiàn)插拔通信線,會(huì)改變可用串口設(shè)備,點(diǎn)擊“更新設(shè)備列表”按鈕,即可在串口號(hào)下拉框中選取最新的可用串口設(shè)備。(目前暫時(shí)是這樣,需要手動(dòng)更新)
3.2.2 數(shù)據(jù)監(jiān)測(cè)(串口示波器)
數(shù)據(jù)的傳輸和解析都是是按照地址——數(shù)據(jù)的形式進(jìn)行的。目前設(shè)置了8個(gè)子標(biāo)簽頁(yè),每個(gè)子標(biāo)簽頁(yè)包含一個(gè)圖表用于數(shù)據(jù)曲線顯示。其中“數(shù)據(jù)曲線00”是地址顯示0x00的數(shù)據(jù),“數(shù)據(jù)曲線01”顯示地址為0x01的數(shù)據(jù),依次類推,前6個(gè)圖表都只顯示一條曲線。“自定義曲線1”和“自定義曲線2”兩個(gè)標(biāo)簽頁(yè)分別可以顯示四條曲線(即四個(gè)地址的數(shù)據(jù)),并且這四個(gè)地址是可以自己設(shè)置的。
下圖顯示的是“數(shù)據(jù)曲線00”標(biāo)簽頁(yè)的數(shù)據(jù),圖表下方橫坐標(biāo)是時(shí)間,時(shí)間是動(dòng)態(tài)滾動(dòng)的,左側(cè)縱坐標(biāo)是數(shù)據(jù)值。圖表下側(cè)以文本框形式顯示數(shù)據(jù)的具體值。圖表上方有三個(gè)輸入框?!霸O(shè)置顯示點(diǎn)數(shù)”設(shè)置圖表區(qū)域顯示的數(shù)據(jù)個(gè)數(shù),這個(gè)數(shù)值越大,顯示的點(diǎn)數(shù)越多,橫坐標(biāo)時(shí)間跨度越長(zhǎng)?!霸O(shè)置y坐標(biāo)范圍”可以設(shè)置y軸坐標(biāo)的最小值和最大值,使曲線能夠完整顯示在圖框中?!皵?shù)據(jù)曲線01”、“數(shù)據(jù)曲線02”、“數(shù)據(jù)曲線03”、“數(shù)據(jù)曲線04”、“數(shù)據(jù)曲線05”使用方法一樣。
下圖顯示的是“自定義曲線1”標(biāo)簽頁(yè)的數(shù)據(jù),圖表下方橫坐標(biāo)是時(shí)間,時(shí)間是動(dòng)態(tài)滾動(dòng)的,左側(cè)縱坐標(biāo)是數(shù)據(jù)值。圖表上方有兩排輸入框。第一排三個(gè)輸入框:“設(shè)置顯示點(diǎn)數(shù)”設(shè)置圖表區(qū)域顯示的數(shù)據(jù)個(gè)數(shù),這個(gè)數(shù)值越大,顯示的點(diǎn)數(shù)越多,橫坐標(biāo)時(shí)間跨度越長(zhǎng)。“設(shè)置y坐標(biāo)范圍”可以設(shè)置y軸坐標(biāo)的最小值和最大值,使曲線能夠完整顯示在圖框中。第二排四個(gè)輸入框,“數(shù)據(jù)1”設(shè)置數(shù)據(jù)1的數(shù)據(jù)地址,“數(shù)據(jù)2”設(shè)置數(shù)據(jù)2的數(shù)據(jù)地址,“數(shù)據(jù)3”設(shè)置數(shù)據(jù)3的數(shù)據(jù)地址,“數(shù)據(jù)4”設(shè)置數(shù)據(jù)4的數(shù)據(jù)地址。四個(gè)數(shù)據(jù)前都有一個(gè)復(fù)選框,當(dāng)勾選相應(yīng)的復(fù)選框時(shí),圖像中就會(huì)顯示這個(gè)數(shù)據(jù)的曲線,當(dāng)取消勾選相應(yīng)的復(fù)選框時(shí),圖像中就會(huì)不顯示這個(gè)數(shù)據(jù)的曲線?!白远x曲線2”標(biāo)簽頁(yè)使用方法一樣。
左側(cè)有一個(gè)“設(shè)置顯示點(diǎn)數(shù)”的編輯框,所有的曲線顯示時(shí)長(zhǎng)我都改成在這個(gè)地方統(tǒng)一設(shè)置了,相應(yīng)標(biāo)簽頁(yè)的“設(shè)置顯示點(diǎn)數(shù)”沒激活。如果下位機(jī)每隔20ms上傳一幀數(shù)據(jù),那么500個(gè)點(diǎn)就是500*20ms = 10s。
3.2.3 數(shù)據(jù)修改
數(shù)據(jù)修改也是是按照地址——數(shù)據(jù)的形式進(jìn)行的,在“更改參數(shù)”標(biāo)簽頁(yè)和左側(cè)“快速設(shè)置寄存器值”都可以修改參數(shù)。“更改參數(shù)”標(biāo)簽頁(yè)里,“參數(shù)修改”那一塊,可以修改0x80~0x8F一共16個(gè)數(shù)據(jù),地址固定。點(diǎn)“查詢參數(shù)”就可以查看當(dāng)前值,點(diǎn)“載入?yún)?shù)”就把當(dāng)前值填充到設(shè)置值那里(這一步非必須,只是為了方便,不需要一個(gè)一個(gè)再敲進(jìn)去),然后在設(shè)定值那一列進(jìn)行修改即可,改成自己想要的參數(shù)。最后點(diǎn)“寫入?yún)?shù)”即可將參數(shù)寫入進(jìn)去。
右側(cè)“指令下發(fā)”那一塊,可以指定起始地址和數(shù)據(jù)個(gè)數(shù),這樣就可以應(yīng)對(duì)所有場(chǎng)合了。比如將起始地址改成0xA0,數(shù)據(jù)個(gè)數(shù)改成10,點(diǎn)擊“寫入指令”,就會(huì)將從0xA0開始的10個(gè)數(shù)據(jù)寫到單片機(jī)了。(不能超過16個(gè)數(shù)據(jù),因?yàn)橹唤o了16個(gè)框框)。
主界面左方“快速設(shè)置寄存器值”那里也是可以靈活修改參數(shù),每個(gè)地址框都是可以滾動(dòng)或敲入修改的,從而修改地址。數(shù)據(jù)框里的值一旦滾動(dòng)或敲入則會(huì)自動(dòng)下發(fā)數(shù)據(jù)下去。這個(gè)地方一次只能修改一個(gè)地址的數(shù)據(jù),適用于測(cè)試場(chǎng)合。
3.2.4 數(shù)據(jù)保存
除了數(shù)據(jù)測(cè)控外,軟件的第三大核心功能是數(shù)據(jù)保存,這個(gè)保存過程是在后臺(tái)自動(dòng)進(jìn)行的,當(dāng)軟件啟動(dòng)時(shí)就會(huì)開始記錄,直到軟件關(guān)閉時(shí)停止記錄。日志文件的生成和命名也是自動(dòng)的。格式為“data_year_month_date_hh_mm.csv”。其存放位置為.exe文件的同級(jí)目錄下。如圖所示。
文件打開之后的格式如圖13所示。第一行為表頭,從左至右前四列為小時(shí)、分鐘、秒、毫秒,四位數(shù)據(jù)標(biāo)記數(shù)據(jù)接收的時(shí)間,之后依次顯示每個(gè)地址的數(shù)據(jù):0x00地址的數(shù)據(jù),0x01地址的數(shù)據(jù),……,0x0F地址的數(shù)據(jù)。本版本軟件暫時(shí)設(shè)置只保存到0x0F的數(shù)據(jù),即最多保存17個(gè)數(shù)據(jù),使用者在使用的過程中要注意,雖然曲線顯示是沒有地址限制的,但是超過0x0F地址的數(shù)據(jù)是不被保存的。所以要優(yōu)先使用低地址的數(shù)據(jù)。
3.3 軟件的硬件連接
最后,說明一下本軟件的硬件連接方式。本軟件與單片機(jī)的連接方式可為串口ttl、485、232任意一種,只要是UART通信協(xié)議即可。
電腦與單片機(jī)之間可以使用一根數(shù)據(jù)線進(jìn)行連接。這種方式是有線方式。也可以使用無線數(shù)傳模塊進(jìn)行連接。電腦和單片機(jī)各連接一個(gè)無線數(shù)傳模塊,即可實(shí)現(xiàn)遠(yuǎn)程無線通信。
四. 通信協(xié)議——STM32移植篇
4.1 通信協(xié)議
依照本軟件所規(guī)定的通信協(xié)議進(jìn)行數(shù)據(jù)上傳,本軟件才能正確解析數(shù)據(jù),進(jìn)行顯示和保存。否則通信失敗,軟件無法正常使用。
本軟件使用的自定義通信協(xié)議,數(shù)據(jù)幀長(zhǎng)度為任意字節(jié),可以一次發(fā)送所有數(shù)據(jù),也可以分多個(gè)數(shù)據(jù)幀上傳數(shù)據(jù)。當(dāng)數(shù)據(jù)過多時(shí),建議分多個(gè)數(shù)據(jù)幀發(fā)送,否則一幀長(zhǎng)度過長(zhǎng),出錯(cuò)概率增大。
數(shù)據(jù)的保存和傳輸按照“地址-數(shù)據(jù)”形式,按照浮點(diǎn)數(shù)32位保存,每個(gè)數(shù)據(jù)占4個(gè)字節(jié)。每個(gè)數(shù)據(jù)都有自己的地址,地址從0開始編號(hào)。
有三種數(shù)據(jù)幀:
(1)單片機(jī)主動(dòng)上傳數(shù)據(jù):
發(fā)送N個(gè)數(shù)據(jù)(32 bits)一共4N+6個(gè)幀字節(jié)。
(2)上位機(jī)下發(fā)更改數(shù)據(jù):
發(fā)送N個(gè)數(shù)據(jù)(32bits)也是一共4N+6個(gè)幀字節(jié)。
(3)上位機(jī)下發(fā)查詢數(shù)據(jù):
查詢從起始地址開始的N個(gè)數(shù)據(jù),查詢幀是6個(gè)字節(jié)。下位機(jī)收到數(shù)據(jù)按照上傳數(shù)據(jù)格式上傳。
4.2 STM32如何傳輸浮點(diǎn)數(shù)
數(shù)據(jù)的傳輸最簡(jiǎn)單的是傳輸整形數(shù)據(jù),本軟件的早期版本是傳輸uint16類型數(shù)據(jù),每個(gè)數(shù)據(jù)占用兩個(gè)字節(jié)。這種方法的缺點(diǎn)是:(1)傳輸浮點(diǎn)數(shù)時(shí)需要進(jìn)行倍數(shù)處理。例如0.12,將其乘100變成整形的12,上位機(jī)收到后除100變成浮點(diǎn)型的0.12。這種方法較麻煩,哪些地址的數(shù)據(jù)需要進(jìn)行倍數(shù),需要下位機(jī)和上位機(jī)同時(shí)定義清楚。(2)有符號(hào)和無符號(hào)類型數(shù)據(jù)區(qū)分。uint16類型數(shù)據(jù)較簡(jiǎn)單,直接傳輸,直接解析,沒問題。int16上位機(jī)解析時(shí),就需要進(jìn)行類型轉(zhuǎn)換了。哪些地址的數(shù)據(jù)要進(jìn)行(int16_t)類型轉(zhuǎn)換,也要定義清楚。(3)表示的數(shù)據(jù)范圍有限,16位整形無符號(hào)數(shù)只能到65535,有符號(hào)數(shù)除2減半。如果是浮點(diǎn)數(shù),乘掉了倍數(shù),表示范圍直接縮水。如果是翻100倍,只能表示到655。
所以,最方便的就是直接傳輸浮點(diǎn)數(shù),省去很多麻煩。當(dāng)然浮點(diǎn)數(shù)的缺點(diǎn)就是,一個(gè)數(shù)據(jù)要占用4個(gè)字節(jié)。因此效率是傳輸整形數(shù)據(jù)的一半。
傳輸浮點(diǎn)數(shù),需要定義一個(gè)聯(lián)合體:
union float_data
{float f_data;uint8_t byte[4];
};
f_data
和byte[4]
共用4個(gè)字節(jié)的內(nèi)存單元,成員f_data
是實(shí)際使用的數(shù)據(jù),成員byte[4]
是通信時(shí)用的數(shù)據(jù),各司其職。
使用方法:
#include <stdio.h>
#include <stdint.h>union float_data
{float f_data;uint8_t byte[4];
};int main()
{union float_data me, you;me.f_data = 0.12;you.byte[3] = me.byte[3];you.byte[2] = me.byte[2];you.byte[1] = me.byte[1];you.byte[0] = me.byte[0];printf("you = %f", you.f_data);return 0;
}
出來的結(jié)果是一樣的,0.12。聰明的讀者可以發(fā)現(xiàn),me和you對(duì)應(yīng)下位機(jī)和上位機(jī)。只要me和you按照這種方式進(jìn)行傳輸,就可以傳輸浮點(diǎn)數(shù)。傳輸多個(gè)浮點(diǎn)數(shù),me和you就可以定義為一個(gè)數(shù)組,例如me[100]
, you[100]
。
數(shù)組的索引就是地址,數(shù)組的索引就是地址,數(shù)組的索引就是地址。 請(qǐng)記住這個(gè)思想和方法。
4.3 簡(jiǎn)單移植(只進(jìn)行簡(jiǎn)單數(shù)據(jù)監(jiān)控)
如果你只是想監(jiān)測(cè)幾個(gè)數(shù)據(jù),可以非常迅速地實(shí)現(xiàn)。
下面給出示例代碼,可以直接寫在main函數(shù)里。
void main()
{// 省略union float_data register[10];uint8_t data[100];while(1){uint8_t data;data[0] = 0xAA;data[1] = 0xFF;data[2] = 0;data[3] = 0;data[4] = 4; data[5] = register[0].byte[3];data[6] = register[0].byte[2];data[7] = register[0].byte[1];data[8] = register[0].byte[0];data[9] = 0;for (i = 0; i < 9; i++)data[9] += data[i];for (i = 0; i < 10; i++)Uart1_send_char(data[i]);delay_ms(20);}
}
這段代碼即按照通信協(xié)議進(jìn)行“填空”,數(shù)據(jù)的起始地址是0x0000,有效數(shù)據(jù)長(zhǎng)度是4,即一個(gè)數(shù)據(jù),一幀數(shù)據(jù)總長(zhǎng)為10個(gè)字節(jié),最后一個(gè)字節(jié)是校驗(yàn)和。這段循環(huán)結(jié)構(gòu)按照20ms的間隔定期上傳數(shù)據(jù)。
void main()
{// 省略union float_data register[10];uint8_t data[100];while(1){data[0] = 0xAA;data[1] = 0xFF;data[2] = 0;data[3] = 0;data[4] = 4; data[5] = register[0].byte[3];data[6] = register[0].byte[2];data[7] = register[0].byte[1];data[8] = register[0].byte[0];data[9] = 0;for (i = 0; i < 9; i++)data[9] += data[i];for (i = 0; i < 10; i++)Uart1_send_char(data[i]);data[0] = 0xAA;data[1] = 0xFF;data[2] = 0;data[3] = 5;data[4] = 8; data[5] = register[0].byte[3];data[6] = register[0].byte[2];data[7] = register[0].byte[1];data[8] = register[0].byte[0];data[9] = register[0].byte[3];data[10] = register[0].byte[2];data[11] = register[0].byte[1];data[12] = register[0].byte[0];data[13] = 0;for (i = 0; i < 13; i++)data[13] += data[i];for (i = 0; i < 14; i++)Uart1_send_char(data[i]);delay_ms(20);
}
這段代碼分兩幀數(shù)據(jù)進(jìn)行了數(shù)據(jù)傳輸。第一幀數(shù)據(jù)從0x0000地址開始,傳輸了一個(gè)數(shù)據(jù)(對(duì)應(yīng)地址0x0000)。第二幀從0x0005開始,傳輸了兩個(gè)數(shù)據(jù)(對(duì)應(yīng)地址0x0005,0x0006)。
4.4 完整移植
使用全部功能,按照步驟移植,也很簡(jiǎn)單。
(1)工程里加入兩個(gè)文件:transmission.h
和transmission.c
#ifndef __TRANSMISSION_H
#define __TRANSMISSION_H#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"union float_data
{float f_data;uint8_t byte[4];
};extern union float_data float_register[255];
extern u8 send_buf[100]; // DMA傳輸緩沖區(qū)u8 ComSendData(u16 addr, u8 len);
u8 cksum(u8 *data,u8 len);
void analyseData(u8 *data,u8 len);#endif
#include "transmission.h"
#include "string.h"u8 send_buf[100] = {0};
union float_data float_register[255];u8 ComSendData(u16 addr, u8 num)
{u8 i;u8 len = 4*num+6; //一幀字節(jié)的長(zhǎng)度send_buf[0] = 0XAA; //幀頭send_buf[1] = 0XFF; //幀頭 上行send_buf[2] = addr << 8; //數(shù)據(jù)地址高8位send_buf[3] = addr; //數(shù)據(jù)地址低8位send_buf[4] = 4*num; //數(shù)據(jù)長(zhǎng)度,單位為字節(jié)for (i = 0; i < num; i++){send_buf[5 + 4*i] = float_register[addr + i].byte[3]; //數(shù)據(jù)高8位send_buf[6 + 4*i] = float_register[addr + i].byte[2]; send_buf[7 + 4*i] = float_register[addr + i].byte[1]; send_buf[8 + 4*i] = float_register[addr + i].byte[0]; //數(shù)據(jù)低8位}send_buf[len-1] = cksum(send_buf,len-1); // 先清零,避免上一幀數(shù)據(jù)這個(gè)位置有數(shù)據(jù)for (i = 0; i < len; i++){Uart1SendChar(send_buf[i]);}return 0;
}// 相加校驗(yàn),輕量計(jì)算
// 經(jīng)使用,會(huì)出錯(cuò),很奇怪
// 出錯(cuò)原因,sum沒有初始化為0,暈
u8 cksum(u8 *data,u8 len)
{u8 sum = 0;u8 i;for (i = 0; i < len; i++)sum += data[i]; //計(jì)算校驗(yàn)和return sum;
}void analyseData(u8 *data,u8 len)
{u16 addr,data_num;u8 i;u8 sum,sum1;if (data[0] != 0xAA) return; // 幀頭不對(duì)if (data[1] != 0xAA && data[1] != 0x55 ) return; // 幀頭不對(duì)if ((u8)cksum(data,len-1) != data[len-1]) return; // (u8)強(qiáng)制類型轉(zhuǎn)換要加上,不然出錯(cuò) if (data[1] == 0x55) // 寫指令{addr = (u16)data[2] << 8 | (u16)data[3];data_num = data[4]/4; // 要更改的寄存器數(shù)據(jù)數(shù)量for (i = 0; i < data_num;i++) // 更改寄存器值{float_register[addr + i].byte[3] = data[5 + 4*i];float_register[addr + i].byte[2] = data[6 + 4*i];float_register[addr + i].byte[1] = data[7 + 4*i];float_register[addr + i].byte[0] = data[8 + 4*i];}ComSendData(addr,data_num); // 上傳控制參數(shù) 寫完之后上傳回去}if (data[1] == 0xAA) // 讀指令{addr = (u16)data[2] << 8 | (u16)data[3];data_num = data[4]/4; // 要查詢的寄存器數(shù)據(jù)數(shù)量ComSendData(addr,data_num); // 上傳控制參數(shù) 控制參數(shù)上傳是慢速的。}
}
這里面干了三件事:(1)定義了一個(gè)內(nèi)存空間:union float_data float_register[255]
,內(nèi)存大小可以自己修改,這里給的255。(2)定義上傳函數(shù):u8 ComSendData(u16 addr, u8 len)
,從起始地址上傳len個(gè)數(shù)據(jù)。(3)定義解析函數(shù):void analyseData(u8 *data,u8 len)
,解析一幀數(shù)據(jù),如果是寫指令,就更新float_register中的值,并且更新完了把新的數(shù)據(jù)上傳上去。如果是讀指令,就按照給定的起始地址和數(shù)據(jù)量上傳數(shù)據(jù)。
代碼很簡(jiǎn)單,核心是其中的思想,請(qǐng)讀者自行體會(huì)~
(2)定義串口中斷函數(shù)和串口發(fā)送函數(shù)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{while (huart->Instance == USART1) //如果是串口1 // 有兩種情況,0xAA AA是讀指令,數(shù)據(jù)幀長(zhǎng)度6個(gè)字節(jié); 0xAA 55是寫指令,數(shù)據(jù)長(zhǎng)度 2N + 6字節(jié){USART1_RX_BUF[USART1_RX_STA] = aRxBuffer1[0];if (USART1_RX_STA == 0 && USART1_RX_BUF[0] != 0xAA) break; //幀頭不對(duì),丟掉if (USART1_RX_STA == 1) {if( USART1_RX_BUF[1] != 0xAA && USART1_RX_BUF[1] != 0x55 ){USART1_RX_STA = 0;break; //幀頭不對(duì),丟掉}}USART1_RX_STA++;if (USART1_RX_STA > USART_REC_LEN) USART1_RX_STA = 0; ///接收數(shù)據(jù)錯(cuò)誤,重新開始接收if ( (USART1_RX_BUF[1] == 0xAA && USART1_RX_STA == 6) || (USART1_RX_BUF[1] == 0x55 && USART1_RX_STA == USART1_RX_BUF[4] + 6) ){//analyseData(&USART1_RX_BUF[0]); analyseData(USART1_RX_BUF, USART1_RX_STA);LED3_TOGGLE();memset(USART4_RX_BUF, 0, USART1_RX_STA);USART1_RX_STA = 0;}break;}
}
串口中斷函數(shù)隨便怎么定義,我這里給的是字節(jié)中斷,你可以按DMA空閑中斷去寫都行,總之就是要按照前面給的通信協(xié)議,把上位機(jī)下發(fā)下來的“修改數(shù)據(jù)”或“查詢數(shù)據(jù)”的數(shù)據(jù)幀解析出來,然后調(diào)用transmission.c
中的void analyseData(u8 *data,u8 len)
函數(shù)進(jìn)行解析數(shù)據(jù)。
前面設(shè)計(jì)一個(gè)串口發(fā)送單個(gè)字節(jié)的函數(shù)int Uart1SendChar(u8 ch)
:
int Uart1SendChar(u8 ch)
{while((USART1->SR&0X40)==0);//循環(huán)發(fā)送,直到發(fā)送完畢 USART1->DR=(u8)ch; return ch;
}
(3)測(cè)試代碼:
提供的STM32工程里面,使用地址0x90作為正弦波和方波的幅值,地址0x91作為正弦波和方波的頻率。地址0x00是正弦波值,地址0x01是方波值,每20ms上傳一次數(shù)據(jù)。上位機(jī)通過修改0x90和0x91地址的數(shù)據(jù),就可以更改正弦波和方波的幅值和頻率。代碼為:
//sign函數(shù)
float Sign(float input)
{float output=0;if(input>0){output=1;}else if(input==0){output=0;}else{output=-1;}return output;
}int main(void)
{uint8_t len;uint16_t times = 0;HAL_Init(); /* 初始化HAL庫(kù) */sys_stm32_clock_init(336, 8, 2, 7); /* 設(shè)置時(shí)鐘,168Mhz */delay_init(168); /* 延時(shí)初始化 */MX_USART1_UART_Init(); /* 串口初始化為115200 */led_init(); /* 初始化LED */u32 run_cnt = 0;u8 dt = 20;u8 i;float amplitude=100, frequency=0.5;float_register[0x90].f_data = 100; float_register[0x91].f_data = 0.5;for (i = 0; i < 16; i++)float_register[0x80+i].f_data = i; // 數(shù)據(jù)賦值, 測(cè)試上位機(jī)讀數(shù)據(jù)while(1){// 測(cè)試上位機(jī)寫數(shù)據(jù)amplitude = float_register[0x90].f_data;frequency = float_register[0x91].f_data;// 測(cè)試從機(jī)主動(dòng)上傳數(shù)據(jù)float_register[0].f_data = amplitude * sin(2*3.14*run_cnt*frequency*dt*0.001);float_register[1].f_data = amplitude * Sign(float_register[0].f_data);ComSendData(0,2); // 0地址開始3個(gè)數(shù)據(jù)delay_ms(dt); // 采樣周期if (run_cnt++ % 10 == 0) LED2_TOGGLE(); }
}
效果如圖。開始時(shí)幅值為100,頻率為0.5Hz,修改為1Hz、幅值200,波形變化了兩次。
寫在最后
(1)由于本軟件是通用軟件,所以都是以“地址0x80”之類的命名,而不是參數(shù)的實(shí)際意義,例如“PID參數(shù)”、“前進(jìn)速度”等。這就需要聰明的你自己在腦袋里定義了。魚和熊掌不可兼得。
(2)開發(fā)上位機(jī)有很多軟件,如LabWindows、labview、Qt、C#等,包括萬能的Matlab,各有利弊。就本人近幾年的開發(fā)經(jīng)驗(yàn),Matlab的實(shí)時(shí)性是災(zāi)難,LabWindows界面太丑、Labview的非編程開發(fā)方式習(xí)慣不了。相對(duì)而言,Qt功能是最為強(qiáng)大的,很適合實(shí)時(shí)系統(tǒng),大名鼎鼎的飛控地面站QGroundControl就是Qt開發(fā)的。想學(xué)習(xí)上位機(jī)編程的強(qiáng)烈建議Qt。
(3)本軟件及其配套STM32示例工程下載需要一點(diǎn)點(diǎn)費(fèi)用。一方面是作者的勞動(dòng)成果,請(qǐng)養(yǎng)成知識(shí)付費(fèi)的思想和行動(dòng)自覺,本人平時(shí)也是經(jīng)常性為知識(shí)付費(fèi),花幾塊幾十塊錢解決大問題是非常非常劃算的。另一方面,付費(fèi)的東西能夠幫助你篩選掉一些無用資源。使用過程中有任何問題歡迎私信。本軟件的下載地址:嵌入式系統(tǒng)遠(yuǎn)程測(cè)控軟件-串口示波器-遠(yuǎn)程修改參數(shù)
(4) 上位機(jī)軟件源碼后續(xù)也會(huì)陸續(xù)開源(一定的知識(shí)付費(fèi)),供有興趣的伙伴學(xué)習(xí)并定義自己的界面。