Comments
Description
Transcript
2.7MB - 高知工科大学
卒業研究報告 題目 PIC で構築した音源を組み込んだゲーム回路の設計と製作 報告者 学籍番号:1150113 氏名:野村 俊介 指導教員 綿森 道夫 准教授 平成26年2月10日 -0- 目次 第1章 第2章 第3章 第4章 第5章 第6章 序論 1.1 研究の背景・・・・・・・・・・・・・・・・・・・・・ 3 1.2 研究の目的・・・・・・・・・・・・・・・・・・・・・ 3 1.3 卒業研究を通して身に着けた技術・・・・・・・・・・・ 4 開発環境 2.1 PIC について・・・・・・・・・・・・・・・・・・・・ 5 2.2 PIC の種類・・・・・・・・・・・・・・・・・・・・・ 5 2.3 今回使用した PIC・・・・・・・・・・・・・・・・・・ 6 2.4 ソフトウェア・・・・・・・・・・・・・・・・・・・・10 容量検知モジュール搭載のオシレータの設計と製作 3.1 概要・・・・・・・・・・・・・・・・・・・・・・・・11 3.2 回路について・・・・・・・・・・・・・・・・・・・・12 3.3 動作原理・・・・・・・・・・・・・・・・・・・・・・13 ピカタワーの設計と製作 4.1 概要・・・・・・・・・・・・・・・・・・・・・・・・18 4.2 回路について・・・・・・・・・・・・・・・・・・・・18 4.3 動作説明・・・・・・・・・・・・・・・・・・・・・・19 超音波・赤外線距離計の設計と製作 5.1 概要・・・・・・・・・・・・・・・・・・・・・・・・23 5.2 回路について・・・・・・・・・・・・・・・・・・・・23 5.3 動作説明・・・・・・・・・・・・・・・・・・・・・・24 PIC で構築した音源を組み込んだゲームの設計と製作 6.1 概要・・・・・・・・・・・・・・・・・・・・・・・・27 6.2 最終回路について・・・・・・・・・・・・・・・・・・28 6.3 動作原理・・・・・・・・・・・・・・・・・・・・・・30 6.4 動作確認・・・・・・・・・・・・・・・・・・・・・・37 -1- まとめ ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・44 謝辞 ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・45 参考文献 ・・・・・・・・・・・・・・・・・・・・・・・・・・・・46 付録 プログラムリスト ・・・・・・・・・・・・・・・・・・・・・47 -2- 第1章 1.1 序章 研究の背景 現在、PIC マイコンは世の中に出回っている自動車や家電製品、産業製品に搭載され ていることが多い。また、インターネットなどを使用することで容易に入手でき、安価 なこともあって PIC を使用した電子工作が一般的に普及している。 2回生の学生実験の時に、ブレットボード上に指定された回路ではあるが実際に回路 を製作し、プログラムを書き込んで PIC を動かす実験を行って楽しかったことと、綿 森准教授の授業で、授業冒頭に綿森研究室の学生が製作したテトリスやオリジナルのマ ウスなどを見た時に自分もそういったモノを作ってみたい思い綿森研究室を希望した。 3回生後期の綿森研究室のセミナーと実験で PIC マイコンを用いた LED 点灯回路を 製作した。プリント基板加工機を用いて基板を削り出し、PIC に C 言語でプログラム を書き込み、作成した回路が自分の思った通りの動作をすることに感銘を受け、さらに 高度な回路の製作をしたいという考えに至った。 1.2 研究の目的 この研究を通して実際に自ら構想したモノを作ることにより、アナログ・デジタル 回路の理解力、回路製作能力、プログラム記述能力などの向上をめざし、モノを作る ための技術力を身につけることを目的としている。この目的は、今後社会に出て回路 設計を行うにあたり必要なことであると思う。この研究を行う中で、この経験はその まま今後の問題解決のモデルになるだろう。具体的な製作として PIC をもちいて音を 鳴らすことのできる回路の設計と製作を行った。この回路は静電容量変化検出方式に よって電極に触れると音を鳴らす仕組みになっている。音は DA コンバータを搭載し た PIC で合成している。Pic-Pic 間の通信により無事に 2 つのチップが協調して動作 する回路を構築することができた。この最終回路の製作に至るまでにいろいろな回路 で試作を重ね、最終作品を完成させることで、無事に目的を達成したと考えている。 -3- 1.3 卒業研究を通して身についた技術 最初に回路図の作成技術をあげることができると思う。Eagle というソフトを用い て回路図を作成できるようになった。次に、Eagle で作成した回路図を基板図にする ことができるようになった。他にも、様々な回路で試作を重ねたことによりはんだ付 けの技術が向上し、回路基板加工機の利用法を習得することができた。また、ソフト ウェア関連では、C 言語文法とプログラミング能力があげられると思う。GCC コンパ イラや PicC コンパイラを用いてプログラムミングを行い、できるようになった。更に Spice を用いて回路のシミュレーションを行えるようになったことがあげられると思 う。これは、オペアンプのシミュレーションを LTspice で実際に行うことで理解が深 まったことからいえる。最後に Pic 組み込みの回路開発があげられると思う。最終作 品で実際に利用してみてできるようになった。 Pic は、日本では多くの書籍にとりあげられ、いわば現代の電子工作になくてはな らないものである。今回の卒業研究で、Pic 電子工作を行ったことは、単に流行を追 うだけではなく、今後就職してからもいろいろな場所と機会で自分を助けてくれると 思う。 -4- 第2章 開発環境 2.1 PIC について PIC(Peripheral Interface Controller)は米マイクロチップテクノロジー社が開発して いるマイクロコントローラーである。8 ピンの小さいものから、100 ピンの大きなもの と様々な用途によって使用法を変えることができる。CPU や ROM、RAM などのメモ リーを内蔵し、部品を多くつける必要がない。また PC があれば無料の開発ツールも用 意されていること、ほかにもインターネットや書籍により参考文献の豊富なことなどが あり、組み込みシステム開発の基礎を学ぶ教材としても有益なマイコンである。近年で は従来の PIC16 というミッドレンジファミリを大幅に機能アップした、新ファミリ「F1 ファミリ」がリリースされた。こちらは、クロックは最高 32MHz (1.6 倍)、プログラム メモリは最大 32k ワード(4 倍)、データメモリは最大 4k バイト(8 倍)と大幅に増強さ れ、間接アドレッシングが扱えるようになった。 2.2 PIC の種類 PIC には様々なファミリと呼ばれる製品の区別が大きく分けて 4 つある。 ・ベースラインファミリ 命令が 12 ビット幅で命令数は 33 命令、最初に開発された PIC マイコンであ る。入出力とタイマ機能だけをもった単機能のシリーズである。型番は PIC10、 PIC12 である。 例)PIC10F322、PIC12F675 など ・ミッドレンジファミリ 命令が 14 ビット幅で命令数は 35 命令、最もよく使われるシリーズである。 A/D 変換機能やシリアルポートなど多くの機能を内蔵するものもあり、種類も 豊富である。型番は PIC16 である。 例)PIC16F876、PIC16F674 など ・F1 ファミリ 命令が 14 ビット幅で命令数は 49 命令、2.1 で述べた他にも、電源電圧範囲の 拡張や 5 または 8 ビットの D/A コンバータの搭載など、ミッドレンジファミ リを大幅に強化したという位置づけにあるシリーズである。ハイエンドファミ リの PIC に迫る性能の 8 ビットマイコンとなる。型番は PIC16F1 である。 例)PIC16F1703、PIC16F1938 など -5- ・ハイエンドファミリ 命令が 16 ビット幅で命令数は 77 命令、高機能を備えたシリーズである。これ までの PIC でやや使いづらかった部分を改良して使いやすくされているのも特 徴である。 2.3 今回使用した PIC 今回使用した PIC は F1 ファミリのものである。それぞれの回路に使用した PIC を以 下に示す。10 ビットの ADC や 5 ビットの DAC、Timer0,1,2,4,6 と豊富な機能を有し、 容量検知モジュールによりタッチセンサを実現できるなど使いやすい PIC である。 ・PIC16F1938・・・ピカタワー、容量検知モジュール搭載オシレータに使用した。 F1 ファミリに属する 28 ピンの PIC である。外観を図 2.3.1 に示す。 仕様 ・タッチセンサ入力:8ch ・LCD ドライバ内臓 ・動作クロック:MAX32MHz ・動作電圧:1.8V~5.5V ・プログラムメモリ:16K ワード ・SRAM:1024 バイト ・EEPROM:256 バイト ・I/O 数:最大 25 本 ・A/D:10 ビット×11ch ・タイマ:5ch ・I2C、SPI、EUSART、MSSP ・28 ピン DIP パッケージ -6- 図 2.3.1 ピン番号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 内容 RE3/MCLR/Vpp RA0/AN0 RA1/AN1 RA2/AN2/VrefRA3/AN3/vref+ RA4/CPS6/CCP5 RA5/AN4/CPS7 Vss RA7/OSC1 RA6/OSC2 RC0/P2B RC1/P2A RC2/CCP1/P1A RC3/SCL/SCK PIC16F1938 の外観 ピン番号 内容 15 RC4/SDI/SDA 16 RC5/SDO 17 RC6/TX 18 RC7/RX 19 Vss 20 Vdd 21 RB0/CPS0/CCP14 22 RB1/AN10/CPS1 23 RB2/AN8/CPS2 24 RB3/AN9/CPS3 25 RB4/AN11/CPS4 26 RB5/AN13/CPS5 27 RB6/ICSPCLK 28 RB7/ICSPDAT 表 2.3.1 PIC16F1938 のピン内容概略 ・PIC16F1939・・・PIC で構築した音源を組み込んだタッチゲームに使用した。 F1 ファミリに属する 40 ピンの PIC である。基本的な仕様は PIC16F1938 と同じな ので相違点のみ以下に示す。図 2.3.2 に外観を示す。 仕様 ・タッチセンサ入力:16ch ・I/O 数:最大 36 本 ・A/D:10 ビット×14ch ・40 ピン DIP パッケージ -7- 図 2.3.2 PIC16F1939 の外観 ピン番号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 内容 RE3/MCLR/Vpp RA0/AN0 RA1/AN1 RA2/AN2/VrefRA3/AN3/vref+ RA4/CPS6/CCP5 RA5/AN4/CPS7 RE0/AN5/CCP3 RE1/AN6 RE2/AN7/CCP5 Vdd Vss RA7/OSC1 RA6/OSC2 RC0/T1OSO RC1/T1OSI/CCP RC2/CCP1 RC5/SCL/SCK RD0/CPS8/COM3 RD1/CPS9/CCP4 ピン番号 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 内容 RD2/CPS10 RD3/CPS11 RC4/SDI/SDA RC5/SDO RC6/TX RC7/RX RD4/CPS12 RD5/CPS13 RD6/CPS14 RD7/CPS15 Vss Vdd RB0/AN12/CPS0 RB1/AN10/CPS1 RB2/AN8/CPS2 RB3/AN9/CPS3 RB4/AN11/CPS4 RB5/AN13/CPS5 RB6/ICSPCLK RB7/ICSPDAT 表 2.3.2 PIC16F1939 のピン内容概略 -8- ・PIC16F1783・・・PIC で構築した音源を組み込んだタッチゲーム、超音波・赤外線 距離計に使用した。 F1 ファミリに属する 28 ピンの PIC である。オペアンプやコンパレータや 12 ビット の ADC や 8 ビット DAC などの機能を備え、アナログの面が強い。細かい仕様を以下 に示す。また、外観を図 2.3.3 に示す。 仕様 ・電源電圧:2.3~5.5V ・動作クロック:MAX32MHz ・プログラムメモリ:4096 ワード ・SRAM:512 バイト ・EEPROM:256 バイト ・I/O 数:最大 25 本 ・A/D:12 ビット×11ch ・タイマ:2ch ・I2C、SPI、EUSART、MSSP ・28 ピン DIP パッケージ 図 2.3.3 PIC16F1783 の外観 -9- ピン番号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 内容 RE3/MCLR/Vpp RA0/AN0/C1~3IN0RA1/AN1/OPA1OUT RA2/AN2/Vref-/DACOUT1 RA3/AN3/Vref+/C1IN1+ RA4/C1OUT/OPA1IN+ RA5/AN4/C2OUT/OPA1INVss RA7/OSC1 RA6/OSC2 RC0/T1OSO/T1CKI/PSMC1A RC1/T1OSI/PSMC1B/CCP2 RC2/PSMC1C/CCP1 RC3/PSMC1D/SCL/SCK ピン番号 15 16 17 18 19 20 21 22 23 24 25 26 27 28 内容 RC4/PSMC1E/SDI/SDA RC5/PSMC1F/SDO RC6/PCMC2A/TX RC7/PCMC2B/RX Vss Vdd RB0/AN10/C2IN1+/PSMC1,2IN RB1/C1~3IN3-/OPA2OUT RB2/AN8/OPA2INRB3/AN9/C1~3IN2-/OPA2INRB4/AN11/C3IN1+ RB5/AN13/C3OUT/T1G RB6/ICSPCLK RB7/ICSPDAT 表 2.3.3 PIC16F1783 のピン内容概略 2.4 ソフトウェア プログラミングは C 言語を使用し、総合開発環境ソフトウェア MPLAB X でプログ ラムを作成した。C コンパイラは xc8 である。プログラムの書き込みには図 2.4.1 の PICkit3 を使用して書き込みを行っている。 図 2.4.1 Pic プログラム書き込みのための Pickit3 - 10 - 第 3 章 容量検知モジュール搭載のオシレータの 設計と製作 3.1 概要 PIC16F1938 の容量検知モジュールを用いることでタッチセンサを搭載しており、 またラダー抵抗回路を使用した 8 ビットの DAC で波形を作成しモノラルサウンド音 を鳴らすユニットである。タッチセンサを利用してみるということと、オシレータを 作成するという目的で、山田達也氏・山本俊一氏著「作れ!音デバイス」を参考に製 作した。また、工夫として音量や周波数をアナログ的に変更できるようにボリューム をつけ、タッチセンサによって出力する波形を変えることで音が変化できるようにし た。図 3.1.1 と図 3.1.2 に製作した回路の外観を示す。 図 3.1.1 容量検知モジュール搭載オシレータの内装 図 3.2.2 容量検知モジュール搭載オシレータの外装 - 11 - 3.2 回路について 回路図を図 3.2.1 に示す。回路の概略は以下のとおりである。 ・電源はアルカリ乾電池またはニッケル水素電池2本で動作する。 ・タッチセンサ入力となる金属板を RB0~RB3 に接続する。 ・周波数変化用のボリュームを RA0 に接続する。 ・RA1、RA2 に 100Ωの抵抗を挟んで LED を接続する。 ・RC ポートはラダー抵抗回路による 8 ビット DAC とする。 ・ラダー回路は同じ抵抗値のものが多いので集合抵抗の 10kΩと 20kΩを2つずつ使 用した。 図 3.2.1 オシレータの回路図 - 12 - 3.3 動作原理 ラダー回路は DAC として動作し、使用したピンの数だけレベルの分割ができる。 ここでは簡略化した出力 3 ポートを利用した 3 ビットの例で説明する。図 3.3.1 でそ れぞれのピン P0、P1、P2 は 1(High)のときに 3V を印加し、0(Low)のときに GND に接続する。そして、P0、P1、P2 のすべての組み合わせを計算すると表 3.3.1 のよう な結果が得られる。 P2 0 0 0 0 1 1 1 1 図 3.3.1 3 ビットのラダー回路 P1 0 0 1 1 0 0 1 1 P0 0 1 0 1 0 1 0 1 10進数 0 1 2 3 4 5 6 7 出力電圧 0 0.375 0.75 1.125 1.5 1.875 2.25 2.625 表 3.3.1 3 ビットラダー回路の出力電圧 3 ビットは 2 の 3 乗=8 段階なので無事に 8 分割することができている。製作した回路 では 8 ポート利用した 8 ビットのラダー回路なので 256 分割した電圧値を得ることが できる。 音は三角波、矩形波、のこぎり波、正弦波のそれぞれを時間で分割した値を RC ポー トに出力し、それをスピーカーに流すことで音を鳴らすことができる。この考えをプロ グラムに反映させるために、それぞれの波形の配列を作成し、それを定期的に読み出す ことで実現している。正弦波の配列に入力する値は次の式で求められる。 255 × {sin ( (入力する値) = 2×π×n 𝑥方向の分割数 2 ) + 1} ここでの n は n 番目のデータの意味である。これを x 方向の分割数を 250 分割、デー タ数を 250 個の条件としてエクセルを使って求めた。その結果求めることのできた配 列が図 3.3.2 のような配列になり、それを RC ポートに出力しラダー抵抗回路で変換す ることによって得られた正弦波が図 3.3.3 になる。 - 13 - 図 3.3.2 正弦波の配列 図 3.3.3 ラダー抵抗回路による DAC で得られた正弦波 周波数をボリュームにて変化させるために RC ポートへの入力を待機時間の変更がし やすいタイマ 2 を使用して実現することにした。その際に行ったタイマ 2 の処理は以 下の通りである。 if(TMR2IF){ TMR2IF=0; if(wavenum==1) PORTC=wavesin[ip]; if(wavenum==2) PORTC=wavetrig[ip]; if(wavenum==3) PORTC=wavesaw[ip]; if(wavenum==4) PORTC=wavehou[ip]; ip++; if(ip==250) ip=0; } 考え方はとても単純で、wavenum の値によって、それぞれ異なる配列から ip 番目のデ ータを取り出している。また main 関数で、周波数を変更するために、以下の処理を行 った。 advalnew=ADRESH; advalnew>>=1; if(adval!=advalnew){ PR2=advalnew+69; - 14 - adval=advalnew; } この処理は ADC によって得られた結果が格納されている ADRESH の値が以前検査し たときの値と違っていれば新しく PR2 に値を入力するというものである。この時 ADRESH には 0 から 255 の間が入力されるので 1 ビット右にシフトしてから 0 から 127 の間の値にし、69 を足すことで、69 から 196 の間の値を作った。これが 1 周期の 時間を決定する。 タッチセンサ入力(静電容量変化検出)は PIC16F1938 に備わっている機能の一つ である。ピンが金属板に接続してあり、指を近づけることで容量性負荷が増加して容 量検知モジュールにおいて周波数シフトが生じることによってセンサとして動作す る。よって非接触でも検出が可能である。PIC における容量検出式入力機構は簡単に 図 3.3.4 に示す。 図 3.3.4 容量変化検出式入力機構の概略 タイマ 0 はクロックとプリスケーラより 16μsec で動いている。タイマ 1 は設定に より 4ms ごとに割り込みがかかる。銅板に電荷がたまり、4msec 後に切り替えにより コンデンサに接続されてコンデンサに電荷がたまると銅板から切り離され、カウンタ に接続される。コンデンサを利用し三角波を発生させる。4msec の間に三角波の頂点 の個数をカウントして、平均を求める。プログラムの tripval で設定した値を超えると 指が近づいたと検出する仕組みになっている。タイマ1での処理のプログラムをまと めたものを図 3.3.5 でフローチャートとして示している。 - 15 - 図 3.3.4 タイマ1の割り込み処理のフローチャート - 16 - この回路の動作例を図 3.3.5~図 3.3.8 に示す。 図 3.3.5 左上をタッチした時の生成波形 図 3.3.6 右上をタッチした時の生成波形 図 3.3.7 左下をタッチした時の生成波形 図 3.3.8 右下をタッチした時の生成波形 - 17 - 第4章 ピカタワーの設計と製作 4.1 概要 ピカタワーとは、6 個×4 段の 24 個のフルカラーLED を制御するユニットである。 株式会社イーケイジャパン社と福岡県立福岡工業高等学校が共同開発プロジェクトに より開発、商品化したピカタワーを参考に製作を行った。工夫を加えた点として、ピ ンの数を増やすために PIC を PIC16F1938 に変更し、それに伴い単色 LED から 3 色 フルカラーLED に変更した。LED の数は減らしたが、段数を 3 段から 4 段に増やし た。完成したピカタワーの外観を図 4.1.1 に示す。 図 4.1.1 ピカタワー外観 4.2 回路について 回路図を図 4.2.1 に示す。回路図では LED の束を省略している。回路の仕様は以下 のとおりである。 ・電源はアルカリ乾電池またはニッケル水素電池2本で動作する。 ・RA0~RA3 を 2SC3325 のベースに R74~R77 =1.2kΩの抵抗を挟んで接続する。 エミッタを GND に接続しコレクタを各列のカソード部に接続する。 ・RA6,RA7,RB1~RB7,RC ポートを各色、各 LED に赤色なら 100Ω、青色または緑 色ならば 20Ωを挟んで接続する。 - 18 - 図 4.2.1 ピカタワー回路図の概略 4.3 動作原理 3 色フルカラーLED を 6 個使用しており、1 つの色につき 10mA の電流を流すの で、1 つの束につき最大 10[mA]×18 個=180[mA]の電流が流れる。PIC16F193x の最 大入力電流が 25mA なので 2SC3325 の NPN 型トランジスタを挟んでいる。設計段階 では 2SC1815 の使用を試みていたが、コレクタ電流の最大が 150mA であり、LED を全て光らせることができないために 2SC3325 を使用することにした。 LED を光るようにする処理は、それぞれの LED に合ったビットが真であれば OR 演算によって光らせることができる。また、行った処理のプログラムの一部を示す。 if(pos==1){ floar|=0x08; if(led1[0]&1) adata|=0x80; if(led1[0]&2) bdata|=0x02; if(led1[0]&4) bdata|=0x04; if(led1[1]&1) bdata|=0x08; if(led1[1]&2) bdata|=0x10; if(led1[1]&4) bdata|=0x20; if(led1[2]&1) bdata|=0x40; if(led1[2]&2) bdata|=0x80; if(led1[2]&4) cdata|=0x01; if(led1[3]&1) cdata|=0x02; if(led1[3]&2) cdata|=0x04; if(led1[3]&4) cdata|=0x08; if(led1[4]&1) cdata|=0x10; - 19 - if(led1[4]&2) cdata|=0x20; if(led1[4]&4) cdata|=0x40; if(led1[5]&1) cdata|=0x80; if(led1[5]&2) adata|=0x10; if(led1[5]&4) adata|=0x40; } この処理を 4 段分行うことによって LED を光らせている。また、各段に電流を供給 するための処理を Timer4 で行っている。Timer2,4,6 の割り込み間隔は (時間) = (PR 設定値 + 1) × プリスケーラ分周比 × クロック周期 × 4 × ポストスケーラ回数 であるので、プリスケーラ 1:4、PR4 の値を 249 に設定し、4MHz のクロックを使用 しているので割り込み間隔は 1msec となる。すべての段の処理をすると、4 段のため に処理時間は 4msec である。しかしながら、ちらつきを感じることはなかったため、 1msec の割り込み間隔でよいと判断した。しかし、点灯処理だけでは上下の段が消え ずに少しだけ光が残ってしまうため、adata,bdata,cdata をそれぞれのポートに代入す る前に PORTA=0; PORTB=0; PORTC=0; と消灯を行うことで光が残ることを防いだ。 また、1 処理での光る時間の違いを出すために、Timer6 を使用した。プリスケーラ を 1:64、ポストスケーラを 1:11、PR6 値を 141 にすることで、約 10msec の割り込み 間隔にし、1 割り込みごとに timecount を 1 増加させて ltime の配列の値になると光 るパターンが次に進むという仕組みである。そのプログラムの一部を以下に示す。 if(timecount==ltime[num+base]){ timecount = 0; num++; if(num==50) num=0; for(i=0;i<6;i++){ led1[i]=pat1[num+base][i]; led2[i]=pat2[num+base][i]; led3[i]=pat3[num+base][i]; led4[i]=pat4[num+base][i]; } } - 20 - その他、ボタンによって光るパターンを変更できるようにした。実際に光っている時 の実行例を図 4.3.1~図 4.3.12 に示す。 図 4.3.1 モード 1 の動作 1 図 4.3.2 モード 1 の動作 2 図 4.3.3 モード 1 の動作 3 図 4.3.4 モード 1 の動作 4 図 4.3.5 モード 1 の動作 5 図 4.3.6 モード 1 の動作 6 - 21 - 図 4.3.7 モード 2 の動作 1 図 4.3.8 モード 2 の動作 2 図 4.3.9 モード 2 の動作 3 図 4.3.10 モード 2 の動作 4 図 4.3.11 モード 2 の動作 5 図 4.3.12 モード 2 の動作 6 - 22 - 第5章 超音波・赤外線距離計の設計と製作 5.1 概要 PIC16F1783 に内蔵してあるオペアンプやコンパレータを使用した回路に挑戦する ことにした。後閑哲也氏著「PIC ではじめるアナログ回路」の超音波距離計の回路図 を参考にさせてもらい、回路シミュレーションソフト LTspice IV を使用して実際にう まく動作するかどうかのチェックを行ってから Eagle で回路図を作成し、回路を製作 した。超音波受信の信号電圧は低いのでオペアンプを 2 個使用し、495 倍にすること で扱いやすい電圧まで増幅する。増幅した信号をコンパレータに通して受信したこと を検出するユニットを作る。表示のための LCD には SC1602BBWB-XA-LB-G を使用 し、赤外距離モジュールは GP2Y0A21YK0F を使用した。この回路の外観を図 5.1.1 に示す。 図 5.1.1 超音波・赤外距離計の外観 5.2 回路について 回路図を図 5.2.1 に示す。回路の仕様は以下のとおりである。 ・電源はアルカリ乾電池またはニッケル水素電池 3 本で動作する。 ・RB0 に赤外距離計のデータを入力する。 ・RC0,RC1 に超音波送信器を 0.1μF のコンデンサを挟んで接続する。 ・表 2.3.3 を参照にオペアンプを使用する。 ・オペアンプで増幅した信号に平滑回路を挟んで RA0 のコンパレータに入力する。 - 23 - ・RB2 の OPA2IN+の入力を差動増幅回路と反転増幅回路を変更できるように SW4 を接続した。 図 5.2.1 超音波・赤外距離計の回路図 5.3 動作説明 最初に超音波受信回路が上手く動作するかシミュレーションで確かめる。超音波受 信センサからは受信と同時にパルス状で 40kHz のパルスが約 1msec 継続する。信号 レベルは受信した信号の強度によって大きく変化するが、およそ数 mV である。よっ てシミュレーションする回路では電源電圧に 4V を使用し、入力信号には 2[mV]、周 波数が 40kHz の信号を使用する。mV オーダーのままでは扱いづらいため、3V 程度 まで増幅する。その結果、約 500 倍のゲインが必要である。これを 1 段で実現するの は無理があるため、2 段構成で初段を 33 倍、次段を 15 倍にすることで 495 倍の増幅 器とした。超音波センサはグランドから浮いているため、初段のオペアンプでは差動 増幅回路を用いる。パルスの有無を検知できればよいため、両波整流し、プラス側の 片側パルスにし、コンパレータに入力して判定するようにする。また単電源回路なの で基準となるオペアンプの+入力端子には電源を 1:1 で抵抗分割した VDD/2 を印加し ている。実際に LTspice IV で行ったシミュレーションの回路を図 5.3.1 に示す。 - 24 - 図 5.3.1 シミュレーションした増幅回路 実際にシミュレーションを行った結果が図 5.3.2、図 5.3.3 である。グラフを見てわ かる通り、振幅がおよそ 1V となっているため、約 500 倍に増幅できている。平滑し た波形はすぐに立ち上がってパルス状の波形に平滑できている。この結果から、コン パレータの基準電圧を 2.5V にすることで検出することができることがわかる。 図 5.3.2 図 5.3.1 をシミュレートし増幅した結果の波形 図 5.3.3 図 5.3.2 を平滑した結果の波形 - 25 - 使用した LCD は「キャラクタ LCD モジュール SC1602BBWB-XA-LB-G」で、外 観を図 5.3.4 に、ピン内容を表 5.3.1 示す。この LCD は白抜き文字表示で、はっきり よく見えるのが特徴である。動作電圧は 2.7V~4.5V だがバックライトが白 LED な ため、電源電圧が 3V 以下だとほとんど発光しないために正しく表示をすることがで きない。そのため 3V 以上の電圧が必要である。コントラスト調整用の半固定抵抗も 必要である。 図 5.3.4 No. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 表 5.3.1 SC1602BBWB-XA-LB-G の外観 端子名 VDD VSS Vo RS R/W E DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7 機能 電源端子 GND端子 コントラスト調整端子 レジスタ選択端子 リード/ライト選択端子 イネーブル信号 データビット0端子 データビット1端子 データビット2端子 データビット3端子 データビット4端子 データビット5端子 データビット6端子 データビット7端子 SC1602BBWB-XA-LB-G のピン内容 この回路に関しては LCD に文字を表示させることに手間取り、実際に超音波の距 離計として動作するかどうかは確認していない。もう少し時間があったらと悔やまれ てならない。 - 26 - 第6章 PIC で構築した音源を組み込んだゲーム回路の 設計と製作 6.1 概要 PIC16F1939 と PIC16F1783 の二つを使用し、PIC16F1939 は主にタッチセンサと LED 点灯、モード管理などを行い、PIC16F1783 は、PIC16F1939 から送られてきた データをもとに音の出力と LCD の表示を担っている。タッチセンサの金属板に LED を取り付け、光ったところをタッチして操作する。モードが進むと、光った LED の 場所をタッチするとタッチした場所に応じた高さの音が鳴る。タッチをすると次の音 に応じた場所の LED が光り、次のタッチをうながす。それを続けると音楽になると いうユニットである。また、自由に音を鳴らすモードとオプションとして波形を変え ることによって音の種類を変えることができるモードがある。この様にゲーム感覚で 音楽を楽しむことができる回路を 2 つの PIC を協調運転することで実現した。 初めに、オペアンプ回路の増幅率の決定のために PIC16F1783 内臓のオペアンプ 一つと BTL アンプモジュールを使用した回路をブレットボード上に図 6.1.1 のよう に組み、どれぐらいの音量で鳴るかを吟味し、DAC によって送られてきた信号を 8 倍になるように設定した。使用した PIC 以外のモジュールは、画面表示には第 5 章 で使用した LCD、SC1602BBWB-XA-LB-G、BLT アンプモジュール、1.5V LED ド ライバモジュール OELLP を使用した。これは LCD のバックライトを 3V の電池で 点灯させることができないので、バックライト用の昇圧回路として動作させるためで ある。 図 6.1.1 増幅率決定のために製作した回路 - 27 - 6.2 最終回路について 最終回路の回路図を図 6.2.1 に示す。回路の仕様は以下のとおりである。試作として 実際に製作した回路が図 6.2.2 である。 ・電源はアルカリ乾電池またはニッケル水素電池2本で動作する。 ・タッチセンサを 16ch 使用し、LED を 4×4 の 16 個使用する。タッチセンサを使用 できるポートは CPS0~15 であり、図 6.2.3 の通り配置した。 ・LCD のバックライトの動作電圧が 3.3V なので OELLP で 4.5V まで昇圧し、アノー ドカソード間に接続する。 ・DAC によって RA2 から出力される信号を内蔵オペアンプと BTL アンプモジュール によって 8 倍に増幅する。 図 6.2.1 PIC で構築した音源を組み込んだゲーム回路 図 6.2.2 試作したタッチゲームの回路 - 28 - 実際に完成した作品の外観を図 6.2.3、内装を図 6.2.4 に示す。この回路はゲーム回 路ということなので、手ごろなサイズに収めるために LCD 部のみ上段の段構造にす ることできれいに収めることができた。 図 6.2.3 実際にケースに入れた完成品の外観 図 6.2.4 完成品の内装 - 29 - 6.3 動作原理 このユニットでは、プログラムによるモード管理においてスイッチ文を用いて制御 している。モード遷移図を図 6.3.1 に示す。 図 6.3.1 タッチゲームのモード遷移図 それぞれのモード移行する条件は、モード 0,1,2,4 は CPS15 をタッチすることであ る。モード 3,6 は CPS4,8 または、CPS7,11 をタッチすることでモードが移行する。 モード 7 からは CPS15、CPS0 、CPS15、CPS0 の順番にタッチすることでモード 2 に移行する。 - 30 - このユニットは PIC 間通信を SPI(Serial Peripheral Interface)通信によって実現 している。この通信の仕組みは図 6.3.2 のようになっている。2 つの SPI のモジュー ルが互いに 3 本または 4 本(SS 信号を使う場合)の線で接続され、片方がマスタ、も う一方がスレーブとなる。グランド線を含めると 4 本または 5 本の線となる。 図 6.3.2 SPI 通信の接続方法 通信はマスタが出力するクロック信号(SCK)を基準にして、互いに向かい合わせて 接続した SDI と SDO で、同時に 1 ビットごとのデータの送受信を行う。常にマス タが主導権を持ち、次の 1~3 のいずれかの種類で 8 ビット単位のデータ通信が行わ れる。 1. マスタからの送信 スレーブが受信すると同時にスレーブからダミーデータが送られるため、マ スタ側にダミーデータが受信される。 2. マスタ、スレーブ同時送信 マスタが送ると同時にスレーブ側も有効なデータを送信する。したがってマ スタ、スレーブ両方に有効なデータが受信される。 3. マスタが受信する ダミーデータがマスタから送信され、同時にスレーブから有効なデータが送 信されマスタ側に届く。 このように、SPI 通信を行うことで 2 つの PIC マイコン同士で簡単に高速通信をし て、データ交換を行うことができる。 実際に動作させるために、SPI 通信制御用レジスタは SSPSTAT、SSPCON1、 SSPCON3 の 3 つのレジスタで制御している。SSPCON1 レジスタ内のビット 5 の SSPEN は SSP 用のピンを使用するかどうかなので必ず high にしておく必要があ り、同じく SSPCON1 レジスタ内のビット 0~3 の SSPM はマスタ側かスレーブ側の 設定を行うため間違えずに設定する。 - 31 - 実際に行った設定のマスタ側を下記のように設定した。 SSPCON1=0b00100000; SSPSTAT=0b00000000; SSPCON3=0b00010000; スレーブ側は下記のように設定した。 SSPCON1=0b00100101; SSPSTAT=0b00000000; SSPCON3=0b00010000; このように設定することによってデータを送受信することができた。 SPI 通信は SPI のバッファに過去のデータが残っているとエラーになるため空読み 出しをし、バッファを空の状態にしてから受信する。また、受信する場合にも何らか のデータを送らないとデータを受信できないのでダミーデータを送信する必要があ る。設定をしたのちに実際に受信するためのプログラムとして下記のような関数を作 成し受信を行った。 unsigned char SPIread(){ unsigned char dumy; dumy = SSPBUF; SSPBUF = 0; while(!BF); return(SSPBUF); } 送信する場合にも空読み出しをして SPI バッファを空にしてから、データを送信す る。毎回ダミー読み出しをしてバッファを空にしておく必要があり、実際に送信する ために使った関数は次の通りであり、これを用いて無事に送信することができた。 void SPIwrite(unsigned char data){ unsigned char dumy; dumy = SSPBUF; SSPBUF = data; while(!BF); dumy = SSPBUF; } - 32 - プログラムを書き始めたころは、両方の PIC でモード管理を行っていたが、それで は PIC 間でのモードがずれてしまうことが起きた。そこで、PIC16F1783 でモードを 変えないようにし、PIC16F1939 でのみモードを変化させることと、現在のモードを 送ることによりモードのずれを回避することができた。また、送信の内容をモードに よって変えることでうまく動作した。送信の内容として表 6.3.1 のようにして送信し た。 モード 0,3,6 1,2,4 5,7 bit 7 bit 6 bit 5 モード モード モード 音を鳴らす bit 4 bit 3 bit 2 bit 1 bit 0 タッチした位置 タッチした位置 選択するもの 音階の情報 表 6.3.1 SPI 通信で送る情報 モード 0,3,6 は単純で常に下位 4 ビットに maxpos(タッチを検出した最大の場所)の 0 ~15 が入る。モード 1,2,4 はそれぞれ選択するモードなので何を選択したかを PIC16F1783 にも送らなければならない。よって選択するものの情報を下位 2 ビット で送り、タッチさせる場所を CPS4(0b00000100)と CPS12(0b00001100)の場所に限定 させることによって上下の動きで選択できるようにした。 製作している中で同音程が連続すると 2 回目以降の音が鳴らない問題が発生し、タ ッチセンサをスイッチのように動作させる必要が生じた。そのため、第 3 章で使用し たアルゴリズムをそのまま使用するだけではうまく動作しないことが分かった。よっ てタイマ 4 割り込みを使用して、スイッチと長押しの防止処理を行った。タイマ 4 割 り込みを 2msec の間隔で処理し、その処理を行うプログラムを以下に示す。 if(TMR4IF){ TMR4IF = 0; maxcond<<=1; if(maxprev == maxpos) { if(onflag[maxpos]) maxcond|=1; } else maxcond = 0; if(maxcond==0xff){ if(!playprev){ playflag=1; } playprev=1; } if(!maxcond) playprev=0; - 33 - maxprev = maxpos; } タッチセンサが反応して確実にタッチしたことを感知できると playflag を 1 度だけ 真にする。1 度離すまで処理ができないようにすることでスイッチのように動作する ことができる。確実にタッチされたことを認知するまでの時間は 8 回割り込みが起 きた時なので 16msec である。よって、100 分の 1 秒レベルの時間での遅れしか発生 しないために一般の人にはラグを感じることはない。 今回使用した BLT アンプモジュールの回路図は図 6.3.3 のようになっている。 図 6.3.3 BTL アンプモジュールの回路図 BLT アンプモジュールの動作として BU7150NUV の内部の上側のオペアンプで 2 倍 の反転増幅回路を構成している。そして、上側のオペアンプで増幅した信号を下側の オペアンプを使用した等倍の反転増幅回路で信号を反転させ、二つの信号を+-それ ぞれの端子に出力することで見かけ上 2 倍にしている。そのため、このアンプのゲ インは 4 倍になる。また、BU7150NUV のピン内容を表 6.3.2 に示す。 - 34 - No. 1 2 3 4 5 6 7 8 9 10 端子名 IN1 SDB MUTEB BYPASS IN2 VSS OUT2 MODE OUT1 VDD 機能 入力端子1 シャットダウン端子 ※1 ミュート端子 ※2 バイパス端子 入力端子2 GND端子 出力端子2 動作モード選択端子 ※3 出力端子1 電源端子 表 6.3.2 BU7150NUV のピン内容 ※1 Low で OFF ※2 Low でミュート ※3 VSS で SE、VDD で BTL 音を出す仕組みとして第 3 章にて説明した DAC を使用した方法を用いる。ただ し、PIC16F1783 には 8 ビットの DAC が内蔵されているので今回はそれを使う。第 3 章では周波数として MAX400Hz だったがそれでは 16 音階用意することができなかっ たため、x方向の分割数を 100 まで減らすことにより 1kHz 程度までの波を用意でき るようになった。これによっての音の乱れなどを感じることはなかったので分割数を 減らすことにした。また、第 3 章と違って決められた音階の音を出さなければならな いので、タイマ 2 を使用し、それぞれの音階の周期にあった割り込み時間で以下のよ うな割り込み処理をすることによって決められた音階を出すことができるようにし た。 if(TMR2IF){ DACCON1 = wavesin[n]; n++; if(n == 100) n = 0; } PR2 を周波数から求めた結果を以下の表 6.3.3 に示す。 - 35 - 音階 周波数(Hz) ラ 220.0 シ 246.9 ド 261.6 レ 293.7 ミ 329.6 ファ 349.2 ソ 392.0 ラ 440.0 シ 493.9 ド 523.2 レ 587.3 ミ 659.3 ファ 698.5 ソ 784.0 ラ 880.0 シ 987.8 ド 1046.5 レ 1174.7 ミ 1318.6 ファ 1397.1 ソ 1568.0 ラ 1760.0 周期(s) 周期(msec) 0.004545 4.55 0.004050 4.05 0.003822 3.82 0.003405 3.41 0.003034 3.03 0.002863 2.86 0.002551 2.55 0.002273 2.27 0.002025 2.02 0.001911 1.91 0.001703 1.70 0.001517 1.52 0.001432 1.43 0.001276 1.28 0.001136 1.14 0.001012 1.01 0.000956 0.96 0.000851 0.85 0.000758 0.76 0.000716 0.72 0.000638 0.64 0.000568 0.57 PR2値 226 201 190 169 151 142 127 113 100 95 84 75 71 63 56 50 47 42 37 35 31 27 表 6.3.3 音階と周波数と PR2 値の関係 この結果をもとにそれぞれの音の PR2 値を決定し、音階としては 220Hz のラの音か ら 16 番目の 987.8Hz のシの音まで使うことにした。理由として、この回路は 20MHz のクロックを使用し、プリスケーラ、ポストスケーラを 1:1 で最速の割り込みの 0.2μ sec で動作させても波形の 1 周期分を出力するために 100 回割り込みがかかること と、割り込み内での処理が終わるまで次の割り込みもかけられないので MAX 約 1kHz の周波数で制限されるからである。 使用する音の PR2 値を配列にし、それを PIC16F1939 から送られてきた maxpos の 値を読みだし、 PR2 = onkai[touch]; と読むことで決まった音階を出力することができた。 - 36 - 6.4 動作確認 本回路を動作させたときの各状態を順に示す。電源を ON にしたとき(モード 0)の動 作を図 6.4.1~図 6.4.3 に示す。 図 6.4.1 電源投入時の最初の動作 図 6.4.2 図 6.4.1 の次の動作 図 6.4.3 図 6.4.2 の次の動作 右下の光っているところタッチすることで、次のモード(モード 2)へ移行することが できた。 - 37 - モード 2 での動作を図 6.4.4~図 6.4.6 に示す。 図 6.4.4 モード 2 の動作 1 図 6.4.5 モード 2 の動作 2 図 6.4.6 モード 2 の動作 3 左の 2 つ光っているところの上の方をタッチすると数字が減り、光っているところ の下の方をタッチすると数字が増え、構想通りに動作した。また、それぞれを選択し ているところで右下をタッチするとそれぞれのモードに移行することができた。 - 38 - モード 3 の動作を図 6.4.7 に示す。 図 6.4.7 モード 3 の動作 構想通りに左側の光っているところをタッチするとモード 2 で選択したモードに進 み、右側の光っているところをタッチするとモード 2 に戻ることができた。 モード 4 での動作を図 6.4.8~図 6.4.10 に示す。 図 6.4.8 モード 4 の動作 1 図 6.4.9 モード 4 の動作 2 - 39 - 図 6.4.10 モード 4 の動作 3 モード 2 と同様に左の 2 つ光っているところの上の方をタッチすると数字が減り、 光っているところの下の方をタッチすると数字が増え、構想通りに動作した。また、 それぞれを選択しているところで右下をタッチするとそれぞれのモードに移行するこ とができた。 モード 5 の動作として「チューリップ」の曲を選んだ時の 3 音目までを図 6.4.11~ 図 6.4.13 に示す。また、残りのどんぐりころころと夕焼け小焼けの曲を選んだ時の 1 音目を図 6.4.14、図 6.4.15 に示す。 図 6.4.11 モード 5 の動作 1 図 6.4.12 モード 5 の動作 2 - 40 - 図 6.4.13 モード 5 の動作 3 図 6.4.14 モード 5 の動作 4 図 6.4.15 モード 5 の動作 5 光っているところをタッチすることで位置に対応する音が鳴り、次の光ったところ をタッチしていくことで音楽になっていることが確認できた。また、同音が連続して いるときも音が鳴ることが確認できた。他の曲も同様に確認することができた。 - 41 - モード 6 の動作を図 6.4.16 に示す。 図 6.4.16 モード 6 の動作 左側の光っているところをタッチするとモード 4 の曲を選ぶ画面になり、右側の光 っているところをタッチするとモード 2 のモードセレクト画面に移行することができ た。 モード 1(オプション)の動作を図 6.4.17~図 6.4.19 に示す。 図 6.4.17 モード 1 の動作 1 図 6.4.18 モード 1 の動作 2 - 42 - 図 6.4.19 モード 1 の動作 3 選択する動作はモード 2、4 と同様の動作をし、選択するとモード 2 のモードセレ クト画面に移行できた。このモードで選択した波形の音を音が鳴るモードで音が変わ ることを確認することができた。 モード 7(フリーモード)の動作を図 6.4.20 に示す。 図 6.4.20 モード 7 の動作 タッチした箇所に対応した音が鳴り、また一瞬ではあるがタッチしたところの LED が光ることが確認できた。左上と右下を交互に左上から 2 回繰り返すことでモードセ レクト画面が表示されモード 2 に移行することができた。 - 43 - まとめ 研究の目的として、回路の理解力や製作能力向上をあげたが、作品を製作していく過 程でどういった効果があるのか確認していき、大きめな回路でも作成できるようにな ったので自分なりに向上したと思われる。ピカタワーや最終作品では宙に浮かしたま ま配線しなければならない場面がいくらか登場したため、はんだ付けの技術も研究を 始めたころに比べ、かなり向上したと言える。 プログラムに関しては、様々な用途の回路に書き込んでいくごとに向上している。 PIC におけるプログラミングはハードウェアに指示を出すだけでなく回路上必要な機 能を PIC 内蔵の機能で実現するために上手に設定する必要がある。その設定を間違え るとうまく動作しない場面に遭遇し、何度も手が止まることがあった。またハードウ ェアとのかかわりにより、今までのパソコンで実行するプログラムと違い、外部の 様々な影響を受ける。グランドに落ちてはいけない線が知らないうちにつながってい たことがあり、そのことが原因であることを見つけるため試行錯誤した。このような 問題も面倒ではあるが、それを見つけた時の安心感や何が起きるかわからないという 期待感はいい体験になったとできたと思う。 - 44 - 謝辞 今回の卒業研究ならびに卒業論文を作成するにあたり、終始に丁寧かつ熱心なご指 導とご助成を賜りました高知工科大学システム工学群電子工学専攻綿森 道夫准教授 に心から感謝申し上げます。本研究は綿森 道夫准教授のご助成がなければ完成に至 らなかったと思います。 また高知工科大学システム工学群電子工学専攻在学中に本研究実行遂行や学生生 活、その他各課程で終始ご厚意と協力を頂きました、高知工科大学システム工学群長 岩下 克教授、八田 章光教授、橘 昌良教授、真田 克教授、山本 真行教授、星野 孝総准教授、古田 寛准教授、密山 幸男准教授、小林 弘和講師、松谷 朝美秘書、中 山 愛秘書の皆様には重ねて感謝の意を述べさせて頂きます。 - 45 - 参考文献 卒業研究するにあたり、参考にさせていただきました。この場を借りて感謝申しあ けます。 ・第 4 版 独習 C ハーバート・シルト 著 : 翔泳社 ・作れ!音デバイス 山田 達也 ・ 山本 俊一郎 著 :ワークスコーポレーション ・改訂版 電子工作のための PIC16F 活用ガイドブック 後閑 哲也 著 : 技術評論社 ・改訂版 電子工作のための PIC16F1 活用ガイドブック 後閑 哲也 著 : 技術評論社 ・PIC マイコンの基礎 後閑 哲也 著 : 毎日コミュニケーションズ ・ボクの電子工作ノート 鈴木 哲哉 著 : ラトルズ出版 ・基礎入門 センサ活用の素① 後閑 著 : 技術評論社 哲也 ・世界で 1 台のオリジナル・アナログシンセを作る 達人と作るアナログシンセサイザー自作入門 岩上 直樹 著 : ラトルズ出版 ・PIC ではじめるアナログ回路 後閑 哲也 著 : 技術評論社 - 46 - 付録 プログラムリスト 容量検知モジュール搭載のオシレータ プログラム - 47 - #include <pic.h> #define _XTAL_FREQ #define TRIP0 20 4000000 //コンパイラにクロック 20MHz 使用を教える //指の検出距離を決定する。小さいほど遠くまで検出できる。 #define TRIP1 20 #define TRIP2 20 #define TRIP3 20 #define TRIP4 20 #define TRIP5 20 #define TRIP6 20 #define TRIP7 20 #define CHMAX 4 const unsigned int tripval[8] = { TRIP0, TRIP1, TRIP2, TRIP3, TRIP4, TRIP5, TRIP6, TRIP7 }; const unsigned char wavetrig[250]={0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30, 32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80, 82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122, 124,126,128,130,132,134,136,138,140,142,144,148,150,152,154,156,158,160,162, 164,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202, 204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240, 242,244,246,248,250,248,246,244,242,240,238,236,234,232,230, 228,226,224,222,220,218,216,214,212,210,208,206,204,202,200,198,196,194,192, 190,188,186,184,182,180,178,176,174,172,170,168,166,164,162,160,158,156,154, 152,150,148,146,144,142,140,138,136,134,132,130,128,126,124,122,120,118,116, 114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70, 68,66,64,62,60,58,56,54,52,50,48,46,44,42,40,38,36,34,32,30,28,26,24,20,18, 16,14,12,10,8,6,4,2 }; - 48 - const unsigned char wavesin[250]={128,131,134,137,140,143,147,150,153,156,159,162, 165,168,171,174,177,180,183,186,189,192,194,197,200,202,205,208,210,212,215, 217,219,222,224,226,228,230,232,233,235,237,238,240,241,243,244,245,247,248, 249,250,251,251,252,253,253,254,254,255,255,255,255,255,255,255,255,254,254, 253,253,252,251,251,250,249,248,247,245,244,243,241,240,238,237,235,233,232, 230,228,226,224,222,219,217,215,212,210,208,205,202,200,197,194,192,189,186, 183,180,177,174,171,168,165,162,159,156,153,150,147,143,140,137,134,131,128, 124,121,118,115,112,108,105,102,99,96,93,90,87,84,81,78,75,72,69,66,63,61,58, 55,53,50,47,45,43,40,38,36,33,31,29,27,25,23,22,20,18,17,15,14,12,11,10,8,7,6, 5,4,4,3,2,2,1,1,0,0,0,0,0,0,0,0,1,1,2,2,3,4,4,5,6,7,8,10,11,12,14,15,17,18,20, 22,23,25,27,29,31,33,36,38,40,43,45,47,50,53,55,58,61,63,66,69,72,75,78,81,84, 87,90,93,96,99,102,105,108,112,115,118,121,124 }; const unsigned char wavesaw[250]={0,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,32,33,34,35,36,37,38,39,40,41,42,43, 44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68, 69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93, 94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113, 114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132, 133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151, 152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170, 171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189, 190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, 209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227, 228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246, 247,248,249 }; const unsigned char wavehou[250]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,250,250,250,250,250,250,250,250,250,250,250,250,250,250, 250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,25 0, 250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, - 49 - 250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,25 0, 250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,25 0, 250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,25 0,250,250,250,250,250,250,250,250,250,250,250,250 }; unsigned char checkflag, channel, onflag[8]; unsigned char i, j, maxpos, posflag; unsigned char wave,ip,derec,wavenum; unsigned char adval,advalnew; unsigned int raw, temp, maxlevel; unsigned int average[8], level[8]; void main() { OSCCON=0b01101000; ANSELA = 0b00000001; //RA0 のみアナログ入力 ANSELB = 0b00001111; //RB0-RB3 がアナログ入力 OPTION_REG = 0b10000011; // pre-scaler 1:64 TRISA = 0b11111001; //RA0 は入力,RA1,RA2 は出力、RA3-RA5 が入 TRISB = 0b00001111; //RB0-RB3 は入力,RB4-RB7 が出力 力 TRISC = 0; //全出力 FVRCON = 0b10001000; //FVR=2.048V DACCON0 = 0b11001000; //DACPSS=FVR DACNSS=VSS DACCON1 = 1; CPSCON0 = 0b11001100; // DAC 電圧は 2.048/32 * 1 // タッチセンスオン、FVR,DA コンバータ利用 High レンジ CPSCON1 = 0; TMR1H = 0; - 50 - TMR1L = 0; T1CON = 0b11000101; // タッチセンス利用、1:1、非同期、タイマー1 T1GCON = 0b11100001; // ゲート機能有効、タイマー0 利用 T2CON=0b00000100; //prescalar 1:1 postscaler 1:1 PR2=99; //20μsec オン TMR2IF=0; TMR2IE=1; //タイマー2割り込み許可 TMR1GIF = 0; TMR1GIE = 1; ADCON1=0b00100000; //Fosc/32, VDD-VSS, 左詰め ADCON0=0b00000001; //channel AN0 AD on for ( i = 0; i < 8; i++ ) { average[i] = 0; onflag[i] = 0; } checkflag = 0; channel = 0; wave=0; derec=1; ip=0; wavenum=1; adval=0; INTCON = 0b11000000; // gie = 1, geie = 1 while (1) { GO_nDONE=1; //A/D 変換開始 if(onflag[maxpos]) wavenum=maxpos+1; - 51 - switch(wavenum){ case 1: RA1=1; RA2=0; break; case 2: RA1=0; RA2=1; break; case 3: RA1=1; RA2=1; break; case 4: default: RA1=0; RA2=0; } advalnew=ADRESH; advalnew>>=1; if(adval!=advalnew){ PR2=advalnew+69; adval=advalnew; } /* if(wave==255) derec=0; if(!wave) derec=1; if(derec) wave++; if(!derec) wave--; PORTC=wave; __delay_us(5); */ } } void interrupt detecttouch(void) { - 52 - if(TMR2IF) { TMR2IF=0; if(wavenum==1) PORTC=wavesin[ip]; if(wavenum==2) PORTC=wavetrig[ip]; if(wavenum==3) PORTC=wavesaw[ip]; if(wavenum==4) PORTC=wavehou[ip]; ip++; if(ip==250) ip=0; } if(TMR1GIF) { TMR1GIF = 0; raw = TMR1H * 256 + TMR1L; if ( !onflag[channel] ) { if ( raw >= average[channel]) average[channel] = average[channel] + (raw average[channel])/16; else { temp = (average[channel] - raw)/16; if ( average[channel] > temp ) average[channel] = average[channel] - temp; else average[channel] = 0; } } if ( average[channel] > raw ) level[channel] = average[channel] - raw; else level[channel] = 0; if ( level[channel] > tripval[channel] ) onflag[channel] = 1; else onflag[channel] = 0; channel++; if (channel == CHMAX) { channel = 0; maxlevel = 0; for (j = 0; j < CHMAX; j++) - 53 - if (level[j] > maxlevel ) { maxlevel = level[j]; maxpos = j; } posflag = 1; } TMR1ON = 0; CPSCON1 = channel; TMR1H = 0; TMR1L = 0; TMR1ON = 1; checkflag = 1; } } - 54 - ピカタワーのプログラム - 55 - #include<pic.h> __CONFIG(FOSC_INTOSC & WDTE_OFF & MCLRE_OFF & PWRTE_ON & BOREN_OFF); __CONFIG(WRT_OFF & PLLEN_OFF & STVREN_OFF & BORV_19 & LVP_OFF); #define _XTAL_FREQ 4000000 unsigned char pos; unsigned char swpush,swprev,swcond; unsigned char led1[6],led2[6],led3[6],led4[6]; unsigned char i,num; unsigned char adata,bdata,cdata; unsigned char floar; unsigned char base; unsigned int timecount; const unsigned char pat1[100][6]={ {0,0,0,0,0,1}, {0,0,0,0,1,2}, {0,0,0,1,2,4}, {0,0,1,2,4,0}, {0,1,2,4,0,0}, {1,2,4,0,0,0}, {2,4,0,0,0,1}, {4,0,0,0,0,3}, {0,0,0,0,0,7}, {1,0,0,0,1,7}, //10 {0,1,0,1,0,7}, {0,0,1,0,0,7}, {2,0,1,0,2,7}, {0,2,1,2,0,7}, - 56 - {0,0,3,0,0,7}, {4,0,3,0,4,7}, {0,4,3,4,0,7}, {0,0,7,0,0,7}, {0,0,7,0,0,7}, {0,0,7,0,0,7}, //20 {0,0,7,0,0,7}, {0,1,6,0,1,6}, {1,2,4,1,2,4}, {2,4,1,2,4,1}, {4,0,3,4,0,3}, {0,0,7,0,0,7}, {1,0,6,1,0,6}, {2,1,4,2,1,4}, {4,2,1,4,2,1}, {0,4,3,0,4,3}, //30 {0,0,7,0,0,7}, {1,0,7,0,1,7}, {0,1,7,1,0,7}, {2,1,7,1,2,7}, {0,3,7,3,0,7}, {4,3,7,3,4,7}, {0,7,7,7,0,7}, {1,7,7,7,1,7}, {3,7,7,7,3,7}, {7,7,7,7,7,7}, //40 {7,7,7,7,7,7}, {7,7,7,7,7,7}, - 57 - {7,7,7,7,7,7}, {7,7,0,7,7,7}, {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, //50 {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {1,0,0,0,0,0}, {1,0,0,0,0,0}, {1,3,0,0,0,5}, {1,3,0,0,0,5}, {1,3,2,0,4,5}, {1,3,2,0,4,5}, {1,3,2,6,4,5}, //60 {0,3,2,6,4,5}, {0,3,2,6,4,5}, {0,0,2,6,4,0}, {0,0,2,6,4,0}, {0,0,0,6,0,0}, {0,0,0,6,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, //70 - 58 - {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,1}, {1,0,1,0,1,2}, {2,1,2,1,2,4}, {4,2,4,2,4,0}, {0,4,0,4,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, //80 {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,1,0,0,0}, {0,1,3,1,0,0}, {1,3,7,3,1,0}, {3,7,7,7,3,1}, {7,7,7,7,7,3}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, //90 {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,0,7,7,7}, {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, - 59 - {0,0,0,0,0,0} //100 }; const unsigned char pat2[100][6]={ {0,0,0,0,0,1}, {0,0,0,0,1,2}, {0,0,0,1,2,4}, {0,0,1,2,4,0}, {0,1,2,4,0,0}, {1,2,4,0,0,0}, {2,4,0,0,0,1}, {4,0,0,0,0,3}, {0,0,0,0,0,7}, {0,0,0,0,0,7}, //10 {1,0,0,0,1,7}, {0,1,0,1,0,7}, {0,0,1,0,0,7}, {2,0,1,0,2,7}, {0,2,1,2,0,7}, {0,0,3,0,0,7}, {4,0,3,0,4,7}, {0,4,3,4,0,7}, {0,0,7,0,0,7}, {0,0,7,0,0,7}, //20 {0,0,7,0,0,7}, {0,1,6,0,1,6}, {1,2,4,1,2,4}, {2,4,1,2,4,1}, {4,0,3,4,0,3}, {0,0,7,0,0,7}, - 60 - {1,0,6,1,0,6}, {2,1,4,2,1,4}, {4,2,1,4,2,1}, {0,4,3,0,4,3}, //30 {0,0,7,0,0,7}, {0,0,7,0,0,7}, {1,0,7,0,1,7}, {0,1,7,1,0,7}, {2,1,7,1,2,7}, {0,3,7,3,0,7}, {4,3,7,3,4,7}, {0,7,7,7,0,7}, {1,7,7,7,1,7}, {3,7,7,7,3,7}, //40 {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,0,7,7,7}, {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, //50 {0,0,0,0,0,0}, {0,0,0,0,0,0}, {1,0,0,0,0,0}, {1,0,0,0,0,0}, - 61 - {1,3,0,0,0,5}, {1,3,0,0,0,5}, {1,3,2,0,4,5}, {1,3,2,0,4,5}, {1,3,2,6,4,5}, {1,3,2,6,4,5}, //60 {1,3,2,6,4,5}, {0,3,2,6,4,5}, {0,3,2,6,4,5}, {0,0,2,6,4,0}, {0,0,2,6,4,0}, {0,0,0,6,0,0}, {0,0,0,6,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, //70 {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,1}, {1,0,0,0,1,2}, {2,0,0,0,2,4}, {4,0,0,0,4,0}, {0,0,1,0,0,0}, {0,1,2,1,0,0}, {0,2,4,2,0,0}, {0,4,0,4,0,0}, //80 {0,0,0,0,0,0}, {0,0,0,0,0,0}, - 62 - {0,0,1,0,0,0}, {0,1,2,1,0,0}, {1,2,4,2,1,0}, {2,4,7,4,2,1}, {4,7,7,7,4,2}, {7,7,7,7,7,4}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, //90 {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,0,7,7,7}, {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0} //100 }; const unsigned char pat3[100][6]={ {0,0,0,0,0,1}, {0,0,0,0,1,2}, {0,0,0,1,2,4}, {0,0,1,2,4,0}, {0,1,2,4,0,0}, {1,2,4,0,0,0}, {2,4,0,0,0,1}, {4,0,0,0,0,3}, - 63 - {0,0,0,0,0,7}, {0,0,0,0,0,7}, //10 {0,0,0,0,0,7}, {1,0,0,0,1,7}, {0,1,0,1,0,7}, {0,0,1,0,0,7}, {2,0,1,0,2,7}, {0,2,1,2,0,7}, {0,0,3,0,0,7}, {4,0,3,0,4,7}, {0,4,3,4,0,7}, {0,0,7,0,0,7}, //20 {0,0,7,0,0,7}, {0,1,6,0,1,6}, {1,2,4,1,2,4}, {2,4,1,2,4,1}, {4,0,3,4,0,3}, {0,0,7,0,0,7}, {1,0,6,1,0,6}, {2,1,4,2,1,4}, {4,2,1,4,2,1}, {0,4,3,0,4,3}, //30 {0,0,7,0,0,7}, {0,0,7,0,0,7}, {0,0,7,0,0,7}, {1,0,7,0,1,7}, {0,1,7,1,0,7}, {2,1,7,1,2,7}, - 64 - {0,3,7,3,0,7}, {4,3,7,3,4,7}, {0,7,7,7,0,7}, {1,7,7,7,1,7}, //40 {3,7,7,7,3,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,0,7,7,7}, {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, //50 {0,0,0,0,0,0}, {1,0,0,0,0,0}, {1,0,0,0,0,0}, {1,3,0,0,0,5}, {1,3,0,0,0,5}, {1,3,2,0,4,5}, {1,3,2,0,4,5}, {1,3,2,6,4,5}, {1,3,2,6,4,5}, {1,3,2,6,4,5}, //60 {1,3,2,6,4,5}, {1,3,2,6,4,5}, {0,3,2,6,4,5}, {0,3,2,6,4,5}, - 65 - {0,0,2,6,4,0}, {0,0,2,6,4,0}, {0,0,0,6,0,0}, {0,0,0,6,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, //70 {0,0,0,0,0,0}, {0,0,0,0,0,1}, {1,0,0,0,1,2}, {2,0,0,0,2,4}, {4,0,0,0,4,0}, {0,0,0,0,0,0}, {0,0,1,0,0,0}, {0,1,2,1,0,0}, {0,2,4,2,0,0}, {0,4,0,4,0,0}, //80 {0,0,0,0,0,0}, {0,0,1,0,0,0}, {0,1,2,1,0,0}, {1,2,4,2,1,0}, {2,4,7,4,2,1}, {4,7,7,7,4,2}, {7,7,7,7,7,4}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, //90 {7,7,7,7,7,7}, {7,7,0,7,7,7}, - 66 - {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0} //100 }; const unsigned char pat4[100][6]={ {0,0,0,0,0,1}, {0,0,0,0,1,2}, {0,0,0,1,2,4}, {0,0,1,2,4,0}, {0,1,2,4,0,0}, {1,2,4,0,0,0}, {2,4,0,0,0,1}, {4,0,0,0,0,3}, {0,0,0,0,0,7}, {0,0,0,0,0,7}, //10 {0,0,0,0,0,7}, {0,0,0,0,0,7}, {1,0,0,0,1,7}, {0,1,0,1,0,7}, {0,0,1,0,0,7}, {2,0,1,0,2,7}, {0,2,1,2,0,7}, {0,0,3,0,0,7}, - 67 - {4,0,3,0,4,7}, {0,4,3,4,0,7}, //20 {0,0,7,0,0,7}, {0,1,6,0,1,6}, {1,2,4,1,2,4}, {2,4,1,2,4,1}, {4,0,3,4,0,3}, {0,0,7,0,0,7}, {1,0,6,1,0,6}, {2,1,4,2,1,4}, {4,2,1,4,2,1}, {0,4,3,0,4,3}, //30 {0,0,7,0,0,7}, {0,0,7,0,0,7}, {0,0,7,0,0,7}, {0,0,7,0,0,7}, {1,0,7,0,1,7}, {0,1,7,1,0,7}, {2,1,7,1,2,7}, {0,3,7,3,0,7}, {4,3,7,3,4,7}, {0,7,7,7,0,7}, //40 {1,7,7,7,1,7}, {3,7,7,7,3,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, - 68 - {7,7,0,7,7,7}, {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, //50 {1,0,0,0,0,0}, {1,0,0,0,0,0}, {1,3,0,0,0,5}, {1,3,0,0,0,5}, {1,3,2,0,4,5}, {1,3,2,0,4,5}, {1,3,2,6,4,5}, {1,3,2,6,4,5}, {1,3,2,6,4,5}, {1,3,2,6,4,5}, //60 {1,3,2,6,4,5}, {1,3,2,6,4,5}, {1,3,2,6,4,5}, {0,3,2,6,4,5}, {0,3,2,6,4,5}, {0,0,2,6,4,0}, {0,0,2,6,4,0}, {0,0,0,6,0,0}, {0,0,0,6,0,0}, {0,0,0,0,0,7}, //70 {0,0,0,0,0,7}, {1,0,0,0,1,7}, {2,0,0,0,2,7}, {4,0,0,0,4,7}, - 69 - {0,0,0,0,0,7}, {0,0,0,0,0,7}, {0,0,0,0,0,7}, {0,0,1,0,0,7}, {0,1,3,1,0,7}, {0,3,7,3,0,7}, //80 {0,7,7,7,0,7}, {0,7,7,7,0,7}, {1,7,7,7,1,7}, {2,7,7,7,2,7}, {4,7,7,7,4,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, {7,7,7,7,7,7}, //90 {7,7,0,7,7,7}, {7,0,0,0,7,7}, {0,0,0,0,0,7}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0} //100 }; const unsigned int ltime[100]={ 2,2,2,2,2,2,2,2,2,2, - 70 - 2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,4,2,2,2,2, 2,3,3,3,3,3,3,3,3,3, 3,3,4,3,2,2,2,2,2,2, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 3,2,2,2,2,2,2,3,3,3, 1,1,1,1,1,1,1,0,0,0 }; void main(void){ OSCCON=0b01101000; // f=4MHz OPTION_REG=0b00000010; // enable weak ptiscalar ANSELB=0; ANSELA=0b00100000; TRISA=0b00100000; // RA0-3 TRISB=0b00000001; // RB0 for switch, other pins for LED TRISC=0; WPUB=0b00000001; // // RA4-7 dig1-4 all output RB0 weak pull ups PORTA=0; PORTB=0; PORTC=0; swpush=swprev=swcond=0; T4CON=0b00000101; PR4=249; T6CON=0b01010111; PR6=141; num = 0; - 71 - for(i=0;i<6;i++) { led1[i]=pat1[0][i]; led2[i]=pat2[0][i]; led3[i]=pat3[0][i]; led4[i]=pat4[0][i]; } pos=1; floar=0; base=0; timecount=0; TMR4IF=0; TMR4IE=1; TMR6IF=0; TMR6IE=1; INTCON=0b11000000; while(1){ if(timecount==ltime[num+base]){ timecount = 0; num++; if(num==50) num=0; for(i=0;i<6;i++){ led1[i]=pat1[num+base][i]; led2[i]=pat2[num+base][i]; led3[i]=pat3[num+base][i]; led4[i]=pat4[num+base][i]; } } - 72 - if(swpush){ swpush=0; if(!base) base=50; else base=0; num=0; } } } interrupt isr1msec(void){ if(TMR4IF){ TMR4IF=0; swcond<<=1; if(!RB0) swcond|=1; if(swcond==0xff){ if(!swprev){ swpush=1; } swprev=1; } if(!swcond) swprev=0; adata=bdata=cdata=0; floar=0; if(pos==1){ floar|=0x08; if(led1[0]&1) adata|=0x80; if(led1[0]&2) bdata|=0x02; - 73 - if(led1[0]&4) bdata|=0x04; if(led1[1]&1) bdata|=0x08; if(led1[1]&2) bdata|=0x10; if(led1[1]&4) bdata|=0x20; if(led1[2]&1) bdata|=0x40; if(led1[2]&2) bdata|=0x80; if(led1[2]&4) cdata|=0x01; if(led1[3]&1) cdata|=0x02; if(led1[3]&2) cdata|=0x04; if(led1[3]&4) cdata|=0x08; if(led1[4]&1) cdata|=0x10; if(led1[4]&2) cdata|=0x20; if(led1[4]&4) cdata|=0x40; if(led1[5]&1) cdata|=0x80; if(led1[5]&2) adata|=0x10; if(led1[5]&4) adata|=0x40; } if(pos==2){ floar|=0x04; if(led2[0]&1) adata|=0x80; if(led2[0]&2) bdata|=0x02; if(led2[0]&4) bdata|=0x04; if(led2[1]&1) bdata|=0x08; if(led2[1]&2) bdata|=0x10; if(led2[1]&4) bdata|=0x20; if(led2[2]&1) bdata|=0x40; if(led2[2]&2) bdata|=0x80; if(led2[2]&4) cdata|=0x01; if(led2[3]&1) cdata|=0x02; if(led2[3]&2) cdata|=0x04; if(led2[3]&4) cdata|=0x08; - 74 - if(led2[4]&1) cdata|=0x10; if(led2[4]&2) cdata|=0x20; if(led2[4]&4) cdata|=0x40; if(led2[5]&1) cdata|=0x80; if(led2[5]&2) adata|=0x10; if(led2[5]&4) adata|=0x40; } if(pos==3){ floar|=2; if(led3[0]&1) adata|=0x80; if(led3[0]&2) bdata|=0x02; if(led3[0]&4) bdata|=0x04; if(led3[1]&1) bdata|=0x08; if(led3[1]&2) bdata|=0x10; if(led3[1]&4) bdata|=0x20; if(led3[2]&1) bdata|=0x40; if(led3[2]&2) bdata|=0x80; if(led3[2]&4) cdata|=0x01; if(led3[3]&1) cdata|=0x02; if(led3[3]&2) cdata|=0x04; if(led3[3]&4) cdata|=0x08; if(led3[4]&1) cdata|=0x10; if(led3[4]&2) cdata|=0x20; if(led3[4]&4) cdata|=0x40; if(led3[5]&1) cdata|=0x80; if(led3[5]&2) adata|=0x10; if(led3[5]&4) adata|=0x40; } if(pos==4){ floar|=1; if(led4[0]&1) adata|=0x80; - 75 - if(led4[0]&2) bdata|=0x02; if(led4[0]&4) bdata|=0x04; if(led4[1]&1) bdata|=0x08; if(led4[1]&2) bdata|=0x10; if(led4[1]&4) bdata|=0x20; if(led4[2]&1) bdata|=0x40; if(led4[2]&2) bdata|=0x80; if(led4[2]&4) cdata|=0x01; if(led4[3]&1) cdata|=0x02; if(led4[3]&2) cdata|=0x04; if(led4[3]&4) cdata|=0x08; if(led4[4]&1) cdata|=0x10; if(led4[4]&2) cdata|=0x20; if(led4[4]&4) cdata|=0x40; if(led4[5]&1) cdata|=0x80; if(led4[5]&2) adata|=0x10; if(led4[5]&4) adata|=0x40; } PORTA=0; PORTB=0; PORTC=0; PORTA=adata|floar; PORTB=bdata; PORTC=cdata; pos++; if(pos==5) pos=1; if(TMR6IF){ - 76 - TMR6IF=0; timecount++; } } } - 77 - 超音波・赤外線距離計 LCD 表示のためのプログラム - 78 - #include <pic.h> #include <stdio.h> #include <stdlib.h> #include <xc.h> // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. // CONFIG1 #pragma config FOSC = HS // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = OFF #pragma config CLKOUTEN = OFF // Brown-out Reset Enable (Brown-out Reset disabled) // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable bit (Vcap - 79 - functionality is disabled on RA6.) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LPBOR = OFF // Low Power Brown-Out Reset Enable Bit (Low power brown-out is disabled) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) #define _XTAL_FREQ 8000000 //コンパイラにクロック 20MHz 使用を教える void init_lcd(void); void disp_pos(unsigned char row, unsigned char col); void lcd_1moji(unsigned char moji); void lcd_num(unsigned char n); unsigned char n,count; /* * */ int main(int argc, char** argv) { ANSELA = 0b00000011; //RA0 のみアナログ入力 ANSELB = 0b00001111; //RB0-RB3 がアナログ入力 OPTION_REG = 0b10000011; // pre-scaler 1:64 TRISA = 0b11110001; //RA0 は入力,RA1,RA2 は出力、RA3-RA5 が入 TRISB = 0b11001101; //RB0-RB3 は入力,RB4-RB7 が出力 力 - 80 - TRISC = 0; //全出力 WPUB=0b110000000; FVRCON=0b10000011; ADCON0=0b00110001; ADCON1=0b00010000; ADCON2=0b00001111; RB5=1; init_lcd(); disp_pos(1,0); lcd_1moji('I'); lcd_1moji('R'); lcd_1moji('_'); lcd_1moji('D'); lcd_1moji('i'); lcd_1moji('s'); lcd_1moji('t'); lcd_1moji('a'); lcd_1moji('n'); lcd_1moji('c'); lcd_1moji('e'); disp_pos(2,10); lcd_1moji('c'); lcd_1moji('m'); while(1){ GO_nDONE=1; while(GO_nDONE){} - 81 - n=ADRESH; disp_pos(2,7); lcd_num(n); for(count=0;count<5;count++) __delay_ms(100); } return (EXIT_SUCCESS); } void init_lcd(void){ __delay_ms(40); PORTC=0b00110000; //DB7-4-> 0011 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_ms(5); PORTC=0b00110000; //DB7-4-> 0011 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_us(150); PORTC=0b00110000; //DB7-4-> 0011 RS->0 E->0 RC3=1; NOP(); RC3=0; - 82 - __delay_us(40); PORTC=0b00100000; //DB7-4-> 0010 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_us(40); PORTC=0b00100000; //DB7-4-> 0010 RS->0 E->0 RC3=1; NOP(); RC3=0; PORTC=0b10000000; //DB7-4-> 0000 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_us(40); PORTC=0b00000000; //DB7-4-> 0000 RS->0 E->0 RC3=1; NOP(); RC3=0; PORTC=0b10000000; //DB7-4-> 1000 RS->0 E->0 RC3=1; NOP(); RC3=0; - 83 - __delay_us(40); PORTC=0b00000000; //DB7-4-> 0000 RS->0 E->0 RC3=1; NOP(); RC3=0; PORTC=0b00010000; //DB7-4-> 1000 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_ms(2); PORTC=0b00000000; //DB7-4-> 0010 RS->0 E->0 RC3=1; NOP(); RC3=0; PORTC=0b01100000; //DB7-4-> 0000 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_us(40); PORTC=0b00000000; //DB7-4-> 0000 RS->0 E->0 RC3=1; NOP(); RC3=0; - 84 - PORTC=0b11110000; //DB7-4-> 1000 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_us(40); } void disp_pos(unsigned char row, unsigned char col){ if(row==1) PORTC=0b10000000; else if(row==2) PORTC=0b11000000; else return; RC3=1; NOP(); RC3=0; if(col>15) col=0; PORTC=col<<4; //DB7-4-> 0000 RS->0 E->0 RC3=1; NOP(); RC3=0; __delay_us(40); } void lcd_1moji(unsigned char moji){ PORTC=(moji & 0b11110000)|0b00000100; - 85 - //DB7-4-> 0000 RS->1 E->0 RC3=1; NOP(); RC3=0; PORTC=(moji & 0b00001111)<<4 | 0b00000100; RC3=1; NOP(); RC3=0; __delay_us(40); } void lcd_num(unsigned char n){ unsigned char ans100,ans10; ans100=n/100; if(ans100>0) lcd_1moji(ans100+'0'); else lcd_1moji(' '); n-=ans100*100; ans10=n/10; if((ans100>0)||(ans10>0)) lcd_1moji(ans10+'0'); else lcd_1moji(' '); n-=ans10*10; lcd_1moji(n+'0'); } - 86 - //DB7-4-> 1000 RS->1 E->0 最終作品 PIC16F1939 に書き込んだプログラム - 87 - #include <stdio.h> #include <stdlib.h> #include <xc.h> #include <pic.h> // CONFIG1 #pragma config FOSC = HS // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = OFF #pragma config CLKOUTEN = OFF // Brown-out Reset Enable (Brown-out Reset disabled) // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable bit (Vcap functionality is disabled on RA6.) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack - 88 - Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) #define _XTAL_FREQ 20000000 // 20MHz #define TRIP0 10 #define TRIP1 10 #define TRIP2 10 #define TRIP3 10 #define TRIP4 10 #define TRIP5 10 #define TRIP6 10 #define TRIP7 10 #define TRIP8 10 #define TRIP9 10 #define TRIP10 10 #define TRIP11 10 #define TRIP12 10 #define TRIP13 10 #define TRIP14 10 #define TRIP15 10 #define CHMAX 16 void ledflash(unsigned char pos); - 89 - void SPIwrite(unsigned char data); void Writesound(unsigned char data); const unsigned int tripval[16] = { TRIP0, TRIP1, TRIP2, TRIP3, TRIP4, TRIP5, TRIP6, TRIP7, TRIP8, TRIP9, TRIP10, TRIP11, TRIP12, TRIP13, TRIP14, TRIP15 }; const unsigned char music3[50] = { 6, 6, 7, 6, 6, 6, 4, 2, 2, 3, 4, 3, 4, 4, 6, 7, 9, 9, 7, 6, 6, 7, 6, 9, 9, 10, 9, 7, 9, 9, 6, 6, 7, 6, 7, 6, 4, 6, 4, 3, 2, 3, 3, 2, 3, 4, 6, 7, 6, 9 }; const unsigned char music1[38]={ 2, 3, 4, 2, 3, 4, 6, 4, 3, 2, 3, 4, 3, 2, 3, 4, 2, 3, 4, 6, 4, 3, 2, 3, 4, 2, 6, 6, 4, 6, 7, 7, 6, 4, 4, 3, 3, 2 }; const unsigned char music2[45] = { 6, 4, 4, 5, 4, 3, 2, 6, 4, 4, 3, 4, 4, 6, 6, 7, 7, 7, 7, 9, 4, 4, 6, 6, 6, 4, 4, 5, 4, 3, 2, 6, 4, 4, 3, 6, 4, 7, 6, 6, 7, 7, 8, 8, 9 }; unsigned char checkflag, channel, onflag[16]; unsigned char i, j, n, maxpos, posflag; - 90 - unsigned char mode, smode, smusic; unsigned char count, writedata; unsigned char wave,ip,derec,wavenum; unsigned char adval,advalnew; unsigned char led1[4],led2[4],led3[4],led4[4]; unsigned char lightdata, lpos, adata; unsigned char playflag, playprev; unsigned char maxprev, maxcond; unsigned char nextflag, firstflag; unsigned char soundflag, swave; unsigned char freeend[4]; unsigned int raw, temp, maxlevel; unsigned int average[16], level[16]; void main() { ANSELA = 0b00110000; // RA4,5 analog bit ANSELB = 0b11111111; // all analog bit ANSELD = 0b11111111; // all analog bit OPTION_REG = 0b10000011; // pre-scaler 1:16 TRISA = 0b11110000; // RA0-3 output, RA4-7 input TRISB = 0b11111111; // all input TRISC = 0b00010000; TRISD = 0b11111111; TRISE = 7; // all output // all input // all input FVRCON = 0b10001000; //FVR=2.048V DACCON0 = 0b11001000; //DACPSS=FVR DACNSS=VSS DACCON1 = 1; CPSCON0 = 0b11001100; // DAC 電圧は 2.048/32 * 1 // タッチセンスオン、FVR,DA コンバータ利用 - 91 - High レンジ CPSCON1 = 0; SSPCON1=0b00100000; SSPSTAT=0b00000000; SSPCON3=0b00010000; TMR1H = 0; TMR1L = 0; T1CON = 0b11000101; // タッチセンス利用、1:1、非同期、タイマー1 T1GCON = 0b11100001; // ゲート機能有効、タイマー0 利用 T2CON = 0b01110111; //prescalar 1:64 postscaler 1:15 オン T4CON = 0b01001110; //prescalar 1:16 postscaler 1:10 T6CON = 0b00100101; //prescalar 1:16 postscaler 1:5 PR2 = 51; //about 10msec PR4 = 249; // 2msec PR6 = 249; // 1msec TMR2IF = 0; TMR2IE = 1; //タイマー2割り込み許可 TMR4IF = 0; TMR4IE = 1; TMR6IF = 0; TMR6IE = 1; TMR1GIF = 0; TMR1GIE = 1; for ( i = 0; i < 16; i++ ) { average[i] = 0; - 92 - onflag[i] = 0; } for ( i = 0; i < 4; i++ ){ led1[i] = 0; led2[i] = 0; led3[i] = 0; led4[i] = 0; freeend[i] = 0; } checkflag = 0; channel = 0; wave = 0; ip =0 ; wavenum = 1; adval = 0; mode = 0; smode = 0; lpos = adata = 0; count = 0; smusic = 0; playflag = 0; writedata = 0; nextflag = 0; soundflag = 0; n = 0; swave = 0; INTCON = 0b11000000; // gie = 1, geie = 1 - 93 - while (1) { switch(mode){ case 0: if(onflag[15] && playflag){ playflag = 0; mode = 2; for(i=0;i<5;i++) __delay_ms(100); } led4[3] = 1; break; case 1: mode = 1; if(onflag[4] && playflag){ playflag = 0; if(!swave) swave = 2; else swave--; } led4[0] = 1; if(onflag[12] && playflag){ playflag = 0; if(swave == 2) swave = 0; else swave++; } led2[0] = 1; if(onflag[15] && playflag){ playflag = 0; - 94 - mode = 2; for(i=0;i<5;i++) __delay_ms(100); } led4[3] = 1; SPIwrite(swave | mode << 4); break; case 2: if(onflag[4] && playflag){ playflag = 0; if(!smode) smode = 2; else smode--; } led4[0] = 1; if(onflag[12] && playflag){ playflag = 0; if(smode == 2) smode = 0; else smode++; } led2[0] = 1; if(onflag[15] && playflag){ playflag = 0; mode = 3; for(i=0;i<5;i++) __delay_ms(100); } led4[3] = 1; freeend[0] = 1; SPIwrite(smode | mode<<4); - 95 - break; case 3: led2[0] = led3[0] = 1; if(onflag[8] | onflag[4] && playflag){ playflag = 0; switch(smode){ case 0: mode = 4; break; case 1: mode = 7; break; case 2: mode = 1; } for(i=0;i<5;i++) __delay_ms(100); } led2[3] = led3[3] = 1; if(onflag[11] | onflag[7] && playflag){ playflag = 0; mode = 2; for(i=0;i<5;i++) __delay_ms(100); } break; case 4: if(onflag[4] && playflag){ playflag = 0; if(!smusic) smusic = 2; - 96 - else smusic--; } led4[0] = 1; if(onflag[12] && playflag){ playflag = 0; if(smusic == 2) smusic = 0; else smusic++; } led2[0] = 1; if(onflag[15] && playflag){ playflag = 0; mode = 5; for(i=0;i<5;i++) __delay_ms(100); } led4[3] = 1; SPIwrite(smusic | mode << 4); break; case 5: if(nextflag) { nextflag = 0; n++; } switch(smusic){ case 0: ledflash(music1[n]); if(playflag){ playflag = 0; if(music1[n] == maxpos){ - 97 - nextflag = 1; Writesound(music1[n]); } } if(n == 38) { mode = 6; n = 0; for(i=0;i<5;i++) __delay_ms(100); } break; case 1: ledflash(music2[n]); if(playflag){ playflag = 0; if(music2[n] == maxpos){ nextflag = 1; Writesound(music2[n]); } } if(n == 45) { mode = 6; n = 0; for(i=0;i<5;i++) __delay_ms(100); } break; case 2: ledflash(music3[n]); if(playflag){ playflag = 0; if(music3[n] == maxpos){ - 98 - nextflag = 1; Writesound(music3[n]); } } if(n == 50) { mode = 6; n = 0; for(i=0;i<5;i++) __delay_ms(100); } } break; case 6: led2[0] = led3[0] = 1; if(onflag[8] | onflag[4] && playflag){ playflag = 0; mode = 4; } led2[3] = led3[3] = 1; if(onflag[11] | onflag[7] && playflag){ playflag = 0; mode = 2; } break; case 7: if(playflag){ playflag = 0; Writesound(maxpos); - 99 - ledflash(maxpos); freeend[3] = freeend[2]; freeend[2] = freeend[1]; freeend[1] = freeend[0]; freeend[0] = maxpos; } if((freeend[1] == 0) && (freeend[3] == 0)) if((freeend[0] == 15) && (freeend[2] == 15)) mode = 2; } writedata = 0; writedata = maxpos | mode << 4; if(playflag) writedata |= 0b10000000; if(!playflag) writedata &= 0b01111111; if(!mode || mode == 3 || mode == 6) SPIwrite(writedata); } } void interrupt detecttouch(void) { if(TMR2IF) - 100 - { TMR2IF=0; for ( i = 0; i < 4; i++ ){ led1[i] = 0; led2[i] = 0; led3[i] = 0; led4[i] = 0; } } if(TMR4IF){ TMR4IF = 0; maxcond<<=1; if(maxprev == maxpos) { if(onflag[maxpos]) maxcond|=1; } else maxcond = 0; if(maxcond==0xff){ if(!playprev){ playflag=1; } playprev=1; } if(!maxcond) playprev=0; maxprev = maxpos; } if(TMR6IF){ - 101 - TMR6IF = 0; lightdata = 0; adata = 0; if(lpos == 0) { adata = 0b00000001; if(led1[0]) lightdata |= 0b00000001; if(led1[1]) lightdata |= 0b00000010; if(led1[2]) lightdata |= 0b00000100; if(led1[3]) lightdata |= 0b01000000; } if(lpos == 1) { adata = 0b00000010; if(led2[0]) lightdata |= 0b00000001; if(led2[1]) lightdata |= 0b00000010; if(led2[2]) lightdata |= 0b00000100; if(led2[3]) lightdata |= 0b01000000; } if(lpos == 2) { adata = 0b00000100; if(led3[0]) lightdata |= 0b00000001; if(led3[1]) lightdata |= 0b00000010; if(led3[2]) lightdata |= 0b00000100; if(led3[3]) lightdata |= 0b01000000; } if(lpos == 3) { adata = 0b00001000; if(led4[0]) lightdata |= 0b00000001; if(led4[1]) lightdata |= 0b00000010; if(led4[2]) lightdata |= 0b00000100; if(led4[3]) lightdata |= 0b01000000; } - 102 - PORTC = 0; PORTA = 0; PORTA = adata; PORTC = lightdata; lpos++; if(lpos == 4) lpos = 0; } if(TMR1GIF) { TMR1GIF = 0; raw = TMR1H * 256 + TMR1L; if ( !onflag[channel] ) { if ( raw >= average[channel]) average[channel] = average[channel] + (raw average[channel])/16; else { temp = (average[channel] - raw)/16; if ( average[channel] > temp ) average[channel] = average[channel] - temp; else average[channel] = 0; } } if ( average[channel] > raw ) level[channel] = average[channel] - raw; else level[channel] = 0; if ( level[channel] > tripval[channel] ) onflag[channel] = 1; else onflag[channel] = 0; - 103 - channel++; if (channel == CHMAX) { channel = 0; maxlevel = 0; for (j = 0; j < CHMAX; j++) if (level[j] > maxlevel ) { maxlevel = level[j]; maxpos = j; } posflag = 1; } TMR1ON = 0; CPSCON1 = channel; TMR1H = 0; TMR1L = 0; TMR1ON = 1; checkflag = 1; } } void ledflash(unsigned char pos){ unsigned char tate, yoko,a; tate = pos / 4; yoko = pos - (tate * 4); for ( a = 0; a < 4; a++ ){ - 104 - led1[a] = 0; led2[a] = 0; led3[a] = 0; led4[a] = 0; } if( tate == 0 ){ if(yoko == 0) led1[0] = 1; if(yoko == 1) led1[1] = 1; if(yoko == 2) led1[2] = 1; if(yoko == 3) led1[3] = 1; } if( tate == 1 ){ if(yoko == 0) led2[0] = 1; if(yoko == 1) led2[1] = 1; if(yoko == 2) led2[2] = 1; if(yoko == 3) led2[3] = 1; } if( tate == 2 ){ if(yoko == 0) led3[0] = 1; if(yoko == 1) led3[1] = 1; if(yoko == 2) led3[2] = 1; if(yoko == 3) led3[3] = 1; } if( tate == 3 ){ if(yoko == 0) led4[0] = 1; if(yoko == 1) led4[1] = 1; if(yoko == 2) led4[2] = 1; - 105 - if(yoko == 3) led4[3] = 1; } } void SPIwrite(unsigned char data){ unsigned char dumy; dumy = SSPBUF; SSPBUF = data; while(!BF); dumy = SSPBUF; } void Writesound(unsigned char data){ writedata = data | mode << 4; writedata |= 0b10000000; SPIwrite(writedata); for(i=0;i<5;i++) __delay_ms(100); } - 106 - 最終作品 PIC16F1783 に書き込んだプログラム - 107 - #include <stdio.h> #include <stdlib.h> //#include <pic.h> #include <xc.h> // CONFIG1 #pragma config FOSC = HS // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = OFF #pragma config CLKOUTEN = OFF // Brown-out Reset Enable (Brown-out Reset disabled) // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable bit (Vcap functionality is disabled on RA6.) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack - 108 - Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LPBOR = OFF // Low Power Brown-Out Reset Enable Bit (Low power brown-out is disabled) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) #define _XTAL_FREQ 20000000 unsigned char SPIread(); void init_lcd(void); void disp_pos(unsigned char row, unsigned char col); void lcd_1moji(unsigned char moji); void lcd_num(unsigned char n); void clear_disp(void); unsigned char Moderead(unsigned char data); unsigned char Touchread(unsigned char data); const unsigned char wavesin[100]={ 128,136,143 ,151,159,167,174,182,189,196,202,209,215,220,226,231, 235,239,243,246,249,251,253,254,255,255,255,254,253,251,249,246, 243,239,235,231,226,220,215,209,202,196,189,182,174,167,159,151, 143,136,128,119,112,104,96,88,81,73,66,59,53,46,40,35,29,24,20, 16,12,9,6,4,2,1,0,0,0,1,2,4,6,9,12,16,20,24,29,35,40,46,53,59,66, 73,81,88,96,104,112,119 }; const unsigned char wavesaw[100]={ 0, 3, 5, 8, 10, 13, 15, 18, 20, 23, 25, 28, 30, 33, 35, 38, 40, 43, - 109 - 45, 48, 50, 53, 55, 58, 60, 63, 65, 68, 70, 73, 75, 78, 80, 83, 85, 88, 90, 93, 95, 98, 100, 103, 105, 108, 110, 113, 115, 118, 120, 123, 125, 128, 130, 133, 135, 138, 140, 143, 145, 148, 150, 153, 155, 158, 160, 163, 165, 168, 170, 173, 175, 178, 180, 183, 185, 188, 190, 193, 195, 198, 200, 203, 205, 208, 210, 213, 215, 218, 220, 223, 225, 228, 230, 233, 235, 238, 240, 243, 245, 248 }; const unsigned char wavehou[100]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,250,250,250,250,250,250,250,250, 250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, 250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, 250,250,250,250,250,250,250,250 }; const unsigned char onkai[16]={ 229, 201, 192, 172, 152, 144, 128, 113, 101, 96, 85, 76, 72, 64, 57, 50 }; unsigned char i,j,n,count; unsigned char sspdata, swave; unsigned char wave, smode, smusic; unsigned char mode, touch; unsigned char startflag, clearflag; unsigned char playflag, soundflag; unsigned char firstflag; int main(int argc, char** argv) { OSCCON = 0b01111000; - 110 - ANSELA = 0b00000000; ANSELB = 0b00001110; TRISA=0b11110000; TRISB=0b00001100; TRISC=0b00011000; OPTION_REG = 0b10000111; DACCON0=0b10100000; DACCON1=255; OPA2CON=0b11000001; SSPCON1=0b00100101; SSPSTAT=0b00000000; SSPCON3=0b00010000; TMR0 = 56; //about 10msec T1CON = 0b00110001; T2CON = 0b00000100; //prescalar 1:1 postscaler 1:1 CCP1CON = 0b00001011; PR2 = 50; TMR2IF = 0; TMR2IE = 1; i=0; n = 0; count = 0; mode=0; smode = 0; smusic = 0; swave = 0; startflag = 0; firstflag = 1; clearflag = 0; soundflag = 0; playflag = 0; - 111 - init_lcd(); disp_pos(1,0); lcd_1moji('T'); lcd_1moji('o'); lcd_1moji('u'); lcd_1moji('c'); lcd_1moji('h'); lcd_1moji(' '); lcd_1moji('G'); lcd_1moji('a'); lcd_1moji('m'); lcd_1moji('e'); for(j=0;j<10;j++) __delay_ms(100); INTCON=0b11100000; // GIE=1, PEIE=1, TMR0IE = 1 while(1){ switch(mode){ case 0: if(firstflag){ firstflag = 0; disp_pos(1,0); lcd_1moji('S'); lcd_1moji('y'); lcd_1moji('s'); lcd_1moji('t'); lcd_1moji('e'); lcd_1moji('m'); lcd_1moji('s'); - 112 - lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); disp_pos(2,0); lcd_1moji('E'); lcd_1moji('n'); lcd_1moji('g'); lcd_1moji('i'); lcd_1moji('n'); lcd_1moji('e'); lcd_1moji('e'); lcd_1moji('r'); lcd_1moji('i'); lcd_1moji('n'); lcd_1moji('g'); for(i=0;i<5;i++) __delay_ms(100); } disp_pos(1,0); lcd_1moji('W'); lcd_1moji('a'); lcd_1moji('t'); lcd_1moji('a'); lcd_1moji('m'); lcd_1moji('o'); lcd_1moji('r'); lcd_1moji('i'); lcd_1moji(' '); lcd_1moji('L'); lcd_1moji('a'); - 113 - lcd_1moji('b'); lcd_1moji('.'); disp_pos(2,0); lcd_1moji('N'); lcd_1moji('o'); lcd_1moji('m'); lcd_1moji('u'); lcd_1moji('r'); lcd_1moji('a'); lcd_1moji(' '); lcd_1moji('S'); lcd_1moji('h'); lcd_1moji('u'); lcd_1moji('n'); lcd_1moji('s'); lcd_1moji('u'); lcd_1moji('k'); lcd_1moji('e'); lcd_1moji(' '); break; case 1: SPIread(); swave = SSPBUF & 0b00001111; mode = 1; disp_pos(1,0); lcd_1moji('S'); lcd_1moji('e'); lcd_1moji('l'); lcd_1moji('e'); lcd_1moji('c'); lcd_1moji('t'); - 114 - lcd_1moji(' '); lcd_1moji('W'); lcd_1moji('a'); lcd_1moji('v'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); disp_pos(2,0); switch (swave){ case 0: lcd_1moji(0x31); lcd_1moji(0x2E); lcd_1moji('S'); lcd_1moji('i'); lcd_1moji('n'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji('W'); lcd_1moji('a'); lcd_1moji('v'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); - 115 - lcd_1moji(' '); break; case 1: lcd_1moji(0x32); lcd_1moji(0x2E); lcd_1moji('S'); lcd_1moji('q'); lcd_1moji('u'); lcd_1moji('a'); lcd_1moji('r'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji('W'); lcd_1moji('a'); lcd_1moji('v'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); break; case 2: lcd_1moji(0x33); lcd_1moji(0x2E); lcd_1moji('S'); lcd_1moji('a'); lcd_1moji('w'); lcd_1moji('t'); lcd_1moji('o'); lcd_1moji('o'); lcd_1moji('t'); - 116 - lcd_1moji('h'); lcd_1moji(' '); lcd_1moji('W'); lcd_1moji('a'); lcd_1moji('v'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji(' '); } mode = 1; break; case 2: SPIread(); smode = SSPBUF & 0b00001111; disp_pos(1,0); lcd_1moji('S'); lcd_1moji('e'); lcd_1moji('l'); lcd_1moji('e'); lcd_1moji('c'); lcd_1moji('t'); lcd_1moji(' '); lcd_1moji('M'); lcd_1moji('o'); lcd_1moji('d'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji(' '); disp_pos(2,0); switch (smode){ - 117 - case 0: lcd_1moji(0x31); lcd_1moji(0x2E); lcd_1moji('M'); lcd_1moji('u'); lcd_1moji('s'); lcd_1moji('i'); lcd_1moji('c'); lcd_1moji(' '); lcd_1moji('P'); lcd_1moji('l'); lcd_1moji('a'); lcd_1moji('y'); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); break; case 1: lcd_1moji(0x32); lcd_1moji(0x2E); lcd_1moji('F'); lcd_1moji('r'); lcd_1moji('e'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji('P'); lcd_1moji('l'); lcd_1moji('a'); lcd_1moji('y'); - 118 - lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); break; case 2: lcd_1moji(0x33); lcd_1moji(0x2E); lcd_1moji('W'); lcd_1moji('a'); lcd_1moji('v'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji('S'); lcd_1moji('e'); lcd_1moji('l'); lcd_1moji('e'); lcd_1moji('c'); lcd_1moji('t'); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); } clearflag = 1; break; case 3: if(clearflag){ - 119 - clearflag = 0; clear_disp(); } startflag = 1; disp_pos(1,0); lcd_1moji('O'); lcd_1moji('K'); lcd_1moji(0x3F); __delay_ms(100); disp_pos(2,0); lcd_1moji(0x7F); lcd_1moji('O'); lcd_1moji('K'); disp_pos(2,11); lcd_1moji('B'); lcd_1moji('a'); lcd_1moji('c'); lcd_1moji('k'); lcd_1moji(0x7E); break; case 4: SPIread(); smusic = SSPBUF & 0b00001111; disp_pos(1,0); lcd_1moji('S'); lcd_1moji('e'); lcd_1moji('l'); lcd_1moji('e'); lcd_1moji('c'); lcd_1moji('t'); - 120 - lcd_1moji(' '); lcd_1moji('M'); lcd_1moji('u'); lcd_1moji('s'); lcd_1moji('i'); lcd_1moji('c'); lcd_1moji(' '); lcd_1moji(' '); disp_pos(2,0); switch (smusic){ case 0: lcd_1moji(0x31); //1 lcd_1moji(0x2E); //. lcd_1moji(0xC1); //? lcd_1moji(0xAD); //? lcd_1moji(0xB0); //? lcd_1moji(0xD8); //? lcd_1moji(0xAF); //? lcd_1moji(0xCC); //? lcd_1moji(0xDF); //? lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); break; case 1: lcd_1moji(0x32); //2 - 121 - lcd_1moji(0x2E); //. lcd_1moji(0xC4); //? lcd_1moji(0xDE); //? lcd_1moji(0xDD); //? lcd_1moji(0xB8); //? lcd_1moji(0xDE); //? lcd_1moji(0xD8); //? lcd_1moji(0xBA); //? lcd_1moji(0xDB); //? lcd_1moji(0xBA); //? lcd_1moji(0xDB); //? lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); break; case 2: lcd_1moji(0x33); //3 lcd_1moji(0x2E); //. lcd_1moji(0xD5); //? lcd_1moji(0xB3); //? lcd_1moji(0xD4); //? lcd_1moji(0xB9); //? lcd_1moji(0xBA); //? lcd_1moji(0xD4); //? lcd_1moji(0xB9); //? lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); - 122 - lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); } startflag = 1; break; case 5: if(startflag){ startflag = 0; clearflag = 1; clear_disp(); disp_pos(1,0); switch (smusic){ case 0: lcd_1moji(0x31); //1 lcd_1moji(0x2E); //. lcd_1moji(0xC1); //? lcd_1moji(0xAD); //? lcd_1moji(0xB0); //? lcd_1moji(0xD8); //? lcd_1moji(0xAF); //? lcd_1moji(0xCC); //? lcd_1moji(0xDF); //? break; case 1: lcd_1moji(0x32); //2 lcd_1moji(0x2E); //. lcd_1moji(0xC4); //? - 123 - lcd_1moji(0xDE); //? lcd_1moji(0xDD); //? lcd_1moji(0xB8); //? lcd_1moji(0xDE); //? lcd_1moji(0xD8); //? lcd_1moji(0xBA); //? lcd_1moji(0xDB); //? lcd_1moji(0xBA); //? lcd_1moji(0xDB); //? lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); break; case 2: lcd_1moji(0x33); //3 lcd_1moji(0x2E); //. lcd_1moji(0xD5); //? lcd_1moji(0xB3); //? lcd_1moji(0xD4); //? lcd_1moji(0xB9); //? lcd_1moji(0xBA); //? lcd_1moji(0xD4); //? lcd_1moji(0xB9); //? lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); - 124 - lcd_1moji(' '); lcd_1moji(' '); } } if(playflag){ playflag = 0; soundflag = 1; } break; case 6: if(startflag){ startflag = 0; clear_disp(); } disp_pos(1,0); lcd_1moji('C'); lcd_1moji('o'); lcd_1moji('n'); lcd_1moji('t'); lcd_1moji('i'); lcd_1moji('n'); lcd_1moji('u'); lcd_1moji('e'); lcd_1moji(0x3F); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); lcd_1moji(' '); - 125 - lcd_1moji(' '); disp_pos(2,0); lcd_1moji(0x7F); lcd_1moji('Y'); lcd_1moji('e'); lcd_1moji('s'); disp_pos(2,13); lcd_1moji('N'); lcd_1moji('o'); lcd_1moji(0x7E); for(i=0;i<5;i++) __delay_ms(100); break; case 7: if(startflag){ startflag = 0; clear_disp(); disp_pos(1,0); lcd_1moji('F'); lcd_1moji('r'); lcd_1moji('e'); lcd_1moji('e'); lcd_1moji(' '); lcd_1moji('P'); lcd_1moji('l'); lcd_1moji('a'); lcd_1moji('y'); } if(playflag){ playflag = 0; soundflag = 1; - 126 - } } SPIread(); sspdata = SSPBUF; touch = 0b00001111 & sspdata; mode = (sspdata & 0b01110000) >> 4; if(sspdata & 0b10000000) playflag = 1; else playflag = 0; PR2 = onkai[touch]; } return (EXIT_SUCCESS); } void interrupt selectfrec (void){ if(TMR0IF){ TMR0IF = 0; if(soundflag) count++; if(count == 25){ count = 0; soundflag = 0; } } if(TMR2IF){ TMR2IF = 0; if(soundflag){ switch(swave){ - 127 - case 0: DACCON1 = wavesin[n]; break; case 1: DACCON1 = wavehou[n]; break; case 2: DACCON1 = wavesaw[n]; } n++; if(n == 100) n = 0; } } } unsigned char SPIread(){ unsigned char dumy; dumy = SSPBUF; SSPBUF = 0; while(!BF); return(SSPBUF); } void init_lcd(void){ // firstset RA0=RA1=0; __delay_ms(45); - 128 - PORTC=0b00000011; //DB7-4-> 0011 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_ms(6); PORTC=0b00000011; //DB7-4-> 0011 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(200); PORTC=0b00000011; //DB7-4-> 0011 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(50); // Function set PORTC=0b00000010; //DB7-4-> 0010 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; - 129 - __delay_us(50); PORTC=0b00000010; //DB7-4-> 0010 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(50); PORTC=0b01000000; //DB7-4-> 1000 RS->0 E->0 NOP(); RA1=1; NOP(); NOP(); RA1=0; __delay_us(50); // Display off PORTC=0b00000000; //DB7-4-> 0000 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(2); PORTC=0b01000000; //DB7-4-> 1000 RS->0 E->0 NOP(); RA1=1; NOP(); NOP(); - 130 - RA1=0; __delay_us(50); // Display ON PORTC=0b00000000; //DB7-4-> 0000 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(2); PORTC=0b00000001; //DB7-4-> 0001 RS->0 E->0 NOP(); RA1=1; NOP(); NOP(); RA1=0; __delay_ms(3); // Entry Mode set PORTC=0b00000000; //DB7-4-> 0010 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(2); PORTC=0b00000110; //DB7-4-> 0000 RS->0 E->0 NOP(); - 131 - RA1=1; NOP(); NOP(); RA1=0; __delay_us(50); // Display reon PORTC=0b00000000; //DB7-4-> 0000 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(2); PORTC=0b01000100; //DB7-4-> 1000 RS->0 E->0 NOP(); RA1=1; NOP(); NOP(); RA1=0; __delay_us(50); } void disp_pos(unsigned char row, unsigned char col){ unsigned char temp; temp=0; - 132 - RA0=0; if(row==1) PORTC=0b01000000; else if(row==2) PORTC=0b01000100; else return; RA1=1; NOP(); NOP(); RA1=0; if(col>15) col=0; temp=col; if(temp && 0b00001000) temp |= 0b01000000; PORTC=temp; RA1=1; NOP(); NOP(); RA1=0; __delay_ms(1); } void lcd_1moji(unsigned char moji){ unsigned char temp; temp=0; temp=moji>>4; if(temp & 0b00001000) - 133 - temp |= 0b01000000; PORTC=temp; RA0=1; RA1=1; NOP(); NOP(); RA1=0; temp=0; temp=moji; temp &= 0b00001111; if(temp & 0b00001000) temp |= 0b01000000; PORTC=temp; RA0=1; RA1=1; NOP(); NOP(); RA1=0; __delay_us(40); } void lcd_num(unsigned char n){ unsigned char ans100,ans10; RA0=0; ans100=n/100; if(ans100>0) lcd_1moji(ans100+'0'); - 134 - else lcd_1moji(' '); n-=ans100*100; ans10=n/10; if((ans100>0)||(ans10>0)) lcd_1moji(ans10+'0'); else lcd_1moji(' '); n-=ans10*10; lcd_1moji(n+'0'); } void clear_disp(void){ RA0 = 0; PORTC=0b00000000; //DB7-4-> 0000 RS->0 E->0 RA1=1; NOP(); NOP(); RA1=0; __delay_us(2); PORTC=0b00000001; //DB7-4-> 0001 RS->0 E->0 NOP(); RA1=1; NOP(); NOP(); RA1=0; __delay_ms(3); } - 135 -