Колокольчик на Arduino (Buzzer)

Тема в разделе "Arduino & Shields", создана пользователем Alexey Zhigalo, 23 май 2016.

  1. Доброго времени суток!
    Вот пытаюсь собрать что то подобное на Arduino.
    Вот ссылка: https://www.drive2.ru/c/1195541/

    Проблема в том, что как обычно, нечего не работает.
    Вот код оригинал:
    Код (C++):
    /*
    * Bell.c
    *
    * Зуммер "Колокольчик"
    *
    * Author: Погребняк Дмитрий, г. Самара, 2014
    *
    * Помещённый здесь код является свободным. Т.е. допускается его свободное использование для любых целей,
    * включая коммерческие, при условии указания ссылки на автора (Погребняк Дмитрий, http://aterlux.ru/).
    */



    #include <avr/io.h>
    #include <avr/pgmspace.h>

    #define WAVE1_FADE_STEP 200
    #define WAVE2_FADE_STEP 150

    #define WAVE1_INITIAL_AMP 180
    #define WAVE2_INITIAL_AMP 200

    // возвращает знаковое произведение знакового и беззнакового параметров, сдвинутое вправо на 8 разрядов
    //extern int8_t mul_s_u_shr8(int8_t, uint8_t);

    // Частота тона = 9600000 (частота МК) / 256 (период таймера) / размер_массива = 37500 / размер_массива
    /*// Колокольчик 585 Гц, размер массива = 64
    const int8_t wave1[] PROGMEM = { // Форманта (синусоида)
      0, 6, 12, 19, 24, 30, 36, 41, 45, 49, 53, 56, 59, 61, 63, 64, 64,
       64, 63, 61, 59, 56, 53, 49, 45, 41, 36, 30, 24, 19, 12, 6, 0,
       -6, -12, -19, -24, -30, -36, -41, -45, -49, -53, -56, -59, -61, -63, -64, -64,
       -64, -63, -61, -59, -56, -53, -49, -45, -41, -36, -30, -24, -19, -12, -6
    };

    const int8_t wave2[] PROGMEM = { // Обертоны
      0, 27, 47, 59, 62, 59, 53, 45, 37, 28, 20, 12, 6, -1, -6, -11, -14,
       -18, -20, -22, -23, -23, -23, -22, -21, -19, -17, -15, -12, -10, -6, -3, 0,
       3, 6, 10, 12, 15, 17, 19, 21, 22, 23, 23, 23, 22, 20, 18, 14,
       11, 6, 1, -6, -12, -20, -28, -37, -45, -53, -59, -62, -59, -47, -27
    };
    */

    // Колокольчик 893 Гц, размер массива = 42
    const int8_t wave1[] PROGMEM = { // Форманта (синусоида)
      0, 10, 19, 28, 36, 44, 50, 55, 60, 62, 64, 64, 62, 60, 55, 50, 44,
       36, 28, 19, 10, 0, -10, -19, -28, -36, -44, -50, -55, -60, -62, -64, -64,
       -62, -60, -55, -50, -44, -36, -28, -19, -10
    };

    const int8_t wave2[] PROGMEM = { // Обертоны
      0, 12, 23, 32, 38, 41, 42, 42, 42, 40, 38, 36, 34, 32, 30, 28, 26,
       24, 22, 20, 18, 16, 15, 13, 12, 10, 9, 7, 6, 4, 3, 1, 0,
       -1, -3, -4, -6, -7, -9, -10, -12, -13
    };


    int main(void)
    {
      DDRB = (1 << PORTB0);
      PORTB = 0;
     
      uint8_t wave_pos = 0;
      uint8_t w1amp = 0;
      uint8_t w2amp = 0;
      uint8_t w1step = 0;
      uint8_t w2step = 0;
     
      OCR0A = 128;
      TCCR0A = 0b11000011;
      TCCR0B = 0b00000001;
     
      while(1)
      {
        if (!w1step) {
          w1step = WAVE1_FADE_STEP;
          if (!w1amp) {
            w1amp = WAVE1_INITIAL_AMP;
            w2amp = WAVE2_INITIAL_AMP;
            w2step = WAVE2_FADE_STEP;
            wave_pos = 0;
          } else {
            w1amp--;
          }
        } else {
          w1step--;
        }
        if (!w2step) {
          w2step = WAVE2_FADE_STEP;
          if (w2amp) {
            w2amp--;
          }
        } else {
          w2step--;
        }
        uint8_t a = 128 +
            mul_s_u_shr8((int8_t)pgm_read_byte(&wave1[wave_pos]), w1amp) +
            mul_s_u_shr8((int8_t)pgm_read_byte(&wave2[wave_pos]), w2amp);
        wave_pos++;
        if (wave_pos >= sizeof(wave1))
          wave_pos = 0;
       
        while (!(TIFR0 & (1 << TOV0)));
        OCR0A = a;
        TIFR0 |= (1 << TOV0);
            //TODO:: Please write your application code
      }
    }
    Вот как перевел для Arduino:

    Код (C++):
    #include <avr/io.h>
    #include <avr/pgmspace.h>

    #define WAVE1_FADE_STEP 200
    #define WAVE2_FADE_STEP 150

    #define WAVE1_INITIAL_AMP 180
    #define WAVE2_INITIAL_AMP 200

    //extern int8_t mul_s_u_shr8(int8_t, uint8_t);
    inline int8_t mul_s_u_shr8(int8_t s, uint8_t u) { return (s * u) >> 8; }

    // Колокольчик 893 Гц, размер массива = 42
    const int8_t wave1[] PROGMEM = { // Форманта (синусоида)
      0, 10, 19, 28, 36, 44, 50, 55, 60, 62, 64, 64, 62, 60, 55, 50, 44,
       36, 28, 19, 10, 0, -10, -19, -28, -36, -44, -50, -55, -60, -62, -64, -64,
       -62, -60, -55, -50, -44, -36, -28, -19, -10
    };

    const int8_t wave2[] PROGMEM = { // Обертоны
      0, 12, 23, 32, 38, 41, 42, 42, 42, 40, 38, 36, 34, 32, 30, 28, 26,
       24, 22, 20, 18, 16, 15, 13, 12, 10, 9, 7, 6, 4, 3, 1, 0,
       -1, -3, -4, -6, -7, -9, -10, -12, -13
    };

      uint8_t wave_pos = 0;
      uint8_t w1amp = 0;
      uint8_t w2amp = 0;
      uint8_t w1step = 0;
      uint8_t w2step = 0;

    void setup()
    {
      DDRB = (2 << PORTB0);
      PORTB = 0;
     
      OCR0A = 128;
      TCCR0A = 0b11000011;
      TCCR0B = 0b00000001;

    }

    void loop()
    {
      if (!w1step) {
          w1step = WAVE1_FADE_STEP;
          if (!w1amp) {
            w1amp = WAVE1_INITIAL_AMP;
            w2amp = WAVE2_INITIAL_AMP;
            w2step = WAVE2_FADE_STEP;
            wave_pos = 0;
          } else {
            w1amp--;
          }
        } else {
          w1step--;
        }
        if (!w2step) {
          w2step = WAVE2_FADE_STEP;
          if (w2amp) {
            w2amp--;
          }
        } else {
          w2step--;
        }
        uint8_t a = 128 +
            mul_s_u_shr8((int8_t)pgm_read_byte(&wave1[wave_pos]), w1amp) +
            mul_s_u_shr8((int8_t)pgm_read_byte(&wave2[wave_pos]), w2amp);
        wave_pos++;
        if (wave_pos >= sizeof(wave1))
          wave_pos = 0;
       
        while (!(TIFR0 & (1 << TOV0)));
        OCR0A = a;
        TIFR0 |= (1 << TOV0);
            //TODO:: Please write your application code
     
    }
    Ошибка была в строке:
    Код (C++):
    // возвращает знаковое произведение знакового и беззнакового параметров, сдвинутое вправо на 8 разрядов
    extern int8_t mul_s_u_shr8(int8_t, uint8_t);
    Заменил на это:
    Код (C++):
    inline int8_t mul_s_u_shr8(int8_t s, uint8_t u) { return (s * u) >> 8; }
    Пробовал компилировать оба кода, только с заменой mul_s_u_shr8.
    Код заливается, но звуки не воспроизводятся.

    В чем может быть проблема ?
     
  2. ostrov

    ostrov Гуру

    Просто интересно, для практического применения или из спортивного интереса? Если первое, то не проще ли мп3 плеер со звуками хоть соловьиной трели поставить?
     
  3. Скорее всего для второго. При mp3 или waw, это намного ресурсозатратно...
     
  4. ostrov

    ostrov Гуру

    Отнюдь, модуль недорогой.
     
  5. Так дело не в цене. Зачем отдельный модуль для такой примитивной задачи ?
     
  6. rust777

    rust777 Нуб

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>

    #ifdef __AVR_MEGA__
    // Если у нас процессор со встроенным умножением (мега) - то его и используем
    inline int8_t mul_s_u_shr8(int8_t s, uint8_t u) { return (s * u) >> 8; }
    #else
    // Для tiny - вызовем функцию которая не более чем за 78 тактов сделает то же самое
    extern int8_t mul_s_u_shr8(int8_t, uint8_t);
    #endif [/code]
    прошло много времени а проблема так и осталась а ведь все просто надо добавить не достающий код
    Код (Text):
    Быстрое умножение на ассемблере

    #include <avr/io.h>

    .global mul_s_u_shr8 // Ассемблерная функция должна быть объявлена global

    // Функция максимум за 78 таков выполняет умножение знакового и беззнакового 8-битных чисел,
    // сдвигает произведенеи вправо на 8 разрядов (возвращает старший байт результата)
    mul_s_u_shr8:
    // r24 - первый множитель (int8_t), r22 - второй множитель (uint8_t), результат (int8_t) в r24

       mov r21, r24
       clr r23 // r24:r23 - сумма
       clr r24
       clr r20 //r21:r20 - второй параметр расширенный до 16 бит, сдвигаемый на каждом шаге вправо арифметически


       tst r22
       breq end // Если ноль, то сразу выходим
      cycle:
         brpl no_bit  // Если старший бит не установлен, то ничего не делаем
           // Иначе прибавляем к сумме наш аргумент
           asr r21
           ror r20
           add r23, r20
           adc r24, r21
           lsl r22
         brne cycle // Продолжаем пока не вытолкаем все биты
         ret
        no_bit:
         asr r21
         ror r20
         lsl r22
       brne cycle // Продолжаем пока не вытолкаем все биты
      end:
    ret