質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.83%

ArduinoDUEで7セグディスプレイ付き正弦波発生装置を作ろうとしたところ、アナログ出力チャンネルにノイズが発生してしまいます。

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 588

_kimura_

score 13

前提・実現したいこと

Arduino DUE を使用し3桁7セグLEDに周波数を表示する正弦波発生装置を作ろうとしています。

発生している問題・エラーメッセージ

GitHubにて配布されていた周波数測定用のコードをサイトの"clone or download"でzip形式にてダウンロードし、あらかじめ作成していたタクトスイッチで
制御を行う7セグLED表示機能つきの正弦波発生プログラムと組み合わせてみました。しかし7セグLEDからは周波数が表示されずランダムな数字が表示されオシロスコープで装置の出力を調べてみたところアナログ出力チャンネルから非連続型のシグナルが発生していることが分かりました。

装置を稼働させている様子を写したものです。
リンク内容

Arduino DUEのDACチャンネルの出力をオシロスコープで測定したものです。 本来は正弦波の滑らかな曲線が出るはずなのですが・・・
リンク内容

該当のソースコード

#include <FreqPeriodDue.h>

#include "Waveforms.h"

#define oneHzSample 1000000/maxSamplesNum
#define DATA 11
#define LATCH 10
#define CLOCK 9

//  0b11111110   DP
//  0b11111101   A
//  0b11111011   B
//  0b11110111   C
//  0b11101111   D
//  0b11011111   E
//  0b10111111   F
//  0b01111111   G

static const int num[] {
  0b10000001,   //ZERO
  0b11110011,   //ONE
  0b01001001,   //TWO
  0b01100001,   //THREE
  0b00110011,   //FOUR
  0b00100101,   //FIVE
  0b00000101,   //SIX
  0b11110001,   //SEVEN
  0b00000001,   //EIGHT
  0b00100001,   //NINE
  0b10000001,   //ZERO

  0b11110010,   //ONE DOT
  0b01001000,   //TWO DOT
  0b01100000,   //THREE DOT
  0b00110010,   //FOUR DOT
  0b00100100,   //FIVE DOT
  0b00000100,   //SIX DOT
  0b11110000,   //SEVEN DOT
  0b00000000,   //EIGHT DOT
  0b00100000,   //NINE DOT
};

int count;
int digits[] = {4, 3, 2};
int LEDdigit[] = {0, 0, 0}; //storage for digits to be displayed
int LEDdecimal[] = {0, 0, 0}; //storage for decimal indicators
byte scanDigit = 0; //tells which digit to display
unsigned int start;  //changed from int to unsigned int
unsigned int timer; //changed from int to unsigned int
unsigned int scanTimer; //timer for display scanning
unsigned int spreod = 50;
//int interval = 5000;
int interval = 100; //update the display once each second
int blinkingtime = 10;
int del = 10;int i = 0;
double startmicros;
volatile int wave1 = 0;
int lfrq;
long int pp;
int periodPin = 25;
int frequency = 40000;
const int plusbuttonPin = 53;
const int minusbuttonPin = 52;
int buttonStateplus = 0;
int buttonStateminus = 0;
unsigned int bmillis;


void setup()
{
  Serial.begin(115200);
  FreqPeriod::begin(periodPin); 
  startPWM(frequency, PIOC, PIO_PERIPH_B, PIO_PC23, PIO_DEFAULT, 6);
  pinMode(DATA, OUTPUT);
  pinMode(LATCH, OUTPUT);
  pinMode(CLOCK, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(DAC0,OUTPUT);
  pinMode(plusbuttonPin,INPUT_PULLUP);
  pinMode(minusbuttonPin,INPUT_PULLUP);
  timer = millis(); //start time for the timer
  scanTimer = millis(); //start the display scan timer
  bmillis = millis();
}

void loop()
{
    pp = FreqPeriod::getPeriod();
  if (pp){
      lfrq= 42000000 / pp;
  }
  start = millis();

  if ((start - scanTimer) >= del) //digit scanning timer
  {
    scanTimer = start; //reset the timer
    scanDigit++;       //display the next digit
    if (scanDigit >= 3) {
      scanDigit = 0;
    }
    digit(scanDigit, LEDdigit[scanDigit], LEDdecimal[scanDigit]);
  }

  //while  (millis() - start < interval)  //this will loop on the code constantly for the duration of interval
  if ((start - timer) >= interval)  //this will execute the code once when interval in reached
  {
    timer = start; //reset the timer   
    LEDdigit[0] = (lfrq / 100) % 10;
    LEDdigit[1] = (lfrq / 10) % 10;
    LEDdigit[2] = (lfrq % 10)  ;
  }
  sineWave();
  attachInterrupt(52,button,CHANGE);
  attachInterrupt(53,button,CHANGE);
}

void digit(int d, int n, int DP)
{ //turn all digits off, digit states are HIGH
  for (int i = 0; i < 3; i++) digitalWrite(digits[i], LOW); //changed from HIGH to LOW to disable the digits
  digitalWrite(LATCH, LOW);                                //add 128 for decimal point
  shiftOut(DATA, CLOCK, MSBFIRST, num[n]);
  digitalWrite(LATCH, HIGH);                               //change display pattern
  digitalWrite(digits[d], HIGH);                           //changed from LOW to HIGH here  //turn digit on, digit state LOW
}

void sineWave() { 
  spreod = constrain(spreod, 50, 100);
  if (micros() - startmicros >= spreod)
  {
  startmicros = micros();
  analogWrite(DAC0, waveformsTable[wave1][i]);  // write the selected waveform on DAC0

  i++;
  if(i == maxSamplesNum)  // Reset the counter to repeat the wave
    i = 0;
  startmicros = micros();
  }
}

void startPWM(uint32_t frequency, Pio* port, EPioType pinType, uint32_t pin, uint32_t pinConfig, uint32_t pwmChannel)
{
  uint32_t rc = frequency * 2;
  pmc_set_writeprotect(false);
  pmc_enable_periph_clk(PWM_INTERFACE_ID);
  //Set clock A to frequency in hz.
  PWMC_ConfigureClocks(rc, 0, VARIANT_MCK);
  //Changes the port and pin over to the requested peripheral.
  PIO_Configure(port, pinType, pin, pinConfig);
  //Set prescaler (PWM_CMR_CPRE_CLKA), alignment (0) and polarity (0).
  PWMC_ConfigureChannel(PWM_INTERFACE, pwmChannel, PWM_CMR_CPRE_CLKA, 0, 0);
  //Set period to 1MHz divided by the desired frequency.
  PWMC_SetPeriod(PWM_INTERFACE, pwmChannel, 2);
  //Set duty cycle to half of the period.
  PWMC_SetDutyCycle(PWM_INTERFACE, pwmChannel, 1); //50% high, 50% low
  PWMC_EnableChannel(PWM_INTERFACE, pwmChannel);
}

void button()
{
  if (millis() - bmillis >50)
  {
  bmillis = millis();  
  buttonStateplus = digitalRead(plusbuttonPin);
  if (buttonStateplus == LOW){
    spreod = spreod+1;  
    } 
  buttonStateminus = digitalRead(minusbuttonPin);
  if (buttonStateminus == LOW){
    spreod = spreod-1;
    }
  }
}

<FreqPeriodDue.h>

/*
  FreqPeriodDue.h

  Based loosely on the FreqPeriod library from:
  FreqPeriod.h - Library for a Frequency Measurement c.
  Created by Martin Nawrath, KHM Lab3, June. 2010
  Released into the public domain.
*/

#ifndef FreqPeriod_h
#define FreqPeriod_h

#include "Arduino.h"

//#define FR_USE_TC3
#define FR_USE_TC4
//#define FR_USE_TC5

#if defined(FR_USE_TC3) //Timer clock 3
  #define FR_USE_TC_IRQ   TC3_IRQn
  #define FR_USE_TC     TC1
  #define FR_USE_CH     0
  #define FR_TIMER_INTR_NAME  TC3_Handler
#elif defined(FR_USE_TC4) //Timer clock 4
  #define FR_USE_TC_IRQ   TC4_IRQn
  #define FR_USE_TC     TC1
  #define FR_USE_CH     1
  #define FR_TIMER_INTR_NAME  TC4_Handler
#elif defined(FR_USE_TC5) //Timer clock 5
  #define FR_USE_TC_IRQ   TC5_IRQn
  #define FR_USE_TC     TC1
  #define FR_USE_CH     2
  #define FR_TIMER_INTR_NAME  TC5_Handler
#endif

namespace FreqPeriod {


extern volatile unsigned char  f_capt;
extern volatile unsigned long capta;
extern volatile unsigned long captd;
extern volatile unsigned int ocnt;

  void FreqPulse();
  void begin(int periodPin);
  unsigned long getPeriod();  
}

#endif

"Waveforms.h"

#ifndef _Waveforms_h_
#define _Waveforms_h_

#define maxWaveform 4
#define maxSamplesNum 120

static int waveformsTable[maxWaveform][maxSamplesNum] = {
  // Sin wave
  {
    0x7ff, 0x86a, 0x8d5, 0x93f, 0x9a9, 0xa11, 0xa78, 0xadd, 0xb40, 0xba1,
    0xbff, 0xc5a, 0xcb2, 0xd08, 0xd59, 0xda7, 0xdf1, 0xe36, 0xe77, 0xeb4,
    0xeec, 0xf1f, 0xf4d, 0xf77, 0xf9a, 0xfb9, 0xfd2, 0xfe5, 0xff3, 0xffc,
    0xfff, 0xffc, 0xff3, 0xfe5, 0xfd2, 0xfb9, 0xf9a, 0xf77, 0xf4d, 0xf1f,
    0xeec, 0xeb4, 0xe77, 0xe36, 0xdf1, 0xda7, 0xd59, 0xd08, 0xcb2, 0xc5a,
    0xbff, 0xba1, 0xb40, 0xadd, 0xa78, 0xa11, 0x9a9, 0x93f, 0x8d5, 0x86a,
    0x7ff, 0x794, 0x729, 0x6bf, 0x655, 0x5ed, 0x586, 0x521, 0x4be, 0x45d,
    0x3ff, 0x3a4, 0x34c, 0x2f6, 0x2a5, 0x257, 0x20d, 0x1c8, 0x187, 0x14a,
    0x112, 0xdf, 0xb1, 0x87, 0x64, 0x45, 0x2c, 0x19, 0xb, 0x2,
    0x0, 0x2, 0xb, 0x19, 0x2c, 0x45, 0x64, 0x87, 0xb1, 0xdf,
    0x112, 0x14a, 0x187, 0x1c8, 0x20d, 0x257, 0x2a5, 0x2f6, 0x34c, 0x3a4,
    0x3ff, 0x45d, 0x4be, 0x521, 0x586, 0x5ed, 0x655, 0x6bf, 0x729, 0x794
  }
  ,

};

#endif m

ダウンロードしたArduino DUE用の周波数測定用コードのリンクです。
リンク内容
正弦波発生プログラムはArduino Forumのこちらのリンクをもとに作成しました。
リンク内容

試したこと

メインソースコードの

    pp = FreqPeriod::getPeriod();
  if (pp){
      lfrq= 42000000 / pp;
  }


を、関数startPWMの中に移動させてみると7セグLEDディスプレイのランダムな数値表示から"000"という表示に変わってしまいました。

補足情報(FW/ツールのバージョンなど)

Arduino DUEの書き込みのためにボードマネージャにてArduino SAM Boards バージン1.6.12をダウンロードしています。
また、FreqPeriodDue.hのコンパイルのためにはGitHubのソースコードをZIP形式でダウンロードしarduino IDEのライブラリのインクルードにてZIP形式で導入する必要があります。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+1

おそらく、割り込みか出力ピンがバッティングしてるんだろうけど、
以下確認してみよう

・7セグ表示を止めて、正弦波ユニットだけを動かせてきちんと出力されるのか
・7セグ表示のコモンラインの切り替えだけ実行させる(表示はしない)で、正弦波は出力されるか
・実際に7セグ表示させて正弦波出力はどうなるか

と、段階を踏んで確認してみる。ダメになったところにバグがあるので、回路図、コード含めて修正していこう


なんかコードを見てたらダメダメですね

  analogWrite(DAC0, waveformsTable[wave1][i]);  // write the selected waveform on DAC0

ここの変数iですが、他の場所でも使ってますね。
それは想定している動作なんでしょうか

#その他のところまで読んでらんない

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/02 19:35

    sineWava内のiはグローバル変数ですけどdigitのiはローカルでは?

    キャンセル

  • 2019/04/02 20:08

    アドバイスありがとうございます。
    とりあえず正弦波関数で使用している変数をiからkに変更してみました。
    アドバイスしていただいた他の関数とのバッティングの可能性についての検証を今度オシロスコープを使える機会にしていこうと思います。

    キャンセル

check解決した方法

0

アナログ出力チャンネルからのノイズの原因はソースコードのコピーミスでした。
本来あるはずだった

  analogWriteResolution(12);


を入れ忘れたのが原因です。
今回の修正でノイズ発生がなくなりました。

まだタクトスイッチを10回押さないと周波数が変化しなかったり時折、装置の出力が一時的に停止する現象があるのでまた質問させていただくかも知れません。

アドバイスしていただいた皆様、ありがとうございます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.83%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • Cに関する質問
  • ArduinoDUEで7セグディスプレイ付き正弦波発生装置を作ろうとしたところ、アナログ出力チャンネルにノイズが発生してしまいます。