忍者ブログ
ようこそ!JQ2RVNのブログです。 PICを使っていろいろな物を作ろうと画策中です。
[9] [10] [11] [12] [13] [14] [15] [16] [17]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

PICでTNCを作るのが目標ですが・・・
まずはその前段階として、
パケットをモニターするデバイスを作成していきたいと思います。

 


 



本日はその予備実験として、
シリアル(RS-232C)にて、データをPCに送る方法を行いました。

というのも、PICはPIC12F683を使用する予定なのですが、
これにはUART機能が付いていないので、
ソフトウェア的に作らないといけないからです。

なら、CCS Cの組み込み関数があるのでは?
という声もあるかもしれませんが、
この関数は、割り込みなどを使わずに作成されるので、
処理中は他の作業ができません。


したがって、割り込みを使って処理をする必要があるわけです。


 


 



まずは、回路なのですが、
それほど難しいものではないので回路図は省きます。

単純に、GP0(7ピン)を、シリアル端子の受信データピンにつなげればOKです。


つぎにソフトウェア的なところ。
ポイントは、RS-232Cの信号は0と1が逆だということ。
ですから、データの流れ的を、ロジックICの論理で書けば、
 0 → 1(スタートビット) → (データの反転8ビット) → 0(ストップビット)
 となります。


ここさえ注意すれば、特に問題はないはずです。



一応、ソースもあげておきます。
単純にAからZまで送り続けるだけです。

ソースファイル

 


 



簡単と言いたいところだったのですが、何か所か躓きました。


・ スタートビットが異様に短い

これはTMR0の割り込みフラグのクリアを忘れていたからでした。
レジでいえば、INTCON.T0IFです。

put_byte()関数が呼び出されるまで、Timer0はフリーランをしています。
つまり、かなりの確率でT0IF=1になってますから、
enable_interrupts( INT_RTCC );とした瞬間に割り込みが入ってしまいます。
ですから、スタートビットが短くなってしまったわけです。

この解決策が、clear_interrupt( INT_RTCC );です。

なお、割り込み処理のときは、コンパイラが自動的にクリアしてくれるので
ユーザー側は意識する必要がありません。

それが却って、クリアし忘れというバグを作ってしまったわけでした(汗




・PICKit2のUART機能で、うまく受信ができない

単純な話です。
PICKit2へは、反転しない状態で送らないといけません。
PICKit2の設計上は、PICとレベル変換IC(MAX232など)の間から
信号を拾うことになっているはずですから。
でも、この単純な問題に気付くのに、2時間くらい使ってしまいました(泣


ちゃんと通信できているところ。あー感動したw
↓↓↓

d841ad1ajpeg

あとの細々としたことは、後日ということで!

PR
C言語の関数で2つ以上の返値を出したいときや、
もともとの変数を直接いじりたいときには、
ポインタを使うのが定石だと思います。



通常のC言語での使い方は・・・・

void func( int* a )
{
    *a=....;
       (この後の例では、*a++;を使います)
}

呼び出しは
func( &x );

となります。

しかし、CCSCの場合は、これではうまく動かないようです。

アセンブラリストを見ると次のようになっています。


まずは呼び出し方。
MOVLW  32    (32は変数xのアドレス)
MOVWF  33   (33はfunc関数の引数aのアドレス)
GOTO     060 (func関数の番地)

(32や33、060という値は、コンパイラが自動的に変更してくれます。)

「33番地に、変数Xのアドレス(32)を入れて、func関数に飛ぶ」
となるので、参照動作(&がついた時の動作)は問題ないようです。

次に、func関数
060   MOVF 33,W
061   INCF 33,F
062   GOTO xxxx

これを見ると変なことがわかります。
061は関数内の処理、a++;に相当するのですが、
それがINCF 33,Fとなって、33番地の内容を直接インクリメントしています。
はじめは32が入っていたので、1プラスされて33になるだけなので、
予期していた動作と違うことがわかると思います。

結論として、ポインタ呼び出しはCCSは使えないことになります。





さて、これでは使いにくいので、次のような方法があります。

void func( int8 &a )
{
    a++;
}

呼び出し側は、
func( a );

この場合のアセンブラリストは・・・

呼び出し側:何も記載がない(呼び出す直前のプログラムメモリは0C3)
関数側:
0C4     INCF 32,F

つまり、コンパイラは関数のコールやジャンプなしに、
直接0C4番地にインクリメント命令を出しています。

なるほどといえば、なるほどな処理ですね。

もし、2か所以上から関数の呼び出しをしている場合はどうなるか?
064     INCF 36,F
0C4    INCF 32,F
というように、同じ処理が2つ書かれます。

なんてことはない、インライン展開をしてるわけですね。



インライン展開にはソースの可読性もよくなり、
ポインタを意識せずとも、関数を使うことができます。

しかし、必然的にプログラムメモリの使用量は増えるので、
複雑な処理を、何か所からかコールするという場合には不適です。

その場合は、グローバル変数を用意しておいて、
そこに値を書き込んでいく処理
が必要になります。





なお、MPLAB Cの場合はポインタ変数が使えますから、
最初の例のままでOKです。


忍者ブログ [PR]
カレンダー
04 2024/05 06
S M T W T F S
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
プロフィール
コールサイン:
JQ2RVN
性別:
男性
自己紹介:
PICの開発を勉強中です。
目標はPICTNCの高性能版を作ること。
まずは、本家を解析しています。
最新コメント
[04/23 Eolande]
[04/16 太田和巳(JF2UJG)]
[09/10 je7ifp]
[08/06 JQ2RVN]
[08/03 OVC]
最新トラックバック
バーコード
ブログ内検索
アクセス解析