「スサニンの足を切り取りましょうか?」(C)

画像 マイクロコントローラを使用する人の大半は、かつて難しい選択に直面していました。

-だから、この足でPWM、これで-ボタン、これらで-LED ...おっと...でも足は終わった。 LEDがなければ、見苦しく、ボタンがなければ機能しません。 水晶の太りを取る必要があります:(

または別の状況-マイクロコントローラを搭載したボードは見えないが、悲しい蛇の付いたインジケータへの配線ハーネスがデバイスの腸を突き刺す。

余分な足を切り捨てることにより、このケーブルの足のあるモンスターを飼いならす時が来ました。



ADCとそのような単純な回路:



そして今、簡単に興味がある人のために、仕事の原則。

回路が表示に従事している時間の主要部分。 一方の足に1を、もう一方の足に0を与えたら、対応するLEDを点灯します。 1つの組み合わせは緑色を、2番目の組み合わせは赤色を示し、すばやく前後に動かすとオレンジになります。

表示を理解し、ボタンについて説明しました。 Port2に論理値0を指定し、Port1を組み込みADCの入力として有効にするとします。 この場合、抵抗R1のおかげで、LEDに小さな電位が生じます。 緑色のLEDが順方向に点灯することに注意してください。 ご存知のように、緑色(および黄色)のLEDは、赤色のLEDよりも大幅に大きな直接電圧降下を持っています。 私たちの場合、この電圧は押されたボタンの状態を確実に読み取るのに十分です。 それらのいずれかが押されると、分圧器が取得され、受信信号をデジタル化してボタンを押すように変換するだけで十分です。 ちなみに、ワイヤの包含の極性を逆にしても-仕切りを正しく選択すると、表示が混同されない限り、ボタンは動作し続けます。 抵抗器R3とR4の選択は非常に自由です。覚えておくべき主なことは2つのルールです。小さな抵抗器はLEDの点灯を妨げないはずです。 私は、図に示されている値を手元にある値から単純に入力し、その後、結果の電圧をプログラムに登録しました。 R2-電流制限、マイクロコントローラーのLEDとフットパラメーターに基づいて選択、時にはそれなしで行うことができます。



そして今、このスキームで動作する実際のライブラリ。 この特定のケースでは、プラットフォームとしてATMega48が使用されましたが、可能な限り鉄に依存しないようにコードを記述し、別のチップに切り替えるには、ポートとADCの初期化を変更するだけで十分です。

/* * biwire.h */ #ifndef BIWIRE_H_ #define BIWIRE_H_ // Define connections (PORTC only!) #define BWPORT1 1 #define BWPORT2 2 // Set pin functions #define ADCPORT BWPORT1 #define GNDPORT BWPORT2
      
      



突然足が1本増えた場合、抵抗R1の代わりにこの場所でプルアップを使用することはかなり可能です

 // State for interrupt loop #define ADC_SET 0x01 #define ADC_WAIT 0x02 // LED flashing frequency (in parrots, without small wing) #define SCAN_FREQ 48 // Work together with SCAN_FREQ to get orange color #define MAX_COLOR_MIX 50 // Event bits when scan complete // Main keyboard event indicator - must be cleared after handle #define BW_EVENT 0x80 // Button pressed #define BW_EVBT1 0x01 #define BW_EVBT2 0x02 // add additional flags here, like BW_EVBT3=0x04 // EVFIN - event "Indication finished" #define BW_EVFIN 0x10 // Button released #define BW_EVOPN 0x20 // If button holds more than BW_LONG_PRESS cycles #define BW_EVLNG 0x40 // How long we wait for 'LongPress' #define BW_LONG_PRESS 10
      
      



ここでは、おおよその値にバス停をプラスまたはマイナスで書き込むことができます。 私たちにとっての主なことは、ボタンの正確な定義の境界を設定することです

 // ADC compare values #define BW_VBTN1 0x1F #define BW_VBTN2 0xFE // Define names for signal array enum SignalNames { LedOff = 0, OneGreen = 1, OneRed = 2, OneOrange = 3, TwoGreen = 4, TwoRed = 5, Alarm = 6, OrangeRG = 7
      
      



同様に、信号を味に追加

 }; // ====== Externals ======= // LED sequence to indicate extern volatile enum SignalNames BwIndicate; // Data about button events extern volatile uint8_t BwButton; // If not null - delay of led indication, then switch LED off extern volatile uint8_t BwLedDelay; // Call on start void biwire_init(void); #endif /* BIWIRE_H_ */
      
      





.hをダウンロードする

さて、ソース自体:

 /* * biwire.c */ #include <avr/io.h> #include <avr/interrupt.h> #include <stdint.h> #include "biwire.h" // Led blink matrix. Only upper 6 bits used for indication loop static uint8_t bwsignalsR[] = { 0x00, 0x00, 0xC0, 0xC0,0x00, 0xA0, 0xA0, 0xFC }; static uint8_t bwsignalsG[] = { 0x00, 0xC0, 0x00, 0xC0,0xA0, 0x00, 0x50, 0xC0 }; // LED sequence to indicate volatile enum SignalNames BwIndicate; // FSM and sequence counter static volatile uint8_t BwState; // "LongPress" counter static volatile uint8_t btn_cnt; // Data about button events volatile uint8_t BwButton; // Orange color created by mixing green and red static volatile uint8_t color_mix; // If not null - delay of led indication, then switch LED off volatile uint8_t BwLedDelay; void biwire_init(void) { // Timer interrupt TCCR0B = _BV(CS00) | _BV(CS01) | _BV(WGM02); // use CLK/64 prescale value, clear timer/counter on compareA match OCR0A = SCAN_FREQ; // preset timer0 OCR byte TIMSK0 = _BV(OCIE0A); // enable Output Compare 0 overflow interrupt // PIN init DDRC |= _BV(BWPORT1) | _BV(BWPORT2); // ADC init ADCSRA = _BV(ADEN) | _BV(ADPS2); // Activate ADC with Prescaler 16 --> 1Mhz/16 = 62.5kHz ADMUX = ADCPORT | _BV(REFS0) | _BV(REFS1) | _BV(ADLAR); // Select input pin using MUX, left adjust and Internal reference
      
      



Atmelyの内部基準はわずか1.1ボルトであり、ボタンが押されていない場合、ADC出力で信頼性が高く貫通できない0xFFが得られます。

  DIDR0 = _BV(ADCPORT); // disable digital input for ADC // Set initial state for bw BwState = ADC_SET; BwIndicate = OneGreen; BwButton = BW_EVOPN; color_mix = 0; BwLedDelay = 0; }
      
      



お好みに合わせてタイマー割り込みをカスタマイズできます。 仕切りとcolor_mixを使用して、ボタンをクリックするだけで点滅速度と反応時間を選択できます。

 SIGNAL (SIG_OUTPUT_COMPARE0A) // handler for Output Compare 0 overflow interrupt { if (BwState&ADC_SET) { // Prepare to keyscan PORTC &= ~_BV(GNDPORT); DDRC &= ~_BV(ADCPORT); ADCSRA |= _BV(ADSC); //Start conversion BwState = ADC_WAIT; color_mix = MAX_COLOR_MIX; if (BwLedDelay) if (!(--BwLedDelay)) { BwIndicate = LedOff; BwButton |= BW_EVFIN; } } else { if (BwState&ADC_WAIT) { // Check if ADC complete if (ADCSRA & _BV(ADSC) ) return; // Wait another tick PORTB = ADCH; if (ADCH > BW_VBTN2) { // Both buttons open if (BwButton & (BW_EVBT1|BW_EVBT2)) { BwButton = BW_EVENT + BW_EVOPN; btn_cnt = 0; } } else if (ADCH > BW_VBTN1) { // Button 2 pressed PORTB ^= 0xff; if (BwButton & (BW_EVBT1|BW_EVOPN)) { BwButton = BW_EVENT + BW_EVBT2; btn_cnt = 1; }
      
      



同様に、3番目以降のボタンの範囲を決定できますが、正確に調整する必要があります

  } else { // Button 1 pressed. Add compare values here if you need more than 2 buttons if (BwButton & (BW_EVBT2|BW_EVOPN)) { BwButton = BW_EVENT + BW_EVBT1; btn_cnt = 1; } } if (btn_cnt) { if(++btn_cnt > BW_LONG_PRESS) { // New event - long press BwButton |= BW_EVENT + BW_EVLNG; btn_cnt = 0; } } // Cleanup if (!(BwButton&(BW_EVBT1|BW_EVBT2|BW_EVOPN))) BwButton = BW_EVOPN; }
      
      



ここでADC_WAIT状態をスキップしない場合、LED点滅サイクルに7番目のビットを追加できます。 しかし、6ビットで十分です。 また、16ビットBwStateの場合、LEDから狂ったディスコをアレンジすることもできます。

  if (color_mix++ > MAX_COLOR_MIX) { // Get next state (LED sequence) BwState = (BwState >> 7) | (BwState << 1); // rotate left, replace by _asm to compact code // Indicate DDRC |= _BV(ADCPORT); PORTC &= ~(_BV(GNDPORT)|_BV(ADCPORT)); if(bwsignalsR[BwIndicate]&BwState) PORTC |= _BV(BWPORT2); if((bwsignalsG[BwIndicate]&BwState) && (!(bwsignalsR[BwIndicate]&BwState)) ) PORTC |= _BV(BWPORT1); color_mix = 0; } if((bwsignalsR[BwIndicate]&BwState) && (bwsignalsG[BwIndicate]&BwState)){ PORTC ^= (_BV(BWPORT1) | _BV(BWPORT2)); } } }
      
      





.cをダウンロードする



以上です。 このコードをソースに埋め込み、配線と足を節約します。 マイナスの点-おそらくボタンへのやや「愚かな」反応ですが、すぐにそれに慣れます。

また、bwsignalsR / bwsignalsGの後に3番目の配列(bwsignalsBなど)を追加し、それを使用して調光を行って滑らかなオンオフを行うこともできます。 宿題にしておきます:)



そうそう、私はほとんど忘れていました。 ライブラリの使用例:

 #include "biwire.h" int main(void) { biwire_init(); sei(); while (1) { if ( BwButton & BW_EVENT ) { BwButton &= ~BW_EVENT; // Clear event flag if (BwButton & BW_EVLNG) { BwIndicate = OrangeRG; BwLedDelay = 5; } else if (BwButton & BW_EVOPN) { //BwIndicate = LedOff; } else if (BwButton & BW_EVBT1) { BwIndicate = OneRed; BwLedDelay = 5; } else if (BwButton & BW_EVBT2) { BwIndicate = OneGreen; BwLedDelay = 5; } } } }
      
      







PS:奇妙なことに、古いエンジンではPasteBinからソースを直接貼り付けることができたことを漠然と覚えていましたか? なぜこのような良い機会が取り除かれたのですか? または私は何かを混乱させていますか?



All Articles