• Как микроконтроллером выводить звук через ШИМ и таймеры?

    Ocelot
    @Ocelot
    Допустим, нужно сгенерировать какой-нибудь семпл — кусок звуковой волны. Неважно, что это будет: синус или что посложнее.

    1) Делим этот семпл на отсчеты. Каждый отсчет представляет собой мгновенное значение уровня сигнала (напряжение на обмотке динамика). Частота следования отсчетов — частота дискретизации — должна быть как мининум вдвое выше максимальной частоты воспроизводимого звука. Нужен голос (диапазон от 300 до 3800 Гц) — берем частоту дискретизации 7,6 кГц. Нужна музыка — еще выше.
    Значения отсчетов можно хранить в виде массивов или генерировать на лету.

    2) Каждому отсчету соответствует своя скважность ШИМ. Соотв., при частоте дискретизации 7,6 кГц нужно 7600 раз в секунду задавать новую скважность.

    3) Какая нужна частота ШИМ? Между соседними отсчетами должно укладываться несколько периодов несущей. Больше — лучше. Сколько именно — зависит от требуемого уровня шума, аналоговых фильтров на выходе и т.д. (там довольно суровый матан). Для простоты возьмем частоту ШИМ в 10 раз выше частоты дискретизации — 76 кГц.

    4) Какая должна быть разрядность ШИМ? Зависит от требуемого динамического диапазона. 8-битный ШИМ даст отношение самого громкого и самого тихого сигнала 256:1 (~24 дБ). 16-битный — 65536:1 (~48 дБ).

    5) Какая в итоге нужна тактовая частота? F = (частота ШИМ) * 2(разрядность ШИМ). Для нашего случая с 8-битным ШИМом — почти 20 МГц. Если нужен phase-correct PWM — еще в два раза выше.
    Ответ написан
    Комментировать
  • Прерываниями по таймерам Arduino MEGA?

    Ocelot
    @Ocelot
    void setup()
    {
    //------ Timer0 ----------
    TCCR0A = (1<<WGM01);   // Режим CTC (сброс по совпадению)
    TCCR0B = (1<<CS00);    // Тактирование от CLK.
                           // Если нужен предделитель :
    // TCCR0B = (1<<CS01);           // CLK/8
    // TCCR0B = (1<<CS00)|(1<<CS01); // CLK/64
    // TCCR0B = (1<<CS02);           // CLK/256
    // TCCR0B = (1<<CS00)|(1<<CS02); // CLK/1024
    
    OCR0A = 123;            // Верхняя граница счета. Диапазон от 0 до 255.
                            // Частота прерываний будет = Fclk/(N*(1+OCR0A)) 
                            // где N - коэф. предделителя (1, 8, 64, 256 или 1024)
    TIMSK0 = (1<<OCIE0A);   // Разрешить прерывание по совпадению
    
    //------ Timer1 ----------
    TCCR1B = (1<<WGM12);    // Режим CTC (сброс по совпадению)
    TCCR1B |= (1<<CS10);    // Тактирование от CLK.
                            // Если нужен предделитель :
    // TCCR1B |= (1<<CS11);           // CLK/8
    // TCCR1B |= (1<<CS10)|(1<<CS11); // CLK/64
    // TCCR1B |= (1<<CS12);           // CLK/256
    // TCCR1B |= (1<<CS10)|(1<<CS12); // CLK/1024
    
    OCR1A = 2678;           // Верхняя граница счета. Диапазон от 0 до 65535.
                            // Частота прерываний будет = Fclk/(N*(1+OCR1A)) 
                            // где N - коэф. предделителя (1, 8, 64, 256 или 1024)
    TIMSK1 = (1<<OCIE1A);   // Разрешить прерывание по совпадению
    
    //------ Timer2 ----------
    TCCR2A = (1<<WGM21);    // Режим CTC (сброс по совпадению)
    TCCR2B = (1<<CS20);     // Тактирование от CLK.
                            // Если нужен предделитель :
    // TCCR2B = (1<<CS21);                     // CLK/8
    // TCCR2B = (1<<CS20)|(1<<CS21);           // CLK/32
    // TCCR2B = (1<<CS22);                     // CLK/64
    // TCCR2B = (1<<CS20)|(1<<CS22);           // CLK/128
    // TCCR2B = (1<<CS21)|(1<<CS22);           // CLK/256
    // TCCR2B = (1<<CS20)|(1<<CS21)|(1<<CS22); // CLK/1024
    
    OCR2A = 234;            // Верхняя граница счета. Диапазон от 0 до 255.
                            // Частота прерываний будет = Fclk/(N*(1+OCR2A)) 
                            // где N - коэф. предделителя (1, 8, 32, 64, 128, 256 или 1024)
    TIMSK2 = (1<<OCIE2A);   // Разрешить прерывание по совпадению
    
    sei ();                 // Глобально разрешить прерывания
    }
    
    ISR (TIMER0_COMPA_vect)
    {
        // Обработчик прерывания таймера 0
    }
    
    ISR (TIMER1_COMPA_vect)
    {
        // Обработчик прерывания таймера 1
    }
    
    ISR (TIMER2_COMPA_vect)
    {
        // Обработчик прерывания таймера 2
    }
    


    Вместо тега CODE тег SOURCE используй, юный падаван.
    Ответ написан
    Комментировать
  • Инструменты для научных вычислений?

    doxtarzlo
    @doxtarzlo
    Научные вычисления? Почему бы не MATLAB?
    Ответ написан
    Комментировать
  • Универсальная IDE?

    @gribozavr
    Можно автоматизировать процесс только для очень общих и часто повторяющихся вещей, но у каждой конкретной ISA всегда свои заморочки. Вот посмотрите в LLVM: довольно большая часть ассемблеров/дизассемблеров генерируется автоматически, но всё равно рядом всегда есть код на C++ для обоработки команд, не попадающих под стандартные случаи.

    И да, «генерируется автоматически» — из описания на специальном языке, которое для большой ISA тоже будет большое.

    Так что чуда не будет.

    llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?revision=168886&view=markup

    Вот например (часть) описания команд ARM. Всего-то 200 Кб, и это на специально созданном для этого языке.
    Ответ написан
    Комментировать
  • Универсальная IDE?

    AterCattus
    @AterCattus
    Люблю быстрый backend
    Может быть RadASM? У него под разные ассемблеры (и более высокоуровневые ЯП) свои настройки. Соотвественно и свои добавить всегда можно.
    Ответ написан
    4 комментария