電子工作8 - PIC16F877とパソコンとの通信(HyperTerminalを使う)

 

概要 

安価で、機能が一杯詰まったPICの使い方を学んで行く中で、PICとパソコンとの通信法を知ることは必須である。小生が使い続けているBasic コンパイラPICBasic Proには、PICに内蔵のUSART(Universal Synchronous Asynchronous Receiver Transmitter)を使うためのコマンドや、PICの任意のポートを通信に使うためのコマンドなどが用意されていて、アッセンブラによるブログラム作成に比べ、格段に楽である。

  とにかくパソコンのRS232ケーブルには、市販の機器しかつないだことがないので、参考にした文献の配線が、どんな働きをするのか、パソコン(PC)を壊さないか。また、PC側で手軽に使えるとされる、Windowsに長く搭載されてきているHyperTerminalとやらは何なのか、どのように使うのか、最初はまったく不明。それでも、Googleの検索結果から得られた内外の参考資料と悪戦苦闘して、約1ヶ月、PICとPC間でデータの通信が一応可能になった。今回は市販されてから結構時間が経ち、関連情報も豊富な40ピンの16F877という¥500円チップを使うことにした。PCは小生が使っているWindows XP機、その中に入っているHyperTerminalがPC側のデータの受け渡しを担う。

 

回路

   PCからのRS232ケーブルの末端をSUB-D9と呼ばれる9ピンのコネクタにつなぎ、それからピン2(Rx)とピン3(Tx)を、レベルコンバータMax232(今回は、同等品ADM3202、¥200秋月)を経由して、PIC16F877(4MHzで動かしている)のピン25(Tx)とピン26(Rx)に接続する。さらに、RS232ケーブルのピン5(GND)を取りだし、16F877のVss(GND)につなぐ。ここで大事なことは、RS232ケーブルの末端につないだSUB-D9のピン1、4と6を結線し、また、ピン7と8を結線することである。これで、PC側で入力したデータがそのまま戻ってくるエコーバックという機能が使えるようになる。RS232の結線法の一つということである。これで、16F877に内蔵のUSARTが使えようになる。このSUB-D9コネクタを使う時、小さくふられている番号に従うと、誤配線を防げる。さらに、PICのRA0(ピン2)からの入力電圧を取り込む目的で、内蔵の10-bitアナログ-デジタルコンバータ(ADC)を使えるように設定を行った。変換の基準電圧として16F877への供給電圧(Vdd) 5.0 Vを使うように設定しているので、入力電圧の範囲は0 - 5.0 Vになる。


 


下の写真は上の回路に基づいて製作した PIC(16F877)ボードです。真中のICが16F877、その右下の小さいICがADM3202、その上部が5V電源、右端にSUB-D9のコネクタがあり、RS232ケーブルでPCにつながっている。このコネクタの末端部分の結線が注意の要るところです。左手のACアダブタと16F877との間にある小さいボードは実験目的の可変式の分圧器で(青色の小さい長方形のものは20回転VRです)、16F877のRA0ピン(ピン2)にADC入力電圧を供給しています。

 


 

 


データ転送手順

PICとPCをRS232ケーブルでつないだ状態で、PICにも電源を入れる。以下のようにしてPCとPICの間に通信状態を成立させる。

1)     PC側のHyperTerminal をクリックして立ち上げる。

2)     表示される[接続の設定]で、キャンセルを選択する。

3)     [プロパテイ]をクリックする。

4)     [接続方法]で、COM2(例えば)を選択する。そして、[モデム構成]で2400bps(例えば)を選ぶ。

5)     HyperTerminal の画面に戻り、Returnキーを押す。これで、PCとPICがつながる。電話器アイコンが沈み、切断アイコンが浮び上がる。

6)     PIC側のResetボタンを押すと、Enter <a.> to get ADC value: と表示される。ここで、”a”

を押すと、以下に示す写真のように3つの値が表示される。得られて値は、ファイルとして保存できる。(*PIC側の電源がすでにONの状態で、Resetボタンを押さずにPC側で”a”を押すとEnter <a.> to get ADC value: は表示されずにデータだけが表示される)

7)     HyperTerminalを終了するには、切断アイコンを押す。

 

データ保存手順

1)     PC側のHyperTerminal をクリックして立ち上げる。

2)     表示される[接続の設定]で、ファイル名(例えば. data20)を入れる。

3)     [接続方法]で、COM2(例えば)を選択する。そして、[モデム構成]で2400bps(例えば)を選ぶ。 これで、PCとPIC間が接続状態になる。

4)     PIC側でResetを押すか、電源を入れとEnter <a.> to get ADC value: が表示される。

5)     または、PC側で”a”を押すと、3個のデータが表示される。

6)     HyperTerminal 上に集まったデータを保存するには、[ファイル]−>[上書き保存]を押す。これで、データはファイルdata20に保存される。

7)     ファイルdata20に保存されたデータを見るには、HyperTerminal を立ち上げ、表示される[接続の設定]で、[キャンセル]を選択する。

8)     次いで、[ファイル]−>[開く]で、ファイルdata20を開く。これでHyperTerminal の上部に(要スクロール)データが現れる(コピー可。しかし、テキスト形式ではないようだ)。

 

 

下の写真は、実際にPC側のHyperTerminal上から出した指令”a”に応答して、PIC側から送られてきたデータの一例です。


 


 

プログラム

まず、内蔵のUSARTを使うための各種の設定をし、さらに10-bitのADCや使用するポートの設定をした後に、メインプログラムが続く。PCとPICをRS232ケーブルでつなぎ、電源を入れ、HyperTerminalを開き通信速度(ここでは、2400 bpsに設定)などを設定した後に、リターンキーを押す。これでPCとPICがつながる。PIC側のリセットキーを押すと、"Enter <a> to get ADC value"と表示されるので、"a" をキーボードから入力すると、Step No., Volt (V) およびTemp(C)の3つの値が表示される。Step No.とは、5.0 Vの最大入力値(RA0からの)を1023 (10 bits)と対応させたもので、入力値が2.5 Vなら1023x2.5/5.0=512となる。ADCINというコマンドを実行するとRA0(ピン2)からの入力電圧がstep数の形で取り込まれる。Volt (V)はそのstep数をvoltageの値に換算したもの。また、Temp(C)の値は、前の“電子工作6”で使用した温度センサLM35DZの出力をアンプ(LMC662CN)で5倍に増幅して、RA0(ピン2)に入力する状況を想定した値である。つまり、LM35DZの出力は10mV/°C。したがって、温度100°Cでは、1.0 Vになり、5倍に増幅すると、5.0 VとADC基準電圧5.0 Vと等しくなる。このことは、温度100°Cではstep数が1023になることを意味している。

 

'RS16877q.bas  05.6.6 

'Exp on communication between PIC16F877 and MicroCode Studio or

'HyperTerminal of Windows XP via RS232C

 

'*****************************************************************

'This prog is to read analog data (voltage) through RA0 (Pin2), send

'them to PC for their display as Step No., Voltage value and Temp.

'(running at 2400 baud): Here a Temp data displayed is when an input voltage

' range is assumed to be 0-5.00 V for 0-1023 (LM35DZ+LMC662CN-Op-amp).

'See my Project Note: 04.8.15

 

'Connection *************************************************

'TX-Pin25(RC6), RX-Pin26(RC7), Anal. voltage input-Pin2 (RA0) 

 

'Defines & settings *****************************************

DEFINE OSC 4           'Using 4MHz oscillator 

DEFINE HSER_RCSTA 90h  'Enable Serial PORT

                       'Enable continuous receive

DEFINE HSER_TXSTA 20h  'Enable transmit

                       'Low baud rate (BRGH=0)

DEFINE HSER_SPBRG 25   'Set USART to 2400 baud (when BRGH=0)

DEFINE HSER_CLROERR 1

 

DEFINE ADC_BITS 10     '10-bit result

DEFINE ADC_SAMPLEUS 30 '30 usec acquisition (settling) time

 

ADCVal VAR WORD        ‘16-bit variable

Result var word

ResultT var word

ADCON0=%10000000   'ADCS2=0, Fosc/32, CH0(RA0), Vref+=Vdd, Vref-=Vss

ADCON1=%10000000   'Right justify result

 

'PROGRAM ****************************************************

HSEROUT ["Enter <a> to get ADC value:",10,13]

         'This phrase is displayed after PIC's Reset Power ON.

Loop:

Loop2:

Pause 100                        'Wait 0.1 sec

Hserin 1000, Loop2, [WAIT ("a")]

         'Wait the input of "a" from PC through Loop2. If "a" is

         'received, jump to ADCCAL.

Pause 100                                                  

 

ADCCAL:

ADCIN 0, ADCVal   'Read an anlog value from RA0 (Pin 2) and store

                  'it as ADCVal

Pause 50

HSEROUT ["Step No.=", DEC ADCVal,10,13]

          'Send the phrase and the decimal value of ADCVal (0 - 1023)

          'PC for display.

Result=ADCVal*/12500   'Trick to convert ADCVal to a Voltage value

Result=(Result+5)/10   'Trick to round a Voltage value (See 04/8/16)

ResultT=Result*2

HSEROUT ["Volt(V)= ", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

          'Digit adjustment to display like Volt(V)= 2.55

HSEROUT ["Temp(C)= ", DEC ResultT Dig 3,Dec ResultT Dig 2,".",DEC ResultT Dig 1,10,13]

          'Digit adjustment to display like Temp(C)= 44.3

Goto Loop

End

 

'Note: The config. values for AKI Programmer are all default values.

 

追加プログラム(改良版)

    上のプログラムを改良して、データを長時間にわたって、一定の時間間隔でサンプリング出来るようにした。下の写真はHyperTerminal上での、60-min間隔でのサンプリングの例で、 0-min、 60-min、 120-minと3回データをサンプリングしています。プログラムは24時間連続サンプリングするように組んであります。

 


 


PIC側でResetを押すと、上記の1行目が現れ、“s”を入力すると、選択項目が現れる。そして、“l”を入力すると、”a”を押すごとに、その時の外部からの入力電圧値が表示される。その他の項目では、選択した時間間隔(1, 5, 15, 30, 45, 60 min間隔)でデータをサンプルし、表示する。この画面の例では、時間間隔60 minが選択され、0 min, 60 min, 120 min のようにサンプリングされていく。ただし、ソフト的に時間間隔をつくり出しているので、精度はあまり良くない(誤差10sec/hour位)。

    以下のように、PIC16F877の約半分弱のメモリを使うほどの、結構長いプログラムになってしまった。PC側からの入力文字に応じて、いろんなところにジャンプさせ、結果を表示させるロジックの作成が要点であった。

 

'RS16877v.bas  2005.7.1

'Modification of RS16877u.bas 

'Communication between PIC16F877 and HyperTerminal of Windows XP

'via RS232C

 

'*****************************************************************

'This prog is to read analog data (voltage) through RA0 (Pin2), send

'them to PC for their display as Voltage value (running at 2400 baud).

'Here a voltage data displayed is when an input voltage

' range is assumed to be 0-5.00 V for 0-1023 steps.

'See my Project Note: 04.8.15

'This time it was designed to be able to choose the measuring interval of

'ADC data (l,m,n,o,p,q,r = 7 interval modes) on HyperTerminal.

 

'******Connection *********

'TX-Pin25(RC6), RX-Pin26(RC7), Anal.volt input-Pin2 (RA0) 

 

'******Defines & settings *****

DEFINE OSC 4           'Using 4MHz oscillator 

DEFINE HSER_RCSTA 90h  'Enable Serial PORT

                       'Enable continuous receive

DEFINE HSER_TXSTA 20h  'Enable transmit

                       'Low baud rate (BRGH=0)

DEFINE HSER_SPBRG 25   'Set USART to 2400 baud (when BRGH=0)

DEFINE HSER_CLROERR 1

 

DEFINE ADC_BITS 10     '10-bit result

DEFINE ADC_SAMPLEUS 30 '30 usec acquisition (settling) time

 

TimeIntval var byte       'Variable

ADCVal VAR WORD      '16-bit ADC value read by ADCIN command

Result var word

ResultT var word

CharVal var byte         'Character value to be read

t var byte                 'All shown below are variables.

t1 var byte

t2 var byte

t3 var byte

t4 var byte

t5 var byte

t6 var byte

t7 var byte

t8 var byte

t9 var byte

t10 var byte

 

ADCON0=%10000000 'ADCS2=0, Fosc/32, CH0(RA0), Vref+=Vdd, Vref-=Vss

ADCON1=%10000000 'Right justify result

 

'******PROGRAM********

HSEROUT [10,13]                  'Line feed and carriage return (1-line space)

HSEROUT ["Enter <s> to start ADC Program",10,13]

Start:

Hserin 1000, Start, [WAIT ("s")] 'Start  'Wait <s> while looping

Pause 50

HSEROUT ["Enter Time Interval value <x> for ADC Data Collection",10,13]

HSEROUT ["Enter <l> for data collection at any time",10,13]

HSEROUT ["Enter <m> for 1-min interval",10,13]

HSEROUT ["Enter <n> for 5-min interval",10,13]

HSEROUT ["Enter <o> for 15-min interval",10,13]

HSEROUT ["Enter <p> for 30-min interval",10,13]

HSEROUT ["Enter <q> for 45-min interval",10,13]

HSEROUT ["Enter <r> for 60-min interval",10,13]

Pause 50

 

Start1:                     

Hserin 50, Start1, [CharVal]    'Routine to wait the entry of letter <x>

IF CharVal="l" then Jumpl     'while forming a loop (Start1)

IF CharVal="m" then Jumpm

IF CharVal="n" then Jumpn

IF CharVal="o" then Jumpo

IF CharVal="p" then Jumpp

IF CharVal="q" then Jumpq

IF CharVal="r" then Jumpr

goto Start1

 

Jumpl: TimeIntval=0

HSEROUT [10,13]                     'Line feed and carriage return

HSEROUT ["Time Interval=none",10,13]   'Display "TimeIntval=0 min"

goto ADCprocess

Jumpm: TimeIntval=1

HSEROUT [10,13]

HSEROUT ["Time Interval=1 min",10,13]

goto ADCprocess

Jumpn: TimeIntval=5

HSEROUT [10,13]

HSEROUT ["Time Interval=5 min",10,13]

goto ADCprocess

Jumpo: TimeIntval=15

HSEROUT [10,13]

HSEROUT ["Time Interval=15 min",10,13]

goto ADCprocess

Jumpp: TimeIntval=30

HSEROUT [10,13]

HSEROUT ["Time Interval=30 min",10,13]

goto ADCprocess

Jumpq: TimeIntval=45

HSEROUT [10,13]

HSEROUT ["Time Interval=45 min",10,13]

goto ADCprocess

Jumpr: TimeIntval=60

HSEROUT [10,13]

HSEROUT ["Time Interval=60 min",10,13]

goto ADCprocess

 

ADCprocess:

Pause 50

HSEROUT ["Enter <a> to get ADC values:",10,13]

         'This phrase is displayed after PIC's Reset Power ON.

        

If TimeIntval=0 then Timer0

If TimeIntval=1 then Timer1

If TimeIntval=5 then Timer5

If TimeIntval=15 then Timer15

If TimeIntval=30 then Timer30

If TimeIntval=45 then Timer45

If TimeIntval=60 then Timer60

goto Start1

 

Timer0:

LoopT0:

Hserin 1000, LoopT0, [WAIT ("a")]   '”a” entry waiting loop

         'Wait the input of "a" from PC through Loop2. If "a" is

         'received, jump to ADCIN0.ADCVal

Pause 100                        'Wait 0.1 sec                          

ADCIN 0, ADCVal   'Read an anlog value from RA0 (Pin 2) and store

                  'it as ADCVal

Pause 50

Gosub Resultcal                   ‘Subroutine for calculation

HSEROUT ["Volt(V)=", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

          'Digit adjustment to display like Volt(V)= 2.55

Goto Timer0

 

Timer1:           '1-min routine

LoopT1

Hserin 1000, LoopT1, [WAIT ("a")]

Pause 100

For t=0 to 60     'Max collection time 0 - 180 min (3 hours)

ADCIN 0, ADCVal

Pause 50

HSEROUT ["Time elapsed=", DEC t, " min",10,13]  ‘Display decimal t value.

Gosub Resultcal

HSEROUT ["Volt(V)=", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

Pause 60000       '60-sec timer

Next t

goto completed

 

Timer5:           '5-min routine

LoopT2:

Hserin 1000, LoopT2, [WAIT ("a")]

Pause 100

For t1=0 to 72    'Max collection time - 6 hours   

ADCIN 0, ADCVal

Pause 50

HSEROUT ["Time elapsed=", DEC t1*5, " min",10,13]  '0*5 all right?

Gosub Resultcal

HSEROUT ["Volt(V)=", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

For t2=1 to 5     '5-min timer

Pause 60000      

Next t2

Next t1

goto completed

 

Timer15:          '15-minute routine

LoopT3:

Hserin 1000, LoopT3, [WAIT ("a")]

Pause 100

For t3=0 to 24    'Max collection time - 6 hours

ADCIN 0, ADCVal

Pause 50

HSEROUT ["Time elapsed=", DEC t3*15, " min",10,13] 

Gosub Resultcal

HSEROUT ["Volt(V)=", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

For t4=1 to 15    '15-min timer

Pause 60000      

Next t4

Next t3

goto completed

 

Timer30:          '30-minute routine

LoopT4:

Hserin 1000, LoopT4, [WAIT ("a")]

Pause 100

For t5=0 to 24    'Max collection time - 12 hours    

ADCIN 0, ADCVal

Pause 50

HSEROUT ["Time elapsed=", DEC t5*30, " min",10,13] 

Gosub Resultcal

HSEROUT ["Volt(V)=", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

For t6=1 to 30    '30-min timer

Pause 60000    

Next t6

Next t5

goto completed

 

Timer45:          '45-minute routine

LoopT5:

Hserin 1000, LoopT5, [WAIT ("a")]

Pause 100

For t7=0 to 16    'Max collection time - 12 hours 

ADCIN 0, ADCVal

Pause 50

HSEROUT ["Time elapsed=", DEC t7*45, " min",10,13] 

Gosub Resultcal

HSEROUT ["Volt(V)=", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

For t8=1 to 45    '45-min timer

Pause 60000    

Next t8

Next t7

goto completed

 

Timer60:          '60-minute routine

LoopT6:

Hserin 1000, LoopT6, [WAIT ("a")]

Pause 100

For t9=0 to 24    'Max collection time - 24 hours 

ADCIN 0, ADCVal

Pause 50

HSEROUT ["Time elapsed=", DEC t9*60, " min",10,13] 

Gosub Resultcal

HSEROUT ["Volt(V)=", DEC Result Dig 3,".", Dec Result Dig 2,Dec Result Dig 1,10,13]

For t10=1 to 60   '60-min timer

Pause 60000    

Next t10

Next t9

goto completed

 

'Subroutine

Resultcal:      

Result=ADCVal*/12500   'Trick to convert ADCVal to a Voltage value

Result=(Result+5)/10   'Trick to round a Voltage value (See 04/8/16)

Return

 

completed:

End

 

'Note: The config. values for AKI Programmer are all default values.

  

余談

    スタート時に、どうやってPICにResetをかけるか(Pin 1を短時間“Low”に落とす、または、電源を入れる)(PICがPCから離れているところに置かれていると仮定して)や、ソフトウエアタイマーの精度などに、まだ問題がある。しかし、回路が簡単で安く製作でき、しかもWindows搭載のHyperTerminalが使えるので、手っとり早くデータを収集する目的には使えそうです。

  通信実験を始めて約2週間、やっとPICからHyperTerminal上に簡単なメッセージ(”The quick d for jumps”)を送ることに成功した時は、感激!。当たり前だが、知らないことをマスターするのはヤッパリ大変。巷に張り巡らされた様々な巨大なネットワーク網、人間様の英知とは凄いもの、感心するばかりです。

 

Menu Pageへ戻る    

Topへ戻る