2017年11月26日 星期日

建置 STM8S 的開發環境 (STVD + COSMIC + SPL)

網頁最後修改時間:2017/11/26
來源:網路
看到上面的圖片與標題,聰明的讀者應該能猜到接下來的網頁內容要說什麼東西 !

使用 ST 原廠軟體 STVD 配合 COSMIC,建置 STM8 的開發環境 (完全不用付費)。藉由三個簡單的 LED 亮滅程式,說明如何使用計時器和中斷服務程式來作時間延遲、說明如何使用直接暫存器與官方提供的標準硬體函式庫 (SPL) 來存取硬體週邊、以及如何快速地複製專案重複使用...等學習 STM8S (因為使用的開發板是 STM8S105K4) 的入門基礎。

*********************************************************************************
STM8 最小開發系統與燒錄器套件可至下面購買:
*********************************************************************************

軟體安裝:
軟體安裝分為兩個部分:第一個部分是燒錄器軟體的安裝;第二部分則是 STM8 開發環境所需的軟體安裝。這兩個部分所需要的軟體都可以在 ST 的官網中下載,而且是免費的全功能版本;至於像是使用 IAR 或是其他軟體開發的,就不在此篇網頁說明的範疇之中。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 燒錄器軟體安裝:
燒錄器軟體不僅可以下載韌體到目標開發板之外,也可以更新燒錄器的韌體版本以支援更多新出的 STM8/STM32 的晶片。

點擊以下連結進入到該網頁中,就可以看到支援的工具軟體的下載連節
ST-LINK/V2 in-circuit debugger/programmer for STM8 and STM32
ST-LINK V2 相關軟體下載網頁
下載 STSW-LINK004 (STM32 ST-LINK utility) 這個工具軟體 (檔名會是 en.stsw-link004_STM32 ST-LINK utility_v#.#.#.zip ),完成後解壓縮並點擊執行檔進行軟體安裝。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* STM8 開發環境安裝:
STM8 的開發環境在官網上有提供幾個作選擇。在此篇網頁所選擇是 SVDT + COSMIC 這個方式,免費且對於 STM8 來說是全功能版本,只需要動動手指頭申請 COSMIC License 而已,很方便。

/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
使用 IAR 做開發也可以在官網中下載功能限制版本試用,相關學習的資料與範例程式可在賣場提供的雲端資料夾中取得。
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*

點擊以下連結進入到網頁中,點擊進入黃色框框連結網頁
ST - MCUs Software Development Tools
ST.com 軟體開發工具頁面
進入之後,就會看到滿滿的 STM8 軟體開發工具集,是不是看到有點眼睛灰灰的!

基本上,STM8 開發環境只需要下載 STVD 就可以;若是要使用 C 語言做開發語言的話,就要另外安裝 COSMIC (C 語言編譯器) 並且取得使用 License:
  • STVD-STM8 (ST Visual develop IDE for develping ST7 and ST8 applications)
STM8 開發軟體 STVD 下載
進入該頁面之後,尋找 STVD-STM8 並點擊連結進入。該網頁最下方的地方會有一個 "Get Software" 按鈕,按下後就會先出現一個 License Agreement 的 POP 視窗,點擊 "ACCEPT" 按鈕接受。接著進入下載畫面,不需要登入(Login/Register),只需要隨便輸入名稱與電子郵件 (要有效且正確) 就可以下載,下載的檔案名稱會是 en.stvd-stm8_##.#.#.zip,解壓縮之後檔名會是 sttoolset_pack##.exe,點擊就能進行安裝。
  • COS-C-COMPILER (Free C Compiler for all STM8, from Cosmic)
STM8 開發軟體 COSMIC 下載
進入該頁面之後,尋找 COS-C-COMPILER 並點擊連結進入。該網頁最下方的地方會有一個 "GO TO SITE" 按鈕,按下後就會開啟一個新的視窗,跳轉到 Cosmic 官網的下載網頁。你(妳) 必須要輸入有星號(*)欄位的資料後,按下 "Submit" 後才會跳轉到下載的連結頁面。

COSMIC 對於 STM8 是免費使用,但是需要申請 License;相關資料填寫的範例請參考下面的畫面欄位中的說明。
STM8 COSMIC軟體下載註冊頁面填寫範例
不過,經過實際的測試發現。即便完整詳細正確的填寫上面資料,軟體下載之後經過了好幾個小時的等待,依舊沒有收到任何來自 COSMIC 的郵件;所以上面是唬爛的欄位!因為不管怎麼填,都不會收到由 COSMIC 寄的電子郵件,所以星號的部分隨便填 (格式要對,尤其是電子郵件) 按下 "Submit" 按鈕都會出現下面這個頁面,所以不管怎麼樣,先下載軟體 ( ">>Click here to download<<" ) 再說。方便起見,旁邊附上紅色字的下載連結,看能不能用。
STM8 COSMIC 軟體下載連結網頁
COSMIC 下載之後,license 的問題還是要解決;按下 "click here" 看看!
COSMICQ&A
說到底,COSMIC license 的申請必須在安裝軟體的同時 (或是安裝好之後到 COSMIC安裝目錄下啟動註冊的程式 {COSMIC}\FSE_Compilers\CXSTM8\Register.bat ) 作申請才會收到從 COSMIC 寄送過來的電子郵件;只有這樣做才會收到!
COSMIC license 申請頁面範例
收到郵件之後,裡面會附件一個名稱 license.lic 的檔案,將其放在 {COSMIC}\FSE_Compilers\CXSTM8\ 和 {COSMIC}\FSE_Compilers\CXSTM32\ 這兩個目錄下就完成 license 的安裝,之後就能夠在 STVD 正常使用了!
COSMIC license 檔案放置位置 - 01
COSMIC license 檔案放置位置 - 02
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* STM8S/A Standard peripheral library (SPL) 標準硬體函式庫下載:
在安裝上面兩個軟體之後,其實就可以進行開發,但是所採用的方式會類似單晶片 8051 的方式 (一個一個的暫存器手動指定),真的會大大地讓人降低繼續往下看的動力 !

所以,為了讓開發更佳的容易,ST 已經將這些底層的東西封裝起來,就像是 Arduino 開發一樣提供了官方的標準硬體函式庫 (SPL) 讓使用者下載。利用 SPL 裡面的函式,可以大大的降低學習與開發的時間。

點擊下面連結進入網頁下載
STSW-STM8069 (STM8S/A Standard peripheral library)

選擇一個目錄將其解壓縮在裡面 (這裡面的資料會一直重複使用,不要對此目錄下的檔案進行任何修改)
STM8S/A Standard peripheral library 目錄結構
如果之前曾經在 Keil 或是 Arduino 寫過程式,那麼對於 STM8/32 建立專案的方式可能會有點陌生,甚至搞不是很懂它的目錄結構!Keil 或是 Arduino 在建立專案檔的時候,只有一個主程式或是自己撰寫的函式庫檔案文件會放在同一個資料夾下,其他有使用到的函式庫已事先設定好在 IDE 軟體中,使用者不需要額外再去管這部分的事。但是 STM8/32 開發就不太一樣,用到的函式庫必須自己加進去 (為了避免混亂都會放置在同一個專案目錄內),然後在專案檔裡面做指定;不再只是同一個函式庫,供所有的專案使用。所以建立 STM8/32 專案檔時,同時就是要自己去管理會用到的硬體函式庫文件,並且正確的引用。因此在解壓縮的檔案目錄 Project 下,就有一個名為 STM8S_StdPeriph_Template 的專案樣本目錄 (總之看看就好,下面有建立專案的過程,會用到,但是不是全部)。若直接使用 COSMIC 的函式庫,就直接引用就可以,STVD 會自己搞定與函式庫的引用部分。

說明一下這些目錄,在下面建立使用 SPL 的專案檔會用到,需要先了解一下。

STM8S_StdPeriph_Lib 目錄下
  • _htmresc
    ST 的 Logo 圖片
  • Libraries\STM8S_StdPeriph_Driver
    這個目錄下還有兩個目錄:inc src。前者放 SPL 的標頭檔 (*.h),後者放 SPL 的程式碼 (*.c),這些都是專案檔目錄下需要的檔案,雖然不會一定全部用到,但是最好一次全部加進去專案目錄下,用到的時候在直接引用加入專案設定就行。
  • Project
    使用 SPL 撰寫的 STM8S 參考範例程式 ( Project/STM8S_StdPeriph_Examples ) 和新專案樣本 ( Project/STM8S_StdPeriph_Template )。樣本目錄下的 stm8s_conf.h 在建立 SPL 專案檔時也會用到,需要加進專案目錄中。
  • Utilits
    ST's 評估板用到的函式庫程式碼,但在這網頁裡不會用到。
除了上述目錄外,stm8s-a_stdperiph_lib_um.chm 是關於 SPL 相關範例與函式的說明文件,對於了解 ST's SPL 很有幫助,對函式或是使用上有問題可以用來查詢。

參考文件下載:
要撰寫 STM8S 的程式之前,有幾份重要的參考資料需要下載,寫程式的時候可以做參考與查詢用
雖然有函式庫可以用,但是能夠了解暫存器以及微控制器硬體動作的關係,對於撰寫程式是很有幫助的。接著,再開始撰寫程式之前,先把手上的燒錄器韌體更新到最新版吧!

燒錄器韌體更新:
既然我們該裝的軟體都裝好了,開始起步走之前,把燒錄器韌體更新到 (網頁寫作時 (2017/11/22) ) 最新版 V2.J28.S7 再說。

首先插上燒錄器到電腦上,再打開電腦的裝置管理員 (Windows 10 按下 Win+X 再按下 M ),如果上面軟體安裝沒有問題的話,尋找 "通用序列匯流排裝置",應該要看到跟下面類似的裝置名稱
裝置管理員中的燒錄器名稱
一但裝置識別沒問題之後,打開程式 STM32 ST-LINK Utility。選單點選 "ST-LINK/Firmware" 後會出現軟體更新的視窗,這時可點下 "Device Connect" 按鈕與燒錄器連線
燒錄器軟體版本更新視窗 - 01
 連線成功之後,會出現現有版本 ( Fiemware Version) 和可更新 (Upgrade the firmware to ) 的版本資訊。使用較新的韌體版本會支援更多的 STM8/STM32 新出晶片燒錄;要更新就按下 "Yes >>>>" 按鈕
燒錄器軟體版本更新視窗 - 02
 按下更新結果提示的 "確定" 按鈕之後,更新之後的新版本就會反應到 Upgrade the firmware to 的訊息中;到此就完成燒錄器韌體更新
燒錄器軟體版本更新視窗 - 03
STM32 ST-LINK Utility 除了可更新燒錄器韌體之外,更可以做為燒錄 STM32 晶片之用;但不能用在 STM8 晶片的燒錄上,要燒錄 STM8 要使用 STVP ( ST Visual Programmer) (這在上面安裝 STVD 步驟時就已經一併安裝了,所以不需要再額外安裝了)。

燒錄器與開發板的接線:
STM8S105K4TC 最小系統開發板採用 SWIM 接線方式進行燒錄。燒錄器上面有接腳標示,開發板上面也有,順序都是一樣的,接法很簡單!
燒錄器與開發板 SWIM 實際接線照片
Hello World - 01 (暫存器存取):
Hello World,學習每個程式語言的第一個程式,當然在這裡也不列外!別以為它很簡單,但它卻是進入另一個世界的門檻,初始化檢查了幾乎所有的編輯環境的設置,連這門檻都跨不過去,任何想法都實現不了!

程式的概念很簡單,就是每隔一個時間點亮與熄滅開發板上的 LED 燈 ( PORT E, PIN 5);由時間設定的不同,區分有使用迴圈、Timer1 中斷和 Timer3 中斷這三種方式。

下面的程式範例,除了會學習到基本的專案建立之外,也會學習到如何建立支援 SPL 的專案建置、GPIO 的指定 (暫存器和函式方法)、Timer 的設定與觸發、中斷設定與建置...等,零零總總就只是為了讓 LED 不停地亮一下、滅一下而已!

別想太多,太難的現在也不會  ^_^

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 建立新專案:
建立新專案的同時,如果 STVD 裡面沒有載入任何 Workspace 的話,建立新專案前會要求先建立 workspace,接著再建立新專案。過程中的儲存路徑可依實際需要去指定存放的位置 (雖然下面示例沒有這樣做);Toolchain 選擇 STM8 Cosmic、MCU 選擇 STM8S105K4,一步步照個下面動畫做就可以
{GIF} STVD 建立新 Workspace 和 Project 載入中...
STVD - 建立新 Workspace 和 Project
建立好的專案在 STVD 左邊視窗會出現幾個資料夾,這幾個資料夾在實際目錄中是不存在的,這是用來引用專案外部函式庫標頭檔 ("Include Files") 與程式碼 ("Source Files") 用的 (會記錄相對的路徑在專案文件);專案儲存的地方只會預設生成 Debug  Release 兩個目錄,以及兩個自動產生的檔案,

main.c:撰寫主程式的檔案,大多程式碼都會寫在這裡。
stm8_interrupt_vector.c:中斷向量程式撰寫的地方。

建立完成之後記得要儲存 "File/Save Workspace"

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 程式碼 - 直接暫存器存取:
複製下面的程式碼,複製貼上複寫 main.c 裡面的程式碼
helloworld_01, main.c
#include "iostm8s105.h"

main()
{
  unsigned int i;
  
  //Set port E pin 5 to an output
  // 設定 GPIO Port E pin 5 為輸出
  PE_DDR = 1 << 5;
  // 設定 GPIO Port E pin 5 為 push-pull 輸出,輸出速度最高到 2MHz
  PE_CR1 = 1 << 5;
  // LED 低態動作,初始值設定為 HIGH = 熄滅
  PE_ODR &= !(1 << 5);
  
  while (1)
  {
    // 延遲 ~0.5 秒鐘
    for (i = 0; i < 20000; i++);    
    // 輸出 HIGH,LED 滅
    PE_ODR |= 1 << 5;   //Set port E pin 5 high
    // 延遲 ~0.5 秒鐘
    for (i = 0; i < 20000; i++);
    // 輸出 LOW,LED 亮
    PE_ODR &= ~(1 << 5);
  }
}

跟著下面動畫的步驟進行編譯、燒錄器設定和上傳程式 (記得插上燒錄器到電腦,再將燒錄器與開發板接好線)。成功之後,開發板式的藍色 LED 燈就會開始一亮一滅! (開發板上的藍色 LED 是接到 GPIO Port E Pin 5, 已外部預設上拉)
{GIF} STVD - HelloWorld_01 編譯與上傳 載入中...
STVD - HelloWorld_01 編譯與上傳
有一點要說明的是,build 專案的時候會根據選擇的是 Debug 或是 Release 模式輸出 helloworld_01.s19 到對應的資料夾裡面去 ( s19 是用在 STVD Light Programmer 的韌體檔,要用這個燒錄),同時候在專案目錄下會另外產生一個新目錄 helloworld_01_Programmer 裡面生成一個 helloworld_01_STVP_OPTION_BYTE.hex 的檔案 (顧名思義是 option byte,STVP 的 Light Programmer 燒錄的時候會自動調用;若直接開啟 STVP 燒錄,那這個檔案就要手動加進去)。總之,接下來的範例,同樣利用上面動畫的步驟就可以完成燒錄的動作!

/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
** Connection error (usb://usb_: gdi-error [40201]: can't access configuration database

編譯時出現的錯誤提示視窗
上面視窗如果在除錯或編譯上傳的時候出現,就跟著下面的步驟進行排除!

進入 STVD 的安裝目錄 {STMicroelectronics}\st_toolset\stvd\dao,雙擊打開 ST Toolset.msi 執行,選擇 Remove 選項
ST Toolset 安裝/移除/修復選項視窗
完全移除成功之後,再次雙擊 ST Toolset.msi 重新執行一次。這次就是新的程式安裝。相信上面的重新安裝之後,就不會再出現相同的錯誤訊息了!
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*

Hello World - 02 (Time2, Interrupt):
Hello World - 01 小節使用暫存器控制 LED,前提是使用者對於這些東西有一定的熟悉度或是了解才會容易上手,一但微控制器的功能很多的時候,那可真是很折騰人的一段過程。所以,ST 提供了 SPL (標準硬體函式庫),是類似 Arduino 開發函式庫,以函式呼叫替代暫存器位元指定的方式,其命名的函式的名稱很容易讓人望文生義。

如下圖,下面範例會用到 GPIO 函式
SPL 輔助說明文件
除了 GPIO 之外,LED 亮滅之間的延遲,在接下來的兩個例子都是使用 Timer 計時中斷來做亮滅的切換;在這個例子是使用 Timer2。

Note: 請自行建立一個新專案,專案名稱與目錄名稱都是 HelloWorld_02

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 程式碼 - Timer2, Interrupt:
helloworld_02 和 helloworld_01 都做著同樣的事:亮滅開發板上的藍色 LED (PORT E, PIN 5)。不過這個例子的延遲時間改為 250 ms,所以每隔 0.5 秒為一個週期,比前一個例子的 LED 速度更快。

程式一起頭必須要宣告 SPL 的標頭檔 stm8s.h

初始化 STM8S 硬體所有的 Clock,接著設定 Internal RC 除頻為 2,降頻為 8MHz,這要給 Timer2 用的。

開發板上的 LED 電路預先已上拉,所以設為 push-pull、初始輸出 LOW、輸出速度最高到 10MHz。

Timer2 初始化,設定 prescale = 8192,每 (8192+1)/8M 秒產生一次計數直到第 244 次產生溢位中斷,跳至 IRQ13 中斷服務函式。

啟動全局中斷,硬體進入無窮迴圈。
helloworld_02, main.c
#include "stm8s.h"

int main(void)
{
  CLK_DeInit();
  CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV2);    / Prescaler = 2, 8 MHz

  GPIO_DeInit( GPIOE );
  GPIO_Init( GPIOE, GPIO_PIN_5,GPIO_MODE_OUT_PP_LOW_FAST );

  TIM2_DeInit();
  // Internal RC = 16MHz, 16MHz/2 = 8MHz, (8192+1)/8M*244 = 0.2498865 second
  TIM2_TimeBaseInit(TIM2_PRESCALER_8192,      // prescale = 8192
                    244);                     // 週期大約 0.5 秒
  TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);      // 致能 overflow 中斷
  TIM2_Cmd(ENABLE);                           // 致能 Timer2 計時器
  
  enableInterrupts();                         // 致能全局中斷
  while(1);
}

//** 下面這個區塊的程式碼不能刪除
#ifdef USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

當每次 Timer 2 終了時會產生一個溢位中斷,程式跳到 IRQ13: Timer 2 update/overflow 中斷服務函式 (ISR) 執行;這些個中斷服務函式全部集中在 stm8s_interrupt_vector.h 檔案裡面。

因為使用到 SPL 的函式,所以在檔案最上頭加入 stm8s.h 標頭檔。

中斷服務程式的原型宣告就是 line 13 - 18,其中函式名稱 ( NonHandledInterrupt ) 是可以自行修改的。line 21 - 29 就是複製 line 13 18 之後修改的中斷服務函式,雖然名稱可以自己取,但是為了望文生義,也因為是給 Timer 2 溢位使用,所以命名為 Timer2_OVF

有了中斷服務函式的宣告與程式碼,只算完成了一半的工作,接下來必須要將其對應到中斷向量表陣列裡面;也就是將 Timer2_OVF 取代原本 line 49 的名稱,這樣才算完成全部的工作。

請將檔案開啟,並對照下面程式碼進行修改
helloworld_02, stm8s_interrupt_vector.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*  BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
 *  Copyright (c) 2007 STMicroelectronics
 */
#include "stm8s.h"

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
  unsigned char interrupt_instruction;
  interrupt_handler_t interrupt_handler;
};

@far @interrupt void NonHandledInterrupt (void)
{
  /* in order to detect unexpected events during development, 
     it is recommended to set a breakpoint on the following instruction
  */
  return;
}

@far @interrupt void Timer2_OVF (void)
{
  /* in order to detect unexpected events during development, 
     it is recommended to set a breakpoint on the following instruction
  */
  GPIO_WriteReverse( GPIOE, GPIO_PIN_5 );              // 反轉 GPIO port E pin 5 的狀態
  TIM2->SR1 = (uint8_t) (~(uint8_t) TIM2_IT_UPDATE);   // 清除中斷旗標
  return;
}

extern void _stext();     /* startup routine */

struct interrupt_vector const _vectab[] = {
  {0x82, (interrupt_handler_t)_stext}, /* reset */
  {0x82, NonHandledInterrupt}, /* trap  */
  {0x82, NonHandledInterrupt}, /* irq0  */
  {0x82, NonHandledInterrupt}, /* irq1  */
  {0x82, NonHandledInterrupt}, /* irq2  */
  {0x82, NonHandledInterrupt}, /* irq3  */
  {0x82, NonHandledInterrupt}, /* irq4  */
  {0x82, NonHandledInterrupt}, /* irq5  */
  {0x82, NonHandledInterrupt}, /* irq6  */
  {0x82, NonHandledInterrupt}, /* irq7  */
  {0x82, NonHandledInterrupt}, /* irq8  */
  {0x82, NonHandledInterrupt}, /* irq9  */
  {0x82, NonHandledInterrupt}, /* irq10 */
  {0x82, NonHandledInterrupt}, /* irq11 */
  {0x82, NonHandledInterrupt}, /* irq12 */
  {0x82, Timer2_OVF}, /* irq13, Timer2 update/overflow */
  {0x82, NonHandledInterrupt}, /* irq14 */
  {0x82, NonHandledInterrupt}, /* irq15 */
  {0x82, NonHandledInterrupt}, /* irq16 */
  {0x82, NonHandledInterrupt}, /* irq17 */
  {0x82, NonHandledInterrupt}, /* irq18 */
  {0x82, NonHandledInterrupt}, /* irq19 */
  {0x82, NonHandledInterrupt}, /* irq20 */
  {0x82, NonHandledInterrupt}, /* irq21 */
  {0x82, NonHandledInterrupt}, /* irq22 */
  {0x82, NonHandledInterrupt}, /* irq23 */
  {0x82, NonHandledInterrupt}, /* irq24 */
  {0x82, NonHandledInterrupt}, /* irq25 */
  {0x82, NonHandledInterrupt}, /* irq26 */
  {0x82, NonHandledInterrupt}, /* irq27 */
  {0x82, NonHandledInterrupt}, /* irq28 */
  {0x82, NonHandledInterrupt}, /* irq29 */
};

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 專案設定:
專案設定的部分在其面 Hello World - 01 小節中的動畫已說明了其中一部分。這一節因為使用到 SPL,所以需要額外的動作:檔案引用、檔案複製;所以請照著步驟做

** (1) 檔案複製
{HelloWorld_02} 路徑下建立一個新資料夾 Libraries,然後複製 SPL 函式庫路徑
{en.stsw-stm8069}\STM8S_StdPeriph_Lib\Libraries\STM8S_StdPeriph_Driver 下 inc 和 src 兩個資料夾到 {HelloWordl_02}\Libraries 目錄下;完成就像這樣
HelloWorld_02 新增 Libraries 目錄與加入 PL 檔案目錄
接著在檔案總管切換目錄到
{en.stsw-stm8069}\STM8S_StdPeriph_Lib\Project\STM8S_StdPeriph_Template,複製 stm8s_conf.h{HelloWorld_02}\Libraries\inc 目錄中;到此就完成全部所需要的手動複製檔案的部分。

**(2) 專案中的函式庫檔案引用
helloworld_02, main.c 程式碼使用到 GPIO、System Clock 和 Timer2,所以我們要將這些函式庫引用到專案中,這樣專案才找的到這些函式庫的標頭檔與程式碼一起編譯。這些引用檔案請參考下圖,並將其加入到對應的資料夾中。
helloworld_02 專案中所需要的函式庫檔案引用
這時若直接按下編譯,編譯會出現錯誤!因為我們下載的是通用於 STM8S/A 的 SPL,但是每一顆晶片支援的硬體週邊都不一樣,因此需要在 stm8s.h 再做細部的指定。
helloworld_02 專案 stm8s.h 位修改時之編譯錯誤輸出訊息

**(3) 修改 stm8s.h
參考下面圖片,取消 line 44 的註解 #define STM8S105,然後重新編譯,可看到專案成功編譯。
stm8s.h 的修改
將編譯後的韌體上傳,就會看到開發板的藍色 LED 以每 0.5 秒亮滅一次的周期變化。

到這邊已經有兩個同一個效果,但使用不同程式碼的專案。現在,若是使用同樣的程式碼、同樣的開發版和同樣的硬體線路,但因為某些原因,不得不改用其他的 Timer 的情況之下,那麼要如何快速產生一個可用的專案 ? 請看,下面第三個範例程式。

Hello World - 03 (Time1, Interrupt):
第三個範例改用 Timer1,基本上跟第二個範例差不多,所以直接用借用的方式來做。

首先,打開檔案總管到專案目錄下,複製 HelloWorld_02 資料夾再直接貼上,修改複製的資料夾名稱為 HelloWorld_03

進入到 HelloWorld_03 目錄,刪除 helloworld_02_Programmer 資料夾和 checkres.spyhelloworld_02.dep 這兩個檔案,最後更名 helloworld_02.stp 為 helloworld_03.stp
HelloWorld_03 檔案刪除與更名
接著使用文字編輯軟體打開剛剛更名後的 helloworld_03.stp,搜尋並取代檔案裏面關於 helloworld_02 的文字為 helloworld_03
取代 HelloWorld_03 資料夾中 helloworld_03.stp 裡的文字
到現在為止,已經解決了檔案移轉的動作。接下來,請照著下面圖片上面的步驟,由點擊滑鼠右鍵開始,將 helloworld_03 將其加入至 STVD 的 Workspace
新增 helloworld_03 至 STVD Workspace
匯入專案至 Workspace 之後,專案依然維持著是 helloworld_02 的設定。標頭檔案的引用中需要移除 stm8s_tim2.hstm8s_tim2.c 並重新引入 stm8s_tim1.h stm8s_tim1.c。如下,為完成 helloworld_03 標頭檔與來源碼的引用
helloworld_03 專案引用標頭檔與來源碼
到此,只剩下程式碼的修改。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* main.c 程式碼修改:
helloworld_03, main.c 程式碼與 helloworld_02, main.c 差不多,主要是修改 Timer2 相關函式為 Timer1,函式幾乎是直接修改 2 為 1,只有 TIM1_TimeBaseInit() TIM2_Tim2BaseInit() 需要較多的引數;請看下面的程式碼 ( LED 改為每秒鐘亮滅一次)
helloworld_03, main.c
#include "stm8s.h"

int main(void)
{
  CLK_DeInit();
  CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV2);  // Prescaler = 2, 8 MHz

  GPIO_DeInit( GPIOE );
  GPIO_Init( GPIOE, GPIO_PIN_5,GPIO_MODE_OUT_PP_LOW_FAST );

  TIM1_DeInit();
  // 16M/2 = 8M, 8M/(0x1F3F+1)=1000Hz,每個計數週期為 1ms
  // LED 每 500 ms 亮或滅一次,所以每 500 次計數一次
  TIM1_TimeBaseInit( 0x1F3F,                // prescaler
                     TIM1_COUNTERMODE_UP,   // count mode
                     0x01F4,                // period
                     0 );                   // repetition counter
  TIM1_ITConfig( TIM1_IT_UPDATE, ENABLE );  // 致能 overflow 中斷
  TIM1_Cmd( ENABLE );                       // 致能 Timer2 計時器

  enableInterrupts();                       // 致能全局中斷
  while(1);
}

//** 下面這個區塊的程式碼不能刪除
#ifdef USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* stm8s_interrupt_vector.h 程式碼修改:
中斷服務程式修改 line 21 為 Timer1_OVF;line 27 修改 TIM1 為 TIM2。
Timer1 overflow 中斷號碼式 IRQ11,所以將 Timer1_OVF 修改至此行,復原 line49 回 NonHandledInterrupt
到這邊全部的修改就已完成。
helloworld_03, stm8s_interrupt_vector.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*  BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
 *  Copyright (c) 2007 STMicroelectronics
 */
#include "stm8s.h"

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
  unsigned char interrupt_instruction;
  interrupt_handler_t interrupt_handler;
};

@far @interrupt void NonHandledInterrupt (void)
{
  /* in order to detect unexpected events during development, 
     it is recommended to set a breakpoint on the following instruction
  */
  return;
}

@far @interrupt void Timer1_OVF (void)
{
  /* in order to detect unexpected events during development, 
     it is recommended to set a breakpoint on the following instruction
  */
  GPIO_WriteReverse( GPIOE, GPIO_PIN_5 );              // 反轉 GPIO port E pin 5 的狀態
  TIM1->SR1 = (uint8_t) (~(uint8_t) TIM1_IT_UPDATE);   // 清除中斷旗標
  return;
}

extern void _stext();     /* startup routine */

struct interrupt_vector const _vectab[] = {
  {0x82, (interrupt_handler_t)_stext}, /* reset */
  {0x82, NonHandledInterrupt}, /* trap  */
  {0x82, NonHandledInterrupt}, /* irq0  */
  {0x82, NonHandledInterrupt}, /* irq1  */
  {0x82, NonHandledInterrupt}, /* irq2  */
  {0x82, NonHandledInterrupt}, /* irq3  */
  {0x82, NonHandledInterrupt}, /* irq4  */
  {0x82, NonHandledInterrupt}, /* irq5  */
  {0x82, NonHandledInterrupt}, /* irq6  */
  {0x82, NonHandledInterrupt}, /* irq7  */
  {0x82, NonHandledInterrupt}, /* irq8  */
  {0x82, NonHandledInterrupt}, /* irq9  */
  {0x82, NonHandledInterrupt}, /* irq10 */
  {0x82, Timer1_OVF},          /* irq11, Timer1 TIM1 update/overflow/underflow/trigger/break */
  {0x82, NonHandledInterrupt}, /* irq12 */
  {0x82, NonHandledInterrupt}, /* irq13, Timer2 update/overflow */
  {0x82, NonHandledInterrupt}, /* irq14 */
  {0x82, NonHandledInterrupt}, /* irq15 */
  {0x82, NonHandledInterrupt}, /* irq16 */
  {0x82, NonHandledInterrupt}, /* irq17 */
  {0x82, NonHandledInterrupt}, /* irq18 */
  {0x82, NonHandledInterrupt}, /* irq19 */
  {0x82, NonHandledInterrupt}, /* irq20 */
  {0x82, NonHandledInterrupt}, /* irq21 */
  {0x82, NonHandledInterrupt}, /* irq22 */
  {0x82, NonHandledInterrupt}, /* irq23 */
  {0x82, NonHandledInterrupt}, /* irq24 */
  {0x82, NonHandledInterrupt}, /* irq25 */
  {0x82, NonHandledInterrupt}, /* irq26 */
  {0x82, NonHandledInterrupt}, /* irq27 */
  {0x82, NonHandledInterrupt}, /* irq28 */
  {0x82, NonHandledInterrupt}, /* irq29 */
};

編譯與上傳之後,就能看到藍色 LED 每秒亮滅一次!

結論:
這篇網頁利用三個簡單的範例程式說明了 STM8S 環境的建置、列出了 STVD 工作空間和專案的建立與複製的步驟、以及使用直接暫存器和 STM8S/A Standard peripheral library 存取硬體週邊和利用計時器與中斷服務函式達到時間延遲的效果;不過這些都只是入門的東西而已,要學習更多或進階的東西,可參考官網上面的資料,或是零件附帶的參考文件。

希望這篇文章對於入門學習 STM8S 有所幫助!

^_^

10 則留言:

  1. 你好,我買了燒錄器與開發板,照著Hello World - 01做一次,在programmer
    會產生這個訊息。而開發板還是一直維持紅燈恆亮,藍燈閃。是哪裡要改進的嗎?

    Device: STM8S105x4
    Board: ST-LINK
    Port: USB
    Programming Mode: SWIM

    Tasks:
    Blank Check (if feasible)
    Program
    Verify

    Nothing to do,
    please, try to select at least one file for at least a memory area
    and/or modify at least one field in the Options.

    回覆刪除
    回覆
    1. 再仔細看看 "STVD - HelloWorld_01 編譯與上傳" 的動畫,應該是少了選擇 Programmer/Memory Area/Memory 需要的檔案

      刪除
  2. 版主大哥,不好意思向您請教一下。我使用的模組是STM8S103F3P6,雖然照您HelloWorld_01的範例能成功燒錄,但是模組的LED卻無法閃爍,請問這是程式腳位沒有正確對上嗎?

    回覆刪除
    回覆
    1. HelloWorld_01 用的是 PORTE, pin5 做 LED 閃爍,改成你板子上面的 PORT 和 PIN 號碼,選擇正確的 MCU 型號編譯後再上傳,應該就可以動作了!

      刪除
    2. 感謝版主大哥,問題已解決,確實是PORT和PIN號碼不同。我昨天也到版主大哥推薦的露天賣場上標一組STM8S105K4T6C來玩玩,謝謝。

      刪除
  3. 你好,我現在就是不知自己的問題在那,無所適從,會寫51/pic(組合語音/因有指令)與書籍参考),這c語就一直卡在這如何下手,比初學者還糟糕,請問有何建議。

    回覆刪除
    回覆
    1. 你好,我相信能寫組合語言的人,學習其他語言會更容易上手,只不過轉換成學習高階語言時,觀念上可能一時不太容易轉過來而已,就像是我學 Python 時也有些東西一開始很難適應,但基本的迴圈、比較和邏輯不管哪種程式語言觀念上都是大同小異的,只需要著重於不同程式語言間的差異性即可。

      別想太多,學習 MCU 的組合語言比學 C 語言難得多了 ^_^

      我這邊的建議是:
      * 不管你是要學 C 語言,或是想用 C 語言撰寫 MCU 韌體程式,都需要了解 C 語言基本的東西(例如變數宣告、陣列、結構、運算子、比較、邏輯、迴圈、判斷式等...語法),至於標頭檔裡所定義的函式或是指標,用到的時候再學就可以。

      * 了解了 C 語言的基本語法後,就可以嘗試用 C 語言撰寫 MCU 韌體程式。市面上有用 C 語言寫單晶片(51)的書,可以去買來看看。若是想學其他的,Arduino 開發板是個不錯的選擇,網路上資源和教學很多,不會怕找不到答案。

      以上建議和想法,希望對你有所幫助!

      刪除
  4. 謝謝!就以此stm8來說,若有類似組語指令,概略就能對項目特性,規劃io配置,功能,,,,查詢適合指令撰寫,而用c寫,就如入萬里雲霧,毫無頭緒,無從下手,也曾試著拿範例學習,例如簡單燈閃爍,若要更改其呈現模式,組語有相關指令查用,c語就完全沒概念,是要怎麼下一步?

    回覆刪除
    回覆
    1. STM8 的官網有提供組合語言和 C 語言相關指令和範例參考程式的資料下載(或是由網路中也可以找到)。有了這些後,自行配合一些教學的網頁或是範例參考程式做自我學習,那邊不懂就補充那邊,慢慢地就會懂,沒有一蹴即成的路徑!

      如果你對 C51 單晶片組合語言熟的話,建議你可以去找本用 C 語言(KeilC)撰寫單晶片程式的書來看,裡面最好要有順便教 C 語言一些簡單語法的內容,依你對單晶片組合語言的熟悉程度會很容易上手和了解的。

      刪除

留言屬名為"Unknown"或"不明"的用戶,大多這樣的留言都會直接被刪除掉,不會得到任何回覆!

發問問題,請描述清楚你(妳)的問題,別人回答前不會想去 "猜" 問題是什麼?

不知道怎麼發問,請看 [公告] 部落格提問須知 - 如何問問題 !