こんにちは、Habr! 私の趣味の1つは知的ゲームです。 これは「なに? どこ? いつ?」、「自分のゲーム」、「スクラブルカルテット」、「ブレインリング」など。 そして、このゲーム用のシステムを自分の手で作りたいと思ったら。 そのようなデバイスをゼロから作成するプロセスに興味がある場合は、catに招待します。
背景
「あなたのゲーム」のルールについて簡単に:
プレイヤーのグループ(通常4人まで)がプレイ場所に座っています。 5つのトピックからなるトピックが発表されます。 質問はますます複雑になり、それに応じて評価されます-10〜50ポイント。 ホストは質問の額面を発表し、読み始めます。 質問を読んだ瞬間に、プレーヤーは合図を出し、その後リーダーは質問の読みを止めてカウントダウンを開始します。合図をしたプレーヤーには答えるのに3〜5秒与えられます。 正解でタイムリーな回答の場合、プレーヤーは質問の額面に等しいポイント数を受け取ります。 それ以外の場合、プレーヤーはこの数のポイントを奪われます(最終スコアは非常にマイナスになる場合があります)。
最も単純なケースで手をたたくことから、「あなたのゲーム」専用のシステムのボタンを押すことまで、このゲームでは何でも合図できます。 このようなシステムの大部分は自家製です(このビジネスをストリームに載せるのにインテリジェントゲームはあまり人気がありません)。 さらに、これらのシステムにはさまざまな欠点があります。
私が対処しなければならなかったシステムの欠点のいくつかをリストします。
- 大きな寸法;
- ネットワーク220Vからのみ動作します。
- コンピューターと連携してのみ動作する(特別なWindowsアプリケーションとの相互作用)。
- 低品質のスティッキーボタン(ドアベルなどから)。
私たちの街では、知的ゲームに関するトレーニングが毎週日曜日に行われています。 さらに、季節や天候によっては、地元の公園に集まることができます-息苦しい部屋で喫煙するよりもずっといいです。 その欠点のために、私たちが自由に使える既製のシステムは家から持ち帰るのが面倒でした。 したがって、しばしば「ポップ」を演奏する必要がありました。 信号を与えることができた最初の人を決定する精度は、望まれるものを残しました。 この件についての出席者の意見が分かれていることがよくありました-あなたに近い方が最初にバタンと思われたようです。 これらすべての要因により、私はゲームシステムの独自の実装を作成するようになりました。 とにかく、プロジェクトから完成品まで、ゼロからデバイスを作成する経験を積むことは興味深いものでした。
プロジェクト
まず、デバイスの基本的な概念を決定することにしました。 私自身のために、システムに実装すべき基本的なポイントに注意しました。
- 信頼性の高いボタンとLEDインジケーターを備えた便利なリモートコントロール(プレーヤーが最初にボタンを押したことの確認)。
- リモートおよびデバイスのプラグイン接続。 リモートコントロールとシステム自体の両方にコネクタを作成することが決定されました。 4P4Cコネクタが選択されました(電話で一般的に使用されるRJ11)。 この選択は、サイズが小さくケーブルの修理が容易なために行われました。圧着ツールとコネクタを使用すると、問題は数分で解決されます。
- 2つの可能な電源は外部と内部です。 将来を見据えて-私が最も多くのミスを犯したのは、電源スキームの実装でした。
- システムには、不要なトラブルなしにマイクロコントローラーのファームウェアを変更できるように、インサーキットプログラミング(ISP)コネクターが必要です。
- 他のデバイス(コンピューターなど)へのバインドはありません。
- 小さい寸法。
デバイスの「頭脳」として、Atmelマイクロコントローラー-Atmega8を選択しました。これはアマチュア無線アマチュアに非常に人気があります。 一部のAttinyはシステムの機能には十分でしたが、致命的な欠陥がありました-それは私の机にありませんでした。 前述のAtmegaとは異なります。
次に、概略図を作成しました。
外部電源として、周囲にある古いモデムの電源ユニットが選択されました-出力に12 Vの交流電圧があります。 内部ソースの役割では、「Krona」タイプのバッテリーを選択しました-エラー1。 マイクロコントローラーに必要な5 Vを生成するために、LM7805リニアスタビライザー-エラーNo. 2を取り付けました。 これらがエラーであるという事実は、デバイスの組み立てとテスト後に実際に学びました。 「クローナ」の容量は非常に低く、その半分近くでさえ、線形安定装置を加熱することができませんでした。 ただし、それについては後で詳しく説明します。
私がデバイス用に選択したボタンとコネクタはeBayで購入する必要がありました。地元のディーラーが高すぎる価格を求めていました。 確かに、ラジオ市場では10 mm LEDを購入する必要がありました-ebayでもaliexpressでも、希望の直径のマルチカラーのインジケータLEDは見つかりませんでした。
最も重要で決定的なさらなる行動ステップの1つは、軍団の選択でした。 私の街では、品質に適したものを見つけることができませんでした。インターネットのトレーディングフロアを使用する必要がありました。 自分に合ったオプションがキエフで見つかりました。キエフでは、メインユニットとコンソール用に5つのケースが注文されました。
そして今、必要なすべての要素を手に入れて、デバイスの設計を考え始めました。
プリント基板
ケースを持って、プリント回路基板の開発を始めました。 私に起こったことは次のとおりです。
本体のPCB
LED回路基板
ボタン回路基板
プリント回路基板のレイアウトは、Sprint Layoutプログラムで作成されました。最後に、ソースへのリンクがあります。 使用、変更-一般に、あなたがそれらでやりたいことをしてください。
私自身はLUT方式(レーザーアイロン技術)を使用してプリント回路基板を作成しました-謙虚な意見では、これは単なる人間にとって許容できる品質のプリント回路基板を作成するための最も簡単で手頃な方法です。
コード
ここで、実際には、マイクロコントローラープログラムのリスト。 コードは最もエレガントではないかもしれませんが、機能し、その機能をバタンと実行します。
Cプログラムコード
#define F_CPU 4000000UL #define f 349 #define a 440 #define cH 523 #include <avr/io.h> // /, #include <util/delay.h> // #include <avr/interrupt.h> // // void clear_led(void) { PORTB = 0b00110000; PORTC = 0xFF; } int blink_led(int num) { clear_led(); _delay_ms(100); PORTB |= (1<<num); _delay_ms(100); clear_led(); _delay_ms(100); PORTB |= (1<<num); _delay_ms(100); clear_led(); _delay_ms(100); PORTB |= (1<<num); _delay_ms(100); clear_led(); _delay_ms(100); PORTB |= (1<<num); _delay_ms(100); clear_led(); _delay_ms(100); PORTB |= (1<<num); _delay_ms(100); return 0; } // , - void song(void) { _delay_ms(500); int T = 1000000/440; int k = 500000/T; int i = 0; int tempo = 1; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTB |= (1<<0); PORTB |= (1<<1); PORTB |= (1<<2); PORTB |= (1<<3); PORTD = 0b01111111; _delay_ms(500/tempo); // :) T = 1000000/440; k = 500000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } clear_led(); _delay_ms(500/tempo); // :) T = 1000000/440; k = 500000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTB |= (1<<0); PORTB |= (1<<1); PORTB |= (1<<2); PORTB |= (1<<3); PORTD = 0b01111111; _delay_ms(500/tempo); // :) T = 1000000/349; k = 350000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTD = 0b01111111; _delay_ms(350/tempo); // :) T = 1000000/523; k = 150000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTD = 0b01111111; _delay_ms(150/tempo); // :) T = 1000000/440; k = 500000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTD = 0b01111111; _delay_ms(500/tempo); // :) T = 1000000/349; k = 350000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTD = 0b01111111; _delay_ms(350/tempo); // :) T = 1000000/523; k = 150000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTD = 0b01111111; _delay_ms(150/tempo); // :) T = 1000000/440; k = 1000000/T; i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(T/2); // PORTD = 0b01111111; // _delay_us(T/2); // . i++; } PORTB |= (1<<0); PORTB |= (1<<1); PORTB |= (1<<2); PORTB |= (1<<3); PORTD = 0b01111111; _delay_ms(1000); // :) clear_led(); } int beep(int k, int j) // { int i = 0; while(i<k) { PORTD = 0b11111111; // : _delay_us(j); // PORTD = 0b01111111; // _delay_us(j); // . i++; } PORTD = 0b01111111; // :) return 0; } void reset_wait(void) { short t = 0; while(t==0) { if(!(PIND & (1<<PIND4))) { _delay_ms(5); if(!(PIND & (1<<PIND4))) { t = 1; clear_scr(); clear_led(); } } } } int bond007(void) // - { short i = 0; short p = 0; int t = 300; int tone = 100; while(i==0) // { // if(!(PIND & (1<<PIND0)) || !(PIND & (1<<PIND1)) || !(PIND & (1<<PIND2)) || !(PIND & (1<<PIND3)) || !(PIND & (1<<PIND6))) // { // " " _delay_ms(5); // if(!(PIND & (1<<PIND0))) // 1 { // " 1" p = beep(t, tone); // i=1; // clear_led(); p = blink_led(0); reset_wait(); i=0; } // " 1" else { if(!(PIND & (1<<PIND1))) // 2, { p = beep(t, tone); i=1; clear_led(); p = blink_led(1); reset_wait(); i=0; } else { if(!(PIND & (1<<PIND2))) // 3 { p = beep(t, tone); i=1; clear_led(); p = blink_led(2); reset_wait(); i=0; } else { if(!(PIND & (1<<PIND3))) // 4 { p = beep(t, tone); i=1; clear_led(); p = blink_led(3); reset_wait(); i=0; } } } } } // " " } // return i; } int main(void) // { // DDRC = 0xFF; // PORTC = 0xFF; // . DDRD = 0b10000000; // , 8 , , PORTD = 0b01111111; // , 8 , . DDRB = 0xFF; // PORTB = 0b00110000; // 5 6 song(); short i = 0; while(1) // { // i = bond007(); } // return 0; }
誰かがカットを開いてコードを見ることが突然起こった場合、この人はおそらく疑問を抱くでしょう-どのようなナンセンスがそれの大部分を占めるのでしょうか。 実際、デバイスにいくつかのハイライトを追加したかったため、このハイライトとして、電源を入れたときに挨拶を選択しました。 最初の電子が回路を通過するとすぐに、多色のLEDと赤いボタンが付いたこのブラックボックスは、有名な「帝国の行進」から楽しい通路を再生し始めます。
これは次のようなものです。
メロディ自体に加えて、この短いビデオでは、システムの例を見ることができます。ボタンを押すと、メインデバイスとインジケータの対応するLEDが点灯します。 この状態では、ホストが赤いシステムリセットボタンを押すまでシステムはロックされます。 それは実際、作品の全体的なロジックです。
プロジェクトエラー
上で書いたように、設計段階での主なエラーはデバイスの電源システムに関係していました。 Kronaを使用した場合、文字通り「余分な」4Vを熱に変える線形安定装置のひどい効率は、エネルギー効率の悪さの神格化です。 そして、クローナ自体は最良の選択からはほど遠い。 このバッテリーは容量が小さく(約600 mA * h)、非常に短時間持続します。 このような電源スキームでは、戦闘状態での最初のテスト中のシステムは1時間以内に機能しました。 これは私にはまったく合わなかったので、回路のこの部分をやり直す必要がありました。
このプロジェクトの少し前に、フォームファクター18650のリチウムイオン電池に精通しました。それらは最高のものであることが証明されました。 少なくとも、安価な中国製バッテリーであっても、単位体積の観点からの容量はクローナの容量よりも大幅に大きかった。
ただし、これらのバッテリーを選択するとすぐに別の問題が発生しました。 このようなバッテリーの定格電圧は3.7 Vです。そして、これはAtmega8に電力を供給するのに十分ではありません。 もう一度、賢明な中国人が助けに来ました-切望された5 Vを得るために、私はLM2577で昇圧ブーストコンバーターを使いました。 不運なLM7805(回路基板に残っている脚は後の写真で見ることができます)を引き裂いたので、勤勉な中国人が電源システムで作成したきちんとした小さな回路図を実装しました。
さらに、このバージョンの回路のテスト中に、外部電源を接続する可能性を放棄することにしました。 現場試験はすぐに合格しました-何時間も運転した後、バッテリーの放電や電圧低下の兆候はありませんでした(クローナが弛んだ-明らかに、回路に電流を流すことができませんでした)。 私は勇敢な18650がサーキットの運営を拒否するまでテストを続けることにしました。
ちなみに、購入時のロットの説明では、約3,700 mAhの容量が宣言されています-3ドルの地域の1つの缶のコストを考えると、中国人でさえ非常に自信があります。 しかし、動作の数か月間(これは、バッテリーの自己放電が低いことも示します)、バッテリーは消耗しませんでした。 そのため、私は以前あきらめて、ある重要なイベントでデバイスのアップタイムのためにバッテリーを充電しました。これについては後述します。
写真
ここに、結果の装置の写真を、内観を含めて持ってきます。 これは、すべてが正直に行われたことを明確にするためです-ネオンは内部にありません。
まとめ
システムは機能することが判明し、その機能を100%実行しました。 トレーニングに加えて、彼女はChUSI-2013(ウクライナ選手権「スボイゲーム」2013年)でテストされました。
それは素晴らしい経験でした。それは難しい間違いの息子であることが知られています。 最終的な実装では、デバイスは当初考えられていた機能の一部を失いました。 たとえば、外部電源を接続する機能を拒否しました-システムを積極的に使用しても、平凡なバッテリーは何ヶ月も持続します。
以下に、プリント回路基板のレイアウト(.lay形式)およびマイクロコントローラ用の完成したファームウェアをダウンロードできるリンクを囲みます。 誰かが私の経験を活用できたら嬉しいです。
主要部分のPCB ;
PCBブロックLED
回路基板のボタン 。
ファームウェア 。