在 CubeMX 可以產生多種編譯環境中常見的程式碼
其中包含 IAR 的 EWARM V7/V8
Keil 的 MDK-ARM V4/V5
還有自家最新推出的 CubeIDE
與第三方(AC6)合作的 SW4STM32
這些編譯環境都可以被 CubeMX 所支援
不過我本身對 MDK 的環境比較熟悉
所以才會以 MDK5 作為範例
如果有機會
建議可以嘗試一下 CubeIDE 或 SW4STM32
官方資源與開源環境是新時代的趨勢
自由度越高的環境才能被更多的使用者接受
等我熟悉過 CubeIDE 及 SW4STM32 後再來跟大家分享
暫時先看看 MDK5 的範例吧 (以官方試用版的空間限制就能完成的專案)
==========================================================
由 CubeMX 所產生的 MDK5 程式碼會包含以下幾個資料夾:
1. Drivers: | 其中包括 CMSIS (Cortex MCU Software Interface Standard) 及 STM32F2xx_HAL_Driver (STM 官方 HAL 庫) |
2. Inc: | 程式所需的 include 檔 |
3. MDK-ARM: | 包含專案捷徑及除錯所需的連結檔、燒錄檔 |
4. Src: | 主要程式的原始碼 (使用者修改專用) |
然後還有一個 Hello.ioc 的 CubeMX 專用 IO 編輯檔
剛剛產生的檔案中
MDK-ARM資料夾內的資料應該都是空的
因為專案本身還沒經過編譯
所以連結檔與燒錄檔都尚未產生
等第一次編譯過後就會有對應的檔案出現
今天的目標是要完成 Hello World 的任務
所以先進入MDK-ARM的資料夾中
由 Hello.uvprojx 的專案檔開啟專案
這是站長習慣的開啟方式
你也可以先打開 MDK5 由 Project -> Open Project 的方式來開啟
因為是第一次開啟專案
所以 Project 應該還沒把專案列入最近清單中
等編譯完成後就可以由最近清單中去開啟專案
另外
進入專案後第一件要確認的就是燒錄環境的設定
如果您使用的是 ST LINK 當作燒錄的工具
那麼就可以忽略接下來的步驟
不過建議還是檢查一下比較保險
我所使用的是 MDK5 專用的 ULINK2
與專案所建立的 ST LINK 是不一樣的工具
所以要先到 Flash -> Configure Falsh Tools... 中
將 Debug 欄位裡的工具更改為 ULINK2
您可以依照自己所使用的工具進行修改
別忘了要替燒錄工具的韌體進行更新
免得不支援選用的 MCU 就 GG 了
==========================================================
要完成 Hello World 的任務
有幾個重要的觀念要先建立
一般來說
周邊功能有三種方式可以呼叫
第一種是用輪詢
第二種是用中斷
第三種是DMA
這個範例會先以輪詢的方式進行撰寫
先驗證IO動作是正確的
之後再嘗試中斷與DMA的寫法
其次
標準 C 語言有內建通訊的函式 printf ()
要使用這個功能必須引用 <stdio.h> 這個開頭檔
否則編譯過程中會發生語法錯誤
由於通訊功能相關的程式碼放在 usart.c 當中
所以首先要改寫的程式便從 usart.c 開始
==========================================================
/* USER CODE BEGIN 0 */
#include <stdio.h>
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 1 */
在 usart.c 中找到 /* USER CODE BEGIN 0 */ 與 /* USER CODE BEGIN 1 */ 的位置
加入上方的程式碼
因為我們接下來會引用 printf 函式
編譯時會檢查編譯環境的設定
所以定義了編譯環境所必須的參數
而 HAL_UART_Transmit 函式則是 HAL 庫內建功能
在 stm32f2xx_hal_uart.c 中可以找到
功能是將 printf 所要丟出的字串一個一個 Byte 傳送出去
==========================================================
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN 3 */
printf("\r\n Hello World !! \r\n");
HAL_Delay(1000);
}
/* USER CODE END 3 */
接下來到主程式 main.c 中
找到 /* USER CODE BEGIN Includes */ 及 /* USER CODE BEGIN 3 */
把上面的程式碼加入
其中 HAL_Dealy 約是每個計數 1mS 的延遲 (在 stm32f2xx_hal.c 中)
設定1000為1秒鐘延遲的意思
然後點擊 Rebuild 鍵先進行第一次編譯動作
之後就等待 MDK5 編譯完成
第一次編譯通常會花上一些時間
完成後執行 Load 將程式燒錄到 MCU 中
如果前面的燒錄工具有設定正確的話
應該很快就可以燒錄(下載)成功
接上 USB<->UART 工具或任何可以觀看 UART 通訊資料的工具
你就可以看到 Hello World !! 字樣
==========================================================
如果你不是很習慣作業系統的寫法
不想使用 printf 來傳送資料
那可以怎麼修改呢?
/* USER CODE BEGIN PV */
uint8_t Enter[] = { 0x0d, 0x0a };
uint8_t Hello[] = { "Hello World !!!" };
/* USER CODE END PV */
/* USER CODE BEGIN 3 */
HAL_UART_Transmit (&huart3, Enter, sizeof(Enter), 0xffff);
HAL_UART_Transmit (&huart3, Hello, sizeof(Hello)-1, 0xffff);
HAL_UART_Transmit (&huart3, Enter, sizeof(Enter), 0xffff);
HAL_Delay(1000);
}
/* USER CODE END 3 */
回歸到單晶片的概念
就是找到傳送的函式
把要丟出去的字串定義好丟出去就可以了
所以可以不要修改 usart.c 中的內容
只在 main.c 中找到 /* USER CODE BEGIN PV */ 及 /* USER CODE BEGIN 3 */
將上面的程式碼寫入對應的位置上
一樣可以看到 Hello World !!! 的字樣
其中
由於宣告為字串的矩陣會多帶一個空字串
所以使用sizeof()這個功能時要將空字串的計數減掉 [sizeof(Hello)-1]
不然會在通訊中多看到一個 0x00 的碼躲在 Hello World !!!後面
==========================================================
最後要提一下 CubeMX 所要帶給我們的改變與新思維:
第一
不要再以硬體底層的概念來看單晶片程式
因為現在的單晶片都不再是以往簡單幾個周邊功能而已
各個周邊之間的關聯性與複雜度都今非昔比
建立以系統觀的思維來看待程式
嘗試以作業系統的寫法來修正以往的撰寫習慣
可以提高程式的可攜性與移植性
避開重複開發以縮短專案完成的時間
第二
我們不是單晶片大廠的員工
也不是設計單晶片的設計師
不應該為單晶片的驅動與除錯負責
這應該是單晶片大廠所要克服的功課
在高度分工的科技時代
如果還要工程師從頭到尾把晶片廠的問題一一克服才開始開發專案
那開發的進度鐵定落後到天荒地老
並不是我們不具備解決問題的能力
也不是我們缺乏學習的動力與毅力
而是在商言商--時間就是金錢
很多舊時代的大廠還停留在工程師就是要解決所有的開發問題
而忽略分工的責任劃分與時間、專案管理的問題
甚至把問題都怪罪到研發工程師的身上
認為他們程度差且懶惰又不負責任
這是非常落伍且不公平的
第三
工欲善其事,必先利其器
如果有更好的工具可以用
就不要因為習慣了舊工具就排斥接觸新工具
每個學習都有陣痛期
但如果陣痛可以帶來脫胎換骨的大提升
那為何不痛一下就好?
而要一直忍受效率不好的開發工具
讓自己的競爭力越來越不好呢?
人本來就是活到老學到老
不是嗎?
希望你會喜歡這篇文章的介紹
下一篇我們要探討一下中斷與DMA的用法
敬請繼續期待
沒有留言:
張貼留言