Count external pulses by "polling" (also software debounce)

back to main tutorial page

Dr Nathan Scott & Dr Hiroyuki Kagawa · July 2002

You have seen how floating inputs and switching noise can cause unwanted behaviour, and how a hardware circuit can be used to condition a noisy input signal. In this tutorial we will explore another way to get input from external switches.

「ポーリング」による外部パルスのカウント(ソフトウェアによるノイズ除去)

メインページに戻る

ネーサン・スコット(訳:香川博之)  · 20027

浮いている入力とスイッチングノイズがどのように望ましくない動作を引起すか,またノイズをもつ入力信号を整えるために回路をどのように利用するかについて理解した。ここでは, 外部スイッチからの入力を得るための別の方法について体験する。


Polling

Suppose that you are waiting to receive some money in your bank account. You do not have any way to know when the money arrives, you must check frequently. In microcontroller language, you must "poll" (check) your bank balance.

This tutorial is based on the results of the earlier tutorial "Seven segment LED using a driver". You should set up the hardware as described in that tutorial, so that at least one 7-segment LED display can be used by the AVR by sending data to PORTC.

  • The only hardware addition needed at this point is a wire from PORTD, PIN6, which will be our "digital input". Refer to the pinout diagram. Leave the wire sticking up in the air for now.
  • Compile the project poll.prj and download it to the AVR. What do you observe?


ポーリング

銀行口座で入金を待っていると仮定する。いつ入金があるかを知る方法はなく,しばしば確認しなければならない。マイクロコントローラでは預金残高を「ポーリング」(確認)しなければならない。

この章は,以前に学習した「LED表示専用ICを使った7セグLEDによる数字表示」に基づいている。その章の記述にしたがってハードウェアを設定し,PORTCにデータを送ることによって少なくともAVRで7セグLEDが表示できるようにする。

  • デジタル入力としてPORTD,(6番ピン)に線を接続する。ピン配置図を参照。 線の反対側を接続せず空中に浮かす。
  • プロジェクトファイル「 poll.prj 」をコンパイルし,AVRに転送する。何が観察されるか?

 

/*
Code for a crash course in AVR programming
Example "poll.c"
Dr Nathan Scott, July 2002
         
This program shows how to respond to an external signal by the "polling"
approach, which means "frequent checking". It also demonstrates a simple
"software debounce" approach.
         
The hardware should be setup as for the project "seven_seg_drv.prj"
i.e. at least one BCD-to-7-segment driver on the low bits of PORTC.
It is assumed that "PORTC = 3" will cause the number 3 to be displayed
on an external 7 segment LED.
*/
#include "environment.h"
#include "delay.h"
         
#define poll_pin 6 // it is good to have names for constants as it helps
// make the meaning of the code clear to the reader
         
// global count of the number of pulses on INT0 pin
char gCount;
         
// it is a good practice to define an interface procedure for each
// hardware function. It means we can change the hardware, and the interface
// procedure, but may not have to alter the rest of the program.
void ShowNumber(char num)
// the calling code does not need to know the detail of how we will display
// the number, we hide all that internally.
{
         PORTC = num;
}
         
void Idle()
// ignore this for now, it is used by the UART code in another example
{
}
         
void main()
{
    char debounce = 0;
        
        // start the global pulse count from zero.
        // Note that declared variables contain NOISE until you set them!
        gCount = 0;
         
        // set up control over PORTC
        PORTC = 0; // put a definite start value into the register for PORTC
        // - it's best not to leave this to chance
        DDRC = 0x0F; // set the direction of some of the pins of PORTC to "output".
        
        // set up control over PORTD
        PORTD = 0;
        DDRD = 0; // set all of PORTD to input mode.
        
        // display start count (zero most likely)
        ShowNumber(gCount);
        
        while (1) // endless loop, will run forever
        {
                 if (!debounce && (PIND & BIT(poll_pin)))
                 {
                        // a valid input event has occurred
                        debounce = 0xFF; // start "countdown" which locks out further
                        // input for a short time.
                        gCount++;
                        gCount %= 10; // we can only display 0 to 9 so only keep
                        // the "remainder" when divided by 10.
                        ShowNumber(gCount);
                        
                        while (PIND & BIT(poll_pin))
                                  ; // do nothing, wait for low voltage on poll_pin
                  }
                 
                 if (debounce)
                 {
                        debounce--; // count down to zero only
                        DelayUs(100);
                 }
        }
}

Figure 1 Example program that polls PORTD, PIN6

  • Now try moving the wire on INT0 (PORTD, PIN6) from GND to VCC. What do you observe?
  • Try touching the INT0 wire. What happens?

It is very likely that you will find that your LED counts at about one per second unless the wire is connected to GND or VCC. This is because of induced electrical noise on the wire. The solution is the same as for the previous tutorial - tie the input to either GND or VCC.

  • Tie the input to GND. Now try touching the input wire to VCC. Does the LED display count reliably?


Software debounce

The main() procedure has a local variable called debounce. When a high voltage is detected on the input pin, we check that the debounce variable equals zero. If it is zero then the program accepts that an input event has happened and the gCount variable and the display are updated. We do not want to respond to noise signals so a value is put into debounce. With time the value is reduced until it is again zero and the program can again respond to input.

This type of software debounce is OK but is only suitable for slow input such as from a human being pressing the buttons on a control panel. For fast input, such as from a communication line, the interrupt driven approach of the previous tutorial is needed.


Exercises

  • Reduce the debounce lock-out time so that hundreds of counts per second are possible. Test your program by removing the tie resistor so that electrical noise drives the count.
  • Remove the part of the program that says "while (PIND & BIT(poll_pin)) ;" - what effect does this have?
  • Change the program so that it will only count high pulses that are longer than one second.
  • INT0PORTD,6番ピン)をGNDからVCCに移動してみる。何が観察されるか。
  • INT0の線に触れてみる。何が起こるか。

It is very likely that you will find that your LED counts at about one per second unless the wire is connected to 線がGNDまたはVCCに接続されていなければ,LEDが少なくとも約1秒に1度はカウントされるであろう。これは線に電気ノイズを誘導したためである。この解決法は以前の章の入力をGNDまたはVCCつなぐことと同じである。

  • 入力をGNDにつなぐ。入力線をVCCに触れてみる。LEDはちゃんとカウントするようになったか。


ソフトウェアによるノイズ除去

main()処理にはdebounceと呼ばれる局所変数がある。入力端子に高い電圧が検出されるとき,debounce変数がゼロであることを確認する。もしゼロならプログラムはある入力イベントが発生することを認め,gCount変数と表示が更新される。ノイズ信号に反応させたくないときにはdebounce変数にある値を代入する。その変数が再びゼロになり入力に反応できるようになるまで,その値は減少する。

このタイプのソフトウェアによるノイズ消去はよいが,人間が制御盤のボタンを押すような遅い入力についてのみ適している。通信回線のように速い入力に対しては以前の章で説明した割込みが必要である。


演 習

  • debounce変数の値を毎秒数百カウントできるようにできるだけ減少させる。 電気ノイズをカウントできるように接続した抵抗をはずし,プログラムを試してみる。
  • プログラム中の「while (PIND & BIT(poll_pin)) ;」という部分を消去する。どんな効果が得られるか。

·         1秒以上の「ハイ」レベルのパルスのみをカウントするようにプログラムを変更する。

back to main tutorial page


Dr Nathan Scott · nscott@mech.uwa.edu.au