kewei_9900 发表于 2014-6-20 21:01:58

arduino中使用tone()函数出错问题

我初学arduino,买了一套arduino套件。我在http://www.geek-workshop.com/thread-2433-1-1.html学习了使用红外遥控器,然后想到用遥控器控制板子发音演奏音乐。我使用A2接受红外信号,4口控制蜂鸣器。使用代码如下#include <IRremote.h>// 使用IRRemote函数库

const int irReceiverPin = 2;// 红外接收器的 OUTPUT 引脚接在 PIN2 接口 定义irReceiverPin变量为PIN2接口

IRrecv irrecv(irReceiverPin); // 设置irReceiverPin定义的端口为红外信号接收端口
decode_results results;    // 定义results变量为红外结果存放位置

void setup()
{
irrecv.enableIRIn();   // 启动红外解码
pinMode(4,OUTPUT);    // 设置4口为输出模式
}

void loop()
{
int a;
if (irrecv.decode(&results)) {
    switch(results.value){
      case 16580863:(a=262);break;
      case 16613503:(a=294);break;
      case 16597183:(a=330);break;
      case 16589023:(a=349);break;
      case 16621663:(a=392);break;
      case 16605343:(a=440);break;
      case 16584943:(a=494);break;
      case 16617583:(a=523);break;
      case 16601263:(a=587);break;
      case 16593103:(a=659);break;
      case 16625743:(a=698);break;
      case 16609423:(a=784);break;
      case 16582903:(a=889);break;
      case 16615543:(a=988);break;
      case 16599223:(a=1046);break;
      case 16591063:(a=1175);break;
      case 16623703:(a=1318);break;
      case 16607383:(a=1397);break;
      case 16586983:(a=1568);break;
      case 16619623:(a=1760);break;
      case 16603303:(a=1976);break;
      default:(a=0); // 使红外代码与频率对应
    }
    tone(4,a,300); // 4口发音,持续300毫秒
    irrecv.resume();    // 继续等待接收下一组信号
}
delay(600); //延时600毫秒,做一个简单的消抖
}
结果编译出错,显示。
经过反复调试,发现故障在tone()函数,只要没有这个函数就能正常工作,比如这个程序能工作#include <IRremote.h>// 使用IRRemote函数库

const int irReceiverPin = 2;// 红外接收器的 OUTPUT 引脚接在 PIN2 接口 定义irReceiverPin变量为PIN2接口

IRrecv irrecv(irReceiverPin); // 设置irReceiverPin定义的端口为红外信号接收端口
decode_results results;    // 定义results变量为红外结果存放位置

void setup()
{
irrecv.enableIRIn();   // 启动红外解码
pinMode(4,OUTPUT);
Serial.begin(9600);
}

void loop()
{
int a;
if (irrecv.decode(&results)) {
    switch(results.value){
      case 16580863:(a=262);break;
      case 16613503:(a=294);break;
      case 16597183:(a=330);break;
      case 16589023:(a=349);break;
      case 16621663:(a=392);break;
      case 16605343:(a=440);break;
      case 16584943:(a=494);break;
      case 16617583:(a=523);break;
      case 16601263:(a=587);break;
      case 16593103:(a=659);break;
      case 16625743:(a=698);break;
      case 16609423:(a=784);break;
      case 16582903:(a=889);break;
      case 16615543:(a=988);break;
      case 16599223:(a=1046);break;
      case 16591063:(a=1175);break;
      case 16623703:(a=1318);break;
      case 16607383:(a=1397);break;
      case 16586983:(a=1568);break;
      case 16619623:(a=1760);break;
      case 16603303:(a=1976);break;
      default:(a=0);
    }
      Serial.println(a);
    irrecv.resume();    // 继续等待接收下一组信号
}
delay(600); //延时600毫秒,做一个简单的消抖
}

请大家赐教,为啥tone()会出错,是不是与红外解码的库有矛盾,怎么解决?

BG2IUG 发表于 2015-1-30 23:08:27

我也出现了同样问题,有高人给解答一下吧!!!

jng114253501 发表于 2015-6-7 07:35:29

4口不支持pwm
建议你换成3/5/6这样的输出口播放声音

TylerTian 发表于 2015-7-15 14:42:05

本帖最后由 TylerTian 于 2015-7-15 14:46 编辑

出错是因为Arduino IDE 中的tone函数和IRremote函数中都用到了同一个定时器,对于这个问题目前还没有好的解决方法,如果你懂的话应该可以重新写一下IRremote.cpp,用一个不同的定时器,或者重新写tone函数也可以

这是在别的地方看到的一个可以代替tone函数的函数:
void newtone(byte tonePin, int frequency, int duration) {
int period = 1000000L / frequency;
int pulse = period / 2;
for (long i = 0; i < duration * 1000L; i += period) {
digitalWrite(tonePin, HIGH);
delayMicroseconds(pulse);
digitalWrite(tonePin, LOW);
delayMicroseconds(pulse);
}
}

飞water 发表于 2015-8-8 13:44:13

TylerTian 发表于 2015-7-15 14:42 static/image/common/back.gif
出错是因为Arduino IDE 中的tone函数和IRremote函数中都用到了同一个定时器,对于这个问题目前还没有好的解 ...

请问Arduino里面的自带函数在哪里可以看到实现原型?
比如说digitalWrite,delay,tone……

mnbvb 发表于 2018-3-3 20:54:21

请问楼主解决了问题没有?我现在遇到同样的麻烦,烦请楼主赐教

shouzama 发表于 2018-3-3 23:42:49

本帖最后由 shouzama 于 2018-3-4 17:03 编辑

mnbvb 發表於 2018-3-3 20:54
請問樓主解決了問題沒有?我現在遇到同樣的麻煩,煩請樓主賜教
當初庫相衝時,我也發現了是它們動用到同一個計時器所造成,
要重寫 IR_REMOTE 或 TONE? 我覺得應該是 TONE 比較簡單,
上網找了一些資料後(因為資料比較雜,已記不得資料來源),
我自己寫了個函式,並且跟 TONE 進行比較,微調常數、修改程式...
反覆測試多次後,完成了取代 TONE 的自製函式

以下是我的測試程式(程式碼是基於 TONE 的範例程式進行修改
做成),可以在 BZ 硬體接線完成的狀態下,先上傳這個程式試試看
自製函式跟 TONE 函式聲音是否明顯不同(我是聽不出來有明顯差別 ^^" ):
==========================

#include <Pitches.h>                //這份 .h 的音符定義檔我有重新改過,必要時請修改 melody 陣列定義內容

//定義 NOP (虛工指令)
#define NOP do { __asm__ __volatile__ ("nop"); } while (0)

#define SPEAKER 11             //定義喇叭接腳

//小蜜蜂 = 62
int melody[]= { Note_G5, Note_E5, Note_E5, 0, Note_F5, Note_D5, Note_D5, 0,
                Note_C5, Note_D5, Note_E5, Note_F5, Note_G5, Note_G5, Note_G5, 0,
            Note_G5, Note_E5, Note_E5, 0, Note_F5, Note_D5, Note_D5, 0,
            Note_C5, Note_E5, Note_G5, Note_G5, Note_E5, 0,
            Note_D5, Note_D5, Note_D5, Note_D5, Note_D5, Note_E5, Note_F5, 0,
            Note_E5, Note_E5, Note_E5, Note_E5, Note_E5, Note_F5, Note_G5, 0,
            Note_G5, Note_E5, Note_E5, 0, Note_F5, Note_D5, Note_D5, 0,
            Note_C5, Note_E5, Note_G5, Note_G5, Note_C5, 0 };   
int noteDurations[]={ 4, 4, 4, 4, 4, 4, 4, 4,
                      4, 4, 4, 4, 4, 4, 4, 4,
                      4, 4, 4, 4, 4, 4, 4, 4, 4,
                      4, 4, 4, 4, 2, 2,
                      4, 4, 4, 4, 4, 4, 4, 4,
                      4, 4, 4, 4, 4, 4, 4, 4,
                      4, 4, 4, 4, 4, 4, 4, 4, 4,
                      4, 4, 4, 4, 2, 2 };

//撰寫自己的延時函式(以奈秒計)
void delayNANO( unsigned long NANO )      //無回傳值,引數 NANO 為延時奈秒值
{
for (unsigned long I=0; I< (unsigned int) (NANO*1.3) ; I++)
    { NOP; }
}

//撰寫自己的響音函式,引數:喇叭接腳定義 SPEAKER_PIN,音頻定義 FREQUENCY,節拍定義 TEMPO
void sz_tone( int SPEAKER_PIN, int FREQUENCY, unsigned long TEMPO )
{
pinMode( SPEAKER_PIN, OUTPUT);      //定義喇叭接腳為輸出用

unsigned long CYCLE = 1000000/FREQUENCY;      //一開始CYCLE*1000倍提高換算精確度,算出週期時間
unsigned long LOOP = ( TEMPO*1000 / CYCLE);   //迴圈數(多=時間長)=分子*1000倍調回正常比例
if ( FREQUENCY == 0)                //若頻率值為 0 (休止符)則延遲 TEMPO 時間不發聲
    delay( TEMPO );
else                                           //若頻率值不為 0 (非休止符) 則發聲
{
    for ( unsigned long I=0; I < LOOP; I++ )    //發聲時間長短由 LOOP 設定
    {
      digitalWrite( SPEAKER_PIN, HIGH );   //發聲音
      delayNANO( CYCLE/2 );                  //延時1/2週期
      digitalWrite( SPEAKER_PIN, LOW );    //不發聲音
      delayNANO( CYCLE/2 );                  //延時1/2週期
    }
}
delay( int ( TEMPO*0.3 ));            //暫停(音符間的區隔)
}

void setup()
{

}

void loop()
{
//先用自己寫的函式演奏小蜜峰,共 62 音符(含休止符)
for (int thisNote = 0; thisNote < 62; thisNote++)
{
    int noteDuration = 1000 / noteDurations;
    sz_tone(SPEAKER, melody, noteDuration);    //函式內已內建音符區隔的暫停
}
delay(2000);
//再用標準 tone 函式演奏
for (int thisNote = 0; thisNote < 62; thisNote++)
{
    // to calculate the note duration, take one second divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000 / noteDurations;
    tone( SPEAKER, melody, noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(SPEAKER);
}
delay(2000);
}
==========================
函式已實測修正過 ^^

msold5 发表于 2018-3-8 12:12:25

shouzama 发表于 2018-3-3 23:42
當初庫相衝時,我也發現了是它們動用到同一個計時器所造成,
要重寫 IR_REMOTE 或 TONE? 我覺得應該是 TON ...

:hug:厉害!
页: [1]
查看完整版本: arduino中使用tone()函数出错问题