在工作中,以什麼樣的方式向領導彙報工作最直接高效呢?當然是圖形界面!圖形界面更好表達一個程序設計的邏輯思維,一目瞭然,本次介紹的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軟件的下載鏈接。
往期精彩
第10期 | ringbuff,通用FIFO環形緩衝區實現庫
ESP8266實戰貼:使用HTTP POST請求上傳數據到公有云OneNet
會C/C++就可以開發Linux/Android應用程序?替代傳統串口屏的Yoxios瞭解一下!
覺得本次分享的文章對您有幫助,隨手點[在看]
並轉發分享,也是對我的支持。