Si5351Aの勉強が一段落しましたので、今年の課題のうち、簡単そうなものを一つ片付けました。
以前に製作したAreduinoレシプロカル式周波数カウンタを7セグメントLED表示にする実験をしました。
レシプロカル式とは、逆数式という意味で、信号の周期Tを測定して、その逆数を計算することによって、周波数fを得る方式です。つまりf = 1/T の式を使います。
7セグメントLEDは、秋月電子で販売している超高輝度4桁7セグメントLED(OSL-40562-LRA)を使います。
約5mAで十分な輝度が得られると書いてあります。予備実験をしました。
5Vの電圧のとき、電流制限抵抗が、680Ωの時、電流は4.5mAで、十分な輝度が得られました。
ということは、7セグメントすべて点灯(8のとき)したとの電流が最大で、31.5mAとなり、Arduinoのデジタルポートで、ドライブできます。
7セグメントLEDは、ダイナミック点灯です。
周期の測定は、外部割り込みattachInterrupt(interrupt,function,mode)を利用し、割り込み番号は0(ピン2)、トリガは立ち上がり(RISING)とします。
回路図です。
ブレッドボードです。
スケッチです。
/*
*レシプロカル式周波数カウンタ
*7セグメントLEDダイナミック点灯
* 2016.12.29
* JH7UBC Keiji Hata
*
* D2 INPUT
* D3 7segLED A
* D4 7segLED B
* D5 7segLED C
* D6 7segLED D
* D7 7segLED E
* D8 7segLED F
* D9 7segLED G
* D10 7segLED #1
* D11 7segLED #2
* D12 7segLED #3
* D13 7segLED #4
*/
*レシプロカル式周波数カウンタ
*7セグメントLEDダイナミック点灯
* 2016.12.29
* JH7UBC Keiji Hata
*
* D2 INPUT
* D3 7segLED A
* D4 7segLED B
* D5 7segLED C
* D6 7segLED D
* D7 7segLED E
* D8 7segLED F
* D9 7segLED G
* D10 7segLED #1
* D11 7segLED #2
* D12 7segLED #3
* D13 7segLED #4
*/
volatile unsigned long duration=0;
volatile unsigned long prevMicros=0;
unsigned int frequency;
int ZeroFlag; //ゼロフラッグ
int N[4]; //表示する数字(4桁)
int Nx;
//LED レイアウト定義 A,B,C,D,E,F,Gセグメントの順
boolean Num_Array[11][7]={
{1,1,1,1,1,1,0}, //0
{0,1,1,0,0,0,0}, //1
{1,1,0,1,1,0,1}, //2
{1,1,1,1,0,0,1}, //3
{0,1,1,0,0,1,1}, //4
{1,0,1,1,0,1,1}, //5
{1,0,1,1,1,1,1}, //6
{1,1,1,0,0,1,0}, //7
{1,1,1,1,1,1,1}, //8
{1,1,1,1,0,1,1}, //9
{0,0,0,0,0,0,0} //space
};
boolean Num_Array[11][7]={
{1,1,1,1,1,1,0}, //0
{0,1,1,0,0,0,0}, //1
{1,1,0,1,1,0,1}, //2
{1,1,1,1,0,0,1}, //3
{0,1,1,0,0,1,1}, //4
{1,0,1,1,0,1,1}, //5
{1,0,1,1,1,1,1}, //6
{1,1,1,0,0,1,0}, //7
{1,1,1,1,1,1,1}, //8
{1,1,1,1,0,1,1}, //9
{0,0,0,0,0,0,0} //space
};
//LED配列
boolean Led_Array[4][4]={
{0,1,1,1}, //LED1
{1,0,1,1}, //LED2
{1,1,0,1}, //LED3
{1,1,1,0} //LED4
};
boolean Led_Array[4][4]={
{0,1,1,1}, //LED1
{1,0,1,1}, //LED2
{1,1,0,1}, //LED3
{1,1,1,0} //LED4
};
void setup()
{
attachInterrupt(0, periodIrq, RISING);
for (int i=3;i<=13;i++) //pin2~13を出力に設定
{
pinMode(i,OUTPUT);
}
}
void loop()
{
frequency = 1000000 / duration; //f=1/T
Num_set(frequency); //周波数の値をN[0]~N[3]にセット
int var = 0;
while(var < 20){ //20の値は、要調節
for(int i=0;i<4;i++){
LedActive(i);
NumPrint(N[i]);
delay(6);
NumPrint(10); //一旦表示を消す
}
var++;
}
}
{
frequency = 1000000 / duration; //f=1/T
Num_set(frequency); //周波数の値をN[0]~N[3]にセット
int var = 0;
while(var < 20){ //20の値は、要調節
for(int i=0;i<4;i++){
LedActive(i);
NumPrint(N[i]);
delay(6);
NumPrint(10); //一旦表示を消す
}
var++;
}
}
void periodIrq() // interrupt handler
{
unsigned long currentMicros = micros();
duration = currentMicros - prevMicros;
prevMicros = currentMicros;
}
{
unsigned long currentMicros = micros();
duration = currentMicros - prevMicros;
prevMicros = currentMicros;
}
//数字表示
void NumPrint(int Number){
for (int w=0; w<=6; w++){
digitalWrite(w+3,Num_Array[Number][w]);
}
}
void NumPrint(int Number){
for (int w=0; w<=6; w++){
digitalWrite(w+3,Num_Array[Number][w]);
}
}
//LED点灯
void LedActive(int Number){
for (int w=0; w<=3; w++){
digitalWrite(w+10,Led_Array[Number][w]);
}
}
void LedActive(int Number){
for (int w=0; w<=3; w++){
digitalWrite(w+10,Led_Array[Number][w]);
}
}
//数字の分解(1000の位、100の位、10の位、1の位)とセット
void Num_set(int X){
ZeroFlag=1;
N[0] = X / 1000;
if (N[0] == 0){
N[0]=10; //10=space
}else{
ZeroFlag=0;
}
void Num_set(int X){
ZeroFlag=1;
N[0] = X / 1000;
if (N[0] == 0){
N[0]=10; //10=space
}else{
ZeroFlag=0;
}
Nx = X % 1000;
N[1] = Nx / 100;
if (N[1] == 0 & ZeroFlag == 1){
N[1]=10;
}else{
ZeroFlag = 0;
}
Nx = X % 100;
N[2] = Nx / 10;
if (N[2] == 0 & ZeroFlag ==1){
N[2]=10;
}
N[1] = Nx / 100;
if (N[1] == 0 & ZeroFlag == 1){
N[1]=10;
}else{
ZeroFlag = 0;
}
Nx = X % 100;
N[2] = Nx / 10;
if (N[2] == 0 & ZeroFlag ==1){
N[2]=10;
}
N[3] = X % 10;
}
}
このスケッチで10Hz~5000Hzまで、OKです。
こんな低い周波数しか測れないカウンタが、どうして必要なのかと言いますと、普通の周波数カウンタは、1秒ごとにしか周波数を測定すりことができません。(0.1秒の場合もあります)レシプロカル式は、1周期の時間があれば良いので、極端なことを言えば、1000Hzは1/1000秒=1msecあれば周波数を測定することができます。
つまり、短い時間で周波数を測定したい時に有効なカウンタなのです。
使い方としては、楽器のチューニングやドップラー効果の測定などが考えられます。