2016年6月6日 星期一

Published 下午3:43 by with 0 comment

[筆記] C語言中使用單一位元的做法:Bit Field 位元欄位

在嵌入式的設計中,經常有判斷旗標要被使用。
但使用 char 或是 _Bool 這些宣告則太過浪費記憶體,
而C語言中有個方法可以只需要一個位元就可以做。

這個方法稱為 Bit Field ,現在較新的 C 語言書都不太提到,
確定有談到這個方法的書目前只看過 K & R 與 Pointers on C

做 Bit Field 時必須使用 struct
例如:

先寫好
                                                          struct Flag{
unsigned F1 : 1;
unsigned F2 : 1;
unsigned F3 : 1;
unsigned F4 : 1;
unsigned F5 : 1;
unsigned F6 : 1;
unsigned F7 : 1;
unsigned F8 : 1;
                                                                      };
最尾數的1代表使用一個bit。
然後要使用時則宣告

struct Flag flagexample;

那麼這個叫做flagexample的變數在記憶體內的實況則會是

如此設定和宣告過後,就可以這樣用:
flagexample.F2 = 1;
flagexample.F6 = 0;

並且可以應用在判斷是,例如:
if ( flagexample.F6 == 1 ) {.........}

如果與 union 聯合  混合使用。例如:
                                                         union{
                                                                unsigned char AllMsg;
                                                                struct {
              unsigned bit0:1 ;
              unsigned bit1:1 ;
              unsigned bit2:1 ;
              unsigned bit3:1 ;
              unsigned bit4:1 ;
              unsigned bit5:1 ;
              unsigned bit6:1 ;
              unsigned bit7:1 ;
                                                                           };
                                                                   } Message;

這段程式代表直接宣告一個變數叫做 Message,程式操作時

Message.AllMsg = 0x80;

可等同於

Message.bit7 = 1; Message.bit6 = 0; Message.bit5 = 0; Message.bit4 = 0;
Message.bit3 = 0; Message.bit2 = 0; Message.bit1 = 0; Message.bit0 = 0;

--------------------------------------------------------------------------------------

在 MSP430 操作的情況下,使用 Bit Field 直接操作硬體位元,為了不要再多定義記憶體來搬運所以操作略有點不同。例如:

                                                          struct SFRbitDef{
unsigned B0 : 1;
unsigned B1 : 1;
unsigned B2 : 1;
unsigned B3 : 1;
unsigned B4 : 1;
unsigned B5 : 1;
unsigned B6 : 1;
unsigned B7 : 1;
                                                                      };

先建好結構後,將結構指向實際配合硬體的位址:

#define P2input  ((struct SFRbitDef *) 0x28 );
#define P1output  ((struct SFRbitDef *) 0x21 );

後面的 0x28 和 0x21 分別是搭配硬體用的記憶體位址。

於是存取的時候,以這樣寫成:

if ( (P2input->B1) == 0 )  {  P1output->B4 = 1; }
// 此段程式是讀取 P2 的 B1接腳,若該接腳電位為零則將 P1 的 B4 接腳輸出為 1 。

同樣的也可以這樣應用:
P1output->B4 =  ~(P1output->B4);
// 直接簡單的將該位元反向


Read More
      edit

2016年6月5日 星期日

Published 下午2:56 by with 0 comment

[基礎] Mspdebug 與 Msp430

較早的文章已經談過Msp430使用開源軟體的開發方法了。
但當時沒有提到程式能夠單步執行的作法,
這一次要談的是如何控制msp430的程式單步執行,
也就是 Mspdebug。

Mspdebug 也是個開源的自由軟體,是專門針對msp430製作的,
可以支援各種不同的ICE運轉。

原作者的網站在此:  http://dlbeer.co.nz/mspdebug/

原作者的網站在這段談到了怎麼在windows底下自己建立這套軟體。
根據操作說明,必須要下載安裝下列軟體:

1. 
Download MinGW installer
Install to C:\mingw - install the 'C Compiler', 'MSYS Basic System' and 'MinGW Developer Toolkit'.

下載 MinGW,這是用來把原始碼編成可執行檔的compiler
在安裝的時候必須安裝這些項目:


千萬不能使用CodeBlocks內附的MinGW,基於一些不明的原因,雖然可以編譯成功但執行起來會是錯誤不斷的。

2.
Download regex-2.7-bin.zip
Open the archive - extract the files from the lib directory to c:\mingw\lib, extract files from include directory to c:\mingw\include.

下載 regex-2.7-bin.zip ,解壓縮後,把lib目錄下的東西拷貝到 MinGw 下的 lib 目錄,而 include 內的東西也拷貝到MinGw下的 include 目錄。

3.
Download libusb-win32
Extract lusb0_usb.h to c:\mingw\include, rename to usb.h
Extract lib/gcc/libusb.a to c:\mingw\lib

下載 libusb-win32 ,解壓縮後把 lusb0_usb.h 拷貝到MinGw下的 include 目錄,並且變更檔案名稱為 usb.h。 把解壓所後的 lib/gcc/  目錄下的libusb.a拷貝到 MinGw下的 lib 目錄。

4.
Download readline-5.0-1-bin.zip
Extract the readline directory from include to c:\mingw\include\readline\
Extract the files from the lib subdirectory to c:\mingw\lib

下載 readline-5.0-1-bin.zip,解壓縮後把readline目錄拷貝到MinGw下的 include 目錄,把lib目錄下的東西拷貝到MinGw下的 lib 目錄。

5.
Download the MSPDebug source code, open a command window, change directory to the MSPDebug sourcecode.

下載mspdebug的原始碼,解壓縮擺放。
修改一下目錄下的makefile,把問號消除

打開命令提示字元視窗,切換到mspdebug解壓縮好的目錄下。


切換進去後,打字輸入
set path=c:\mingw\bin;c:\MinGW\msys\1.0\bin\
make
就會建立出一個叫做 mspdebug 的執行檔。

最後,從剛剛下載解壓縮的檔案中,把 regex2.dll、readline5.dll 拷貝進 mspdebug 的目錄下,
以及根據 libusb 的安裝指引--libusb-win32-bin-README 把 libusb0.dll 安裝進系統。

這樣 mspdebug 就可以執行了。但如果要運作在 Launchpad,還需要安裝一個驅動程式:
在 libusb-win32 目錄的bin底下,有個執行檔 inf-wizard ,USB線連接好Launchpad 執行 inf-wizard之後按下一步,則會出現:
其中兩個 Vendor ID 是 0x0451 的就是 Launchpad  ,有一個是UART介面被佔用了,所以點選另一個 (Interface 1) 產生驅動程式。

這個驅動程式安裝之後,mspdebug 才能連到板子。如果系統是win10,則必須參考強制停止數位簽章的安裝法。

在命令列視窗下,執行 mspdebug rf2500 則會出現:

這樣就代表連線成功了。

接下來先鍵入exit,然後啟動CodeBlocks來改設定讓單步執行可以操作。

在Tools設定裡,添加一個啟動 mspdebug 並且燒錄程式檔的功能:

然後在 debugger設定 裡添加 msp430-elf-gdb 的啟動設定:

開啟上一次用過的LED閃爍專案,在 Properties 設定中增加遠端連線設定
跟OpenOCD的情況不同,這裡的 Additional GDB commands 不需要加任何指令。

在專案設定裡,編譯的項目要添加 -g 以產生除錯用的標誌

編譯成功的話會出現
而加了 -g 之後編譯出的組合語言碼則會是這樣
這樣才能夠讓除錯器自動計算斷點產生的位置。

都完成之後,啟動 tools 下的 mspdebug:
這樣就是 mspdebug 正在等待 GDB 的連線。而連線用的 port 是 2000。

在CodeBlocks的Debug功能中,記得Active debuggers點選你所屬的 msp430 gdb 。
按下Star 後,就可以像之前操作STM32一樣操作斷點的設定。

而斷點操作的時候,mspdebug 的文字視窗也會出現對應的活動
以上完成了msp430的單步執行操作。

必須注意的是,在我的實驗中,舊版的mspgcc (4.6.3)對於和mspdebug的連線,不知道為什麼會出現中斷,這方面是變更為新版 (5.3.0.219) 後才得到解決。

而新版必須要多做的事情包括中斷設定有變,然後編譯完會添加一些啟動碼,必須在link的時候使用 -minrt 這個操作來消除。









Read More
      edit

2016年6月4日 星期六

Published 下午4:46 by with 1 comment

[基礎] MSP430 與開源軟體

這次的實驗晶片對象是msp430。
mps430 是 TI 所出的MCU,性能優異而且長年霸佔省電應用的市場。
近幾年來價格也大幅度下殺。

直接從TI網站擷取的價格(2016年),大抵上低於一美元

本次實驗的硬體則是LaunchPad,除了主晶片是msp430g2553之外還附帶燒錄器

網拍購得,大約四五百元。

Compiler 則是使用 mspgcc
IDE 使用 CodeBlocks 

燒錄器可以使用 MSP430Flasher
(下載來的壓縮包名稱應該會是slac435f.zip包括板子的驅動程式)

或是 mspdebug (僅有原始碼,須根據不同機器自己compiler,這東西日後另外開文章再談)

接下來吧 mspgcc 解壓縮放到  C:\HighTec\Msp430
把 MSP430Flasher 放到 C:\HighTec\MSP430Flasher

啟動 Code Blocks 建立空白新專案




Compiler 記得選擇 MSP430專用的,然後compiler後的obj檔就放進目錄obj,最後的輸出放在目錄bin


Compiler 設定要改一點東西,從Code Blocks 的 Settings >> Compiler...  進入
在 Selected compiler 選擇 GNU GCC Compiler for MSP430 ,
接著看下面的 Toolchain executables 設定是否有確實鏈結

專案設定這樣做點改變,從Code Blocks 的 Project >> Properties 進入設定。
點選標籤 Build targets ,使得 compiler 編完之後是elf檔。

從Code Blocks 的 Project >> Build options 進入設定。
點選標籤 Search directories 接著點下面的子標籤 Linker,
按下Add新增目錄把 Loader Script 的指定放進來。

同樣在Code Blocks 的 Project >> Build options 進入設定。
點選標籤 Pre/post build steps ,在Post-build steps 添加點指令,
讓編譯與鏈結完成後,將elf檔編為hex檔準備燒錄。
在這裡添加的指令是
C:\HighTec\Msp430\bin\msp430-objcopy -O ihex ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.elf  ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.hex
cmd /c "C:\HighTec\Msp430\bin\msp430-objdump -S ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.elf > ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.asm"
C:\HighTec\Msp430\bin\msp430-size  ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.elf
分別是將elf編為hex檔做燒錄使用、將elf檔編為組合語言asm檔以利除錯,
以及顯示elf檔內部的實際資料量。
其中 ${} 代表的是Code Blocks的巨集指令,這樣使用後就會自動找到專案對應的目錄和檔案名稱。

最後的設定是燒錄器,從Code Blcoks 的 Tools >> Configure tools.. 進入設定
進入後使用Add添加燒錄器用的操作。

Excutable 項目內設定的是燒錄軟體的所在,Parameters 則是對應的參數。
這裡所使用的參數為
-n msp4302553 -w ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.hex -v -g -z [VCC]
一樣有巨集描述,讓Code Blocks自動指定好目標檔案。

在新專案之後,並且完成前面的設定,新增一個叫做 main.c 的檔案並且加入專案中


 寫個閃爍 LED 的程式
文字編輯視窗是黑底的,因為我做了點不同的設定讓眼睛舒適,詳見 Code Blocks Theme
在此LED的閃爍程式是:
#define TIMERA0_VECTOR TIMER0_A0_VECTOR
#define TIMERA1_VECTOR TIMER0_A1_VECTOR
#endif

#include "msp430g2553.h"

#define P1output ((struct SFRbitDef *) 0x21)
#define P1input  ((struct SFRbitDef *) 0x20)
#define LED1     (P1input->B0)
#define LED2     (P1input->B6)
struct SFRbitDef {
    unsigned B0 :1;
    unsigned B1 :1;
    unsigned B2 :1;
    unsigned B3 :1;
    unsigned B4 :1;
    unsigned B5 :1;
    unsigned B6 :1;
    unsigned B7 :1;
};

unsigned int time10ms;

// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
  time10ms++;

}

int main()
{
    WDTCTL = WDTPW | WDTHOLD ;
    BCSCTL1=CALBC1_1MHZ;
    DCOCTL =CALDCO_1MHZ;

    time10ms=0;
    P1DIR = BIT0 | BIT6 ;         // P1.0 = LED1, P1.6 = LED2
    P1output->B0=1;P1output->B6=0;

    /*
     * SMCLK = 1MHz, 10mS = 10^(-2) Sec
     * CCR0 = (10^(-2)) * (1* (10 ^ 6)) / 4 =  2500
     */
    TACTL = TASSEL_2 + MC_1 + ID_2;           // SMCLK/4, upmode
    CCR0 =  2500;
    CCTL0 = CCIE;                             // CCR0 interrupt enabled

    _EINT();                                  // Enable interrupt
    while(1)
    {
        if(time10ms>50)
        {
            P1output->B0=~(P1output->B0);
            P1output->B6=~(P1output->B6);  // 看不懂為什麼這樣能夠操作的,詳見這邊
            time10ms = time10ms-50;
        }

    }
    return 0;
}


完成後存檔。
按下 Build 功能鍵,將整個專案編譯好
Build log 視窗則會出現

把訊息拿出來看則是
-------------- Clean: Debug in LED (compiler: GNU GCC Compiler for MSP430)---------------

Cleaned "LED - Debug"

-------------- Build: Debug in LED (compiler: GNU GCC Compiler for MSP430)---------------

msp430-gcc.exe     -IC:\HighTec\Msp430\msp430\include -c main.c -o obj\main.o
msp430-gcc.exe -LC:\HighTec\Msp430\msp430\lib\ldscripts\msp430g2553 -o bin\LED.elf obj\main.o   
Output file is bin\LED.elf with size 6.24 KB
Running project post-build steps
C:\HighTec\Msp430\bin\msp430-objcopy -O ihex bin\LED.elf  bin\LED.hex
cmd /c "C:\HighTec\Msp430\bin\msp430-objdump -S bin\LED.elf > bin\LED.asm"
C:\HighTec\Msp430\bin\msp430-size  bin\LED.elf
   text   data    bss    dec    hex filename
    326      0      4    330    14a bin\LED.elf
Process terminated with status 0 (0 minute(s), 4 second(s))
0 error(s), 0 warning(s) (0 minute(s), 4 second(s))

一切都很順暢地完成了編譯,組合語言碼也順利產生,整個程式的容量是330行指令。
點個LED也能寫出這麼多程式,其實是沒有使用最佳化功能的關係。

組合語言的asm檔,則可以用另外的編輯器打開來看,幫助除錯。
LED.asm 檔案內容,使用Notepad++ 檢視

最後就是燒錄的動作了,
點選 Code Blocks 的 Tools >> MSP430Flasher 就會出現DOS的文字視窗運作燒錄軟體。
在win10下不明原因有時會失敗,多執行幾次燒錄就會成功。在XP和Win7則沒有這種現象。


於是燒錄完成。可以看到LED隨著每秒變化閃動。

Read More
      edit

2016年6月3日 星期五

Published 下午3:47 by with 0 comment

[基礎] Windows程式與開源軟體

本次的實驗是寫個windows的GUI程式。
傳統上認為windows視窗程式只能由Visual C來寫,但其實自由軟體也是能做的。

一樣使用CodeBlocks,但必須增加 compiler 稱作 mingw 的,
這是個支援windows程式開發的compiler。

 不過現在的 CodeBlocks 在下載頁面 已經增加了包裹mingw的版本。

下載附有mingw的安裝後即可直接使用
另外,為了能夠輕鬆的做視窗環境設計,打字描述視窗大小之類的事情太累了,
我們使用Resource Edit 資源編輯器,在資源編輯器將視窗畫好之後,
會自動產生 rc 檔 和 resource.h 供呼叫使用。



本實驗室最開始安裝就是這個版本。
所以一樣先建立個空白專案,我們不選擇內建的 Win32 GUI Project 樣式,因為那是C++的。

建立新專案和之前msp430的模式一樣,但是compiler選擇 GNU GCC Compiler

然後建立個 main.c 檔。

這個 main.c 檔用是 dailog 視窗法,這樣曾能夠輕易地從資源編輯器做設計。
檔案內容為:
#include "resource.h"
#include <windows.h>


HINSTANCE hInst;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR lpCmdLine,
                   int iCmdShow)
{
     MSG  msg;
     HWND hwnd;
     hInst = hInstance;

     hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, WndProc) ;

     ShowWindow (hwnd, iCmdShow);
     //UpdateWindow(hwnd);

     while (GetMessage(&msg, NULL, 0, 0))
     {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
     return msg.wParam;
}

LRESULT CALLBACK WndProc (HWND hwnd,
                          UINT message,
                          WPARAM wParam,
                          LPARAM lParam)
{
     switch (message)
     {
     case WM_CLOSE:
         DestroyWindow(hwnd);
         return TRUE;
         break;
     case WM_DESTROY:
         PostQuitMessage(0);
         return TRUE;
     };

     return FALSE;
}
所有windows程式的幾乎都差不多是這個形式,
至於這個程式為什麼是長這個樣子,
可以去問問微軟或者是參考書本 Programming Windows第五版
或者看看 theForger's Win32 API Programming Tutorial
學習windows的程式方法。

就像做msp430的開發時一樣,專案設定裡,
CodeBlocks 的設定 Project >> Properties >> Build Targets 要修改點設定

Types 要改為 GUI application 

接者使用 ResEdit 編一個視窗
設定編好的資源叫做rc檔,並且儲存在你程式的目錄下。

隨便開個Dialog視窗

按下儲存後,資源編輯器會產生兩個檔案,resource.h 檔內容是

#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif

#define IDD_DIALOG1                             100


和 Dialog.rc 檔,內容是

// Generated by ResEdit 1.6.6
// Copyright (C) 2006-2015
// http://www.resedit.net

#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"
//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG1 DIALOG 0, 0, 186, 95
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "Ms Shell Dlg"
{
    PUSHBUTTON      "Cancel", IDCANCEL, 129, 24, 50, 14, 0, WS_EX_LEFT
    DEFPUSHBUTTON   "OK", IDOK, 129, 7, 50, 14, 0, WS_EX_LEFT
}

其中  resource.h 內描述了這個dialog視窗的代號,寫著100。
而 Dialog.rc 內描述了視窗的大小、位置、使用字形,有什麼按紐之類的,
當然如果寫程式的人很厲害要人工撰寫這些內容也不是不行...

注意,要呼叫視窗成功,在main.c的程式中
hwnd = CreateDialog(hInstance, MAKEINTRESOURCE( IDD_DIALOG1 ), 0, WndProc) ;
紅字中的 IDD_DIALOG1 和 resource.h 檔內描述的必須一致。

將這兩個檔案加入專案中,按下Build就可以建立執行檔了。

執行後的結果:


由於在main.c中的CALLBACK WndProc 並沒有處理那兩個按鈕訊息,
所以按下也不會有任何反應的,有需要添加按鈕的功能則必須再寫上。

更詳細的windows程式寫作資訊請參考
書本 Programming Windows第五版
網站  theForger's Win32 API Programming Tutorial





Read More
      edit
Published 下午2:51 by with 2 comments

[基礎] STM8 的基本系統

為了要能夠利用單晶片做各種事情,
必須準備一個基本的系統來調控各種功能。

絕大部分的控制,都跟時間有關,
所以接下來要講的是一個根據時間運作來操作的系統。

並且要把UART的連線做起來,
使得PC或者另一端能夠藉此下指令或是讀取晶片內部資料之類的。

基本的硬體如圖連接。



如上圖所示,為了方便所以將 STM8發展板放在麵包板上。
接線也只是使用 UART的端口接往 CP2102。

CP2102 是一顆UART轉 USB的晶片,安裝後在PC端機將會出現個RS-232介面。
我們使用 Terminal  這個軟體讀取資訊。

按照之前的教學建立一個新的STM8專案。


寫出的程式碼如下:

main.c
#include <stdint.h> #include <stdio.h> #include "STM8S.h" #include "misc.h" struct BitFlag SysFlag; unsigned char time10ms,RXTimer; unsigned char RXIndex; unsigned char RXBuf[20]; void UART2Recive(void) __interrupt 21 { RXBuf[RXIndex++] = UART2->DR; RXTimer=0; __asm__("bres 0x5240,#5\n"); //clear UART2->SR->RXNE } void Tim4Int(void) __interrupt 23 { TIM4->SR1=0; time10ms++; if(RXIndex>0){RXTimer++;} } void main(void) { SystemInit(); UartInit(); SysFlag.RXDone = 0; RXIndex=0; time10ms=0; RXTimer=0; GPIOE->ODR&=~(0x20); enableInterrupts(); while(1) { if(time10ms>50) { __asm__("bcpl 0x5014,#5\n");//GPIOE->ODR = GPIOE->ODR ^ 0x20; time10ms=time10ms-50; } if(RXTimer>10) { unsigned char i; printf("%d",RXIndex); for(i=0;i<RXIndex;i++) { putchar(RXBuf[i]); } RXIndex=0; RXTimer=0; SysFlag.RXDone=1; } if(SysFlag.RXDone) { SysFlag.RXDone=0; } } }

在main.c之中,建立了兩個中斷,分別是UART與Timer4。

晶片的震盪頻率是 2MHz,而 Timer 4 根據取得的系統頻率去除頻
產生每次中斷時間為 10.04mS。
這段程式被寫在副程式 SystemInit() 並且放在misc.c內。

UartInit()副程式啟動了 UART,同樣放在misc.c內。

time10ms 則是被作用於時間的計數值,每經過10ms就會被加一。
在下面的永久回圈內,可以利用每計時到 500ms 也就是 0.5 秒的時候,
將LED的腳位信號反轉。

RXTimer則是UART接收的計數值,在UART接收資料停止後開始計時,
計時滿100ms時代表已經接收完畢,進行接收資料後的處理。
之後對於接收指令後的解碼與相對應的處理程式可以放在這。
此處的範例是接收後回傳收到的字元數以及字元內容。

SysFlag 是一組旗標組合成的資料區,目前暫時沒有使用。

misc.c
#include "stm8s.h" #include "misc.h" extern struct BitFlag SysFlag; void SystemInit(void) { CLK->CKDIVR = CLK_CKDIVR_RESET_VALUE; // Set the frequency to 2 MHz GPIOE->DDR = 0x20; GPIOE->CR1 = 0x20; /* Configure timer fmaster = 2 MHz, Tim4 clk time = 1/(2M/(2^7)) =1/15.625KHz=64uS one interrupt time is 64us * 157 = 10.048mS */ TIM4->CR1 = TIM4_CR1_CEN; TIM4->PSCR = 0x07; TIM4->EGR = 0x01; TIM4->ARR = 157; TIM4->IER = 0x01; } void UartInit(void) { /* UART2 Baud rate =9600, BR register = 2M / 9600 = 208.3 = 0xD1 */ UART2->SR &=0xBF; UART2->BRR1 =0x0D;UART2->BRR2=0x01; UART2->CR1 = 0x00; UART2->CR2 = UART2_CR2_RIEN | UART2_CR2_TEN|UART2_CR2_REN; UART2->CR3 = 0x00; } void putchar(char c) { while(((UART2->SR)&0x80) != 0x80); UART2->DR=c; }

在misc.c內除了基本的系統初始化與UART初始化之外,
還放了一個副程式 putchar。

這個副程式的目的是要讓sdcc的printf函式能夠被使用。
當然使用這個副程式後整個程式碼大爆增了 2Kbyte,
通常會在整個製作完成後移除printf這個功能,儘量使用puts就好。


misc.h
#ifndef _MISC_H #define _MISC_H void SystemInit(void); void UartInit(void); void putchar(char); struct BitFlag{ unsigned x1 :1; // UART received OK unsigned RXDone :1; unsigned x2 :1; // Go to boot loader unsigned x3 :1; // unsigned x4 :1; unsigned x5 :1; unsigned x6 :1; unsigned x7 :1; }; #endif // misc_H

最後是 misc.h 。這裡利用 struct 建立一個 bit field。
準備做系統旗標使用。
不過sdcc在轉譯這方面的程式,並不像mspgcc那樣會轉譯為針對單一位元運作的指令。
轉譯結果,相當占code空間
之後得考慮這段插入組合語言直接操作的手法了。

完成這些程式並且燒錄後,可以運用PC端來跟晶片通訊:
如這個Terminal軟體所呈現的,發送了7個字元後,回傳了開頭字為7,其他為送出的字碼。

並且LED燈呈現每0.5秒就變化一次,方便確認是否出現當機。

所有程式碼均已放上GitHub


Read More
      edit

2016年6月2日 星期四

Published 下午3:16 by with 0 comment

[基礎] STM8 與開源軟體


這塊小板子叫做 STM8S105K4T6C 最小核心板,
露天拍賣售價 145 元。

然後這顆IC差不多系列的 STM8S105K4T6C
露天拍賣售價 30 元。



這兩款的差別就只是程式記憶體(Flash)大小
原廠分類圖

這顆單晶片的參數看一看,大抵上該有的介面也都有,

Key Features
  • Core
    • 16 MHz advanced STM8 core with Harvard architecture and 3-stage pipeline
    • Extended instruction set
  • Memories
    • Program memory: up to 32 Kbyte Flash; data retention 20 years at 55 °C after 10 kcycle
    • Data memory: up to 1 Kbyte true data EEPROM; endurance 300 kcycle
    • RAM: up to 2 Kbyte
  • Clock, reset and supply management
    • 2.95 to 5.5 V operating voltage
    • Flexible clock control, 4 master clock sourcesLow power crystal resonator oscillatorExternal clock inputInternal, user-trimmable 16 MHz RCInternal low-power 128 kHz RC
    • Clock security system with clock monitor
    • Power management:Low-power modes (wait, active-halt, halt)Switch-off peripheral clocks individually
    • Permanently active, low-consumption power-on and power-down reset
  • Interrupt management
    • Nested interrupt controller with 32 interrupts
    • Up to 37 external interrupts on 6 vectors
  • Timers
    • Advanced control timer: 16-bit, 4 CAPCOM channels, 3 complementary outputs, dead-time insertion and flexible synchronization
    • 2x16-bit general purpose timer, with 2+3 CAPCOM channels (IC, OC or PWM)
    • 8-bit basic timer with 8-bit prescaler
    • Auto wake-up timer
    • Window watchdog and independent watchdog timers
  • Communication interfaces
    • UART with clock output for synchronous operation, SmartCard, IrDA, LIN master mode
    • SPI interface up to 8 Mbit/s
    • I2C interface up to 400 kbit/s
  • Analog to digital converter (ADC)
    • 10-bit, ±1 LSB ADC with up to 10 multiplexed channels, scan mode and analog watchdog
  • I/Os
    • Up to 38 I/Os on a 48-pin package including 16 high sink outputs
    • Highly robust I/O design, immune against current injection
  • Unique ID
    • 96-bit unique key for each device

所以似乎蠻適合拿來當產品設計的核心使用。
同樣這種功能包一堆的MCU來說,幾乎沒有更便宜的了。

使用Open Source的Complier SDCC 和 CodeBlocks 編輯器來嘗試寫程式。

根據
http://blog.podstuff.de/setup-codeblocks-for-stm8s-discovery/
這個網制進行STM8的函式庫編成
不過他裡面寫錯了測定,新增CPU的設定應該是 -mstm8 而不是 -stm8
於是可以編出 STM8S_lib.lib 之後被其他程式引用。


再來根據
http://blog.podstuff.de/stm8s-discovery-first-program/
這樣寫個程式

於是可以得到成果
Read More
      edit

2016年6月1日 星期三

Published 下午4:34 by with 0 comment

[基礎] 8051與開源軟體

8051是一款老式的控制晶片,因為優異的設計使得從1981年推出至今仍沒被淘汰,
也連帶的產生了許多衍生系列,而Intel目前已經沒再生產。

雖說主角是8051,不過現在純正的8051已經不那麼好用,
而且純正的大概也很難買到,大多使用相容型的衍伸系列。
衍伸系列通常具有記憶體大、容易燒錄等等優點,一顆晶片即可解決問題,
不再需要那麼多外部記憶體或是IC。

本次的主角是 STC12C5A60S2
這塊叫做最小核心板,已經附上燒錄後自動重新啟動和USB轉UART的IC。
接腳也都拉出方便使用,把這片核心板插在麵包板上方便等一下和LED連接。

Compiler 一樣是 SDCC,而 IDE 一樣是 CodeBlocks

兩者都安裝好後,啟動CodeBlocks並開啟新專案。

(第一次安裝SDCC和CodeBlokcs時,必須從 Settings >> Compilers 進入
 選擇Compiler 為SDCC,到標籤 Other settings 點選 Advanced Options ,
 進入後選擇 Others 標籤,將 Object file extension 的檔案名稱設定變更為rel
 可以詳見此blog )


建立新專案從 File >> New >> Projects... 開始

可以注意到有個叫做 MCS51 Projects ,Code Blocks 已經預備好了,所以使用它

這畫面使問要不要省略接下來的設定,我們要自己設定所以不要勾選,
按下 Next 進入下一步。

一樣訂好專案名稱,並且設定好目錄

Compiler 選項會自動放在SDCC所以不必更動。
其他的是我個人這樣設定顯得會比較簡單易用。之後燒錄用的檔案會在bin目錄下。

在51系列下記憶體有幾種不同的模式,如果是老8051就只能選Small,8052則能使用medium。
而我們這次選擇的STC12有著相當大的記憶體,要完全利用得選擇large model。

選完memory model後,因為STC12C5A60S2具有60K的Flash、256的RAM和1024的Extend Ram。
所以底下的CODE Size設定為 60K、IDATA 為256、XDATA 為 1024。
為了要燒錄所以選擇Intel hex檔案。最後按下Finsih。

專案設定完成後,會發現專案已經自動開好檔案了。

自動開好main.c

然後確認一下之前使用不同mcu時要改寫的一些設定:



原則上都已經自動設定好了不必修改。


在這個 main.c 裡我們添加自己的程式。


程式碼如下:

/* */ #include <mcs51/8051.h> #include <mcs51/stc12.h> void Delay (unsigned int time) { while (--time); } void main(void) { // Insert code P0_0=1; while(1) { P0_0=!P0_0; Delay(50000); } }


輸入完畢後按下存檔,然後按下 build 按鈕

接著看一下Build log 訊息

如果訊息是這樣並且沒有別的錯誤代表成功。
接下來可以啟動燒錄軟體  STC ISP下载软件 (v6.28)



燒錄成功後即可以看見閃燈的成果。



Read More
      edit