【STM32F429的DSP教程】第9章 Matlab的串口通信實現


完整版教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547

第9章   Matlab的串口通信實現

本章節主要為大家講解Matlab的串口方式波形數據傳輸和后期數據分析功能,非常實用。

9.1 初學者重要提示

9.2 程序設計框架

9.3 下位機STM32H7程序設計

9.4 上位機Matlab程序設計

9.5 Matlab上位機程序運行

9.6 實驗例程說明(MDK)

9.7 實驗例程說明(IAR)

9.8 總結

 

 

9.1   初學者重要提示

1、  測試本章節例程注意事項。

  •   請優先運行開發板,然后運行matlab。
  •   調試matlab串口數據發送前,請務必關閉串口助手。

2、  函數delete(instrfindall);

如果不用matlab了,請在matlab的命令輸入窗口調用此函數,防止matlab一直占用串口。

9.2   程序設計框架

上位機和下位機的程序設計框架如下:

 

上位機和下位機做了一個簡單的同步,保證數據通信不出錯。

9.3   下位機STM32F429程序設計

STM32F429端的程序設計思路。

9.3.1  第1步,發送的數據格式

為了方便數據發送,專門設計了一個數據格式:

__packed typedef struct
{
    uint16_t data1;
    uint16_t data2;    
    uint16_t data3;    
    uint8_t  data4;    
    uint8_t  data5;
    uint8_t  data6;        
    uint8_t  data7;
}
SENDPARAM_T;

SENDPARAM_T g_SendData;

為了保證數據的連續存儲,特地在前面加了一個關鍵詞__packed。關於結構體變量占用多少字節問題,此貼進行了詳細說明:http://www.armbbs.cn/forum.php?mod=viewthread&tid=89103

9.3.2  第2步,接收同步信號$

Matlab發送同步信號$(ASCII編碼值是13)給開發板。

int main(void)
{
    /* 省略未寫,僅留下關鍵代碼 */

    /* 進入主程序循環體 */
    while (1)
    {

        /* 判斷定時器超時時間 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔100ms 進來一次 */  
            bsp_LedToggle(2);
        }
        
        if (comGetChar(COM1, &read))
        {
            /* 接收到同步幀'$'*/
            if(read == 13)
            {
                bsp_LedToggle(4);
                bsp_DelayMS(10);
                Serial_sendDataMATLAB();
            }
        }
    }
}

通過函數comGetChar獲取串口接收到的數據,如果數值是13,說明接收到Matlab發送過來的同步信號了。

這里要注意一點,程序這里接收到同步信號后,延遲了10ms再發數據給matlab,主要是因為matlab的波形刷新有點快,程序這里每發送給matlab一次數據,matlab就會刷新一次,10ms就相當於100Hz的刷新率,也會有一定的閃爍感。

9.3.3  第3步,發送數據給Matlab

下面是給Matlab回復同步信號和相應數據的實現:

/*
*********************************************************************************************************
*    函 數 名: Serial_sendDataMATLAB
*    功能說明: 發送串口數據給matlab
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
static void Serial_sendDataMATLAB(void)
{
    /* 先發同步信號'$' */
    comSendChar(COM1, 13);
    
    /* 發送數據,一共10個字節 */
    g_SendData.data1 = rand()%65536;
    g_SendData.data2 = rand()%65536;
    g_SendData.data3 = rand()%65536;
    g_SendData.data4 = rand()%256;  
    g_SendData.data5 = rand()%256;  
    g_SendData.data6 = rand()%256;  
    g_SendData.data7 = rand()%256;  
    comSendBuf(COM1, (uint8_t *)&g_SendData, 10);
}

開發板接收到同步信號后,會回應一個同步信號,然后將10個字節的數據發送給matlab。通過這三步就完成了STM32H7端的程序設計。

9.4   上位機Matlab程序設計

Matlab端的程序設計要略復雜些,需要大家理解matlab端的API。具體說明可以看如下地址:

https://ww2.mathworks.cn/help/matlab/serial-port-devices.html

9.4.1  第1步,配置並打開串口

下面操作是配置並打開串口:

close all
clear all
 
%刪除所有已經打開的串口,這條很重要,防止之前運行沒有關閉串口
delete(instrfindall);  

%打開串口COM1,波特率115200,8位數據位,1位停止位,無奇偶校驗,無流控制
s = serial('COM1', 'BaudRate', 115200, 'DataBits', 8, 'StopBits', 1, 'Parity', 'none', 'FlowControl', 'none');
s.ReadAsyncMode = 'continuous';
fopen(s);
 
fig = figure(1);

這里有以下幾點需要大家了解:

  •   函數delete(instrfindall)

這個函數比較重要,防止上次matlab操作串口,結束時沒有關閉串口。通過這個函數會將其關閉。

  •   函數serial

大家要特別注意打開的COM序號,務必要根據實際使用的COM號進行設置。

  •   函數fopen

通過函數fopen打開串口。

9.4.2  第2步,相關變量設置

程序里面對這些變量的注釋已經比較詳細:

AxisMax =  65536;    %坐標軸最大值
AxisMin = -65536;    %坐標軸最小值
window_width = 800;  %窗口寬度

g_Count =0;          %接收到的數據計數
SOF = 0;             %同步幀標志
AxisValue = 1;       %坐標值
RecDataDisp = zeros(1,100000); %開辟100000個數據單元,用於存儲接收到的數據。
RecData = zeros(1,100);        %開辟100個數據單元,用於數據處理。
Axis = zeros(1,100000);        %開辟100000個數據單元,用於X軸。

window = window_width * (-0.9); %窗口X軸起始坐標
axis([window, window + window_width, AxisMin, AxisMax]); %設置窗口坐標范圍

%子圖1顯示串口上傳的數據
subplot(2,1,1); 
grid on;
title('串口數據接收');
xlabel('時間');
ylabel('數據');

%子圖2顯示波形的幅頻響應
subplot(2,1,2);
grid on;
title( 'FFT');
xlabel( '頻率');
ylabel( '幅度');

Fs = 100;       % 采樣率
N = 50;         % 采樣點數
n = 0:N-1;      % 采樣序列
f = n * Fs / N; %真實的頻率

這里有以下幾點需要大家了解:

  •   變量RecDataDisp,RecData和Axis

這幾個變量專門開辟好了數據空間,防止matlab警告和刷新波形慢的問題,大家根據需要可以進行加大。

  •   采樣率Fs = 100和采樣點數N = 50

這個地方要根據實際的情況進行設置。

9.4.3  第3步,數據同步部分

這部分代碼比較關鍵,matlab先發送同步信號$出去,然后等待開發板回復同步信號$,並讀取本次通信的數據。

%設置同步信號標志, = 1表示接收到下位機發送的同步幀
SOF = 0;  

%發送同步幀
fwrite(s, 13);

%獲取是否有數據
bytes = get(s, 'BytesAvailable');
if bytes == 0
     bytes = 1;
end

%讀取下位機返回的所有數據
RecData = fread(s, bytes, 'uint8');

%檢索下位機返回的數據中是否有字符$
StartData = find(RecData == 13);

%如果檢索到$,讀取10個字節的數據,也就是5個uint16的數據
if(StartData >= 1)
    RecData = fread(s, 5, 'uint16');
    SOF =1;
    StartData = 0;
end

這里有以下幾點需要大家了解:

  •   函數fwrite(s, 13)

用於發送同步信號$(ASCII值是13)。

  •   函數get(s, 'BytesAvailable')

用於獲取串口緩沖中的字節數。

  •   函數fread(s, bytes, 'uint8')

將串口緩沖的數據讀取輸出。

  •  函數find(RecData == 13)

檢索接收到串口數據中是否有同步信號$。

  •   函數fread(s, 5, 'uint16')

如果檢索到$,繼續讀取10個字節的數據,也就是5個uint16的數據。

9.4.4  第4步,顯示串口上傳的數據

下面matlab的數據顯示波形

%更新接收到的數據波形
if(SOF == 1)
    %更新數據
    RecDataDisp(AxisValue) =  RecData(1);
    RecDataDisp(AxisValue + 1) =  RecData(2);
    RecDataDisp(AxisValue + 2) =  RecData(3);
    RecDataDisp(AxisValue + 3) =  RecData(4);
    RecDataDisp(AxisValue + 4) =  RecData(5);
    
    %更新X軸
    Axis(AxisValue) = AxisValue;
    Axis(AxisValue + 1) = AxisValue + 1;
    Axis(AxisValue + 2) = AxisValue + 2;
    Axis(AxisValue + 3) = AxisValue + 3;
    Axis(AxisValue + 4) = AxisValue + 4;

    %更新變量
    AxisValue = AxisValue + 5;
    g_Count = g_Count + 5;
    
    %繪制波形
    subplot(2,1,1);
    plot(Axis(1:AxisValue-1),  RecDataDisp(1:AxisValue-1), 'r');
    window = window + 5;
    axis([window, window + window_width, AxisMin, AxisMax]);
    grid on;
    title('串口數據接收');
    xlabel('時間');
    ylabel('數據');
    drawnow
end

這里有以下幾點需要大家了解:

  •   數組RecDataDisp,RecData和Axis

這里要尤其注意,matlab的數組索引是從1開始的,也是開頭直接定義AxisValue = 1的原因。

  •   函數plot

這里plot的實現尤其重要,務必要注意坐標點和數值個數要匹配。

9.4.5  第5步,FFT數據展示

FFT部分會在在后面章節為大家詳細講解,這里也做個說明,這里是每接收夠50個數據,做一次FFT:

if(g_Count== 50)
   subplot(2,1,2); 
   %對原始信號做 FFT 變換
   y = fft(RecDataDisp(AxisValue-50:AxisValue-1), 50); 
   
   %求 FFT 轉換結果的模值
   Mag = abs(y)*2/N;  
   
   %繪制幅頻相應曲線
   plot(f, Mag, 'r'); 
   grid on;
   title( 'FFT');
   xlabel( '頻率');
   ylabel( '幅度');
   g_Count = 0;
   drawnow
end

9.5   Matlab上位機程序運行

M文件的程序代碼在例子V7-203_Matlab串口波形刷新和數據分析m文件里面。M文件的運行方法在第4章的4.2小節有詳細說明。

9.6   實驗例程說明(MDK)

配套例子:

V6-202_Matlab的串口通信實現

實驗目的:

  1. 學習matlab的串口數據通信。

實驗內容:

  1. 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  2. 請優先運行開發板,然后運行matlab。
  3. 調試matlab串口數據發送前,請務必關閉串口助手。

使用AC6注意事項

特別注意附件章節C的問題

上電后串口打印的信息:

波特率 115200,數據位 8,奇偶校驗位無,停止位 1

 

Matlab的上位機效果:

 

程序設計:

  系統棧大小分配:

 

  硬件外設初始化

硬件外設的初始化是在 bsp.c 文件實現:

/*
*********************************************************************************************************
*    函 數 名: bsp_Init
*    功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32H429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鍾:
       - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。
       - 設置NVIV優先級分組為4。
     */
    HAL_Init();

    /* 
       配置系統時鍾到168MHz
       - 切換使用HSE。
       - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。
    */
    SystemClock_Config();

    /* 
       Event Recorder:
       - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder並開啟 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
    bsp_InitTimer();      /* 初始化滴答定時器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitExtIO();   /* 初始化擴展IO */
    bsp_InitLed();        /* 初始化LED */    
}

  主功能:

主程序實現如下操作:

  •   接收matlab發送過來的同步信號,並回一個同步信號后,傳輸相應的數據過去
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程序入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;        /* 按鍵代碼 */
    uint8_t read;
    
    bsp_Init();        /* 硬件初始化 */
    
    PrintfLogo();    /* 打印例程名稱和版本等信息 */
    PrintfHelp();    /* 打印操作提示 */

    bsp_StartAutoTimer(0, 50);  /* 啟動1個100ms的自動重裝的定時器 */
    
    /* 進入主程序循環體 */
    while (1)
    {
        bsp_Idle();        /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */

        /* 判斷定時器超時時間 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔100ms 進來一次 */  
            bsp_LedToggle(2);
        }
        
        if (comGetChar(COM1, &read))
        {
            /* 接收到同步幀'$'*/
            if(read == 13)
            {
                bsp_LedToggle(4);
                bsp_DelayMS(100);
                Serial_sendDataMATLAB();
            }
        }
        
        /* 按鍵濾波和檢測由后台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。 */
        ucKeyCode = bsp_GetKey();    /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1鍵按下 */
                    printf("K1鍵按下\r\n");
                    break;

                case KEY_UP_K1:            /* K1鍵彈起 */
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下 */
                    printf("K2鍵按下\r\n");
                    break;

                case KEY_UP_K2:            /* K2鍵彈起 */
                    printf("K2鍵彈起\r\n");
                    break;

                case KEY_DOWN_K3:            /* K3鍵按下 */
                    printf("K3鍵按下\r\n");
                    break;

                case KEY_UP_K3:            /* K3鍵彈起 */
                    printf("K3鍵彈起\r\n");
                    break;
                
                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        
        }
    }
}

/*
*********************************************************************************************************
*    函 數 名: Serial_sendDataMATLAB
*    功能說明: 發送串口數據給matlab
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
static void Serial_sendDataMATLAB(void)
{
    /* 先發同步信號'$' */
    comSendChar(COM1, 13);
    
    /* 發送數據,一共10個字節 */
    g_SendData.data1 = rand()%65536;
    g_SendData.data2 = rand()%65536;
    g_SendData.data3 = rand()%65536;
    g_SendData.data4 = rand()%256;  
    g_SendData.data5 = rand()%256;  
    g_SendData.data6 = rand()%256;  
    g_SendData.data7 = rand()%256;  
    comSendBuf(COM1, (uint8_t *)&g_SendData, 10);
}

9.7   實驗例程說明(IAR)

配套例子:  

V6-202_Matlab的串口通信實現

實驗目的:  

  1. 學習matlab的串口數據通信。

實驗內容:

  1. 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  2. 請優先運行開發板,然后運行matlab。
  3. 調試matlab串口數據發送前,請務必關閉串口助手。

上電后串口打印的信息:

波特率 115200,數據位 8,奇偶校驗位無,停止位 1

 

Matlab的上位機效果:

 

程序設計:

  系統棧大小分配:

 

  硬件外設初始化

硬件外設的初始化是在 bsp.c 文件實現:

/*
*********************************************************************************************************
*    函 數 名: bsp_Init
*    功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32H429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鍾:
       - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。
       - 設置NVIV優先級分組為4。
     */
    HAL_Init();

    /* 
       配置系統時鍾到168MHz
       - 切換使用HSE。
       - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。
    */
    SystemClock_Config();

    /* 
       Event Recorder:
       - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder並開啟 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
    bsp_InitTimer();      /* 初始化滴答定時器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitExtIO();   /* 初始化擴展IO */
    bsp_InitLed();        /* 初始化LED */    
}

  主功能:

主程序實現如下操作:

  •   接收matlab發送過來的同步信號,並回一個同步信號后,傳輸相應的數據過去
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程序入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;        /* 按鍵代碼 */
    uint8_t read;
    
    bsp_Init();        /* 硬件初始化 */
    
    PrintfLogo();    /* 打印例程名稱和版本等信息 */
    PrintfHelp();    /* 打印操作提示 */

    bsp_StartAutoTimer(0, 50);  /* 啟動1個100ms的自動重裝的定時器 */
    
    /* 進入主程序循環體 */
    while (1)
    {
        bsp_Idle();        /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */

        /* 判斷定時器超時時間 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔100ms 進來一次 */  
            bsp_LedToggle(2);
        }
        
        if (comGetChar(COM1, &read))
        {
            /* 接收到同步幀'$'*/
            if(read == 13)
            {
                bsp_LedToggle(4);
                bsp_DelayMS(100);
                Serial_sendDataMATLAB();
            }
        }
        
        /* 按鍵濾波和檢測由后台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。 */
        ucKeyCode = bsp_GetKey();    /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1鍵按下 */
                    printf("K1鍵按下\r\n");
                    break;

                case KEY_UP_K1:            /* K1鍵彈起 */
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下 */
                    printf("K2鍵按下\r\n");
                    break;

                case KEY_UP_K2:            /* K2鍵彈起 */
                    printf("K2鍵彈起\r\n");
                    break;

                case KEY_DOWN_K3:            /* K3鍵按下 */
                    printf("K3鍵按下\r\n");
                    break;

                case KEY_UP_K3:            /* K3鍵彈起 */
                    printf("K3鍵彈起\r\n");
                    break;
                
                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        
        }
    }
}

/*
*********************************************************************************************************
*    函 數 名: Serial_sendDataMATLAB
*    功能說明: 發送串口數據給matlab
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
static void Serial_sendDataMATLAB(void)
{
    /* 先發同步信號'$' */
    comSendChar(COM1, 13);
    
    /* 發送數據,一共10個字節 */
    g_SendData.data1 = rand()%65536;
    g_SendData.data2 = rand()%65536;
    g_SendData.data3 = rand()%65536;
    g_SendData.data4 = rand()%256;  
    g_SendData.data5 = rand()%256;  
    g_SendData.data6 = rand()%256;  
    g_SendData.data7 = rand()%256;  
    comSendBuf(COM1, (uint8_t *)&g_SendData, 10);
}

9.8   總結

本章講解的例程非常實用,需要大家熟練掌握。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM