本應用筆記和支持源代碼提供了一個簡單的便攜式框架,用于使用串行傳輸(如RS-232)在嵌入式系統和運行MATLAB的PC之間實現實時數據傳輸。
介紹
嵌入式控制和測量系統通??梢詮氖褂弥T如此類工具的高級算法開發中受益 作為 MATLAB。為此,有必要將數據從嵌入式系統導出到PC。雖然數學作品 提供便于嵌入式算法開發的附加包,這些包可能很昂貴。 通常,只需要一種從嵌入式系統收集數據以進行基本分析的簡單方法。?
本應用筆記和支持源代碼為完成 使用串行傳輸在嵌入式系統和運行 MATLAB 的 PC 之間實時傳輸數據,例如 RS-232.
要求
本應用筆記所述架構的實現已在MAX35103EVKIT2#PCB上進行了測試,該PCB是MAX35103EVKIT2評估板軟件的一部分。 但它可以很容易地移植到其他平臺。建議使用MAX35103EVKIT2進行初始評估和 參考。
本應用筆記假設用戶對 MATLAB、MATLAB MEX、C 語言和 Win32 API。在基于 IAR 系統的技術、基于 ARM 的系統和視覺C++方面的經驗也是 有益的。????
全面評估需要以下工具:
Maxim MAX35103EVKIT2評估板
微軟視覺C++
MATLAB(無需額外的軟件包)
適用于 ARM 的 IAR 嵌入式工作臺
Microsoft Visual C++ Community Edition 可從 Microsoft 網站免費下載。IAR ARM 是 可從IAR系統進行評估。提供MAX35103EVKIT2評估板軟件 來自Maxim以及Digi-Key和貿澤電子等許多電子分銷商。MATLAB 可從 The Mathworks, Inc. 獲得。
MAX35103EVKIT2實現示例
MAX35103EVKIT2評估板軟件 被選中用于本應用筆記中描述的框架的初始實現。 MAX35103EVKIT2板由MAX32620(ARM Cortex M4)和MAX35103(超聲波時間數字轉換器)組成。 這些組件共同支持通過超聲波流體收集液體流量測量值。 這些測量結果被格式化并傳輸到運行 MATLAB 的主機 PC。?
基本了解MAX35103EVKIT2評估板軟件 MAX35103有助于理解框架傳輸的數據和主機/目標的格式 協議數據包。請參考MAX35103EVKIT2文檔,了解嵌入式平臺的詳細信息。
MAX35103EVKIT2嵌入式目標向運行MATLAB的主機PC傳輸的數據是 MAX35103時間數字轉換器該數據流是超聲波脈沖發射和接收之間的時間測量數組。test.m MATLAB腳本(詳見本文檔后面)為從MAX35103EVKIT2板收集數據提供了快速起點。圖1所示如何從MAX35103EVKIT2板檢索和訪問前<>個上游時間測量值。
圖1.使用 test.m 的 MATLAB 數據收集示例
系統架構
使用此框架進行數據收集需要能夠運行 MATLAB 的主機 PC 和具有 串行接口。此處提供的框架專門支持 RS-232,但可以輕松移植以支持其他接口(參見圖 2)。
圖2.主機/目標體系結構。
該框架跨越電腦主機和嵌入式目標。C 代碼針對目標嵌入式系統編譯為 以及主機系統。當前的主機實現需要 Win32 平臺,但可以將其移植到 另一個操作系統,如Linux。?
嵌入式目標硬件必須提供某種串行接口。當前框架實現 支持 UART,但設計為可移植到其他傳輸。目標微控制器必須有足夠的 支持框架數據和代碼要求的資源,但也有足夠的吞吐量來移動數據,而無需 過度影響嵌入式系統的性能??蚣懿恍枰?a href="http://m.1cnz.cn/tags/RTOS/" target="_blank">RTOS,但它確實需要 不排除使用一個。
當前的框架實現是使用96MHz Cortex-M4處理器開發的,可以在 UART 接近最大吞吐量,處理器開銷很小。較小的系統可能需要調整 框架可以接受地工作。
圖 3 描述了主機和目標上的軟件組件。藍色組件是 C 語言模塊 在主機上運行。紅色組件是在目標上運行的 C 語言模塊。綠色組件是 兩個域通用。紫色的 MATLAB 腳本是標準的 m 腳本,可與 特定于應用程序的接口。此處描述的嵌入式框架實現是為在 MAX35103EVKIT2評估板軟件,超聲波水流量測量平臺
灰色組件是特定于外部平臺的組件。
圖3.系統架構。
可以使用 C/C++ 和 4GL 語言與 Win32 DLL(如 C# 或 Python)交互,使用 “Win32 DLL I/F”模塊。這允許輕松支持可能不需要 MATLAB 的自定義主機應用程序。
“COM”模塊實現基本主機/目標協議。這是數據包定義特定于 找到嵌入式應用程序?!靶蛄谢蹦K實現了二進制數據的基于轉義的分組。 這兩個模塊都可以使用與通信API(主機)或嵌入式接口的回調輕松移植 外圍設備(嵌入式目標)。
“COM”模塊中的定義驅動“主機端協議”和“設備端”中的實現 協議“組件。這些實現是特定于主機和目標的命令/響應所在的位置 實現并且通常具有很多共性。
以下各節從上到下詳細介紹了從主機開始的每個主要體系結構模塊。
電腦主機架構
圖 2 中描述的架構的主機端主要由 MATLAB 和特定于操作系統的接口組成, 并在以下各節中詳細介紹。
MATLAB 腳本
主機堆棧的頂部是執行特定于應用程序的數據收集和控制的 MATLAB 腳本。 代碼清單 1 中顯示的腳本 test.m 是如何使用 MATLAB MEX 接口打開、設置 參數,并從MAX35103EVKIT2評估板軟件收集數據。
h_flow = svflow('open',6);
if( h_flow )
svflow('start',h_flow,100);
samples = flow('get_samples',h_flow,1000);
svflow('stop',h_flow);
svflow('close',h_flow);
clear h_flow;
plot(samples.timestamp,samples.toff_diff)
hold on
transit = (samples.up.average + samples.down.average) ./ 2
yyaxis right
plot(samples.timestamp,transit)
hold off
else
error('failed to open com port');
end
代碼清單 1.測試.m.
MEX 接口模塊中只能存在一個公共函數。在本例中,它是 svflow()。這個函數是怎么 MATLAB 腳本調用 MEX 模塊。函數的名稱是任意的,但選擇“svflow”作為 MAX35103EVKIT2評估軟件上實現的整體主機/目標協議的名稱值 (水流量測量平臺)。
svflow() 的第一個參數是一個文本字符串,指示要調用的子函數。第二個參數是 引用特定流對象的處理對象。此對象由 svflow('open',...) 返回。這是基本的 框架用于適應 MEX 同時支持面向對象的體系結構的方法。
代碼清單 1 中的 test.m 腳本調用子函數 'open' 來打開 Windows 主機上的 COM6。下一個 調用“start”以指定 100Hz 的采樣率并開始樣本收集。然后調用“get_samples” 以定義的采樣率收集 1000 個樣本。此同步集合完成后,流對象 已停止并關閉。MATLAB plot() 函數用于顯示數據集和派生數據。
MATLAB MEX 接口
用于MAX35103EVKIT2評估板軟件的MATLAB MEX接口元件 在一組 C 語言文件中實現。它可以訪問內部 MATLAB 函數并公開一個標準 MATLAB 腳本可以調用的接口。所有特定于 MEX 的功能都包含在 mex.c 中,它提供了 特定于 MATLAB 的核心協議功能的包裝器,用于在 flow.c 中實現,該功能也用作 Win32 DLL 接口和 serialize.c/com.c,這是主機和嵌入式目標通用的。
該模塊是使用 MATLAB mex() 函數創建的。代碼清單 2 中的 compile.m 腳本編譯 將 C 文件托管為 MATLAB 可用的表單。此命令的輸出是 MATLAB MEX 可執行文件。馬特實驗室 必須先前配置為使用本機工具鏈。訪問 The Mathworks 網站以獲取有關 如何設置用于編譯 MEX 模塊的工具鏈。
mex -g -output svflow -I'dll' -I'..' dll/mex.c dll/svflow.c ../serialize.c ../com.c
代碼清單 2.編譯.m.
MAX35103EVKIT2評估板軟件專用的MATLAB MEX接口在mex.c中實現。MATLAB 要求所有 MEX 模塊實現函數 mexFunction() 作為唯一函數 模塊提供的功能的接口。為了給單個 MEX 模塊提供一種提供多個面向對象成員函數的方法,使用了子函數機制。在代碼清單 3 中,mexFunction() 引用函數調用表用于調度子函數。調用表本身如代碼清單 4 所示。
for (i = 0; i < ARRAY_COUNT(s_function_table); i++)
{
if (!lstrcmpA(s_function_table[i].p_name, func))
{
s_function_table[i].p_func(nlhs, p_lhs, nrhs - 1, p_rhs + 1);
return;
}
}
代碼清單 3.mexFunction() 子函數調度。
static const function_table_t s_function_table[] =
{
{ "get_samples", mex_get_samples },
{ "open", mex_open },
{ "close", mex_close },
{ "start", mex_start },
{ "stop", mex_stop }
};
代碼清單 4.子函數調用表。
調用表中引用的 mex_* 函數是 Win32 DLL 函數的精簡包裝器,詳見下文 部分。
MATLAB MEX 接口還以與 MATLAB的雙矩陣定向性質。MATLAB MEX 接口返回的頂級對象是 MATLAB 具有以下字段的結構:
圖4.頂級 MATLAB 數據對象。
雙精度數組時間戳和toff_diff的大小是可變的。
向上和向下成員是具有以下格式的 MATLAB 結構:
圖5.包含MAX35013時間測量值的MATLAB結構。
同樣,每個數組的長度是可變的。該數據與MAX35103EVKIT35103評估板上MAX2輸出的數據直接對應。
在 mex.c 中,函數 mex_get_samples() 使用 MATLAB mx* 格式化嵌入式目標接收的數據 功能。
static void mex_get_samples(int nlhs, mxArray *p_lhs[], int nrhs, const mxArray *p_rhs[])
{
char * sample_fieldnames[] =
{
"timestamp",
"up",
"down",
"toff_diff"
};
svflow_sample_t sample;
void **pp = (void*)mxGetData(p_rhs[0]); uint32_t sample_count = (uint32_t)mxGetScalar(p_rhs[1]);
mxArray *p_sample_struct = mxCreateStructMatrix( 1, 1, ARRAY_COUNT(sample_fieldnames), sample_fieldnames );
mxArray *p_timestamp = mxCreateNumericMatrix( 1, sample_count, mxDOUBLE_CLASS, mxREAL );
mxSetField( p_sample_struct, 0, "timestamp", p_timestamp );
mxSetField( p_sample_struct, 0, "up", create_direction_struct( sample_count, &sample.up ) );
mxSetField( p_sample_struct, 0, "down", create_direction_struct( sample_count, &sample.down ) );
mxArray *p_toff_diff = mxCreateNumericMatrix( 1, sample_count, mxDOUBLE_CLASS, mxREAL );
mxSetField( p_sample_struct, 0, "toff_diff", p_toff_diff );
sample.p_timestamp = (double_t*)mxGetData( p_timestamp );
sample.p_tof_diff = (double_t*)mxGetData( p_toff_diff );
svflow_get_samples( *pp, &sample, sample_count );
p_lhs[0] = p_sample_struct;
}
代碼清單 5.mex_get_samples() 在墨西哥
“up”和“down”結構成員在 mex.c 的 create_direction_struct() 函數中構造。
Win32 DLL 接口
Win32 DLL 接口在 svflow.c 中實現,其中還包含大部分協議和平臺 特定代碼。與此應用筆記關聯的源代碼包包含一個 Visual Studio 項目,該項目可以是 用于生成 DLL。但是,MATLAB 不需要 DLL。它只是為了幫助那些對 使用可與 DLL 交互的語言編寫自定義數據分析代碼。?
下面的代碼清單6顯示了MAX35103EVKIT2評估板軟件支持的DLL接口功能。這些函數與代碼清單 1 中所示的 MATLAB 腳本中調用的子函數完全對應。
void* svflow_open( uint32_t comport);
void svflow_close(void *pv_context);
uint32_t svflow_get_samples(void *pv_context, flow_sample_t
*p_flow_sample, uint32_t sample_count);
void svflow_start( void *pv_context, float_t sample_rate_hz );
void svflow_stop( void *pv_context );
代碼 6.- flow.h.
svflow_open () 返回與給定 Win32 COM 端口關聯的不透明流通信上下文對象或 如果發生錯誤,則為 NULL。
svflow_close() 使用 svflow_open() 返回的上下文對象關閉通信并釋放資源。
svflow_start() 告訴嵌入的目標開始以指定的采樣率收集流樣本。
svflow_stop() 告訴嵌入式目標結束數據收集。
這些功能特定于MAX35103EVKIT2評估板軟件, 它們可以很容易地被適合其他嵌入式應用程序的功能所取代。
主機協議
主機和嵌入式目標使用的協議基于 com.c/h 中的通用定義和函數構建,并且 序列化.c/h.體系結構支持的協議通常由命令/響應和指示事件組成。 主機協議在 svflow.c 中實現,依賴于 com.c 和 serialize.c,這對于 主機和嵌入的目標。
主機端協議使用 com_* 函數發出命令并解碼響應和指示。例如,在 代碼清單 6, com_tx() 用于向嵌入式目標發送 'com_host_start_sampling_t' 命令數據包。
請務必注意,所有協議函數都是單線程阻塞調用。
void svflow_start( void *pv_context, float_t sample_rate_hz )
{
context_t *p_context = (context_t*)pv_context;
if( p_context )
{
com_host_start_sampling_t cmd;
cmd.sample_rate_hz = sample_rate_hz;
com_tx( &p_context->com, &cmd, COM_ID_HOST_START_SAMPLING,
sizeof( com_host_start_sampling_t ) );
}
}
代碼清單 7.flow_start() 在 flow.c.
主機協議模塊還定義了與傳輸通信的數據類型相對應的數據類型 鏈接,但與它們不完全相同。這種差異允許對 此模塊和上述模塊。具體來說,它將數據包格式解耦(簡潔的單精度浮點數) 來自用于容納 MATLAB(詳細、面向矩陣的雙精度)的數據格式。這意味著翻譯 代碼必須存在于 flow.c 中,如代碼清單 7 中的序列化回調函數所示。
static bool serialize_cb(void *pv_context, const void *pv_data, uint16_t length)
{
context t * p_context = (context_t *)pv_context;
const com_union_t *p_packet = (const com_union_t*)pv_data;
if (p_packet->hdr.id == COM_ID_DEVICE_FLOW_SAMPLE )
{
com_device_flow_sample_t *p_com_sample =
(com_device_flow_sample_t*)&p_packet->flow_sample;
if (!p_context->sample_ndx )
{
p_context->time_offset = p_com_sample->timestamp;
}
svflow_sample_t *p_flow_sample = p_context>p_flow_sample;
uint32_t ndx = p_context->sample_ndx;
direction( &p_flow_sample->up, &p_com_sample->up, ndx );
direction( &p_flow_sample->down, &p_com_sample->down, ndx );
p_flow_sample->p_timestamp[ndx] = ( (double_t)( p_com_sample->timestamp –
p_context->time_offset ) ) / 96000000.0;
p_flow_sample->p_tof_diff[ndx] = p_com_sample->tof_diff;
p_context->sample_ndx++;
if( p_context->sample_ndx >= p_context->sample_count )
return true;
}
return false;
}
代碼清單 8.flow.c 中的數據轉換
svflow.c 還包含初始化和回調函數,以便在 Win32 平臺上使用 comports 所需的函數,如下所示 在代碼清單 8 中。
static uint16_t uart_write(com_t *p_com, void *pv, uint16_t length)
{
DWORD written;
context_t *p_context = (context_t*)p_com;
WriteFile(p_context->hComm, pv, length, &written, NULL);
return (uint16_t)written;
}
static uint16_t uart_read(com_t *p_com, void *pv, uint16_t length)
{
DWORD read;
context_t *p_context = (context_t*)p_com;
ReadFile(p_context->hComm, pv, length, &read, NULL);
return (uint16_t)read;
}
代碼清單 9.flow.c 中的 Win32 串口回調。
COM 模塊實現抽象串行傳輸的例程。com_init() 初始化抽象 調用對象和 com_read() 來反序列化和調度特定的命令/響應和指示。
嵌入式目標架構
嵌入式目標體系結構在概念上很簡單,并且反映了主機端體系結構,不包括 平臺和 MATLAB 特定組件。
嵌入式應用程序包含支持 svflow.c 中定義的主機端 svflow_* 調用的函數。這些 功能包括MAX35103EVKIT2特有的回調和配置,可在board.c中找到。
與主機端的 comport 抽象一樣,嵌入式目標具有串行端口回調,如 Code 所示 清單 9.讀回調調用芯片支持庫 (CSL) 函數調用,以將長度字節寫入 UART。 返回值是實際寫入的字節數。讀回調使用 CSL 函數調用來讀取端口上當前可用的所有字節(最多長度)。
static uint16_t uart_write(com_t * p_com, void * pv, uint16_t length)
{
return UART_Write(MXC_UART0, (uint8_t *)pv, length);
}
static uint16_t uart_read(com_t * p_com, void * pv, uint16_t length)
{
return UART_Read(MXC_UART0, (uint8_t *)pv, length, NULL);
}
代碼 10.main.c 中的串行端口回調。
嵌入式目標使用 COM 模塊從主機調度命令。com_read() 從主節點調用 轉換循環和命令在代碼清單 10 中列出的 serialize_cb() 中調度。
main.c包含MAX35103EVKIT2評估軟件上用于流量測量的嵌入式應用,使用: MAX3510x.c模塊,用于與MAX35103芯片接口。Board.c 包含特定于板的初始化和 中斷調度代碼。
雖然本示例針對MAX35103EVKIT2評估板軟件, COM 和序列化模塊不是特定于平臺的,可以輕松移植到大多數現代微控制器 和電路板設計。
static bool serialize_cb(void *pv_context, const void *pv_packet, uint16_t length)
{
const com_union_t *p_com = (const com_union_t*)pv_packet;
switch( p_com->hdr.id )
{
case COM_ID_HOST_START_SAMPLING:
{
if( p_com->start_sampling.sample_rate_hz > 0.0F &&
p_com->start_sampling.sample_rate_hz <= 200.0F )
{
s_sampling_underflow = 0;
s_sampling_overrun = 0;
s_sample_state = sample_state_idle;
s_send_samples = true;
SYS_SysTick_Config( (uint32_t)((float_t)SYS_SysTick_GetFreq() /
p_com>start_sampling.sample_rate_hz), 1);
}
break;
}
case COM_ID_HOST_STOP_SAMPLING:{
{
SYS_SysTick_Config( (uint32_t)((float_t)SYS_SysTick_GetFreq() / 10.0F), 1);
s_send_samples = false;
break;
}
}
return false;
}
代碼 11.Serialize_cb在主
軟件包內容
目標固件和Windows主機軟件可從Maxim網站下載。它以拉鏈形式提供 檔案。將存檔解壓縮到計算機上方便的目錄中。圖 6 顯示了 目標固件和主機軟件實現。?
圖6.軟件目錄結構。
根目錄包含 main() 以及 COM 和序列化模塊。此外,傳感器 c/h 包含 MAX35103EVKIT2評估軟件附帶的超聲傳感器參數
電路板目錄包含 MATLAB 示例固件應用程序支持的每個開發板的子目錄。 可以在此處添加對自定義用戶板的支持。
csl和MAX3510x目錄包含MAX35103EVKIT2評估板軟件微控制器和外設的專用代碼。
IAR目錄包含用于構建和調試MAX35103EVKIT2評估板軟件固件的項目文件。 可以添加新的項目配置以支持自定義用戶板。最簡單的方法是 復制配置,然后對其進行修改以適應新目標。
主機和 dll 目錄包含生成 Win32 DLL 和 MEX 接口模塊所需的所有源代碼。 此外,還提供了用于編譯 MEX 接口模塊的 MATLAB 腳本以及 中詳述的測試腳本 代碼清單 1.
構建目標固件
MATLAB 示例固件可以使用 IAR ARM 構建。IAR 項目文件位于 iar 目錄中。加載后 項目中,請務必檢查調試器配置是否正確(請參閱圖 4)。微控制器上的 MAX35103EVKIT2評估板軟件 可以使用 IAR 支持的任何 ARM JTAG 適配器使用 10 引腳 ARM 接頭 (J1) 進行編程。
圖7.IAR 調試器選項。
Project.out 是在生成項目時創建的固件映像。
圖8.使用 IAR 構建固件。
構建主機軟件
MATLAB MEX 接口可以使用位于主機目錄中的 compile.m 腳本從 MATLAB 內部構建。 如圖 6 所示。構建的輸出是 flow.mexw64。
要使用 compile.m,您必須安裝 MATLAB 支持的 C 編譯器。請訪問 The Mathworks 網站了解詳情 這可能會從一個版本的 MATLAB 更改為下一個版本。
在撰寫本文時,MATLAB 2016a 可以使用 Microsoft Visual C++ 的免費版本來生成 MEX 文件。
圖9.構建 MEX 接口。
主機軟件也可以內置到 DLL 模塊中,供知道如何與 DLL 通信的非 MATLAB 程序使用。用于生成 DLL 的 Microsoft Visual C++ 項目文件可以在 dll 目錄中找到。
硬件配置
MAX35103EVKIT2 PCB必須連接到超聲波流體,如MAX35103EVKIT2評估板數據資料中所述。圖 10 顯示了 上可用的連接 MAX35103EVKIT2電路板
電源應連接到6-24V AC或能夠提供200mA的直流電源。
閥門可以保持未連接狀態。
PIEZO UP±應連接到其中一個流體傳感器
PIEZO DOWN±應與另一流動體換能器連接。
RTD/熱敏電阻可以保持未連接狀態。
固件不使用旋轉開關。
圖 10.MAX35103EVKIT2 J12引腳排列
結論
MATLAB 為數據分析和算法開發提供了一個很好的平臺。本應用筆記介紹了一種簡單、可定制的軟件架構,可用于將數據導入 MATLAB,而無需成本和 市售附加模塊的復雜性。
審核編輯:郭婷
-
matlab
+關注
關注
185文章
2980瀏覽量
230817 -
嵌入式
+關注
關注
5090文章
19176瀏覽量
306915 -
源代碼
+關注
關注
96文章
2946瀏覽量
66854
發布評論請先 登錄
相關推薦
評論