搞嵌入式開發卻不會寫上位機?來了解下小白的福音Micro-Lab(多個案例帶你快速入門)...

在工作中,以什麼樣的方式向領導彙報工作最直接高效呢?當然是圖形界面!圖形界面更好表達一個程序設計的邏輯思維,一目瞭然,本次介紹的Micro-Lab出自風媒科技-趙工之手,趙工在前兩年也出版本過一本技術書籍<<STM32物聯網實戰教程>>,將自己畢生的開發經驗彙集成冊並開源pdf,並在電子發燒友等論壇推出了自己的30天入門物聯網的免費教程。

1、什麼是Micro-Lab?

Micro-Lab可以稱得上是迄今爲止最棒的嵌入式調試工具,在調試過程中遇到的所有痛點,在這裏都得以解決,並引入了很多新的功能,如串口/網絡示波器,串口/網絡指令編程,革命性的事件驅動型上位機生成器——組態畫布等數十個功能,無論是在使用手感上還是功能實用方面都是絕對一流,可以說Micro-Lab重新定義了嵌入式調試工具,同時也成爲行業工具的標杆。(當前介紹引自碼雲:https://gitee.com/fengmeitech/Micro-Lab),來看看具體長什麼樣吧:

功能很豐富,基本上常見的調試功能都已經集成了,但這篇文章的重點是怎麼用Micro-Lab與MCU進行交互。

2、Micro-Lab圖形界面設計與使用

2.1 設計基本圖形界面

切換到組態畫布頁面,然後手動將左邊相關控件拖放到中間控件放置區域,選中其中一個控件時,可以通過右邊更改控件的屬性,和玩串口屏是類似的操作,即使完全沒有用過,不看說明文檔也能快速上手。

當控件佈局完畢以後,在控件放置區域點擊鼠標右鍵選擇Run,這時候就會彈出剛剛畫好的界面,如下:

在MCU與Micro-Lab建立通信之前我們要先了解三大控件類的用途:

  • 控制組件

控制組件目前有按鍵、開關、滑動條、旋鈕,意思就是通過Micro-Lab去操作這些控件,Micro-Lab就會下發對應的協議指令給MCU,MCU收到對應的指令後,則根據SDK提供的接口去處理不同的事務。

  • 顯示組件

顯示組件目前有進度球、電池、儀表盤、時鐘、指南針、點陣屏、數碼管、LED、飛行儀、刻度計、文本、時間日期這些組件,當組態畫圖佈局了對應組件,MCU往Micro-Lab發送對應的協議指令,Micro-Lab接收到對應的協議指令後進行數據解析,將數據展示在顯示組件上。

  • 圖表組件

圖表控件目前僅有曲線波形,用於展示波形數據。

該項目還在持續成長中,相信將來會有越來越多的控件加入。

2.2 MCU與MicroLab建立通信

2.2.1 下載SDK

界面設計完畢,接下來需要下載SDK,將SDK移植到MCU上,讓MCU和Micro-Lab建立通信,建立通信目前有兩種方式,一種是串口通信,還有另一種是網絡通信。

下載SDK的方法如下,在組態畫布控件佈局區域鼠標右鍵,然後選擇Download MCU SDK

接下來會跳轉到碼雲,點擊下載SDK包,SDK包提供了stm32f103有關組態畫布的例程,sdk則是與Micro-Lab通信的協議代碼,關於怎麼使用這個Micro-Lab以及如何移植到MCU上,up主趙工也在bibi上開了視頻專門講解,感興趣的可以去看看,地址如下:

https://space.bilibili.com/281029341?from=search&seid=2143076487604252529

2.2.1 將SDK移植到小熊派上

這裏我直接用小熊派自帶的光強傳感器例程進行移植

(1)將SDK包拷貝到工程中

(2)在Keil中包含SDK包

(3)修改工程

當然這個發送字節的接口也可以改成TCP/IP傳輸,下面再結合智能小車控制的例程進行修改。

(3)使用Micro-Lab

1、包含相應的頭文件並導入外部event變量

2、初始化組態畫布

3、調用更新畫布接口發送數據到上位機

這裏我用的是數碼管控件,簡單來說明下updateCanvas這個接口:

/**
 * brief : update Canvas`components state with serialport/net
 * parameter:
 *      componenttype  : component type
 *      componentnumber: component number
 *      data           : data that to canvas
 *      datalen        : data lenth
 * ret: none
 */
void updateCanvas(COMPONENT_TYPE componenttype, unsigned short componentnumber, char * data, unsigned short datalen)
{
    static char tbuffer[TBUFFERSIZE];
    static short size;

    packProtocol(ORGANIZATION, SECTION, DATAPOINT, componenttype, componentnumber, NONE_MSG, data, datalen, tbuffer, &size);
    sendBytes(tbuffer, size);
}

其中componenttype表示控件類型,sdk中用枚舉進行描述,對應如下:

/* component type */
typedef enum
{
    NONE_COMPONENT =    -1,

    /*define ctrol component*/
    PUSHBUTTON     =    1,      //push button
    SWITCHBUTTON   =    2,      //switch
    SLIDER         =    3,      //slider
    DIAL           =    4,      //dial

    /*define show component*/
    WATERLEVER     =    1001,   //water level
    BATTERY        =    1002,   //battery power
    CARDASHBOARD   =    1003,   //car dashboard
    CLOCK          =    1004,   //clock with hour, minute, second hands
    COMPASS        =    1005,   //compass
    LEDDOT         =    1006,   //LED dot matrix
    LCDNUMBER      =    1007,   //lcd number
    LEDSTATE       =    1008,   //LED state
    PLANEDASHBOARD =    1009,   //plane dashboard
    TEMPMETER      =    1010,   //temperature meter
    LABEL          =    1011,   //text label
    LCDDATETIME    =    1012,   //datetime lcdnumber

    /*define chart component*/
    WAVECHART      =    2001,   //wave chart

    /*KEY & MOUSE*/
    KEYBOARD       =    9001,
    MOUSE          =    9002
}COMPONENT_TYPE;

對應的這些數值,比如1001、1002,其實就是畫布上的屬性區域的type值,例如我用的是數碼管控件,對應的type值爲1007。

componentnumber表示的是畫布中控件的序號,比如創建了第一個數碼管控件,那麼索引值爲0,第二個則爲1,以此類推。

data表示顯示在控件上數據

datalen表示數據長度

(4)運行結果

將移植後的工程編譯下載後,設置好Micro-Lab串口參數,然後打開串口,運行畫布即可看到數據已經上傳上來了:

3、Micro-Lab按鈕組件控制開發板上燈亮滅

3.1 設計基本圖形界面

然後設置按鈕按下和釋放的事件值

這裏設置按下爲0,釋放爲1。

3.2 移植SDK,添加處理接口

以下只寫關鍵的代碼部分,其餘部分請下載完整工程查看。

在串口接收中斷中添加處理函數:processBytes

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
    if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);
        HAL_UART_DMAStop(&huart1);
        cmd_parse_typedef.no_rx_count  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 獲取DMA中未傳輸的數據個數
        cmd_parse_typedef.rx_count =  CMD_STR_SIZE - cmd_parse_typedef.no_rx_count; //總計數減去未傳輸的數據個數,得到已經接收的數據個  
        processBytes((char *)cmd_parse_typedef.cmd_buffer, cmd_parse_typedef.rx_count);
        HAL_UART_Receive_DMA(&huart1,cmd_parse_typedef.cmd_buffer,CMD_STR_SIZE);//重新打開DMA接收  
        cmd_parse_typedef.BufferReady = 1 ;
    }
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

這裏我用的是串口1的接收,採用空閒中斷+DMA的方式接收。

在主函數中,處理接收到的數據,根據觸發添加做自己想做的事情。

int main(void)
{
    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART1_UART_Init();
    /* USER CODE BEGIN 2 */
    //初始化畫布
    initCanvas(events);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        //如果串口數據接收完畢了,開始處理串口數據
        if(1 == cmd_parse_typedef.BufferReady)
        {
            cmd_parse_typedef.BufferReady = 0 ;

            ///遍歷事件
            for(char i = 0; i < CANVASEVENTLIST_SIZE; ++i)
            {
                //如果當前SDK包含對應的控件事件,則處理
                if(events[i].componenttype != NONE_COMPONENT)
                {
                    //當前componenttype爲按鈕
                    if(PUSHBUTTON == events[i].componenttype)
                    {
                        //當前畫布的Index爲0
                        if(events[i].componentnumer == 0)
                        {
                            //當前觸發了按下,點燈
                            if(PUSHBUTTON_PRESS == events[i].componentmsgtype)
                            {
                                HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
                            }
                            //當前觸發了釋放,滅燈
                            else if(PUSHBUTTON_RELEASE == events[i].componentmsgtype)
                            {
                                HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
                            }
                        }
                    }

                    //清除事件
                    events[i].componenttype = NONE_COMPONENT;
                    events[i].componentnumer = 0;
                    events[i].componentmsgtype = NONE_MSG;
                    events[i].msglen = 0;
                }
            }
        }

        /* USER CODE END 3 */
    }
}

其它控制控件也是類似的操作方法,非常簡單。

連接好Micro-Lab後,打開串口,運行畫布,鼠標按下button,開發板上的LED點亮,釋放鼠標,則LED燈熄滅。

4、Micro-Lab按鈕組件控制坦克小車

由於坦克小車是基於ESP8266 WIFI無線,所以我們就需要通過Micro-Lab的網絡TCP/IP的模式與WIFI坦克小車進行通信,控制流程如下,詳細代碼見文末,在後臺回覆關鍵字獲取。

4.1 Micro-Lab端的設置

4.2 小車端程序流程(基於STM32F103ZET6)

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_TIM1_Init();
    MX_USART1_UART_Init();
    MX_USART2_UART_Init();
    MX_TIM3_Init();
    /* USER CODE BEGIN 2 */
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
    //setServoAngle(6);
    ESP8266_Init();
    //初始化畫布
    initCanvas(events);
    printf("正在配置 ESP8266 ......\n" );
    ESP8266_Rst();

    while(!ESP8266_AT_Test());

    while(!ESP8266_Net_Mode_Choose(STA_AP));

    while(!ESP8266_JoinAP(User_ESP8266_ApSsid, User_ESP8266_ApPwd));

    while(!ESP8266_Enable_MultipleId(DISABLE));

    while(!ESP8266_Link_Server(enumTCP, User_ESP8266_TcpServer_IP, User_ESP8266_TcpServer_Port, Single_ID_0));

    while(!ESP8266_UnvarnishSend());

    //使能空閒中斷
    __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
    printf("配置 ESP8266 完畢\n");
    //配置完畢,打開指示燈,代表此時已經連接服務器成功
    HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        ESP8266_Data_Handler();
    }

    /* USER CODE END 3 */
}

接收到Micro-Lab發送來的數據後,調用SDK進行協議解析,然後解析得到的指令調用不同的小車控制邏輯:

//ESP8266接收數據處理
void ESP8266_Data_Handler(void)
{
    ESP8266_ReceiveString(ENABLE);

    if ( strEsp8266_Fram_Record .InfBit .FramFinishFlag )
    {
        //接收到數據閃爍燈
        HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
        strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';

        for(int i = 0 ; i < strEsp8266_Fram_Record .InfBit .FramLength ; i++)
            printf("%x ", strEsp8266_Fram_Record .Data_RX_BUF[i]);

        printf("\r\n");
        //處理Canvas發來的數據
        processBytes(strEsp8266_Fram_Record .Data_RX_BUF, strEsp8266_Fram_Record .InfBit .FramLength);
        //執行事件處理
        Car_Event_Handler();
        //清楚串口緩存區
        memset(strEsp8266_Fram_Record.Data_RX_BUF, 0, strlen(strEsp8266_Fram_Record.Data_RX_BUF));
    }
}

小車事件處理:

//小車事件處理
void Car_Event_Handler(void)
{
    ///遍歷事件
    for(int i = 0; i < CANVASEVENTLIST_SIZE; ++i)
    {
        //如果當前SDK包含對應的控件事件,則處理
        if(events[i].componenttype != NONE_COMPONENT)
        {
            //當前componenttype爲按鈕
            if(PUSHBUTTON == events[i].componenttype)
            {
                //小車前進
                if(events[i].componentnumer == 0)
                {
                    if(PUSHBUTTON_PRESS == events[i].componentmsgtype)
                        car_go();
                    else if(PUSHBUTTON_RELEASE == events[i].componentmsgtype)
                        car_stop();
                }

                //小車後退
                if(events[i].componentnumer == 1)
                {
                    if(PUSHBUTTON_PRESS == events[i].componentmsgtype)
                        car_back();
                    else if(PUSHBUTTON_RELEASE == events[i].componentmsgtype)
                        car_stop();
                }

                //小車左轉
                if(events[i].componentnumer == 2)
                {
                    if(PUSHBUTTON_PRESS == events[i].componentmsgtype)
                        car_left();
                    else if(PUSHBUTTON_RELEASE == events[i].componentmsgtype)
                        car_stop();
                }

                //小車右轉
                if(events[i].componentnumer == 3)
                {
                    if(PUSHBUTTON_PRESS == events[i].componentmsgtype)
                        car_right();
                    else if(PUSHBUTTON_RELEASE == events[i].componentmsgtype)
                        car_stop();
                }

                //小車瞄準
                if(events[i].componentnumer == 4)
                {
                    if(PUSHBUTTON_PRESS == events[i].componentmsgtype)
                        car_aim();
                    else if(PUSHBUTTON_RELEASE == events[i].componentmsgtype)
                        car_stop();
                }

                //小車發射
                if(events[i].componentnumer == 5)
                {
                    if(PUSHBUTTON_PRESS == events[i].componentmsgtype)
                        car_shot();
                    else if(PUSHBUTTON_RELEASE == events[i].componentmsgtype)
                        car_stop();
                }
            }

            //清除事件
            events[i].componenttype = NONE_COMPONENT;
            events[i].componentnumer = 0;
            events[i].componentmsgtype = NONE_MSG;
            events[i].msglen = 0;
        }
    }

}

運行效果:

實際演示效果:

Micro-Lab還在不斷的成長中,相信未來會有越來越多好玩的功能,敬請期待!

5、案例下載

公衆號後臺回覆:Micro-Lab 即可獲取本節所有程序案例以及Micro-Lab軟件的下載鏈接。

往期精彩

STM32在線升級OTA,看這一篇就夠啦~

第10期 | ringbuff,通用FIFO環形緩衝區實現庫

ESP8266實戰貼:使用HTTP POST請求上傳數據到公有云OneNet

會C/C++就可以開發Linux/Android應用程序?替代傳統串口屏的Yoxios瞭解一下!

覺得本次分享的文章對您有幫助,隨手點[在看]並轉發分享,也是對我的支持。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章