You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
IoT-For-Beginners/translations/fi/6-consumer/lessons/1-speech-recognition/wio-terminal-audio.md

25 KiB

Tallenna ääntä - Wio Terminal

Tässä oppitunnin osassa kirjoitat koodia äänen tallentamiseen Wio Terminal -laitteellasi. Äänen tallennusta ohjataan yhdellä Wio Terminalin yläosassa olevista painikkeista.

Ohjelmoi laite tallentamaan ääntä

Voit tallentaa ääntä mikrofonista C++-koodilla. Wio Terminalissa on vain 192KB RAM-muistia, mikä ei riitä tallentamaan kuin muutaman sekunnin ääntä. Siinä on kuitenkin 4MB flash-muistia, jota voidaan käyttää tallentamalla ääni flash-muistiin.

Sisäänrakennettu mikrofoni tallentaa analogisen signaalin, joka muunnetaan digitaaliseksi signaaliksi, jota Wio Terminal voi käyttää. Kun ääntä tallennetaan, tiedot on tallennettava oikeaan aikaan esimerkiksi 16 kHz:n äänen tallentamiseksi ääni on tallennettava tarkalleen 16 000 kertaa sekunnissa, tasaisin välein jokaisen näytteen välillä. Sen sijaan, että koodisi hoitaisi tämän, voit käyttää suoran muistin pääsyn ohjainta (DMAC). Tämä on piiri, joka voi tallentaa signaalin jostain ja kirjoittaa sen muistiin keskeyttämättä prosessorilla ajettavaa koodiasi.

Lue lisää DMA:sta Wikipedia-artikkelista suorasta muistin pääsystä.

Ääni mikrofonista menee ADC:n kautta DMAC:lle. Tämä kirjoittaa yhteen puskuriin. Kun tämä puskuri on täynnä, se käsitellään ja DMAC kirjoittaa toiseen puskuriin

DMAC voi tallentaa ääntä ADC:ltä kiintein välein, esimerkiksi 16 000 kertaa sekunnissa 16 kHz:n ääntä varten. Se voi kirjoittaa nämä tallennetut tiedot ennalta varattuun muistipuskuriin, ja kun tämä on täynnä, se ilmoittaa koodillesi, että puskuri on valmis käsiteltäväksi. Tämän muistin käyttö voi viivästyttää äänen tallennusta, mutta voit asettaa useita puskureita. DMAC kirjoittaa puskuriin 1, ja kun se on täynnä, se ilmoittaa koodillesi käsitellä puskuri 1, samalla kun DMAC kirjoittaa puskuriin 2. Kun puskuri 2 on täynnä, se ilmoittaa koodillesi ja palaa kirjoittamaan puskuriin 1. Näin kauan kuin käsittelet jokaisen puskurin nopeammin kuin sen täyttymiseen kuluva aika, et menetä mitään tietoja.

Kun jokainen puskuri on tallennettu, se voidaan kirjoittaa flash-muistiin. Flash-muistiin on kirjoitettava määritellyillä osoitteilla, jotka määrittävät, mihin kirjoitetaan ja kuinka paljon kirjoitetaan, mikä on samanlaista kuin tavutaulukon päivittäminen muistissa. Flash-muistilla on rakeisuus, mikä tarkoittaa, että tyhjennys- ja kirjoitustoiminnot eivät perustu vain kiinteään kokoon, vaan myös kohdistuvat siihen kokoon. Esimerkiksi, jos rakeisuus on 4096 tavua ja pyydät tyhjennystä osoitteessa 4200, se voi tyhjentää kaikki tiedot osoitteista 40968192. Tämä tarkoittaa, että kun kirjoitat äänitiedot flash-muistiin, niiden on oltava oikean kokoisissa paloissa.

Tehtävä - konfiguroi flash-muisti

  1. Luo uusi Wio Terminal -projekti PlatformIO:lla. Nimeä tämä projekti smart-timer. Lisää koodia setup-funktioon sarjaportin konfiguroimiseksi.

  2. Lisää seuraavat kirjastoriippuvuudet platformio.ini-tiedostoon, jotta saat pääsyn flash-muistiin:

    lib_deps =
        seeed-studio/Seeed Arduino FS @ 2.1.1
        seeed-studio/Seeed Arduino SFUD @ 2.0.2
    
  3. Avaa main.cpp-tiedosto ja lisää seuraava include-direktiivi flash-muistikirjastolle tiedoston alkuun:

    #include <sfud.h>
    #include <SPI.h>
    

    🎓 SFUD tarkoittaa Serial Flash Universal Driveria, ja se on kirjasto, joka on suunniteltu toimimaan kaikkien flash-muistisirujen kanssa.

  4. Lisää setup-funktioon seuraava koodi flash-muistikirjaston alustamiseksi:

    while (!(sfud_init() == SFUD_SUCCESS))
        ;
    
    sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25Q32_DEVICE_INDEX), 2);
    

    Tämä silmukoi, kunnes SFUD-kirjasto on alustettu, ja kytkee sitten päälle nopean lukemisen. Sisäänrakennettuun flash-muistiin pääsee Queued Serial Peripheral Interface (QSPI) -liitännän kautta, joka on eräänlainen SPI-ohjain, joka mahdollistaa jatkuvan pääsyn jonon kautta minimaalisella prosessorin käytöllä. Tämä tekee flash-muistin lukemisesta ja kirjoittamisesta nopeampaa.

  5. Luo uusi tiedosto src-kansioon nimeltä flash_writer.h.

  6. Lisää tämän tiedoston alkuun seuraava:

    #pragma once
    
    #include <Arduino.h>
    #include <sfud.h>
    

    Tämä sisältää tarvittavat otsikkotiedostot, mukaan lukien SFUD-kirjaston otsikkotiedoston flash-muistin kanssa vuorovaikuttamista varten.

  7. Määritä uusi luokka nimeltä FlashWriter tässä otsikkotiedostossa:

    class FlashWriter
    {
    public:
    
    private:
    };
    
  8. Lisää private-osioon seuraava koodi:

    byte *_sfudBuffer;
    size_t _sfudBufferSize;
    size_t _sfudBufferPos;
    size_t _sfudBufferWritePos;
    
    const sfud_flash *_flash;
    

    Tämä määrittää kenttiä puskurille, jota käytetään tietojen tallentamiseen ennen niiden kirjoittamista flash-muistiin. Siinä on tavutaulukko, _sfudBuffer, johon tiedot kirjoitetaan, ja kun tämä on täynnä, tiedot kirjoitetaan flash-muistiin. Kenttä _sfudBufferPos tallentaa nykyisen sijainnin, johon kirjoitetaan tässä puskurissa, ja _sfudBufferWritePos tallentaa sijainnin flash-muistissa, johon kirjoitetaan. _flash on osoitin flash-muistiin, johon kirjoitetaan joissakin mikrokontrollereissa on useita flash-muistisiruja.

  9. Lisää seuraava metodi public-osioon tämän luokan alustamiseksi:

    void init()
    {
        _flash = sfud_get_device_table() + 0;
        _sfudBufferSize = _flash->chip.erase_gran;
        _sfudBuffer = new byte[_sfudBufferSize];
        _sfudBufferPos = 0;
        _sfudBufferWritePos = 0;
    }
    

    Tämä konfiguroi Wio Terminalin flash-muistin kirjoittamista varten ja asettaa puskurit flash-muistin rakeisuuden perusteella. Tämä on init-metodissa, eikä konstruktorissa, koska tämä on kutsuttava sen jälkeen, kun flash-muisti on alustettu setup-funktiossa.

  10. Lisää seuraava koodi public-osioon:

    void writeSfudBuffer(byte b)
    {
        _sfudBuffer[_sfudBufferPos++] = b;
        if (_sfudBufferPos == _sfudBufferSize)
        {
            sfud_erase_write(_flash, _sfudBufferWritePos, _sfudBufferSize, _sfudBuffer);
            _sfudBufferWritePos += _sfudBufferSize;
            _sfudBufferPos = 0;
        }
    }
    
    void writeSfudBuffer(byte *b, size_t len)
    {
        for (size_t i = 0; i < len; ++i)
        {
            writeSfudBuffer(b[i]);
        }
    }
    
    void flushSfudBuffer()
    {
        if (_sfudBufferPos > 0)
        {
            sfud_erase_write(_flash, _sfudBufferWritePos, _sfudBufferSize, _sfudBuffer);
            _sfudBufferWritePos += _sfudBufferSize;
            _sfudBufferPos = 0;
        }
    }
    

    Tämä koodi määrittää metodit tavujen kirjoittamiseen flash-muistijärjestelmään. Se toimii kirjoittamalla muistipuskuriin, joka on oikean kokoinen flash-muistille, ja kun tämä on täynnä, se kirjoitetaan flash-muistiin, tyhjentäen kaikki olemassa olevat tiedot kyseisestä sijainnista. Mukana on myös flushSfudBuffer, joka kirjoittaa epätäydellisen puskurin, koska tallennettavat tiedot eivät ole tarkkoja rakeisuuden monikertoja, joten tiedon loppuosa on kirjoitettava.

    💁 Tiedon loppuosa kirjoittaa ylimääräisiä ei-toivottuja tietoja, mutta tämä on ok, koska vain tarvittavat tiedot luetaan.

Tehtävä - aseta äänen tallennus

  1. Luo uusi tiedosto src-kansioon nimeltä config.h.

  2. Lisää tämän tiedoston alkuun seuraava:

    #pragma once
    
    #define RATE 16000
    #define SAMPLE_LENGTH_SECONDS 4
    #define SAMPLES RATE * SAMPLE_LENGTH_SECONDS
    #define BUFFER_SIZE (SAMPLES * 2) + 44
    #define ADC_BUF_LEN 1600
    

    Tämä koodi määrittää joitakin vakioita äänen tallennusta varten.

    Vakio Arvo Kuvaus
    RATE 16000 Äänen näytteenottotaajuus. 16 000 on 16 kHz
    SAMPLE_LENGTH_SECONDS 4 Tallennettavan äänen pituus sekunteina. Tämä on asetettu 4 sekuntiin. Jos haluat tallentaa pidempään, lisää tätä arvoa.
    SAMPLES 64000 Tallennettavien ääninäytteiden kokonaismäärä. Asetettu näytteenottotaajuus * sekuntien määrä
    BUFFER_SIZE 128044 Äänipuskurin koko tallennusta varten. Ääni tallennetaan WAV-tiedostona, jossa on 44 tavun otsikko ja 128 000 tavua äänidataa (jokainen näyte on 2 tavua)
    ADC_BUF_LEN 1600 Puskureiden koko äänen tallentamiseen DMAC:lla

    💁 Jos huomaat, että 4 sekuntia on liian lyhyt ajastimen pyytämiseen, voit kasvattaa SAMPLE_LENGTH_SECONDS-arvoa, ja kaikki muut arvot lasketaan uudelleen.

  3. Luo uusi tiedosto src-kansioon nimeltä mic.h.

  4. Lisää tämän tiedoston alkuun seuraava:

    #pragma once
    
    #include <Arduino.h>
    
    #include "config.h"
    #include "flash_writer.h"
    

    Tämä sisältää tarvittavat otsikkotiedostot, mukaan lukien config.h- ja FlashWriter-otsikkotiedostot.

  5. Lisää seuraava määrittääksesi Mic-luokan, joka voi tallentaa mikrofonista:

    class Mic
    {
    public:
        Mic()
        {
            _isRecording = false;
            _isRecordingReady = false;
        }
    
        void startRecording()
        {
            _isRecording = true;
            _isRecordingReady = false;
        }
    
        bool isRecording()
        {
            return _isRecording;
        }
    
        bool isRecordingReady()
        {
            return _isRecordingReady;
        }
    
    private:
        volatile bool _isRecording;
        volatile bool _isRecordingReady;
        FlashWriter _writer;
    };
    
    Mic mic;
    

    Tämä luokka sisältää tällä hetkellä vain muutaman kentän, joilla seurataan, onko tallennus alkanut ja onko tallennus valmis käytettäväksi. Kun DMAC on asetettu, se kirjoittaa jatkuvasti muistipuskureihin, joten _isRecording-lippu määrittää, pitäisikö näitä käsitellä vai ohittaa. _isRecordingReady-lippu asetetaan, kun tarvittavat 4 sekuntia ääntä on tallennettu. _writer-kenttää käytetään tallentamaan äänidata flash-muistiin.

    Globaalimuuttuja määritellään sitten Mic-luokan instanssille.

  6. Lisää seuraava koodi Mic-luokan private-osioon:

    typedef struct
    {
        uint16_t btctrl;
        uint16_t btcnt;
        uint32_t srcaddr;
        uint32_t dstaddr;
        uint32_t descaddr;
    } dmacdescriptor;
    
    // Globals - DMA and ADC
    volatile dmacdescriptor _wrb[DMAC_CH_NUM] __attribute__((aligned(16)));
    dmacdescriptor _descriptor_section[DMAC_CH_NUM] __attribute__((aligned(16)));
    dmacdescriptor _descriptor __attribute__((aligned(16)));
    
    void configureDmaAdc()
    {
        // Configure DMA to sample from ADC at a regular interval (triggered by timer/counter)
        DMAC->BASEADDR.reg = (uint32_t)_descriptor_section;                    // Specify the location of the descriptors
        DMAC->WRBADDR.reg = (uint32_t)_wrb;                                    // Specify the location of the write back descriptors
        DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);           // Enable the DMAC peripheral
        DMAC->Channel[1].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(TC5_DMAC_ID_OVF) | // Set DMAC to trigger on TC5 timer overflow
                                        DMAC_CHCTRLA_TRIGACT_BURST;             // DMAC burst transfer
    
        _descriptor.descaddr = (uint32_t)&_descriptor_section[1];                    // Set up a circular descriptor
        _descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg;                           // Take the result from the ADC0 RESULT register
        _descriptor.dstaddr = (uint32_t)_adc_buf_0 + sizeof(uint16_t) * ADC_BUF_LEN; // Place it in the adc_buf_0 array
        _descriptor.btcnt = ADC_BUF_LEN;                                             // Beat count
        _descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD |                            // Beat size is HWORD (16-bits)
                                DMAC_BTCTRL_DSTINC |                                    // Increment the destination address
                                DMAC_BTCTRL_VALID |                                     // Descriptor is valid
                                DMAC_BTCTRL_BLOCKACT_SUSPEND;                           // Suspend DMAC channel 0 after block transfer
        memcpy(&_descriptor_section[0], &_descriptor, sizeof(_descriptor));          // Copy the descriptor to the descriptor section
    
        _descriptor.descaddr = (uint32_t)&_descriptor_section[0];                    // Set up a circular descriptor
        _descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg;                           // Take the result from the ADC0 RESULT register
        _descriptor.dstaddr = (uint32_t)_adc_buf_1 + sizeof(uint16_t) * ADC_BUF_LEN; // Place it in the adc_buf_1 array
        _descriptor.btcnt = ADC_BUF_LEN;                                             // Beat count
        _descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD |                            // Beat size is HWORD (16-bits)
                                DMAC_BTCTRL_DSTINC |                                    // Increment the destination address
                                DMAC_BTCTRL_VALID |                                     // Descriptor is valid
                                DMAC_BTCTRL_BLOCKACT_SUSPEND;                           // Suspend DMAC channel 0 after block transfer
        memcpy(&_descriptor_section[1], &_descriptor, sizeof(_descriptor));          // Copy the descriptor to the descriptor section
    
        // Configure NVIC
        NVIC_SetPriority(DMAC_1_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for DMAC1 to 0 (highest)
        NVIC_EnableIRQ(DMAC_1_IRQn);      // Connect DMAC1 to Nested Vector Interrupt Controller (NVIC)
    
        // Activate the suspend (SUSP) interrupt on DMAC channel 1
        DMAC->Channel[1].CHINTENSET.reg = DMAC_CHINTENSET_SUSP;
    
        // Configure ADC
        ADC1->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN12_Val; // Set the analog input to ADC0/AIN2 (PB08 - A4 on Metro M4)
        while (ADC1->SYNCBUSY.bit.INPUTCTRL)
            ;                              // Wait for synchronization
        ADC1->SAMPCTRL.bit.SAMPLEN = 0x00; // Set max Sampling Time Length to half divided ADC clock pulse (2.66us)
        while (ADC1->SYNCBUSY.bit.SAMPCTRL)
            ;                                         // Wait for synchronization
        ADC1->CTRLA.reg = ADC_CTRLA_PRESCALER_DIV128; // Divide Clock ADC GCLK by 128 (48MHz/128 = 375kHz)
        ADC1->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT |    // Set ADC resolution to 12 bits
                            ADC_CTRLB_FREERUN;          // Set ADC to free run mode
        while (ADC1->SYNCBUSY.bit.CTRLB)
            ;                       // Wait for synchronization
        ADC1->CTRLA.bit.ENABLE = 1; // Enable the ADC
        while (ADC1->SYNCBUSY.bit.ENABLE)
            ;                       // Wait for synchronization
        ADC1->SWTRIG.bit.START = 1; // Initiate a software trigger to start an ADC conversion
        while (ADC1->SYNCBUSY.bit.SWTRIG)
            ; // Wait for synchronization
    
        // Enable DMA channel 1
        DMAC->Channel[1].CHCTRLA.bit.ENABLE = 1;
    
        // Configure Timer/Counter 5
        GCLK->PCHCTRL[TC5_GCLK_ID].reg = GCLK_PCHCTRL_CHEN |     // Enable peripheral channel for TC5
                                            GCLK_PCHCTRL_GEN_GCLK1; // Connect generic clock 0 at 48MHz
    
        TC5->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ; // Set TC5 to Match Frequency (MFRQ) mode
        TC5->COUNT16.CC[0].reg = 3000 - 1;            // Set the trigger to 16 kHz: (4Mhz / 16000) - 1
        while (TC5->COUNT16.SYNCBUSY.bit.CC0)
            ; // Wait for synchronization
    
        // Start Timer/Counter 5
        TC5->COUNT16.CTRLA.bit.ENABLE = 1; // Enable the TC5 timer
        while (TC5->COUNT16.SYNCBUSY.bit.ENABLE)
            ; // Wait for synchronization
    }
    
    uint16_t _adc_buf_0[ADC_BUF_LEN];
    uint16_t _adc_buf_1[ADC_BUF_LEN];
    

    Tämä koodi määrittää configureDmaAdc-metodin, joka konfiguroi DMAC:n, yhdistää sen ADC:hen ja asettaa sen täyttämään kaksi vuorottelevaa puskuriä, _adc_buf_0 ja _adc_buf_1.

    💁 Yksi mikrokontrollerikehityksen haitoista on monimutkainen koodi, jota tarvitaan laitteiston kanssa vuorovaikuttamiseen, koska koodisi toimii hyvin matalalla tasolla suoraan laitteiston kanssa. Tämä koodi on monimutkaisempaa kuin mitä kirjoittaisit yksikorttitietokoneelle tai pöytätietokoneelle, koska käyttöjärjestelmä ei auta. Joitakin kirjastoja on saatavilla tämän yksinkertaistamiseksi, mutta monimutkaisuutta on silti paljon.

  7. Tämän alapuolelle lisää seuraava koodi:

    // WAV files have a header. This struct defines that header
    struct wavFileHeader
    {
        char riff[4];         /* "RIFF"                                  */
        long flength;         /* file length in bytes                    */
        char wave[4];         /* "WAVE"                                  */
        char fmt[4];          /* "fmt "                                  */
        long chunk_size;      /* size of FMT chunk in bytes (usually 16) */
        short format_tag;     /* 1=PCM, 257=Mu-Law, 258=A-Law, 259=ADPCM */
        short num_chans;      /* 1=mono, 2=stereo                        */
        long srate;           /* Sampling rate in samples per second     */
        long bytes_per_sec;   /* bytes per second = srate*bytes_per_samp */
        short bytes_per_samp; /* 2=16-bit mono, 4=16-bit stereo          */
        short bits_per_samp;  /* Number of bits per sample               */
        char data[4];         /* "data"                                  */
        long dlength;         /* data length in bytes (filelength - 44)  */
    };
    
    void initBufferHeader()
    {
        wavFileHeader wavh;
    
        strncpy(wavh.riff, "RIFF", 4);
        strncpy(wavh.wave, "WAVE", 4);
        strncpy(wavh.fmt, "fmt ", 4);
        strncpy(wavh.data, "data", 4);
    
        wavh.chunk_size = 16;
        wavh.format_tag = 1; // PCM
        wavh.num_chans = 1;  // mono
        wavh.srate = RATE;
        wavh.bytes_per_sec = (RATE * 1 * 16 * 1) / 8;
        wavh.bytes_per_samp = 2;
        wavh.bits_per_samp = 16;
        wavh.dlength = RATE * 2 * 1 * 16 / 2;
        wavh.flength = wavh.dlength + 44;
    
        _writer.writeSfudBuffer((byte *)&wavh, 44);
    }
    

    Tämä koodi määrittää WAV-otsikon rakenteena, joka vie 44 tavua muistia. Se kirjoittaa siihen tiedot äänitiedoston taajuudesta, koosta ja kanavien määrästä. Tämä otsikko kirjoitetaan sitten flash-muistiin.

  8. Tämän koodin alapuolelle lisää seuraava metodi, joka kutsutaan, kun äänipuskurit ovat valmiita käsiteltäväksi:

    void audioCallback(uint16_t *buf, uint32_t buf_len)
    {
        static uint32_t idx = 44;
    
        if (_isRecording)
        {
            for (uint32_t i = 0; i < buf_len; i++)
            {
                int16_t audio_value = ((int16_t)buf[i] - 2048) * 16;
    
                _writer.writeSfudBuffer(audio_value & 0xFF);
                _writer.writeSfudBuffer((audio_value >> 8) & 0xFF);
            }
    
            idx += buf_len;
    
            if (idx >= BUFFER_SIZE)
            {
                _writer.flushSfudBuffer();
                idx = 44;
                _isRecording = false;
                _isRecordingReady = true;
            }
        }
    }
    

    Äänipuskurit ovat 16-bittisten kokonaislukujen taulukoita, jotka sisältävät ADC:ltä saadun äänen. ADC palauttaa 12-bittisiä allekirjoittamattomia arvoja (01023), joten nämä on muunnettava 16-bittisiksi allekirjoitetuiksi arvoiksi ja sitten muunnettava 2 tavuksi, jotta ne voidaan tallentaa raakana binääridatana.

    Nämä tavut kirjoitetaan flash-muistipuskureihin. Kirjoitus alkaa indeksistä 44 tämä on WAV-tiedoston otsikkona kirjoitettujen 44 tavun siirtymä. Kun kaikki tarvittavat näytteet äänen pituudelle on tallennettu, jäljellä olevat tiedot kirjoitetaan flash-muistiin.

  9. Lisää Mic-luokan public-osioon seuraava koodi:

    void dmaHandler()
    {
        static uint8_t count = 0;
    
        if (DMAC->Channel[1].CHINTFLAG.bit.SUSP)
        {
            DMAC->Channel[1].CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME;
            DMAC->Channel[1].CHINTFLAG.bit.SUSP = 1;
    
            if (count)
            {
                audioCallback(_adc_buf_0, ADC_BUF_LEN);
            }
            else
            {
                audioCallback(_adc_buf_1, ADC_BUF_LEN);
            }
    
            count = (count + 1) % 2;
        }
    }
    

    Tämä koodi kutsutaan DMAC:n toimesta, kun puskureita on käsiteltävänä. Se tarkistaa, että käsiteltävää dataa on, ja kutsuu audioCallback-metodia oikealla puskurilla.

  10. Luokan ulkopuolella, Mic mic;-määrittelyn jälkeen, lisää seuraava koodi:

    void DMAC_1_Handler()
    {
        mic.dmaHandler();
    }
    

    DMAC_1_Handler kutsutaan DMAC:n toimesta, kun puskureita on valmiina käsiteltäväksi. Tämä funktio löytyy nimen perusteella, joten sen tarvitsee vain olla olemassa, jotta sitä voidaan kutsua.

  11. Lisää seuraavat kaksi metodia Mic-luokan public-osioon:

    void init()
    {
        analogReference(AR_INTERNAL2V23);
    
        _writer.init();
    
        initBufferHeader();
        configureDmaAdc();
    }
    
    void reset()
    {
        _isRecordingReady = false;
        _isRecording = false;
    
        _writer.reset();
    
        initBufferHeader();
    }
    

    init-metodi sisältää koodin Mic-luokan alustamiseen. Tämä metodi asettaa oikean jännitteen Mic-pinnille, alustaa flash-muistikirjoittimen, kirjoittaa WAV-tiedoston otsikon ja konfiguroi DMAC:n. reset-metodi nollaa flash-muistin ja kirjoittaa otsikon uudelleen sen jälkeen, kun ääni on tallennettu ja käytetty.

Tehtävä - tallenna ääntä

  1. Lisää main.cpp-tiedostoon mic.h-otsikkotiedoston include-direktiivi:

    #include "mic.h"
    
  2. Lisää setup-funktioon C-painikkeen alustaminen. Äänen tallennus alkaa, kun tätä painiketta painetaan, ja jatkuu 4 sekuntia:

    pinMode(WIO_KEY_C, INPUT_PULLUP);
    
  3. Tämän alapuolelle alusta mikrofoni ja tulosta konsoliin, että ääni on valmis tallennettavaksi:

    mic.init();
    
    Serial.println("Ready.");
    
  4. Lisää loop-funktion yläpuolelle funktio tallennetun äänen käsittelemiseksi. Tällä hetkellä tämä ei tee mitään, mutta myöhemmin tässä oppitunnissa se lähettää puheen tekstiksi muunnettavaksi:

    void processAudio()
    {
    
    }
    
  5. Lisää seuraava loop-funktioon:

    void loop()
    {
        if (digitalRead(WIO_KEY_C) == LOW && !mic.isRecording())
        {
            Serial.println("Starting recording...");
            mic.startRecording();
        }
    
        if (!mic.isRecording() && mic.isRecordingReady())
        {
            Serial.println("Finished recording");
    
            processAudio();
    
            mic.reset();
        }
    }
    

    Tämä koodi tarkistaa C-painikkeen, ja jos sitä painetaan eikä tallennus ole alkanut, Mic-luokan _isRecording-kenttä asetetaan todeksi. Tämä saa Mic-luokan audioCallback-metodin tallentamaan ääntä, kunnes 4 sekuntia on tallennettu. Kun 4 sekuntia ääntä on tallennettu, _isRecording-kenttä asetetaan epätodeksi ja _isRecordingReady-kenttä asetetaan todeksi. Tätä tarkistetaan loop-funktiossa, ja kun se on tosi, kutsutaan processAudio-funktiota ja sitten mic-luokka nollataan.

  6. Käännä tämä koodi, lataa se Wio Terminal -laitteeseesi ja testaa se sarjamonitorin kautta. Paina C-painiketta (vasemmalla puolella, lähimpänä virtakytkintä) ja puhu. 4 sekuntia ääntä tallennetaan.

    --- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
    --- More details at http://bit.ly/pio-monitor-filters
    --- Miniterm on /dev/cu.usbmodem1101  9600,8,N,1 ---
    --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
    Ready.
    Starting recording...
    Finished recording
    

💁 Löydät tämän koodin code-record/wio-terminal -kansiosta. 😀 Äänitysohjelmasi oli menestys!


Vastuuvapauslauseke:
Tämä asiakirja on käännetty käyttämällä tekoälypohjaista käännöspalvelua Co-op Translator. Vaikka pyrimme tarkkuuteen, huomioithan, että automaattiset käännökset voivat sisältää virheitä tai epätarkkuuksia. Alkuperäistä asiakirjaa sen alkuperäisellä kielellä tulisi pitää ensisijaisena lähteenä. Kriittisen tiedon osalta suositellaan ammattimaista ihmiskäännöstä. Emme ole vastuussa väärinkäsityksistä tai virhetulkinnoista, jotka johtuvat tämän käännöksen käytöstä.