XBee Walkie Talkie
Componenten en benodigdheden
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Over dit project
Ik bouw een geavanceerde Arduino-kloon op basis van de AVR ATmega1284p MCU met enkele speciale functies, waaronder een 12-bits DAC MCP4822, hoofdtelefoonversterker, 2x SPI-geheugen (SRAM, EEPROM) en een SD-kaart. Er zijn veel echte toepassingen voor analoge uitgangen, maar omdat het Arduino-platform geen geïntegreerde DAC-mogelijkheid heeft, zijn er maar heel weinig gepubliceerde toepassingen voor analoge signalen. Een Walkie Talkie is een voorbeeld van het samen gebruiken van digitaal en analoog om een eenvoudig maar zeer nuttig project te maken.
Goudlokje Analoog - Prototype 3De eigenlijke Walkie Talkie-functionaliteit is eigenlijk maar een paar regels code, maar het is gebouwd op een fundament van analoge input (sampling), analoge output op de SPI-bus naar de MCP4822 DAC, sample-timingroutines en het XBee digitale radioplatform. Laten we bovenaan beginnen en dan door de lagen naar beneden graven.
XBee-radio
Ik gebruik XBee Pro S2B-radio's, geconfigureerd om van punt tot punt te communiceren. Voor de XBee Pro moet er één radio zijn geconfigureerd als de coördinator en de andere als een router. Er zijn configuratiehandleidingen op internet.
Ik heb de radio's geconfigureerd om de maximale inter-tekentijd te wachten voordat een pakket wordt verzonden, wat inhoudt dat de pakketten alleen worden ingesteld als ze vol zijn (84 bytes). Dit maximaliseert de radiodoorvoer. De onbewerkte doorvoer is 250 kbit/s, maar de werkelijke gebruikersgegevenssnelheid is beperkt tot ongeveer 32 kbit/s. Dit heeft invloed op de bemonsteringsfrequentie en dus op de kwaliteit van de spraak die kan worden verzonden.
Met behulp van 8-bits samples heb ik ontdekt dat ongeveer 3 kHz-sampling ongeveer evenveel gegevens genereert als zonder compressie kunnen worden verzonden. Ik verlaat de compressie voor een ander project.
De XBee-radio's zijn geconfigureerd in de AT-modus, die fungeert als een transparante seriële pijp tussen de twee eindpunten. Dit is de eenvoudigste manier om twee apparaten via digitale radio met elkaar te verbinden. En het stelde me in staat om eenvoudige tests uit te voeren, met behulp van draad, voordat ik me zorgen maakte of het radioplatform werkte of niet.
Als we naar de tracering van een logische analysator kijken, kunnen we de XBee-datapakketten zien aankomen op de (paarse) Rx-lijn van de seriële poort. De ontvangen pakketgegevens worden opgeslagen in een ringbuffer en met een constante snelheid afgespeeld. Ik heb maximaal 255 bytes toegestaan in de ontvangstringbuffer en dit is voldoende omdat de XBee-pakketgrootte 84 bytes is.
De samples die naar het andere apparaat moeten worden verzonden, worden verzonden op de (blauwe) Tx-lijn, min of meer in elke sampleperiode, hoewel ze vóór verzending worden gebufferd. De XBee-radio buffert deze bytes voor maximaal 0xFF intersymboolperioden (configuratie) en verzendt alleen een pakket naar het andere eindpunt als het een volledig pakket heeft.
Bemonsteringsfrequentie
Als we kijken naar het bitbudget voor de transmissielink, moeten we berekenen hoeveel gegevens kunnen worden verzonden zonder het XBee-radioplatform te overbelasten en monsterverlies te veroorzaken. Omdat we de spraaksamples niet openlijk comprimeren, hebben we 8 bit-samples maal 3.000 Hz-sampling of 24 kbit/s om te verzenden. Dit lijkt redelijk goed te werken. Ik heb 4 kHz-sampling geprobeerd, maar dit ligt te dicht bij het theoretische maximum en werkt niet al te effectief.
Als we naar de logische analysator kijken, kunnen we de aankomst van een pakket bytes zien beginnend met 0x7E en 0x7C op de Rx-lijn. Zowel de microfoonversterker als de DAC-uitgang zijn voorgespannen rond 0x7F(FF), dus we kunnen lezen dat de signaalniveaus die hier worden vastgelegd en verzonden, erg laag zijn. De getoonde samplefrequentie is 3.000 Hz.
Monsterverwerking
Ik heb een "ping" op één uitgang gezet om vast te leggen wanneer de bemonsteringsinterrupt wordt verwerkt (geel). We kunnen zien dat de hoeveelheid tijd die wordt besteed aan de onderbrekingsverwerking voor deze toepassing erg klein is in verhouding tot de totale beschikbare tijd. Mogelijk zou een soort van gegevenscompressie kunnen worden geïmplementeerd.
Tijdens de sampling-onderbreking zijn er twee belangrijke activiteiten:het genereren van een audio-uitvoer, door een sample op de DAC te plaatsen en vervolgens de ADC te lezen om een audiosample op te nemen en deze naar de USART-buffer te verzenden.
Dit wordt gedaan door de functie audioCodec_dsp, die wordt aangeroepen vanuit de code in een timer-interrupt.
Ik gebruik de AVR 8 bit Timer0 om de reguliere sample-intervallen te genereren door een interrupt te activeren. Door een MCU FCPU-frequentie te gebruiken die een binair veelvoud is van de standaard audiofrequenties, kunnen we nauwkeurige reproductiebemonsteringsfrequenties genereren door alleen de 8-bits timer te gebruiken met een klokprescaler van 64. Om oneven audiofrequenties te genereren, zoals 44.100 Hz, de 16 bit Timer1 kan worden gebruikt om voldoende nauwkeurigheid te krijgen zonder dat een klokprescaler nodig is.
De ATmega1284p ADC is ingesteld op free-run-modus en is verkleind tot 192 kHz. Hoewel dit dicht bij de maximale acquisitiesnelheid ligt die is gedocumenteerd voor de ATmega ADC, valt het nog steeds binnen de specificatie voor 8-bits samples.
Deze interrupt neemt 14 us in beslag en is erg kort in vergelijking met de 333 us die we hebben voor elke steekproefperiode. Dit geeft ons voldoende tijd om andere bewerkingen uit te voeren, zoals het uitvoeren van een gebruikersinterface of verdere audioverwerking.
SPI-transactie
Op het laatste detailniveau kunnen we de daadwerkelijke SPI-transactie zien om het binnenkomende monster naar de MCP4822 DAC te sturen.
Omdat ik deze applicatie heb gebouwd op het Goldilocks Analogue Prototype 2 dat de standaard SPI-bus gebruikt, is de transactie normaal. Mijn latere prototypes gebruiken de Master SPI-modus op USART 1 van de ATmega1284p, die de SPI-transactie enigszins versnelt door dubbele buffering, en de normale SPI-bus vrijmaakt voor gelijktijdig lezen of schrijven naar de SD-kaart of SPI-geheugen, voor audiostreaming. In de Walkie Talkie-applicatie is het niet nodig om de audio vast te leggen, dus er is geen nadeel aan het gebruik van de oudere prototypes en de normale SPI-bus.
Afsluiten
Met behulp van een paar reeds bestaande tools en een paar regels code, is het mogelijk om snel een digitaal gecodeerde walkietalkie te bouwen die in staat is om (begrijpelijke, maar niet hoogwaardige) stem te communiceren. En er zullen in de toekomst geen CB-truckers luisteren naar de familiegesprekken.
Dit was een test om microfooningang op basis van de MAX9814 toe te voegen aan de Goldilocks Analogue. Ik ga het prototype 3 herzien en een microfoonversterkingscircuit toevoegen om toepassingen te ondersteunen die audio-invoer nodig hebben, zoals dit walkietalkie-voorbeeld, of stemwisselaars of muzieksynthesizers met stembesturing.
Twee Goldilocks analoge prototypes met XBee-radio's en microfoonversterkers.Ik gebruik de ATmega1284p-apparaten ook op de verhoogde frequentie van 24,576 MHz, boven de standaardsnelheid van 20 MHz. Deze specifieke frequentie maakt een zeer nauwkeurige weergave mogelijk van audiosamples van 48 kHz tot 4 kHz (of zelfs tot 1.500 Hz). De extra MCU-klokcycli per sampleperiode zijn zeer welkom als het gaat om het genereren van gesynthetiseerde muziek.
Code zoals gewoonlijk op Sourceforge AVR freeRTOS Ook een oproep aan Shuyang bij SeeedStudio, wiens OPL geweldig is, en de bron is van veel componenten en PCB's.
Code
- Code
- Code
- Code
CodeC/C++
void audioCodec_dsp( uint16_t * ch_A, uint16_t * ch_B){ int16_t xn; uint8_t cn; /*----- Audio Rx -----*/ /* Haal het volgende teken uit de ringbuffer. */ if( ringBuffer_IsEmpty( (ringBuffer_t*) &(xSerialPort.xRxedChars)) ) { cn =0x80 ^ 0x55; // zet A-Law nulled signaal op de uitgang. } else if (ringBuffer_GetCount( &(xSerialPort.xRxedChars) )> (portSERIAL_BUFFER_RX>>1) ) // als de buffer meer dan halfvol is. {cn =ringBuffer_Pop( (ringBuffer_t*) &(xSerialPort.xRxedChars)); // pop twee samples om in te halen, gooi de eerste weg. cn =ringBuffer_Pop( (ringBuffer_t*) &(xSerialPort.xRxedChars)); } else { cn =ringBuffer_Pop( (ringBuffer_t*) &(xSerialPort.xRxedChars)); // pop een voorbeeld } alaw_expand1(&cn, &xn); // breid de A-Law-compressie uit *ch_A =*ch_B =(uint16_t)(xn + 0x7fff); // verplaats het signaal naar positieve waarden, zet het signaal op A &B-kanaal. /*----- Audio Tx -----*/ AudioCodec_ADC( &mod7_value.u16 ); // sample is 10 bits links uitgelijnd. xn =mod7_waarde.u16 - 0x7fe0; // centreer het monster op 0 door 1/2 10-bits bereik af te trekken. IIRFilter( &tx_filter, &xn); // filter verzonden voorbeeldtrein alaw_compress1(&xn, &cn); // comprimeren met A-Law xSerialPutChar (&xSerialPort, cn); // verzend het voorbeeld}
CodeC/C++
ISR(TIMER0_COMPA_vect) __attribute__ ((hot, flatten));ISR(TIMER0_COMPA_vect){#if gedefinieerd(DEBUG_PING) // startmarkering - controleer op start van onderbreking - alleen voor foutopsporing (gele trace) PORTD |=_BV( PORTD7); // Ping IO-lijn.#endif // MCP4822-gegevensoverdrachtroutine // verplaats gegevens naar de MCP4822 - eerst gedaan voor regelmaat (verminderde jitter). DAC_out (ch_A_ptr, ch_B_ptr); // audioverwerkingsroutine - doe de verwerking op de invoer die nodig is - bereid de uitvoer voor op de volgende sample. // Activeer de globale audio-handler die een call-back-functie is, indien ingesteld. if (audioHandler!=NULL) audioHandler(ch_A_ptr, ch_B_ptr);#if gedefinieerd(DEBUG_PING) // eindmarkering - controleer op einde van onderbreking - alleen voor foutopsporing (gele trace) PORTD &=~_BV(PORTD7);#endif}
CodeC/C++
void DAC_out(const uint16_t * ch_A, const uint16_t * ch_B){ DAC_command_t write; if (ch_A !=NULL) {write.value.u16 =(*ch_A)>> 4; write.value.u8[1] |=CH_A_OUT; } else // ch_A is NULL dus we zetten de DAC uit {write.value.u8[1] =CH_A_OFF; } SPI_PORT_SS_DAC &=~SPI_BIT_SS_DAC; // Trek SS laag om de Goldilocks Analoge DAC te selecteren. SPDR =schrijf.waarde.u8[1]; // Begin verzending ch_A. while ( !(SPSR &_BV(SPIF)) ); SPDR =schrijf.waarde.u8[0]; // Ga door met verzenden ch_A. if (ch_B !=NULL) // begin met het verwerken van ch_B terwijl we de ch_A-transmissie doen {write.value.u16 =(*ch_B)>> 4; write.value.u8[1] |=CH_B_OUT; } else // ch_B is NULL dus we zetten de DAC uit {write.value.u8[1] =CH_B_OFF; } while ( !(SPSR &_BV(SPIF)) ); // controleer of we klaar zijn met ch_A. SPI_PORT_SS_DAC |=SPI_BIT_SS_DAC; // Trek SS hoog om de Goldilocks Analogue DAC te deselecteren en de waarde in DAC te vergrendelen. SPI_PORT_SS_DAC &=~SPI_BIT_SS_DAC; // Trek SS laag om de Goldilocks Analoge DAC te selecteren. SPDR =schrijf.waarde.u8[1]; // Begin verzending ch_B. while ( !(SPSR &_BV(SPIF)) ); SPDR =schrijf.waarde.u8[0]; // Ga door met verzenden ch_B. while ( !(SPSR &_BV(SPIF)) ); // controleer of we klaar zijn met ch_B. SPI_PORT_SS_DAC |=SPI_BIT_SS_DAC; // Trek SS hoog om de Goldilocks Analogue DAC te deselecteren en de waarde vast te zetten in DAC.}
AVRfreeRTOS bij Sourceforge
Repository van de AVR-poort van freeRTOS, inclusief de DAC.h en analoge testbestanden die in dit project worden gebruikt. Gebruik de gekoppelde github-repository NIET. Ga naar sourceforge voor de nieuwste code.https://sourceforge.net/projects/avrfreertos /https://github.com/feilipu/avrfreertosSchema's
Het is niet helemaal correct, omdat het een MCP4725 DAC (I2C) gebruikt en geen MCP4822 DAC (SPI), maar Fritzing had niet het juiste Adafruit-breakoutboard.Het wordt ook slechts in één richting getekend... (met uitzondering van de onderling verbonden Rx en Tx).
De XBee-kaarten vervangen eenvoudig de twee draden die de Rx en Tx verbinden. Elke radioset die voldoende gegevens kan dragen, zou werken. Schema's voor de DAC-uitgang en de hoofdtelefoonversterker.
Microfooningangsversterker wordt toegevoegd aan prototype 4.
Productieproces
- Overwegingen voor Zwitserse machinale bewerking met hoge productie
- Gids voor CNC-prototyping
- Het fabricageproces van de schacht begrijpen
- Wat is RVS-passivering?
- Analoge sensoren uitlezen met één GPIO-pin
- Analoge sensoren op de Raspberry Pi met een MCP3008
- Een uiterst nauwkeurige golfvorm genereren met behulp van een DAC en een aangepaste PCB
- Win10 IOT-irrigatiecontroller met vochtsensoren
- De waarde van analoge meting
- Teken iets op uw oscilloscoop
- Afgeschermde kabels voor signaalcircuits (deel 2)