UARTを動かすプ ログラム(その1)

LEDをチカチカ点灯させても、別段おもしろくはありません.
それは、マイコンをスタンドアロンで動かしているからです.
PCとマイコンを通信させて、PCからマイコンを制御する、あるいはマイコンから何らかのリアクションがあってこそ面白みが生じると思います.

そこで、いきなりUARTでPCと通信するプログラムをつくろうと思います.


UARTでPCと通信するとはどういうことか? イメージがわかないかもしれませんので、まず全体ブロック図の説明からします.
PCを操作する人間から見えるのは、terminal ソフトという通信アプリの画面です.
PCとマイコンとはUSBケーブルで接続されます.昔のPCならCOM PORTが付いていたのですが、今時のPCにはCOM PORTは付いてないことが多いので、USB仮想COM PORTというPCのカラクリを利用して往年のCOM PORT接続と同じ環境を作るのです.terminal softは元来COM PORT経由で通信するアプリでありました.
USBケーブルの先っちょには、USBシリアル変換回路がつきます.
そして最後に、マイコンであるSTM8SーDISCOVERYに内蔵されているUARTに信号がたどり着きます.
この通信経路で、いろいろな文字情報(コマンドやデータ)をやりとりするのが、PCからマイコンを制御するということです.


USBシリアル変換回路とSTM8S-DISCOVERYの部分を写真で示すとこうなっています.
右下の黄色の囲いがUSBシリアル変換回路です.秋月電子の製品です.同基板に刺さっているMini-USBがPCのUSB仮想COM PORTと化しています.
中央の水色の囲いがSTM8Sマイコンです.USBシリアル変換回路と配線されています.
左の赤い囲いは、ブロック図には描きませんでしたがSTM8Sを焼くために必須な回路です.同基板に刺さっているUSBケーブルは、STM8Sを焼くため のケーブルです.
緑色の○の意味はあとで説明します.


もちろん、デバッグが済んだプログラムを焼いてしまえば、焼き用のUSBケーブルは不要になるわけで、下図のように外しても使えるわけです.
(上の緑色の○に関連するちょっとしか小細工が必要ですが)
あるいは、ミシン目のところで基板をザクッと切断してしまってもよいわけです.
ちなみに、左端のUSBは、USB仮想COM PORTとしては動作してくれません.


作る物のイメージはわきましたか?

ついでに回路図もここで示します.留意するべきところはUSBシリアル変換基板と STM8S-DISCOVERYの接続だけですので、その部分だけの回路図です.
この回路図を元に製作してください.
●STM8SのPD5とPD6には、UARTの送信信号と受信信号が出てきますので、それをUSBシリア ル基板に配線しています.線を4本配線です.
●電源についての重要な注意点があります. STM8S-DISCOVERYでは、電源は焼き回路(上記赤枠)から5V or 3.3Vが供給されますが、これを切断し、USBシリアル変換基板から3.3Vが供給されるようにするのです.そのために、ジャンパーをつぎのように設定 してください.
  注意1:  USBシリアル変換基板のジャンパーピンは、下図のようにします.
  注意2:  STM8S-DISCOVERYのJP1のジャンパーピンは、外しておきます.



作 る物のハードウエアは上記のとおりですが、ソフトウエアにどんな動作をさせるかを決めます.

まずは、極シンプルな仕様で始めましょう.

PCのTerminalソフトとマイコンの接続を確立してから、マイコンの電源を入れると、Terminalソフト画面に、次の表示が出ます.
This is a converter small words to capital words.
key in any words.

その下に、あなたが、PCの任意の文字を入力します.
ABCDefgh1234

すると、マイコンが、大文字を小文字に、小文字を大文字に変換して、terminalソフト画面に表示してくれます.
ABCDefgh1234 => abcdEFGH1234

たったこれだけの仕様です.


PCはwindows7を使います.
歴代のwindowsにはterminalソフトが組み込まれていました.hyperterminalという名前でした.
しかし、windows7にはhyperterminalが組み込まれていません.
そこで、こちらからdownloadしてインストールしてつかうことをオススメします.TeraTermというフリーソフトです.
http://www.vector.co.jp/soft/win95/net/se320973.html

TeraTermのインストール手順は割愛させていただきます.



STVDのworkspaceを作ってゆきます. workspaceをつくる詳細な手順はLED点滅プログラムで示したので、省略します.

次の設定で作ったworkspaceをこちらに置いておきます.
  フォルダ         STVD\test02
  workspace名      test02
  project名        test02


このプログラム専用のファイルは main.cだけです.以下で はmain.cの詳細な説明をいたします.


●#include "stm8s.h"
STMicro社提供のライブラリを呼び出すには、stm8s.hのinclude一発でOKです.
Raisonance Cコンパイラの場合は、stdio.hとかstdlib.hのようなおなじみのヘッダファイルのincludeは不要です.
printf()とかatof()をいきなり使っても、Raisonance Cコンパイラが自動的にincludeしてくれるので便利です.

●CLK_ClockSwitchConfig ( CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE );
mainルーチンの冒頭で、クロックの設定をします.
この関数もSTMicro社のライブラリ関数です.
引数で留意しておくべきなのは、CLK_SOURCE_HSE のところだけです.
STM8Sのクロックのブロックダイヤグラムは下図のようになっています.
この図から読み取るべきことは、クロックの源発信が4つあることです.
図の上から、
1) OSCINへ入力される、外部クロック     →  引数
CLK_SOURCE_HSE とする
2) OSCINとOSCOUTへ接続される水晶発振子    → 
引数 CLK_SOURCE_HSE とする   (1と2には別のスイッチがある
     STM8S-DISCOVERYには16MHzの水晶発振子が載っています.
3) HSI RC 16MHz と描かれた内部クロックで、後段に1,2,4,8の分周回路があるもの   →  
引数 CLK_SOURCE_HSI とする
4) LSI RC 128kHzと描かれた内部クロック      →  
引数 CLK_SOURCE_HSI とする  (加えて別のスイッチがある
クロックの解説は別のところで詳しくやります.
ここでは、
CLK_SOURCE_HSE として、16MHzの水晶発振子を選択することとします.


●UART2_DeInit();
UART2の初期化をします.

●@// PC setting = 115200bps  8bit  NO-parity   stop=1bit
UART2_Init((u32)115200, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO,  UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);

A// PC setting = 115200bps  7bit  ODD-parity  stop=1bit
//UART2_Init((u32)115200, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_ODD, UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);

B// PC setting = NG
//UART2_Init((u32)115200, UART2_WORDLENGTH_9D, UART2_STOPBITS_1, UART2_PARITY_NO, UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);

C// PC setting = 115200bps  8bit  ODD-parity  stop=1bit
UART2_Init((u32)115200, UART2_WORDLENGTH_9D, UART2_STOPBITS_1, UART2_PARITY_ODD, UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);

4種類のUARTの通信パラメータを記述してあります.こ れらのどれか一つを生かして使います.
(といってもBは動作しないんですが)

ここでは、Cを生かしています.留意するべき引数は次の4つ.
1) (u32)115200          ボーレートを115200bpsに設定しています.9600とかいろいろ選択できます.
2) UART2_WORDLENGTH_9D  1バイトを9bitに設定しています.UART2_WORDLENGTH_8D (8bit)にもできます
3) UART2_STOPBITS_1     ストップbitの長さを1bitに設定しています.UART2_STOPBITS_2 (2bit)にもできます.
4) UART2_PARITY_ODD     奇数パリティに設定しています.UART2_PARITY_NO (パリティなし)UART2_PARITY_EVEN(偶数パリティ)にもできます.

@ABCのそれぞれに対応するPCのterminalソフトの設定がありますのでご注意ください.
これを守らないと正しく通信できません.要点は、
Aのように UART2_WORDLENGTH_8D かつ UART2_PARITY_ODD に設定すると、1バイトが総合8bitだと決めたうえでパリティを1bit追加したのですから、PCが受信するうえでの1バイトは7bitなのだ、という カラクリです.ちょっとわかりにくい仕様ですね.混乱しないように注意しましょう.
ゆえにBが正しく動作しない理由は、パリティ無しで1バイトが総合9bitだと決めたのだが、PCには1バイト=9bitという選択肢はないからだ、とい うわけです.
設定
1バイトのbit数設定
パリティ設定
PCのterminalソフトのbit数
PCのterminalソフトのパリティ
@
UART2_WORDLENGTH_8D UART2_PARITY_NO 8bit
なし
A
UART2_WORDLENGTH_8D UART2_PARITY_ODD 7bit
ODD

UART2_WORDLENGTH_8D UART2_PARITY_EVEN 7bit
EVEN
B
UART2_WORDLENGTH_9D UART2_PARITY_NO 正しく動きません
正しく動きません
C
UART2_WORDLENGTH_9D UART2_PARITY_ODD 8bit
ODD

UART2_WORDLENGTH_9D UART2_PARITY_EVEN 8bit
EVEN

UART2_ITConfig(UART2_IT_RXNE_OR, ENABLE);
UART2_Cmd(ENABLE);
enableInterrupts();
これらは定型のおまじない程度に考えておけばよいでしょう.

●SerialPutString("This is a converter small words to capital words.\r\n");
SerialPutString("key in any words.\r\n");
openingメッセージを表示します.

●while(1)      // Main loop
    {   UART_Menu();   }
UART_Menu()を呼び出す永久ループでmain()を締めくくります.


void SerialPutChar(char c){
    UART2_SendData8(c);
    while ((UART2->SR & UART2_SR_TXE ) != UART2_SR_TXE ); }
STMicro社のライブラリをcallして、1バイトを送信するサブルーチンを形成しています.

●void SerialPutString(char *s){
    while (*s != '\0'){
        SerialPutChar(*s);
        s ++;    } }
文字列を送信するサブルーチンです.よくつかいます.

void UART2RX_isr(void) interrupt 21
{
     中略
        c = UART2_ReceiveData8();

                   中略
        else if(c == '\r'){  // CR
                   中略
                   UART_STR_EXIST=1
        }
        else if(c == '\b'){  // BS
                   中略
        }
        else if(bytes_read >= LENGTH ){
                        中略
        }
        else if(c >= 0x20 && c <= 0x7E){
            command[bytes_read++] = c;
        }
  }
UART受信割り込みルーチンです.重要なところをかいつまんで説明します.

まず、raisonance cコンパイラにおける割り込みルーチンの特徴的な記述方法が冒頭にあります.
   void UART2RX_isr(void) interrupt 21
void XXXX(void) で関数名を決めた後に、この関数がどの割り込みで呼び出されて欲しいかを、interrupt 21 のように決めます.21が割り込み番 号なわけですが、何番 にしたらよいかはSTM8Sのハードウエア(pdf)で決まっています.UART2が文字を受信したら発生する割り込み番号は21なのだ、という ことがこの資料に書かれています.

結果としてSTM8Sは、UART2が文字を受信すると 21番の割り込みに割り当てたUART2RX_isr()を呼び出すように動作します.
UART2RX_isr()の中に、文字処理プログラムが記述されていれば、文字を受信したたびに逐次処理ができるというカラクリが出来上がります.

UART2RX_isr()の内部では、まず、
   c=UART2_ReceiveData8()
で、バッファから1文字だけ取り出します.
次に、
その文字がCRならば
    UART_STR_EXIST=1
にセットして1行受信完了のフラグを立てます.
その文字がBSならば、受信文字列command[]を1文字減らします.
その文字で1行に100文字を超えたら、エラーにします.
その文字がasciiコードで20(スペース)〜7Eの間であったら、受信文字列command[]に1文字追加します.
このようにして、UART2から1行の文字列を抽出します.

UART受信割り込み処理は以上で終わりです.

コマンド解釈のような処理は、UART_Menu()で行います.


●void UART_Menu(void)  {
    if(!UART_STR_EXIST) return;
    SerialPutString(command);
    SerialPutString(" => ");
    for(i=0;i<LENGTH;i++){
        if(command[i]==0) {
            SerialPutString(command);
            SerialPutString("\r\n\n");
            goto RET;
        }
        else if(command[i]>=0x41 && command[i]<=0x5a) { command[i]=command[i]+0x20; } // capital -> small
        else if(command[i]>=0x61 && command[i]<=0x7a) {
command[i]=command[i]-0x20; } // small -> capital
    }
RET:
    SerialPutString("This is a converter small words to capital words.\r\n");
    SerialPutString("key in any words.\r\n");
    UART_STR_EXIST = 0;
    return;
}
UART_Menu()は、UART_STR_EXIST=1 になったら1行分の処理をするルーチンで、main ()の中の永久ループからcallされつづけます.
UART2受信割り込み処理
ルーチン UART2RX_isr()の中で、1行受信したら UART_STR_EXIST=1 にフラグセットされます.
これがUART_Menu()が処理を開始するきっかけです.ゆえにまず、

    if(!UART_STR_EXIST) return;
でフラグがクリア状態なら何もせずにreturnします.
次に、
    SerialPutString(command);
    SerialPutString(" => ");
でterminalソフトに入力文字列のエ コーバックを表示します.
次のfor文でcommand[]を1文字づつなめてゆきます.
command[i]=0だったら文字列末尾なのでcommand[]をterminalに送信してRETにジャンプします.
command[i]=0でなければ、

    command[i]=command[i]+0x20   大文字→小文字変換
   
command[i]=command[i]-0x20   小文字→大文字変換
その文字を小文字大文字変換して sommand[i]に上書きします.
RET:はメッセージをterminalソフトに送信し て、UART_STR_EXISTをクリアして処理終了です.

●#ifdef USE_FULL_ASSERT
void assert_failed(u8* file, u32 line)
{
  while (1)  {  }
}
#endif

このルーチンは、STMicro社のライブラリのVersion2.0.0の、stm8s_conf.hでprototypeが記述されたのを受けてここ に記述しておきます.
おかしな引数を与えたらerrorメッセージを表示するといった使われ方をするルーチンなので、プログラムのデバッグオンリーの機能なので、本質的には不 要なルーチンですが、記述しないでビルドするとエラーが出ます.なので、ここで「なにもしないルーチン」として書いておきましょう.

以上でソースコードの記述はおしまいです.ビルドしてください.


PCとの接続と焼き方を説明します.

PCとは、下図のようにUSBを2系統接続します.片方だけだとダメです.


PCでデバイスマネージャーの「ポート(COMとLPT)」を開きます.
この中でUSB Serial Port (COMxx)に着目します.xxのところを憶えておきます.


PCでTeraTermを起動します.メニューの設定→シリアルポートをクリック.
ポートには、上記で憶えたxxを選択します.
その下には、ソースファイルに記述したUART2の通信パラメータと同じくTeraTermを設定します.


STVPを起動します.メニューからFile→Openで、
    STVD\test02-UART\Debug\test02.hex
を読み込む.
メニューから、program→current tabをクリックすと、STM8Sが焼かれます.
STVPからExitします.ExitしないとSTM8Sが動き出さないので注意.

TeraTermの画面を見ると、
This is a converter small words to capital words.
key in any words.

というメッセージが表示されているはずです.なにかキーボードを叩いてEnterを押すと、その下に小文字大文字変換された結果が表示されます.



一度焼いてしまえば、焼く回路は不要なわけです.焼く回路をミシン目でバキッと折ってしまってもよいわけです.
そんな乱暴なことはしないまでも、下の写真のように、せめて焼くためのUSBケーブルは外したくなるのが人情でしょう.
ところが、単に焼くためのUSBケーブルを外しただけでは、STM8Sにリセットがかかってしまって動かなくなってしまいます.
そこで、下の写真の○の中にあるSB1とSB2をハンダごてでOPENにしてやればリセット線が切断されるので、STM8Sが動きます.
この方法は後でも使うので憶えておきましょう.



release 2011.10

inserted by FC2 system