2013年6月26日水曜日

PIC C18 メモ(ファイル分割/hファイル)

-----------------------------
ファイル分割
-----------------------------
ファイル分割(*1)の利点は、
  • コンパイル時間の短縮
  • 関数の部品化による資産活用
  • 複数開発者で並行作業
などか。一方次のような点が、
  • RAMの使用量を見ていると、ファイル分割することで増えてしまう場合がある
  • 分割しても、相互の関係が深いと、プロトタイプ宣言が多く必要となるため、小規模の場合はかえって煩雑になる
ということで、
  • hファイルにプロトタイプ宣言や、構造体等の定義、宣言部を分けることで、全体を見やすくする
  • hファイルに相互の関係性が表れる
  • 関係の薄い部分は分割する
改造依頼があって二年前のプログラムを見直した時に、着目すべき個所が見つけやすく、不必要な部分は安心してブラックボックスのままににしておけることで、メリットを実感できた。
 -----------------------------
hファイル・ガイドライン(*2)
-----------------------------
  • ファイル間にまたがる関数や変数の宣言を一ヶ所にまとめる
  • 関数のプロトタイプは、ヘッダファイルのみで宣言
  • ヘッダファイルでメモリが確保される変数の定義をしない(*3)
  • ヘッダファイルには、実体のない定数定義( #define )や宣言
    構造体等( struct, union, enum )の宣言
    typedef による外部変数、外部関数の宣言
  • ヘッダファイルに実行コードを書かない
  • 他から使われることのない関数をヘッダで宣言して公開しない
  • ソースファイルの中で完結する関数は static をつけておく
  • 多重インクルードを防ぐため、インクルードガードに使う名前の付け方を決めておく
  • 宣言の重複は問題なし(エラーにならない)
  • #defineは、何度呼び出されても構わない
  • Configuration は実行コードなので hファイルに記述しない

(*1)ファイル分割とは、複数の Cファイルを個別にコンパイル(oファイル)し、リンカがオブジェクト、ひとつのバイナリファイル(hexファイル)を作る。
(*2)「組込み現場のCプログラミング/標準コーディングガイドライン」(p104~)より
(*3)定義の重複は関数や変数の実体を作ることになるので重複するとエラーになる
(おまけ)最初の頃は、編集しやすいように Cファイルを分割して、インクルードしていただけだった。この場合、コンパイル単位は一つであり、インクルードする場所や順番を意識して作らないとならない。
よく言われているように「ひと月たてば他人の作ったソフトになる」の通りなので、「ガイドライン」は重要。

2010.01 - 2013.07.02

PIC C18 メモ(ファイル分割の例)

-----------------------------
他人様の作ったものを勉強のため分析
-----------------------------
Microchip Solution にあるサンプルよりコンパクトだったので、uALFAT(注)用に提供されているサンプルソースファイルを分析(メインのソースファイルは、PIC_example.c)してみた。図はヘッダファイルの相互関係で、矢印方向へインクルードしている。hファイルの記述内容は次の通り。




(*1)エラーの内容に対してエラーコードを割り付け(#define)
(*2)改版履歴のコメント
(*3)デバイスのピン割り付けなど標準のヘッダーファイル
(*4)プロトタイプ宣言と型の別名宣言(#define)
(*5)LED,SPI のピン割り付け(#define)とプロトタイプ宣言
(*6)日時の構造体の宣言とプロトタイプ宣言
(*7)LCD のピン割り付け(#define)とプロトタイプ宣言

UART, SPI, I2C の選択部分など #ifdef が出てきて複雑だが、規模が大きくないのでお手本に使えた。

(注)
uALFAT:組込み用ファイルシステム(FAT16,FAT32)を提供してくれるICで、メーカーは GHI Electronics 社。UART, SPI, I2Cからインターフェイスを選択して使う。

2010.01 - 2013.06.26

2013年6月25日火曜日

PIC C18メモ(変数の定義場所)

-----------------------------
ヘッダファイルで、変数定義しない
-----------------------------
//Sub.h
static char X;



----------------
//FuncA.c

static char A;  //(*1)

X=0;    //(*1)

----------------
//FuncB.c


exturn char A;  //(*2)

X=0;    //(*1)

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

(*1)A は同じメモリ、1バイト使う(一方のCファイルに定義して、exturn で使うこと)
(*2)X は別モノで2バイト使う(hファイルに変数を定義したら二重にRAMが割り当てられてしまった)

2010.01 - 2013.06.26

PIC C18メモ(インクルードガード)

-----------------------------
インクルードガード
-----------------------------
二重インクルードでエラーにならないように、インクルードガードをしておかないとならない。
下の例は、S.h で、SS.h をインクルードすると SSS.h のインクルードが出てくるが、すでに SSS.h はインクルード済。従って、INCLUDED_SSS がすでに定義済なので二度目に出てきたら
#endif まで読み飛ばされる。


----------------
//SSS.h
#ifndef INCLUDED_SSS
#define INCLUDED_SSS

#endif
----------------
//SS.h
#ifndef INCLUDED_SSS
#define INCLUDED_SSS

#include "SSS.h"

#endif
----------------
//S.h
#ifndef INCLUDED_S
#define INCLUDED_S

#include "SSS.h"
#include "SS.h"     //(注意)

#endif
----------------
2011.01 - 2013.06.26


#ifdef->#ifndef へ訂正
2018.06.02

PIC C18 メモ(チャタリング除去)

-----------------------------
フィルタとエッジ検出
-----------------------------
下側の波形のようにスイッチ入力にはチャタリングがある。チャタリングがあると、何度も押されたような意図しない動作をするので、上側の波形のように成形して取り込む必要がある。

スイッチ入力の処理は、「時間をおいて何度か読み直す」と教科書にはあるが、もう少しちゃんとしたものにしたい。また、押しボタンの場合、指を離されたときに動作するようにしたい場合もある。

この為だけにメモリをいくつか使ってしまうが、H->L, L->H のどちらもフィルタがかかる方法をとった。


【フィルタ】
時間をおいて読み込み、状態が継続(安定)していたらカウントする。
必要なレジスタは、
  • 前:前回の入力の状態を保存
  • 数:カウント回数を保存
  • 出力:フィルタ後の出力

【エッジ検出】

H->L  L->H
 111   101    <-旧と
~101  ~111    <-新をEX-OR
----  ----
 010   010    <-変化ビット
&111  &010    <-旧または旧の反転とAND
----  ----
 010   010

  • H->L 検出は、旧とEX-ORして旧とAND
  • L->H 検出は、旧とEX-ORして旧の反転とAND
  • フィルタと組み合わせる場合、新にフィルタ出力を使う
  • どちらも Lアクティブで表現、両方とも真ん中のビット変化を検出の例
【関数として】
  • 例によって、割り込みは使わない。操作入力とは別の入力信号もあるので定周期でポーリングする
  • フィルタ部分とエッジ検出部分と分離したプログラムとしてもいいし、規模の小さいプログラムでは一体化して使う
  • 変化点だけでなく、現在の状態も戻り値に含めて(構造体にして)返した方がいい
【フィルタが必要な入力信号】
  • スイッチ以外は、リレーの接点がある
  • 機械的な動きを検出するインターラプタなどの出力も、メカはスムースに動いていてもエッジの微妙な反射光でチャタリングが出たりする
【エッジ検出(変化点)が必要な時】
  • ボタンが押され続けた時処理を繰り返す場合、「ボタンオフ」が必要
  • 2つのボタンの同時操作に「意味」を与えたとき(Aを押しながらBを、みたいに)
【間隔と回数】
  • オンオフ時のカウント回数は、別々にした方がいい(いらない場合もある)
  • 10~20msくらいの周期で、数回カウント
  • 早く反応しすぎると、誤動作、反応が鈍いといらいらする
スイッチの場合は結果と連動するので操作してみて、自分の感覚によって調整する。信号入力に対するフィルタは、ノイズ誤動作や、全体の動作時間に関わるので大事なところ。

2008.11 - 2013.08.05

2013年6月24日月曜日

PIC C18 メモ(LCDの表示文字を編集)

-----------------------------
LCDのカーソル位置の文字を編集
2009.11.18
-----------------------------
LCDに表示されている、「タイトル」などの文字を編集できるようにする方法。操作ボタンは、アップ、ダウン、エンターの3つ使う(ただし根気がいるので、簡易的方法)

letter="ABCDEFG--------567890*_"
  1. 現在のカーソル位置にある、文字を読み込む
  2. 文字の位置を上の letter (有効文字列)からサーチして調べる
  3. 押されたボタンが「アップ」か、「ダウン」かによって
  4. サーチ結果の位置にひとつ足すかまたは引いて
  5. その位置の文字をLCDへ再表示する
ASCII変換の応用だ。 表示文字列を保存する必要があれば、メモリー上で編集してからLCD表示を更新、EEPROMに書き込むなど工夫する。

2013年6月23日日曜日

PIC C18 メモ(16進数値をASCII変換)

-----------------------------
0~F 16進数値をASCII変換
2009.11
-----------------------------
【1】
rom char hex[ 16 ]="0123456789ABCDEF";

上は文字列の中から該当する数値のASCII値を取り出す

【2】
rom char *rom hex[ 16 ]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F",};

上は一文字の文字列として読み出せるので、LCDに表示する場合などに使える
  • 一文字だけの場合、手軽に変換できる
  • どちらも、簡単な変換テーブルとして他の使い方もできることがわかる
  • くれぐれも、配列番号は制限値を超えないよう
  • 二桁以上は、素直に itoa 関数を使う

2013年6月12日水曜日

PIC C18 メモ(共用体の例)

-----------------------------
Microchip の [ GenericTypeDefs.h ] から
-----------------------------
typedef unsigned char          BYTE;        /* 8-bit unsigned  */
typedef unsigned short int    WORD;      /* 16-bit unsigned */
typedef unsigned long          DWORD;    /* 32-bit unsigned */
typedef union
{
    DWORD Val;  /* 32-bit unsigned */
    WORD w[2] __PACKED;  /* 16-bit unsigned [2] */
    BYTE v[4] __PACKED;   /* 8-bit unsigned [4] */
    struct __PACKED
    {
        WORD LW;  /* 16-bit unsigned */
        WORD HW;  /* 16-bit unsigned */
    } word;
    struct __PACKED
    {
        BYTE LB;        /* 8-bit unsigned */
        BYTE HB;        /* 8-bit unsigned */
        BYTE UB;        /* 8-bit unsigned */
        BYTE MB;        /* 8-bit unsigned */
    } byte;
} DWORD_VAL;

  • 32bit のデータを5通りに表現している
  • 16bit の2個のワード (WORD) として扱うことができるし、配列データとしても
  • 8bit の4個の独立したデータとしても、4個の配列としても扱うことができる
  • 外部にデータを出力するとき(例えば12bitD/A コンバータ)、これは必須となる

自分なりの共通ファイルに、まとめてこんな風に定義しておけばいい。人が作ったものをよーくみると「なるほど」ということになるし、理解できる力がついてきているということもわかる。

2010.01.25 - 2013.07.03 

PIC C18 メモ(共用体)

-----------------------------
基本
-----------------------------
union name{ struct{ int a; int b; }; char c; }bar;
      ~~~~共用体タグ(共用体の名前)          ~~~nameという型の変数bar

  • 定義するときはタグか変数のどちらか省略できる
  • char a ,b; の書き方が可能なように、同時に複数の変数定義も可
  • 同じタグ名の構造体同士は丸ごと代入可能
-----------------------------
共用体の初期化
-----------------------------
union { short long okcount; char byte[ 3 ]; } cat1 = 0x010203;  //OK
union { char byte[ 3 ]; short long okcount; } cat2 = 0x010203;  //NG
union { char byte[ 3 ]; short long okcount; } cat2 = {0x01,0x02,0x03,}; //OK

  • 先に書いた形式で初期化すること(二行目の NG は正しく初期化できない)
2010.05 - 2013.07.02

2013年6月11日火曜日

プロクソン マイクロクロステーブル を購入

以前から試してみようと思っていたトリマービットを買おうとして、アマゾンのサイトを眺めていたら、7千円台で売り出されているプロクソンのクロステーブルが目に留まった。
一晩考え、購入決定。
届いたので、トリマービットとともに早速試してみた。ちょうど、テスト用の冶具にスイッチを付けたかったところだった。

ホーザンの K-21 卓上ドリルに問題なく取付けできた。
透明ケースに組まれた回路はばらさず、テーブルに固定した。スライドスイッチ用の角穴を明けることにする。

テーブルはダイヤル一回転で1mm移動する。等ピッチの穴が正確に明けられる。
普通に「けがいてポンチを打って穴明け」では、±0.1mm程度の出来栄えで、このように連続した等ピッチの穴明けはなかなか満足いく結果がこれまで出せなかった。

この後、トリマービットを使ってテーブルを送りながら角穴にした。

次は、小さな穴をたくさん明けて仕上げの削り代を減らしてみよう。その方が、よりきれいに出来るかもしれない。
「マイクロ」なので可動範囲は狭く、コネクタやスイッチの穴明け程度。かつ、樹脂ボックスの側面など、穴明け位置によっては、そのワークの固定方法にすごく悩ませられるだろう。ただこれまで「丸穴で済む部品」を探して買っていたが、その必要がなくなった。

2013.09.07 記事を追加 コネクタの角穴加工(樹脂ケース)

2013年6月10日月曜日

トリマービット

ネットで角穴の仕上げに使った例を見つけ気になっていた、スターエム トリマービット 1.6X6MM を購入(アマゾンで1180円)、早速使ってみた。
左写真は、透明プラスチックケースに組んだ電流発生冶具に、レンジ選択のスライドスイッチを、卓上ドリル+マイクロクロステーブルを使って追加工した。
こまで角穴の加工にはてこずっていたが、樹脂ケースならこれでいいかも。
刃の形状をよく見ないままにいきなり使った。虫眼鏡で見ると、初めて見る刃の形。刃の形を、よく見てから使うべきだった。次はもう少しシャープに仕上げられるかもしれない。