トップページ > dsPIC入門 > 知っておきたいテクニック

小ワザいろいろ

はじめに

ここではシリアル通信の最低限の方法が分かった上で、実用的なプログラムへつなげるためのいくつかのテクニック (…というほど大げさなものではありませんが)を紹介します。 dsPICから送られた文字をハイパーターミナル上で見やすくなるように改行させたり、 dsPICが受信した文字列をもとに条件分岐などをしたい時に必要な知識を扱います。 各事例ごとに短いソースコードを書いて、実際に動作させた場合どうなるのか…という様子を示す ようにしました。

改行コード : \n\r

ハイパーターミナルへ「改行コード」を送ると次の段落へカーソルが移ります。 また、ハイパーターミナルにおいてEnterキーを押した場合には改行コードが 送信されているようです。 単にハイパーターミナルで文字列を見やすくするために改行コードを送ってみたり、 Enterキー検出を行うするためにこの\n\rを条件文に取り入れたり…と。 シリアル通信である程度楽しいことをやるならば必ず使用することになると思います。

注意しておきたいのは、基本的に日本語用のエディタではバックスラッシュが表示されず、「\」記号 が表示されてしまうことです。MPLABのエディタでは、ちゃんとバックスラッシュ(/が逆になったやつ) のキー(「ろ」のキーです)を押すとバックスラッシュが表示されますが、 日本語エディタでは¥記号になってしまいます。 ただし、エディタにおいてどのように表示されていようと、バイナリデータとしては同じ文字コード になっていますからコンパイルの際には気にする必要はありません。

\nと\r

とりあえず、ゴチャゴチャ言うよりもソースコードを見た方が分かりやすいと思います。 以下の処理はメイン関数内に書かれているものと思ってください…

 //==================================================================
 //UART初期設定
 //速度は115kbpsとします(80MHzクロックでは実用的に最も速い設定)
 
 OpenUART1(config1,config2,10);

 //==================================================================
 //改行の実験

 putsUART1("あいうえお");
 while(BusyUART1());

 WriteUART1('\n');
 while(BusyUART1());

 WriteUART1('\r');
 while(BusyUART1());

 putsUART1("かきくけこ");
 while(BusyUART1());

これを前回までのメイン関数等にコピー&ペーストしてコンパイル、ハイパーターミナルを起動して dsPICを走らせると…実行画面は以下のとおりになります。

「\n」とか「\r」というのは一見2文字分のデータに見えますが、 ¥記号が付くとエスケープシーケンス(だっけ?)扱いになるので¥記号+1文字で、まとめて1文字扱いと なります。だからシングルコーテーションでくくってWriteUART1()関数で送信できることになります。 また、‘\n’というのは「次の行へ移る」という意味(new lineの略?)で、 ‘\r’は「カーソルを左端へよせる」という意味(returnの略?)のコードです。 我々が普段考える「改行」の動作はこの2つを同時にやっていますが、プログラムで記述する際は1つ1つの エスケープシーケンスに分かれていますから、2つの動作を記述する必要があります。 もちろん“putsUART1("\n\r");”としても同じことです。分かりやすくするために、上のソースコード のように分けて書いてみました。また、\nだけをコメントアウトしたり、\rだけをコメントアウトして どのような動作になるか確認してみるとよく分かります。


いちいち改行用のコードを記述するのが面倒な場合は、以下のように改行用の関数を作ってしまうと便利です。


 void newline(void)
 {
  putsUART1("\n\r");
  while(BusyUART1());
  return;
 }

UARTの受信バッファはFIFOバッファだから…

次は、ハイパーターミナル側でEnterキーが押された際にそれを検出する方法を考えます。 Enterキー検出は、コマンド入力などによって処理を開始するようなプログラムを書くときに 頻出となります。さっきまでの話から、おそらくEnterキーが押されると「\n\r」が送信されることと 予想できます。しかし、dsPIC側の受信関数は(いままで使ってきたものでは)1文字受信のReadUART1() 関数しかありません。「\n\r」は2文字扱いなので、これをどうやって検出するかが問題となります。 そこで、以下のようなプログラムを組んで実験してみました。あと、newline()関数を使っています。 newline()関数は上記のとおりの内容です。(例のごとくメイン関数内にコピペしてコンパイル…)


 //==================================================================
 //UART初期設定
 //速度は115kbpsとします(80MHzクロックでは実用的に最も速い設定)
 
 OpenUART1(config1,config2,10);

 //==================================================================
 //Enterキー検出
 char temp;

 while(1)
 {

  while(!DataRdyUART1());
  temp = ReadUART1();

  switch(temp)
  {
   case '\n':
   
    putsUART1("Enterキーが押されました。¥nで検出。");
    while(BusyUART1());
    newline();
    break;

   case '\r':
   
    putsUART1("Enterキーが押されました。¥rで検出。");
    while(BusyUART1());
    newline();
    break;
  
   case '\n\r':
   
    putsUART1("Enterキーが押されました。¥r¥nで検出。");
    while(BusyUART1());
    newline();
    break;
  } 
 }


switch文の最後の条件は、1文字データだというのにも関わらず\n\rの両方を入れてあります。 コードとしてはナンセンスですが、一応…。
上記ソースコードを打つ際の注意点です。まず、putsUART1()関数内に日本語を入れるとMPLABのエディタでは なにやら"*"マークがたくさん並びます。よくわかりませんが、コンパイルには影響ありませんでした。 なので、無理やりBackSpaceなんかを連打して消そうとしないでください(汗)
あと、「¥nで検出。」などの記述は全角で書いてください。半角だと例の如くエスケープシーケンス扱いになって、 肝心の“どのコードでEnterキーが検出されたのか?”が表示されなくなってしまいます…。

で、結果は上のようになりました。\rで検出されるんですね。\rっていうことは…後から送られてくる 方のコード(なんでしょうか?)でもdsPICの受信バッファはFIFO(First In First Out)でした…。 おそらく先に送られてくる'\n'はどっかいっちゃって(爆)後から来た'\r'が受信バッファにひっかかっている ところを読みだした…的な感じでしょうか??とりあえず検出方法がわかったので良しとしましょう(汗)

「0」は文字列の終わりを示す。(NULL文字)

改行コードの知識があれば、「改行コードが来るまでは(Enterキーが押されるまでは)送信されてきた 文字を1文字ずつ保存していって、改行コードが来たら文字列完成とみなして各種条件分岐へつなげる」 なんてことが可能になります。ハイパーターミナルからdsPICへ動作コマンドを送信するイメージです。 このときに、1文字ずつ受信した文字データをchar型配列に格納していって、最後に 文字列データとして取り出す…という手法がよく使われます。それをちょっと試してみましょう。

 int cnt = 0;  //文字数カウント用
 int i;  //for文用
 char temp;  //一時保存用
 char string[100];  //最終的につくる文字列。長さはテキトーです。

 //==================================================================
 //UART初期設定
 //速度は115kbpsとします(80MHzクロックでは実用的に最も速い設定)
 
 OpenUART1(config1,config2,10);

 //==================================================================
 //Enterキー検出して、入力された文字列をそのまま返す


 while(1)
 {
  while(!DataRdyUART1());
  temp = ReadUART1();

  //Enterキーか判別
  if(temp != '\r')
  {
   string[cnt] = temp;
   cnt++;
  }
  else
  {
	  
   newline();
	  
   //文字数分だけループして表示していく
   for(i=0;i<cnt;i++)
   {
    WriteUART1(string[i]);
    while(BusyUART1());
   }
   
   newline();
   cnt=0;
  }
 }

ハイパーターミナルで、適当に文字列を打ちこんでEnterキーをおすと、その下の行に同じ文字列が表示されます。 ソースコードを読んでいくと、だいたいの流れがわかりますが、なんというか…まわりくどい方法だと思います。 汎用性にも若干欠けるような。ここで、「NULL文字」についての知識があれば、以下のような(比較的) スマートなプログラムを書くことができます。



 int cnt = 0;  //文字数カウント用
 int i;  //for文用
 char temp;  //一時保存用
 char string[100];  //最終的につくる文字列。長さはテキトーです。

 //==================================================================
 //UART初期設定
 //速度は115kbpsとします(80MHzクロックでは実用的に最も速い設定)
 
 OpenUART1(config1,config2,10);

 //==================================================================
 //NULL文字の実験

 while(1)
 {
  while(!DataRdyUART1());
  temp = ReadUART1();

  //Enterキーか判別
  if(temp != '\r')
  {
   string[cnt] = temp;
   cnt++;
  }
  else
  {
	  
   newline();
 
   //null文字挿入
   string[cnt]=0;

   //文字列として表示
   putsUART1(string);
   while(BusyUART1());
   
   newline();
   cnt=0;
  }
 }


「0」はNULL文字(ヌル文字)と呼ばれていて、文字列データがそこで最後であることを示します。 プログラムで書くときは「0」です。0x00です。「‘0’」ではありません。こう書いてしまうと、 「数字の0という文字」というASCIIコードになってしまいます。注意。




前へ   次へ