Пощебечем? Часть I.

Тема в разделе "Глядите, что я сделал", создана пользователем parovoZZ, 1 авг 2019.

Метки:
  1. parovoZZ

    parovoZZ Гуру

    Во многих датчиках в качестве аварийного сигнала используется звуковое оповещение. Давайте тоже научим МК издавать такой сигнал. Исходные данные:
    МК MSP430FR2433
    Излучатель звука - пьезоэлемент.
    Напряжение питания - 3-3.3в
    Минимизация токов потребления.
    1. Схемотехника.
    Как подключить пьезоэлемент, чтобы получить максимальное акустическое давление при минимальном токе и минимальном напряжении? Во-первых, необходимо раскачивать пьезоизлучатель н частоте механического резонанса (всего резонансов у пьезоизлучателей - три). Во-вторых, необходимо акустическое оформление. В нашем случае я обойдусь просто диффузором, приклеенным к излучателю. Ну и третье - электрическое подключение. Самый верный способ при малом напряжении питания - автотрансформация. Способ хорош, но требует расчета и изготовления трансформатора. Поэтому пойдем другим путем. Применим мостовое включение пьезоизлучателя к МК. Да,теряем две ноги, но зато получаем удвоенный размах сигнала.
    2. Форма сигнала.
    Сигнал будет напоминать прерывистое щебетание. Вот его осциллограмма:
    tweet2.png
    3. Алгоритм программы.
    По осциллограмме четко прослеживаются следующие состояния: генерация меандра частотой 4кГц, пауза в генерации меандра, пауза между генерациями. Так и напрашивается конечный автомат. А так как периоды чередования состояний автомата заранее известны, то сделаем автоматический секвенсор состояний.
    4. Реализация.
    В нашем МК есть все для того, чтобы реализовать задуманное аппаратно. Генерацию меандра будем осуществлять на таймере TA0. Для этого воспользуемся двумя его компараторами. А вот для отсчета периодов состояний конечного автомата будем использовать таймер RTC. Таким бразом, большую часть времени мы будем спать просыпаясь лишь только для того, чтобы сменить состояние автомата.
     
    Un_ka, alex_rnd61 и Daniil нравится это.
  2. ИгорьК

    ИгорьК Гуру

    Лучше бы начали с инструкции как к нему провода присоединять. Или вы верите, что на форуме найдётся больше трёх человек, которые хотя бы слышали что это.
     
    Andrey12 нравится это.
  3. MSP430FR2433 - Что это ? :D
     
  4. DetSimen

    DetSimen Guest

    Великий знает.
     
  5. Airbus

    Airbus Радиохулиган Модератор

    ОНО?
    [​IMG]
    Стоит 1200 рублей
     
  6. Airbus

    Airbus Радиохулиган Модератор

  7. KindMan

    KindMan Гуру

    Он знает места в штатах, где за 4.30 можно взять.
    А продолжение где? А то пока только мы тут щебечем.
     
  8. Airbus

    Airbus Радиохулиган Модератор

    Я предложил дешевле пощебетать на одном транзисторе
    [​IMG]
     
    Aleksej и issaom нравится это.
  9. KindMan

    KindMan Гуру

    Тут вся загвоздка в трансформаторе, хрен найдешь такой, у кого есть радиоприемник Юность?
    А ТС нам пост образовательный пишет, так что ждём лектора.
     
  10. SergeiL

    SergeiL Оракул Модератор

    @parovoZZ похоже Абдурину второй версии готовит! :)
    Ждем!!! :)
     
    Airbus нравится это.
  11. Airbus

    Airbus Радиохулиган Модератор

    Мне влом под такую хрень 1200 платить.У меня Мурка на звонке играла на Тини13.Я лучше TTGO Esp32 с дисплеем за эту цену куплю
     
  12. ИгорьК

    ИгорьК Гуру

    Все вы о материальном... А человек рассказывает как он новые вершины покоряет.
    Вот смотри, в альпинизме, считай, никакой практической пользы, а люди этим увлекаются.
    Так и здесь - создам звоночек на никому неизвестной плате. Это уважаемо.
     
    Arduino_man и Airbus нравится это.
  13. DetSimen

    DetSimen Guest

    На этой плате можно не просто звоночек, а аркестар с 40-ка голосной полифонией сделать
     
  14. parovoZZ

    parovoZZ Гуру

    5. Выбор источника тактирования.
    Серия МК MSP430 обладает весьма развитой системой тактирования. Для серии MSP430FR2xx структурная схема этой системы представлена на рисунке ниже.
    CLK_MSP.png
    MCLK - это главный тактовый сигнал. От него тактируется ядро.
    SMCLK - это дополнительный тактовый сигнал.
    VLOCLK - это тактовый сигнал от микромощного внутреннего осциллятора VLO, который работает на частоте около 10 кГц.
    XT1CLK - это тактовый сигнал от внешнего осциллятора. Он может быть как низкочастотным (например, при работе от часового кварца), так и высокочастотным. Резонаторы для этого осциллятора могут быть как керамическими, так и кварцевыми.
    ACLK - дополнительный источник тактирования.
    MODLOCK - тактовый сигнал от осциллятора MODO. В MSP430FR2433 не представлен.
    Теперь об осцилляторах.
    DCO - это внутренний цифровой осциллятор с фазовой стабилизацией частоты. К нему можно подключить источники тактовых сигналов MCLK и SMCLK (по умолчанию они к нему и подключены). По умолчанию он работает на частоте 2 МГц.
    REFO - внутренний осциллятор с фазовой стабилизацией частоты. Типовая частота 32768 Гц. К этому осциллятору можно подключить все источники, кроме VLOCLK и MODCLK.
    Чтобы определиться, какой таймер к какому источнику подключить, необходимо вспомнить про наше требование о минимизации токопотребления. Начнем с режима сна. Всего их 6. Но самые интересные это LPM3, LPM4 и LPM3.5. LPM4.5 нам не интересен - там не работает вообще ничего.Смотрим таблицу из даташита.
    LPM3_4.png
    Сразу договоримся - система SVS у нас выключена. Смотрим: режим сна LPM3 с включенным внешним осциллятором и запущенным таймером RTC - 1.13 мкА. Это много. Тоже самое, но с VLO - 0.98 мкА. Уже лучше. LPM4: данных о токе с запущенными осцилляторами даташит не приводит, но можно ожидать, что VLO с запущенным RTC в этом режиме будет потреблять меньше, чем в LPM3. На этом и остановимся.
    Таймер TA0 мы можем подключить либо к ACLK, либо к SMCLK. Я пока выберу SMCLK. Позже сравним его с ACLK.
     
    Daniil нравится это.
  15. parovoZZ

    parovoZZ Гуру

    Покодим?
    Определяем состояния нашего конечного автомата
    Код (C++):
    enum    state_enum
            {
            pwm,
            pause,
            sleep
            } volatile  state = pwm;
    Состояния pwm и pause - это состояние генерации меандра и небольшая пауза между этими генерациями. Для входа в состояние sleep мы будем считать количество переходов pwm->pause. Для этого определим константу:
    Код (C++):
    #define CNT_TWEET   10
    и счетчик:
    Код (C++):
    volatile uint8_t    cnt_tweet;
    Отсчет периодов, в течение которых мы будем проводить в состояниях, будет осуществлять таймер RTC. Тактируем его от VLOCLK с частотой 10 кГц. У таймера всего одно прерывание по переполнению счетчика - по нему и будем определять конец периода текущего состояния. Чтобы было удобно отсчитывать интервалы, таймер RTC включим через делитель на 100. Таким образом, таймер RTC будет тикать каждые 0.1 сек. Соответственно, определяем ещё константы:
    Код (C++):
    #define FRQ_TWEET   2
    #define PAUSE_TWEET 40
    Максимальное значение счетчика определяется регистром RTCMOD. Этот регистр буферизированный. Значение из буфера в рабочий (так называемый теневой) регистр попадает тогда, когда счетчик таймера сбрасывается (либо принудительно из программы, либо по переполнению).
    Теперь запишем наш секвенсор состояний. Целиком функция выглядит так:
    Код (C++):
    inline void Set_State(void)
    {
        switch (state)
        {
        case pwm:

            TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;

            state = pause;
            break;

        case pause:

            TA0CTL = MC__STOP;

            if (--cnt_tweet)
            {
                state = pwm;
            }
            else
                {
                    state = sleep;

                    RTCMOD = PAUSE_TWEET;
                }      
            break;

        case sleep:
            cnt_tweet = CNT_TWEET;

            RTCMOD = FRQ_TWEET;

            state = pwm;

            break;

        }
    }
    Что же здесь происходит? При первом вызове данной функции мы находимся в состоянии pwm, т.е. генерации меандра. Поэтому при входе в обработчик этого состояния мы запускаем таймер TA0 в режим Up_Mode (см. рисунок ниже) и переключаемся в режим короткой паузы pause. В этом режиме мы выключаем таймер, при этом генерация меандра прекращается. Затем инкрементируем счетчик переходов pwm -> pause чтобы выяснить, наступил ли момент для "большой перемены" (sleep). Если наступил, то записываем в регистр RTCMOD значение константы, соответствующей желаемому периоду "большой перемены". На самом деле здесь программа выполняется так: в теневом регистре RTCMOD ещё лежит значение короткого периода для состояний pwm и pause. Значение периода "большой переменной" запишется в теневой регистр только после сброса счетчика RTCMOD. А произойдет это тогда, когда программа окажется в обработчике sleep. Нам такой сдвиг во времени никак не мешает и экономит выполнение одной инструкции - сброс счетчика таймера RTC.
    В обработчике состояния "большой перемены" мы взводим счетчик переходов pwm -> pause и записываем в RTC значение короткого периода.
    Вызывается эта функция-секвенсор в обработчике прерывания RTC.
     
    Последнее редактирование: 3 авг 2019
    Daniil нравится это.
  16. parovoZZ

    parovoZZ Гуру

    Главный цикл выглядит так:
    Код (C++):
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;                    // Stop WDT

        // Configure GPIO
        P1DIR = BIT1 | BIT2;
        P1SEL1 = BIT1 | BIT2;


        PM5CTL0 &= ~LOCKLPM5;

        // Configure Timer_A
        TA0CCR0 = 256;

        TA0CCTL1 = OUTMOD_2;                                                // Output mode Capture/Compare1 toggle/reset
        TA0CCR1 = MEANDR;

        TA0CCTL2 = OUTMOD_6;                                                // Output mode Capture/Compare2 toggle/set
        TA0CCR2 = MEANDR;

        TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;// | TAIE;        

        // Configure RTC
        RTCMOD = FRQ_TWEET;

        RTCCTL = RTCSS__VLOCLK | RTCPS__100 | RTCIE | RTCSR;                // RTC period ~0.1s, enable interrupt

        __bis_SR_register(LPM4_bits | GIE);                                 // Enter LPM4, enable interrupts
       // __no_operation();                                               // For debugger
    }
    Первые две строчки переводят пины МК на выход и подключают их к выходам компараторов таймера TA0. Далее следует настройкка таймера TA0.
    Код (C++):
    TA0CCR0 = 256;
    Здесь мы указываем максимальное значение счетчика таймера, после которого идет его сброс.
    Посмотрим на картинку из даташита:
    TA0.png
    Откуда видим, что чтобы получить разнополярные импульсы на выходе двух наших компараторов, необходимо первый заинициализировать как Output Mode 2, второй как Output Mode 6. Что мы и делаем:
    Код (C++):
        TA0CCTL1 = OUTMOD_2;                                                // Output mode Capture/Compare1 toggle/reset
        TA0CCR1 = MEANDR;

        TA0CCTL2 = OUTMOD_6;                                                // Output mode Capture/Compare2 toggle/set
        TA0CCR2 = MEANDR;
    Максимальная звуковая отдача пьезоэлемента будет при подаче на него меандра. Поэтому в регистры сравнения записываем половину от максимального счета счетчика таймера.
    Далее конфигурируем таймер TA0 на тактирование от SMCLK, задаем режим счета - считать вверх до значения регистра TA0CCR0 и далее сброс. Чтобы сменить режим счета, необходимо таймер сбросить. Для этого необходимо взвести бит TACLR:
    Код (C++):
    TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;// | TAIE;
    Далее инициализируем таймер RTC. Задаем значение регистра RTCMOD, по достижении значения которого таймер сбрасывается и формирует прерывание. Также задаем источник тактирования, включаем делитель со значением 100, разрешаем формирование прерывания и сбрасываем таймер.
    Код (C++):
    // Configure RTC
        RTCMOD = FRQ_TWEET;

        RTCCTL = RTCSS__VLOCLK | RTCPS__100 | RTCIE | RTCSR;                // RTC period ~0.1s, enable interrupt
    Значение делителя 100 выбрано для облегчения рассчета периодов сброса. При таком значении делителя счетчик таймера будет тикать примерно каждые 0.1 сек.
    Здесь нет цикла while(). Почему? Всё просто. Последняя инструкция - это режим сна. Когда MCU выходит из него (по прерыванию), значение регистра SR целиком помещается в стек, а сам MCU переходит в активный режим работы (если нет других указаний по смене текущего режима). После завершения обработки процедуры прерывания, значение регистра SR копируется из стека и MCU возвращается в тот режим, который был до прерывания. Таким образом, чтобы сменить текущий режим работы, необходимо явно это указать в программе.
    Ну и в обработчике прерывания мы просто вызываем рассмотренную раннее функцию:
    Код (C++):
    #pragma vector=RTC_VECTOR
        __interrupt void RTC_ISR(void)
    {
        switch (RTCIV)
        {
        case RTCIV_NONE:
            break;

        case RTCIV_RTCIF:
            Set_State();
            break;  

        }
    }
    Код полностью лежит здесь
    https://github.com/dashkova/MSP430FR/tree/master/MSP430FR2433/tweeter
     
    Последнее редактирование: 10 авг 2019
    Daniil нравится это.
  17. parovoZZ

    parovoZZ Гуру

    Программируется он по двум проводам. Не считая Vss и Vcc.

    Я уже писал, какие цели преследуются мной.

    хотел было взять у китайцев. Но у китайцев дороже, чем на маузере. А на маузере дороже, чем на сайте TI. А у них там ещё и скидка
    это очень громоздко, не энергоэффективно, не управляемо, не современно, дорого.

    без меня справились
    https://store.arduino.cc/usa/nano-every
    ATMega4809 - это полноценная версия аттиньки817, которую я здесь представлял.
     
  18. DetSimen

    DetSimen Guest

    Да ты все никак не угамонишься, демон. :)
     
    Airbus нравится это.
  19. Airbus

    Airbus Радиохулиган Модератор

    Пусть пишет.Изчо.
     
  20. Arduino_man

    Arduino_man Гик

    Четвертой. Известная сейчас Arduino Uno на самом деле R3 - третьей ревизии.