2016年6月3日 星期五

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


      edit

2 則留言:

  1. 前輩 可以跟您請教一下 目前您還有在使用 STM8S 系列的MCU做開發嗎?
    目前有建議什麼 IDE與toolchain嗎?

    感謝您的無私分享~

    回覆刪除
    回覆
    1. 可以用IAR 或者 COSMIC 這兩套軟體來開發, IAR 須用付費軟體,COSMIC 免費https://www.cosmic-software.com/download.php

      刪除