Atmega8 ringetoner. Enkle lydsirener på MK AVR. Bruke lydmodulen

Artikkelen beskriver prinsippene for musikksyntese på en AVR. Den medfølgende programvaren lar deg konvertere alle midi-filer til kilde i C for AVR-mikrokontrollere for å legge til avspilling av musikalske fragmenter til ferdige utviklinger. Et eksempel på bruk av programvare i en musikkboks vurderes.

Først en kort video av hvordan det hele fungerer:

Hva programvaren tillater

PC-programvare lar deg få en C-kilde for CodeVision AVR, som spiller av den valgte midi-filen:

1. Koble common\hxMidiPlayer.h, common\hxMidiPlayer.c til prosjektet ditt. Kopier malene ATMega8Example\melody.h, ATMega8Example\melody.c, ATMega8Example\hxMidiPlayer_config.h og koble til.
2. Start MidiToC.exe
3. Last inn Midi-filen.
4. Sett opp spilleren: samplingshastighet, antall kanaler, bølgeform osv. Programvaren spiller melodien på samme måte som AVR-en vil spille.
5. Klikk "Create player config" og lim inn kilden i hxMidiPlayer_config.h.
6. Klikk på "Opprett melodikode" og lim inn kilden i melodi.c
7. I prosjektet vårt implementerer vi Player_Output()-metoden for å sende ut lyd via PWM eller en ekstern DAC.
8. Sett tidtakeren til samplingsfrekvensen og ring Player_TimerFunc() fra avbruddet.
9. Ring Player_StartMelody(&s_melody, 0).

Melodien spilles fra timeravbruddet. Dette betyr at under avspilling kan mikrokontrolleren også gjøre nyttig arbeid.

Hvordan det fungerer

I resten av artikkelen skal jeg prøve å kort forklare hvordan alt dette er implementert. Dessverre blir det ikke veldig kort - det er mye materiale. Hvis du ikke er interessert, kan du umiddelbart gå til delene "Programvarebeskrivelse" og "Player API".

Hva er musikk

Musikk er en sekvens av lyder av ulik frekvens og varighet. Frekvensen til den grunnleggende harmoniske til en lyd må samsvare med frekvensen til en viss tone. Hvis vibrasjonsfrekvensen til lyder er forskjellig fra frekvensene til noter, ser det ut til at musikeren er "ustemt".

Bord. Merk frekvenser, Hz.

Alle toner er delt inn i oktaver, 7 toner i hver + 5 halvtoner (svarte tangenter på pianoet). Frekvensene til noter i tilstøtende oktaver avviker med nøyaktig 2 ganger.

Den enkleste musikkspilleren inneholder en tabell med notesekvensen (note + varighet) til en melodi og en tabell med notefrekvenser. For å syntetisere lyd brukes en av timerkanalene, som danner en meander:

Dessverre har en slik primitiv spiller en fast bølgeform (firkantbølge), som er lite lik ekte musikkinstrumenter, og kan bare spille en tone om gangen.

En ekte melodi inneholder minst to deler (solo + bass), og når den spilles på piano, fortsetter den forrige tonen å høres når den neste har begynt. Dette er lett å forstå ved å huske strukturen til et piano - hver tone tilsvarer en egen streng. Vi kan få flere strenger til å høres samtidig ved å føre hendene over tangentene.

Noen mikrokontrollere har flere timerkanaler, disse kan brukes til å spille flere toner samtidig. Men vanligvis er disse kanalene en verdifull ressurs, og det er ikke tilrådelig å bruke dem alle. Med mindre vi selvfølgelig bare lager en musikkboks.
Totalt, for å oppnå polyfoni og ulike lyder av musikkinstrumenter, må du bruke lydsyntese.

Lydsyntese på AVR

hxMidiPlayer bruker lydsyntese og kan spille polyfoni med forskjellige bølgeformer. Spilleren beregner amplituden til utgangssignalet i timeravbruddsbehandleren med en frekvens på 8-22 KHz (hvor mye prosessorkraft er nok; avhenger også av bølgeformen og antall kanaler).

Prinsippet for lydsyntese kan forklares ved å bruke eksemplet med sinussyntese.

La oss ta en tabell med størrelse 64, i hver celle hvor verdiene av sinusamplituden er skrevet på punktindeks * 2 * PI / 64 (en periode):

Statisk konstant flash uint8_t s_sineTable[ 64 ] = ( 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8D, 0x8F, 0x90, 0x91, 0x90,x, 0x90,x, 0x90,x 9 5, 0x95, 0x95, 0x94 , 0x93, 0x93, 0x91, 0x90, 0x8F, 0x8D, 0x8C, 0x8A, 0x88, 0x86, 0x84, 0x82, 0x80, 0x7E, 0x7C, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7 x7 1, 0x70, 0x6F, 0x6D, 0x6D, 0x6C, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6C, 0x6D, 0x6D, 0x6F, 0x70, 0x71, 0x73, 0x74, 0x76, 0x00, 0x7A, 0x7A, 0x7A, 0x76, 0

128 (0x80) tilsvarer null, 255 (0xff) til det største positive punktet, 0 til det største negative punktet.

La oss nå si at vi vil sende ut verdiene fra tabellen til en ekstern DAC i et timeravbrudd kalt ved en frekvens på 1000 Hz:

Statisk uint8_t s_index = 0; // Timer1 output compare A interrupt service routine interrupt void timer1_compa_isr(void) ( SetDac(s_sineTable[ s_index]); if (s_index == 63) ( s_index = 0; ) else ( s_index++; ) )

Hva får vi som resultat? Vi vil få sinusformede oscillasjoner med en frekvens på 1000/64 Hz.

La oss nå øke indeksen i avbruddet ikke med 1, men med to.
Åpenbart vil utgangssvingningsfrekvensen allerede være 1000/64 * 2 Hz.

Generelt, for å få frekvens F, må du øke indeksen i tabellen med:
legg til = F / 1000 * 64

Dette tallet kan være brøkdelt, men for å oppnå høy hastighet brukes fastpunktaritmetikk.

Antall oppføringer i tabellen og frekvensen til timeren påvirker kvaliteten på den syntetiserte lyden. I vårt tilfelle er 64 oppføringer i tabellen per periode tilstrekkelig, og timerfrekvensen er 12kHz. Minste akseptable timerfrekvens er 8 kHz, det ideelle er 44 kHz.

Åpenbart, med en timer-frekvens på 12 kHz, kan vi generere maksimalt 6 kHz firkantbølger, siden vi må gjøre minst to brytere per periode. Høyere frekvenser vil imidlertid fortsatt kunne gjenkjennes hvis utgangstilstanden er korrekt beregnet ved hver tidtaker.

Du kan legge inn verdier for perioden med ikke-sinusformede oscillasjoner i tabellen og få en annen lyd.

Demping

Hvis et musikkinstrument er basert på strenger (for eksempel et piano), så tones lyden jevnt ut etter å ha trykket på en tast. For å få en mer naturlig synthesizerlyd, må du jevnt redusere amplituden til vibrasjonene etter starten av noten (“pakke inn” vibrasjonene i en dempningsform – “konvolutt”).

Spilleren inneholder en decay-tabell som den bruker til å redusere amplituden til sinusen (eller annen bølgeform) fra det øyeblikket tonen starter.
"Sinus" "innpakket" i et slikt skall ligner lyden av en mekanisk musikkboks.

Meander syntese

Den spesielle formen til meanderbølgen gjør at syntesen kan forenkles betydelig. Tabeller brukes ikke i dette tilfellet. Det er nok å beregne hvilken tilstand (1 eller 0) utgangen skal ha ved en gitt frekvens ved gjeldende tidtaker. Dette gjøres ved hjelp av heltallsaritmetikk og fungerer veldig raskt, noe som forklarer populariteten til å bruke en firkantbølge for å spille melodier i 8-bits set-top-bokser.

Eksempel: erklære en teller:

Statisk uint16_t s_counter = 0;

som vi vil øke med 0x8000 i hvert timeravbrudd, og den viktigste biten av telleren vil sendes ut til porten:

// Timer1 output compare A interrupt service rutine avbrudd void timer1_compa_isr(void) ( PORTA.0 = (s_counter >> 15) & 1; s_counter += 0x8000; )

Siden 0x8000 + 0x8000 = 0x10000, flyter s_counter-variabelen over, den 17. biten forkastes og 0x0000 skrives til variabelen.
Dermed, med en timerfrekvens på 8KHz, vil utgangen være en 4KHz firkantbølge.
Øker du telleren med 0x4000 får du en 2KHz firkantbølge.

Generelt kan du få frekvensen F ved å legge til:
legg til = F / 8000 * 0x10000

For eksempel, for å få en firkantbølge med en frekvens på 1234Hz, må du legge til 0x277C. Den faktiske frekvensen vil avvike litt fra den gitte, fordi vi runder av begrepet til et helt tall. Dette er akseptabelt i en synthesizer.

Syntese av lyder fra ekte instrumenter

Du kan digitalisere lyden til noten før pianoet (ved å bruke en ADC for å lagre lydamplitudeverdiene i minnet med jevne mellomrom):
og spill deretter lyden (bruk DAC for å sende ut de innspilte verdiene med jevne mellomrom).

Generelt, for å syntetisere trommer, må du spille inn trommelyder og spille dem av i riktig øyeblikk. I 8-bits konsoller brukes "hvit støy" i stedet for trommelyder. Amplitudeverdier for "hvit støy" oppnås ved hjelp av en generator tilfeldige tall. Minnekostnadene er minimale.
hxMidiPlayer bruker "hvit støy" for trommesyntese.

Kanalmiksing

Lydamplituden ved en gitt timer-tikk beregnes for hver kanal separat. For å få den endelige amplitudeverdien, må du legge til verdiene for alle kanaler. Riktig er det nødvendig å justere summen, siden den oppfattede lydstyrken adlyder en logaritmisk avhengighet, men i en så enkel synthesizer må du nøye deg med enkel addisjon. Derfor er maksimal amplitude for hver kanal 255/N.

Sender ut lyd fra AVR

Etter å ha utført alle nødvendige beregninger, mottar spilleren signalnivået som må konverteres til analogt. For disse formålene kan du bruke en ekstern DAC eller PWM.
Det skal bemerkes her at i begge tilfeller er det tilrådelig å filtrere det mottatte signalet - for å fjerne høyfrekvent støy som oppstår på grunn av den lave frekvensen av syntese og avrunding.

Utgang til ekstern parallell DAC

Siden det ikke gir mening å bruke presise DAC-brikker, nøyer slike prosjekter seg vanligvis med en R2R-matrise:

Med dette opplegget sender vi ganske enkelt ut den beregnede amplituden til porten:

PORTB = prøve;

Feil:
1) utgangen til R2R-matrisen er også svakt signal, bruk av en analog forsterker er obligatorisk;
2) det er nødvendig å bruke minst 5 pinner (og helst 8);
Denne metoden er berettiget bare når det ikke er noen gratis PWM-kanaler.

(for å lagre pinner kan du bruke en ekstern ADC med et SPI-grensesnitt).

PWM

Hvis det er en gratis PWM-kanal, er den enkleste måten å bruke denne metoden.

PWM-initialisering (ATMega8):

// Timer/Teller 2 initialisering // Klokkekilde: System Klokke // Klokkeverdi: 20000.000 kHz // Modus: Rask PWM topp=0xFF // OC2 utgang: Ikke-invertert PWM ASSR=0x00; TCCR2=0x69; TCNT2=0x00; OCR2=0x00; Og prøveutgangen: void Player_Output(uint8_t sample) ( OC2 = sample. )

Vanlig praksis for bruk av PWM involverer utjevning av utgangssignalet ved hjelp av et RC-filter:

Etter filtrering blir signalet dessverre svekket for mye, så du må lage en analog forsterker for å koble til høyttaleren.

For å forenkle kretsen er det bedre å forbli "digital" til selve høyttaleren. Siden en billig høyttaler fortsatt ikke kan gjengi frekvenser over 30 kHz, er det ikke nødvendig å filtrere dem. Selve diffusoren vil "filtrere ut" de høye PWM-frekvensene.

Trenger du å få mer strøm kan du bruke en transistorforsterker. R1 er valgt for å gi den nødvendige strømmen til høyttaleren.

Slik kan du koble til små høyttalere fra leker:

For større høyttalere er det bedre å sette sammen stasjonen med 2 transistorer og installere et LC-filter for å fjerne støy:

Kondensator C1 tjener til å begrense strømmen gjennom høyttaleren når PWM ikke fungerer. På grunn av inkluderingen av en seriekondensator, når et signal som er symmetrisk omtrent null høyttaleren. Dermed vil høyttalerkjeglen bevege seg i forhold til den sentrale "avslappede" posisjonen, noe som har en positiv effekt på lydkvaliteten.
I dette tilfellet fungerer transistorene i byttemodus, så det er ikke nødvendig å kompensere for grunnforskyvningen.

PWM, to pins tilkobling

Ulempen med de to første kretsene er at høyttaleren får strøm i én retning. Hvis vi endrer retningen på strømmen, kan volumet økes med 2 ganger uten å overskride den tillatte effekten. For å gjøre dette er høyttaleren koblet til to pinner på mikrokontrolleren - ikke-invertert og invertert, for eksempel OC1A og /OC1A. Hvis det ikke er noen ikke-invertert utgang, kan du bruke den andre kanalen i invertert modus (OC1B):

// Timer/Teller 1 initialisering // Klokkekilde: System Klokke // Klokkeverdi: 24500 000 kHz // Modus: Rask PWM topp=0x00FF // OC1A utgang: Non-Inv. // OC1B-utgang: Invertert // Noise Canceler: Off // Input Capture on Falling Edge // Timer1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Sammenlign A Match Avbrudd: Av // Sammenlign B Match Avbrudd: Av TCCR1A =0xB1; TCCR1B=0x09; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; void Player_Output(uint8_t sample) ( OCR1A = sample; OCR1B = sample; )

PWM, To pinner, Klasse D forsterker

Ulempen med de foreslåtte kretsene er strømforbruket under stillhet.
"Silence" for oss tilsvarer et signalnivå på 128, det vil si PWM med 50% fylling - strøm flyter alltid gjennom høyttaleren!

Ved å endre programvaren litt, kan du få en ganske kraftig programvare og maskinvare klasse D forsterker:

Void Player_Output(uint8_t sample) ( if (sample >= 128) ( TCCR2=0x21; //normal, fjern ved sammenligning TCCR2=0x21 | 0x80; //CLEAR OC2 PORTC.0 = 0; TCCR2=0x69; //non -inverterende PWM OCR2 = (sample-128) * 2; ) else // if (sample< 128) { TCCR2=0x31; //normal, set on compare match TCCR2=0x31 | 0x80; //SET OC2 PORTC.0 = 1; TCCR2=0x79; //inverting PWM OCR2 = (128-sample) *2; } }

I dette tilfellet er ett par transistorer koblet til PWM-utgangen, den andre - til en vanlig digital utgang.

Som du kan se av koden, anser vi et signal over 128 som en strøm rettet i én retning, og et signal under 128 som en strøm rettet i den andre retningen. Ved 128 er begge høyttalerpinnene koblet til den samme strømforsyningspinnen og det er ingen strøm. Ved avvik fra nivå 128 øker PWM-fyllingen, og en strøm med tilsvarende polaritet flyter gjennom høyttaleren.

Et viktig poeng i implementeringen er tvungen svitsjing av PWM-utgangen til ønsket tilstand i øyeblikket for å bytte den andre (vanlige digitale) pinnen (PORTC.0). Skriving til OCR2-registeret er bufret for å eliminere PWM-feil. Vi må bytte PWM-utgangen umiddelbart, uten å vente på slutten av perioden.

Sistnevnte krets er IMHO det beste alternativet når det gjelder enkelhet, energibesparelser og effekt.

Lydutgang med SquareWave-bølgeform

Når du syntetiserer en meander, brukes forenklede algoritmer.

Hver kanal (inkludert trommer) gir ut enten 0 eller 1. Dermed gir en 3-kanals platespiller verdier i området 0...3. Derfor, når du bruker PWM, ser utgangsprosedyren slik ut:

Void Player_Output(uint8_t sample) ( OCR2 = sample * (255 / HXMIDIPLAYER_CHANNELS_COUNT); )

Hvis du ikke bruker PWM, er det nok med to vanlige digitale utganger og en 2-bits R2R-matrise for å sende ut en 3-kanals melodi.

MIDI-format

Hvis du ser på den resulterende melodikoden, kan du enkelt se at matrisen bruker repeterende tall fra et lite område. Dette er forståelig: melodien bruker et begrenset antall toner innenfor 1-2 oktaver, meloditempoet er fast - like forsinkelser, antall kanaler er i området 0..15.
Alt dette betyr at den resulterende matrisen kan reduseres betydelig ved å bruke en slags komprimeringsalgoritme.
Algoritmer som ZIP gir god komprimering, men krever også mye minne for å fungere (ZIP-ordbok - 64Kb). Vi kan bruke en veldig enkel komprimeringsmetode som nesten ikke krever noe minne, hvis essens er som følger.

I én byte er alle tall jevnt fordelt i området 0...255, og hvert tall er representert med 8 biter. I vårt tilfelle er noen tall mye mer vanlige enn andre. Hvis du koder hyppig forekommende tall med færre biter, og sjeldnere forekommende med flere, kan du få en minnegevinst.

Vi velger en fast kodingsmetode: kombinasjoner av bit 000 001 og 010 (lengde - 3 biter) vil representere de 3 hyppigst forekommende tallene. Bitkombinasjoner 0110, 0111 (lengde – 4 bits) – de neste 2 vanligste tallene osv.:

//000..010 - 0..2 //011 x 3..4 //100 xx 5..8 //101 xxx 9..16 //110 xxx 17..24 //111 umiddelbar

Kombinasjonen som starter med 111 (lengde – 11 biter) vil kode alle andre tall.
Bitkodingsmetoden kan være annerledes. Jeg prøvde flere metoder og valgte denne for å gi de beste resultatene på slike data.

Kompresjonsprosedyren ser slik ut:
1. Beregn det totale antallet X i strømmen for X = .
2. Sorter etter synkende frekvens av utseende i strømmen.
3. Ta de første 25 tallene. De vil bli kodet i færre biter.
4. Kod inn inngangsstrømmen.

Utgangen er en matrise av de 25 hyppigst forekommende tallene og en bitstrøm.
Denne komprimeringen lar deg oppnå 50 % komprimering med minimale minne- og ytelseskostnader. Dessverre øker dette spillerkoden, så komprimering anbefales ikke for korte melodier.

Lagring av notatfrekvenser

Det er ganske dyrt å lagre frekvensene til alle toner i en tabell fra minnet. Faktisk er det en formel for å bestemme frekvensen til en tone ved midi-nummeret:

F = 2^((N - 69)/12) * 440, Hz

Men å beregne brøkkraften er ganske vanskelig. I stedet lagrer spilleren 12 tonefrekvenser i den øvre oktaven. Frekvensene til noter i lavere oktaver bestemmes ved å redusere frekvensen med 2^Y flere ganger, hvor Y er antall oktaver ned.

Videreutvikling av kompresjon

Melodien inneholder ofte repeterende fragmenter ("refreng", "vers"). Ved å finne repeterende fragmenter og presentere melodien i form av fragmenter, kan du redusere melodien med ytterligere 50 %, og bruke nesten ingen tid RAM og produktivitet. Jeg implementerte ikke en slik algoritme for ikke å komplisere prosjektet.

Programvarebeskrivelse

Hovedvinduet til konverteringsprogrammet:

Last inn midi-knappen lar deg laste inn en midi-fil. Programmet begynner umiddelbart å spille av filen med de valgte parameterne, og simulerer lyden som vil være i maskinvaren.

Informasjonsvinduet (4) viser:
– Lengde – lengden på det valgte melodifragmentet i ms;
– Maks aktive synthesizerkanaler – maksimalt antall samtidig aktive synthesizerkanaler;
– Maks aktive trommekanaler – det maksimale antallet samtidig aktive synthesizerkanaler som gjengir "trommer";
– Maks. aktive stereotoner – maksimalt antall kanaler som gjengir samme note (se nedenfor);
– Estimert størrelse, byte – melodistørrelse i byte. I "Custom Sample"-modus vises størrelsen som A+B, der A er melodistørrelsen, B er prøvestørrelsen. Størrelsen på spillerkoden er ikke spesifisert her.

Fremdriftsvinduet viser gjeldende avspillingsposisjon.
Du kan klikke på fremdriftslinjen for å starte avspilling fra det angitte punktet.
Inndatabokser til venstre og høyre lar deg spesifisere begynnelsen og slutten av melodifragmentet i ms.

"Ikke nok kanaler til å spille melodi"-etiketten i rødt indikerer at det ikke er nok synthesizer-kanaler til å spille melodien med gjeldende innstillinger. Hvis spilleren ikke finner en ledig kanal, slår den av den eldste tonen. I mange tilfeller vil dette fungere bra. Det er bare fornuftig å øke antall kanaler når melodien høres feil ut i øret.

Innstillingene kan deles inn i spillerinnstillinger og midi-filbehandlingsinnstillinger. Spilleren vil kunne spille den resulterende melodikoden hvis spillerkonfigurasjonen og melodikoden ble opprettet med de samme spillerinnstillingene. I tillegg vil spilleren kunne spille en melodi hvis kode ble opprettet for en spiller med et mindre (men ikke større) antall kanaler.

Spillerens maskinvareinnstillinger inkluderer:

– Sampling Rate – syntesefrekvens. Maksimal fusjonsfrekvens bestemmes eksperimentelt. Basert på Atmega 16MHz kan du starte på 12000Hz for en spiller med 6 kanaler, og øke den etter ønske til melodiforvrengning blir merkbar i maskinvarespilleren. Maksimal frekvens avhenger av antall kanaler, bølgeform og kompleksiteten til selve melodien.

– Bølgeform – bølgeform:
– Firkantbølge – meander;
– Sinus – sinus;
– Sinus + Envelope – sinus med demping;
– Bølgeform * + Envelope – ulike alternativer for ikke-sinusformede bølger med og uten demping;
– Custom Sample – bruk en prøve av instrumentet.

"Load Sample"-knappen lar deg laste en prøve fra en WAV-fil. WAV-filen må være i PCM 8-bit mono, 4173Hz, C-5. Hint: Du kan øke frekvensen og senke tonen, men endre tonehøyden i spillerinnstillingene. Det er ingen formatkontroller - hvis formatet er annerledes, vil ikke lyden spilles riktig.
Pitch – lar deg endre tonehøyden på lyden. For å spille 1 oktav høyere, må du for eksempel sette Pitch +12.

Bruk kompresjon – bruk melodikompresjon.
Aktiver drums synteser – aktiver trommesynthesizeren.

Spillerkanaler: Antall synthesizerkanaler (maksimalt antall toner som vil høres samtidig).

Midi-filbehandlingsinnstillinger inkluderer:

Vanligvis er slik finjustering ikke nødvendig. Disse innstillingene kan stå som standard.

Player API

Spillerimplementeringen ligger i filene Common\hxMidiPlayer.c og Common\hxMidiPlayer.h. Disse filene skal inkluderes i prosjektet. Du må også lage en fil hxMidiPlayer_config.h, der du må plassere konfigurasjonen.
Spilleren er skrevet i C uten monteringsinnsatser, noe som gjør det enkelt å portere den til andre mikrokontrollere.

Ekstern void Player_StartMelody(konst flash TMelody* _pMelody, uint16_t _delay);

Begynn å spille melodien. _delay setter startforsinkelsen før avspilling, 255 enheter = 1 sekund.

Void Player_Stop();

Slutt å spille melodien.

Ekstern bool Player_IsPlaying();

Returnerer falsk hvis melodien er ferdig spilt.

Ekstern void Player_WaitFinish();

Vent til melodien er ferdig spilt.

Ekstern void Player_TimerFunc();

Denne funksjonen må kalles opp i et timeravbrudd med samplingshastigheten som er spesifisert i konfigurasjonen. Når melodien er ferdig spilt, trenger du ikke å ringe.

Ekstern void Player_Output(uint8_t sample);

Må implementeres av brukeren. Ringes opp av spilleren når neste prøve skal sendes ut.

Ekstern void Player_Started();

Må implementeres av brukeren. Ringes når spilleren begynner å spille en melodi. Kan brukes til å konfigurere timeravbrudd.

Ekstern void Player_Finished();

Må implementeres av brukeren. Ringes når spilleren er ferdig med å spille melodien. Kan brukes til å deaktivere timeravbrudd, eller begynne å spille en annen melodi.

//#define NOTES_TO_EEPROM //#define SINETABLE_TO_EEPROM //#define ENVELOPE_TO_EEPROM

Disse linjene må ikke kommenteres i filen hxMidiPlayer_config.h hvis notetabellen, sinustabellen og dempningstabellen må plasseres i eeprom.

Eksempelprosjekter

ATMega644Eksempel – prosjekt for ATMega644, 25MHz, PWM-utgang på PB3.

Minnekrav

Bord. Størrelse på spiller og melodier i flash.

*når du legger til en spiller i et eksisterende ikke-tomt prosjekt, vil kodestørrelsen være mindre

**det er ikke nok kanaler for normal melodiavspilling

Melodi 1: bach_minuet_in_g.mid, 35 sek
Melodi 2: yiruma-river_flows_in_you.mid, 165 sek
Melodi 3: Franz Schubert – Serenade.mid, 217 sek

Som du kan se fra tabellen, kan du i minimumskonfigurasjonen presse en ganske lang melodi selv inn i ATTiny2313. Komprimering kan redusere melodien med mer enn to ganger, men størrelsen på spillerkoden øker med ~600 byte.

Sinus- og decay-notetabeller kan plasseres i EEPROM, og sparer henholdsvis ca. 16, 50 og 100 byte med flash.

Når du bruker en prøve fra en wav-fil, må du legge til prøvestørrelsen i byte til størrelsen på spillerkoden.

Eksempel på bruk

Som et eksempel på bruk av en spiller, la oss vurdere prosessen med å lage en musikkboks.

Vi tar en ferdig MDF-boks:

Som mikrokontroller tar vi ATTiny85 i SO-8-pakke som den billigste med tilstrekkelig stor mengde minne. Vi vil overklokke den til 27MHz for å få en syntesefrekvens på 18KHz med 4 Sine+Envelope-kanaler.

Forsterkeren vil være D-klasse med 4 transistorer for å spare batterier.

Transistorer fungerer i byttemodus og kan være av hvilken som helst type. Induktor L1 og kondensator C6 velges etter smak for å oppnå lyd uten høyfrekvent støy. R1 og R2 kan heves opp til 2K for å senke volumet og redusere høyttalersprett.

Grensebryteren fra diskstasjonen passer perfekt, som om den ble laget spesielt for boksen (den fungerer for å åpne - når du åpner lokket, leveres strøm til brettet):

Fastvarekildene er plassert i ATTiny85MusicBox-katalogen.

8Kb passer til:
1) spiller: 18000Hz, 4 kanaler, Sine+Envelope, Pitch+12, komprimering, spiller melodier én etter én (den siste er lagret i EEPROM)
2) Yiruma – elven renner i deg
3) Franz Schubert – Serenade
4) P.I. Tsjaikovskij "oktober"

Resultat på video:

Videre utvikling

I prinsippet kan spilleren videreutvikles, og bringe den til en fullverdig Midi- eller MOD-spiller. Jeg tror personlig at for å få en melodi av høy kvalitet ville det være lettere å koble til et SD-kort og spille av WAV-filer fra det med mye mer beste kvalitet enn det som generelt er mulig å oppnå ved programvaresyntese. Og en slik spiller er mye enklere i programvare og maskinvare. Nisjen til hxMidiPlayer er å legge til god lyd til ferdige prosjekter når det er et par ben igjen og litt plass i blitsen. Den takler denne oppgaven "utmerket" allerede i sin eksisterende form.

Jeg tror dette kan lukke problemet med å lage alle slags musikkbokser/klokker på AVR :)

Fortsettelsen av leksjonen tok lang tid, noe som er forståelig; jeg måtte mestre å jobbe med minnekort og filer FETT system. Men likevel skjedde det, leksjonen er klar - faktisk et nyttårsmirakel.

For ikke å overbelaste artikkelen med informasjon, vil jeg ikke beskrive strukturen til wav-filformatet; det er mer enn nok informasjon i søkemotorer. Det er nok å si at hvis du åpner en fil med en slags Hex-editor, så inneholder de første 44 bytene all informasjon om filtype, samplingsfrekvens, antall kanaler osv. Hvis du trenger å analysere filen, les dette header og du vil bli fornøyd.

Nyttelastdataene starter på 44 byte, og inneholder i hovedsak spenningsnivåene som utgjør lyden. Vi snakket allerede om spenningsnivåer i siste del av leksjonen. Dermed er alt enkelt, du må sende disse trinnene til høyttaleren med samplingsfrekvensen til filen.

Hvordan få en høyttaler til å riste fysisk? Du må sende ut disse spenningsnivåene ved hjelp av PWM, eller bruke R2R. I alle fall er det veldig enkelt å bruke, les nummeret, legg det inn i enten OCR eller PORTx. Så, etter en viss tid, erstattet jeg neste verdi og så videre til slutten av filen.

Eksempel, en viss wav-fil, dataene kommer fra byte 44=0x2C, tallet 0x80 er skrevet der, vi reproduserer lyden, for eksempel ved PWM av den første timeren, skriv OCR1A=0x80; La oss si at samplingsfrekvensen er 8 kHz, så avbruddet bør settes til samme frekvens. I avbruddet erstatter du neste verdi 0x85 etter 1/8000 = 125 µs.

Hvordan sette avbrudd til 8kHz? La oss huske at hvis timeren opererer med en frekvens på 250 kHz, må erstattes (250/8)-1=31-1 eller 0x1E. Med PWM er alt også enkelt; jo høyere frekvens den opererer på, jo bedre.

For at fastvaren skal fungere, er vi enige om at flash-stasjonen er formatert i FAT32, ved å bruke PetitFat lib fra leksjon 23.2. Filen er i wav-format, enten 8kHz eller 22.050kHz, mono. Filnavn 1.wav. La oss analysere fastvaren.

#inkludere #inkluder "diskio.h" #inkluder "pff.h" usignert tegnbuffer[ 512 ] ; /* buffer der informasjonen kopieres fra flash-stasjonen */ flyktig usignert int teller; //kopiert datateller avbryte [TIM2_COMP] void timer2_comp_isr(void) //avbrudd der verdier erstattes( OCR1A = buffer[ teller ] ; // gi lyd til høyttaleren if (++ antall >= 512 ) //øk telleren telle = 0 ; //hvis 512 er tilbakestilt) void main(void) ( usignert int br; /* fil lese-/skriveteller */ usignert char buf = 0 ; //variabel som definerer hvilken del av bufferen som leses FATFS fs; /* Arbeidsområde (filsystemobjekt) for logiske stasjoner */ PORTB= 0x00 ; DDRB= 0x02 ; //hopp shim ocr1a // Timer/Teller 1 initialisering// Klokkekilde: System Klokke // Klokkeverdi: 8000 000 kHz // Modus: Rask PWM topp=0x00FF // OC1A utgang: Non-Inv. TCCR1A= 0x81; TCCR1B= 0x09 ; TCNT1= 0x00 ; OCR1A= 0x00 ; // Timer/Counter 2 initialisering// Klokkekilde: System Klokke // Klokkeverdi: 250 000 kHz // Modus: CTC topp=OCR2 TCCR2= 0x0B ; TCNT2= 0x00 ; //OCR2=0x1E; //sette opp sammenligningsregisteret for 8kHz OCR2= 0xA; //for 22kHz #asm("sei") // Timer(e)/Teller(e) Avbrudd(e) initialisering if (disk_initialize() == 0 ) //initialiser flash-stasjonen( pf_mount(&fs) ; //mount filsystem pf_open("1.wav" ); //åpne en tråd pf_lseek(44) ; //flytt pekeren til 44 pf_read(buffer, 512 ,& br) ; //for første gang svelger vi 512 byte på en gang TIMSK= 0x80 ; //slå på musikken mens (1) ( if (! buf && count> 255 ) //hvis mer enn 255 byte reproduseres,( pf_read(& buffer[ 0 ], 256 ,& br) ; //så leser vi informasjonen fra flash-stasjonen inn i første halvdel av bufferen buf= 1 ; hvis (br< 256 ) //hvis bufferen ikke inneholder 256 verdier, betyr det slutten på filen gå i stykker ; ) if (buff && count< 256 ) { pf_read(& buffer[ 256 ] , 256 ,& br) ; // les inn i den andre delen av bufferen fra flash-stasjonen buf = 0 ; hvis (br< 256 ) break ; } } TIMSK = 0x00 ; //глушим все pf_mount(0x00 ) ; //demonter sløret) mens (1) ( ))

#inkludere #inkluder "diskio.h" #inkluder "pff.h" usignert tegnbuffer; /* buffer som informasjon kopieres til fra flash-stasjonen */ volatile unsigned int count; //teller for kopierte data avbrudd void timer2_comp_isr(void) //avbrudd der verdiene er erstattet (OCR1A = buffer; //gi lyd til høyttaleren hvis (++teller >= 512) //øk telleverket = 0; //if 512 reset ) void main(void) (usignert int br; /* file read/write counter */ unsigned char buf = 0; //variabel som definerer hvilken del av bufferen som leses FATFS fs; /* Fungerer område (filsystemobjekt) for logiske stasjoner */ PORTB=0x00; DDRB=0x02; //jump the shim ocr1a // Timer/Teller 1 initialisering // Klokkekilde: System Klokke // Klokkeverdi: 8000 000 kHz // Modus: Rask PWM topp=0x00FF // OC1A-utgang: Ikke-inv. TCCR1A=0x81; TCCR1B=0x09; TCNT1=0x00; OCR1A=0x00; // Initialisering av timer/teller 2 // Klokkekilde: Systemklokke // Klokkeverdi : 250 000 kHz // Modus: CTC topp= OCR2 TCCR2=0x0B; TCNT2=0x00; //OCR2=0x1E; //setting av sammenligningsregisteret for 8kHz OCR2=0xA; //for 22kHz #asm("sei") // Timer(e)/Teller(e) Interrupt(s) initialisering if(disk_initialize()==0) //initialiser flash-stasjonen ( pf_mount(&fs); //monter filsystemet pf_open("1.wav"); //åpne grenen pf_lseek(44); //flytt pekeren til 44 pf_read(buffer, 512,&br); //for første gang svelger vi 512 byte samtidig TIMSK=0x80; //slå på musikken mens(1) ( if(!buf && count>255) //hvis mer enn 255 byte har blitt spilt, ( pf_read(&buffer, 256,&br);//les deretter informasjonen fra flashen kjør inn i den første halvdelen av bufferen buf=1 ; hvis (br< 256) //если буфер не содержит 256 значений значит конец файла break; } if(buf && count<256) { pf_read(&buffer, 256,&br); // читаем во вторую часть буфера с флешки buf = 0; if (br < 256) break; } } TIMSK = 0x00; //глушим все pf_mount(0x00); //демонтируем фат } while (1) { } }

For å sjekke, kobler vi en høyttaler til OCR1A-pinnen via en 100uF kondensator, "+" til mikrokontrollerpinnen, "-" til høyttaleren. "-" høyttaler til jord, "+" til kondensator.

Ikke forvent et høyt signal ved utgangen; du trenger en forsterker for å høres høyt. Dette er godt synlig i videoen. Til testen lastet jeg hanen med 8 kHz og banen med 22 kHz.

De som ønsker det kan trygt øke frekvensen til timer2 for å spille av 44 kHz-filer; eksperimenter viser at ganske god lydkvalitet kan oppnås. I videoen er lyden svak og kvaliteten dårlig, men faktisk skyldes dette at jeg filmet det med kamera.

Jeg legger også ut materiale som er vennlig levert av Apparatchik - kildekoden for GCC, som fastvaren for CAVR ble skrevet fra.

Og video med 44kHz-avspilling.

Jeg benytter anledningen til å gratulere alle med det nye året, jeg ønsker at all firmware og enheter fungerer for deg :)

wav-spillerprosjekt på Atmega8

Jeg skrev en programvaremodul som lar deg legge til funksjonen for å spille melodier eller lydsekvenser til nesten alle prosjekter på AVR-mikrokontrolleren.

Modulfunksjoner:

Enkel integrasjon med et ferdig prosjekt

Bare 8-bits timeren t2 brukes, mens det fortsatt er mulig å bruke den til polling eller forming av tidsintervaller

Modulen kan justeres til nesten hvilken som helst klokkegeneratorfrekvens

Tonehøyden er spesifisert som symbolske konstanter (C0, A2, etc.) eller i Hertz

Varighetene angis i standardform (kvartdeler, åttendedeler osv.) eller i millisekunder

Det er mulig å stille inn tempoet for avspilling av melodien og antall repetisjoner

Under avspilling kan melodien settes på pause


Koble til en lydmodul

1. Kopier alle modulfiler (tone.h, sound.h, sound.c) inn i prosjektmappen.

2. Koble sound.c-filen til prosjektet.

For IAR `a – høyreklikk i arbeidsområdevinduet og velg Legg til > Legg til filer...

For WINAVR er det omtrent det samme, bare sound.c må legges til makefilen:

SRC = $(MÅL).c lyd.c

3. Inkluder overskriftsfilen sound.h i den tilsvarende modulen. For eksempel i main.c

#inkluder "sound.h"

4. Still inn modulinnstillingene i filen sound.h

//hvis du kommenterer ut, vil varigheten av notatene være

//beregnet fra BPM spesifisert i melodien

//hvis venstre, deretter fra verdien spesifisert nedenfor

//#define SOUND_BPM 24

//klokkefrekvens μ

#define SOUND_F_CPU 16U

//utgang fra mikrokontrolleren som lyden skal genereres på

#define PORT_LYDPORTB

#define PINX_SOUND 0

//antall spesifiserte melodier.

#define SOUND_AMOUNT_MELODY 4

5. Legg til melodiene dine i sound.c og skriv navnene på melodiene inn i melodiarrayen.

Legge til ringetoner

Melodien er en rekke 16-biters tall og har følgende struktur

BPM (kvartnoter per minutt) er en konstant som brukes til å beregne varigheten av noter og bestemmer hastigheten melodien spilles med.

BPM kan variere fra 1 til 24, som tilsvarer henholdsvis 10 og 240 kvartnoter per minutt.

Hvis varigheten av noter/lyder er spesifisert i millisekunder, bør BPM skrevet i matrisen være lik 1.

Hvis SOUND_BPM-konstanten er kommentert ut i headerfilen sound.h, beregnes varigheten av notene under programkjøring i henhold til BPM spesifisert i arrayet. Hvis SOUND_BPM ikke kommenteres ut, beregnes varigheten av notene på kompileringsstadiet, basert på verdien av denne konstanten, og alle melodiene spilles i samme tempo. Dette begrenser funksjonaliteten, men sparer noen byte med kode.

Antall repetisjoner. Kan ta verdier 1 ... 254 og LOOP (255). LOOP - betyr at melodien vil gjentas uendelig til SOUND_STOP eller SOUND_PAUSE kommandoen er gitt.

Merk varighet– tiden som en gitt lydtone genereres eller en pause opprettholdes. Kan spesifiseres i ms, ved å bruke ms(x)-makroen, eller som standardnoteverdier - åttendenoter, sekstendenoter, etc. Nedenfor er en liste over støttede varigheter. Hvis det er behov for noen eksotiske varigheter, kan du alltid legge dem til i tone.h-filen

n1 - helnote

n2 - halvtone

n4 - kvartal

n8 - åttende

n3 - åttende triplett

n16 - sekstende

n6 - sekstol

n32 - trettisekunder

Legg merke til tonehøyde spesifiseres ved hjelp av symbolske konstanter beskrevet i tone.h-filen, for eksempel C2, A1, etc. Tonehøyden kan også spesifiseres i Hertz ved å bruke f(x)-makroen.

Programmet har begrensninger på minimum og maksimum lydfrekvens!

Melodi sluttmarkør. Verdien til det siste elementet i matrisen må være null.

Bruke lydmodulen

På begynnelsen av main må du kalle SOUND_Init()-funksjonen. Denne funksjonen setter mikrokontrollerens utgangspinne, konfigurerer timer T2 og initialiserer modulvariabler.

Deretter må du sette avbruddsaktiveringsflagget - __enable_interrupt(), fordi modulen bruker T2 timeroverflyt og tilfeldighetsavbrudd.

Etter dette kan du begynne å spille melodier.

For eksempel slik:

SOUND_SetSong(2);

SOUND_Com(LYD_PLAY); //spill melodi

//sett pekeren til den andre melodien

//og start avspilling

SOUND_PlaySong(2);

Avspilling av melodien kan stoppes når som helst ved å gi kommandoen SOUND_STOP.
Du kan også sette melodien på pause ved å bruke SOUND_PAUSE-kommandoen. Etterfølgende utstedelse av SOUND_PLAY-kommandoen gjenopptar avspilling av melodien fra punktet der den ble stoppet.

I prinsippet er ikke denne funksjonaliteten spesielt nødvendig (jeg har nettopp funnet den opp) og når du jobber med modulen, er SOUND_PlaySong-funksjonen (unsigned char numSong) nok;

Filer

Du kan laste ned eksempler på bruk av lydmodulen fra lenkene nedenfor. Jeg tegnet ikke et diagram fordi alt er enkelt der. koblet til pinne PB0, er melodistartknappen koblet til pinne PD3. Det er definert 4 melodier i prosjektene. Ved å trykke på knappen starter en ny melodi hver gang. Atmega8535 mikrokontrolleren brukes. I utgangspunktet ville jeg bry meg med et prosjekt med fire knapper – SPILL, STOPP, PAUSE og NESTE, men så tenkte jeg at det var unødvendig.

PS: Modulen har ikke gjennomgått omfattende testing og leveres "som den er". Hvis det er noen rasjonelle forslag, la oss sluttføre det.

I denne artikkelen skal vi se på hvordan du spiller toner og lærer hvordan du spiller en monofonisk melodi.

Forberedelse til arbeid

Programmet erklærer to arrays. Array med notater notater inneholder en enkel liste med notater. Disse notatene samsvarer med lydvarigheten i arrayet beats. Varighet i musikk bestemmes av deleren til en note i forhold til hele tonen. Verdien tatt som en hel note er 255 . Halvdeler, fjerdedeler, åttedeler oppnås ved å dele dette tallet.
Vær oppmerksom på at varigheten av den første tonen ikke oppnås ved å dele 255 med en potens av to. Her må du gå over til musikkteori. Notene til den originale melodien kan sees. Disse notatene er kombinert til trillinger. Når de kombineres på denne måten, høres tre åttendedelsnoter det samme som en kvartnote. Derfor er deres relative varighet 21.
Brukeren må også eksplisitt spesifisere antall notater i sekvensen med direktivet:

# definer SEQU_SIZE 19

I hovedprogrammet blir først og fremst frekvensmatrisene beregnet på nytt og varigheten inn i perioder med signaler og varigheten av notater.
Med signalperioder (array signal_periode) alt er enkelt. For å få periodens varighet i mikrosekunder deler du ganske enkelt 1 000 000 på signalfrekvensen.
For å beregne den absolutte varigheten av noter, må tempoet til det musikalske verket spesifiseres. Dette gjøres ved direktiv

# definer TEMPO 108

Tempo i musikk er antall kvartnoter per minutt. På linje

# definer WHOLE_NOTE_DUR 240000 / TEMPO

Varigheten av en hel tone i millisekunder beregnes. Nå er det nok å beregne de relative verdiene fra matrisen ved å bruke formelen beats til absolutt utvalg note_duration.
I hovedsløyfen, variabelen elapsed_timeøkes etter hver periode av det spilte signalet med varigheten av denne perioden til den overskrider notens varighet. Det er verdt å ta hensyn til denne oppføringen:

while(forløpt_tid< 1000 * ((uint32_t) note_duration[ i] ) )

Variabel elapsed_time 32-bit, og array-elementene notes_duration 16-bit. Hvis et 16-bits tall multipliseres med 1000, garanteres et overløp og variabelen elapsed_time vil bli sammenlignet med søppel. Modifikator (uint32_t) konverterer et matriseelement notes_duration[i] i et 32-bits tall er det ingen overløp.
Du kan se en annen funksjon i lydsløyfen. Det vil ikke være mulig å bruke funksjonen _delay_us(), siden argumentet ikke kan være en variabel.
For å opprette slike forsinkelser, bruk funksjonen VarDelay_us(). I den rulles en løkke med en forsinkelse på 1 μs et spesifisert antall ganger.

void VarDelay_us(uint32_t takt) ( while (takt- - ) ( _delay_us(1 ) ; ) )

Når du spiller en melodi, brukes ytterligere to forsinkelser. Hvis notene spilles uten pauser, vil de slå seg sammen til en. For å gjøre dette settes det inn en forsinkelse på 1 ms mellom dem, spesifisert av direktivet:

# define NOTES_PAUSE 1

Etter hver full syklus med avspilling av melodien, stopper programmet i 1 sekunder og begynner å spille igjen.
Som et resultat fikk vi en kode der det er enkelt å endre tempo, justere varigheten eller helt omskrive melodien. For å gjøre dette vil det være nok å bare transformere den delen av programmet med direktiver og variable erklæringer.

Individuelle oppgaver

  1. I den foreslåtte melodien, prøv å endre tempoet og ta en pause på 5 sekunder mellom repetisjonene.
  2. Array-elementer beats aksepter kun verdier fra 0 til 255. Endre bitbredden til array-elementene og se i kompilatorutgangen for å se hvordan dette påvirker mengden minne som er okkupert av programmet.
  3. Prøv nå å endre melodien selv. For eksempel, her er "Imperial March" fra samme film: int notes = ( A4, R, A4, R, A4, R, F4, R, C5, R, A4, R, F4, R, C5, R, A4, R, E5, R, E5, R, E5, R, F5, R, C5, R, G5, R, F5, R, C5, R, A4, R); int beats = ( 50 , 20 , 50 , 20 , 50 , 20 , 40 , 5 , 20 , 5 , 60 , 10 , 40 , 5 , 20 , 5 , 60 , 80 , 0 , 0 , 5 0 , 0 , 5 20, 40, 5, 20

    Hvis bilen din ikke har en lydsirene installert, og du fortsatt ikke kan bestemme deg for hvilken du skal kjøpe og installere, er denne artikkelen bare for deg. Hvorfor kjøpe dyre alarmer hvis du kan montere det hele selv på en ganske enkel måte?

    Jeg presenterer to av disse enkle kretser på AVR ATmega8 og Attiny2313 mikrokontrollerne, eller rettere sagt, den samme kretsen er ganske enkelt implementert for å fungere på disse to mikrokontrollerne. Forresten, i arkivet finner du to versjoner av fastvare for Atmega8 mikrokontroller, hvorav den første gjengir en lyd som ligner på bilalarm, og den andre lyden ligner på en bygningsalarm (raskt og skarpt signal).

    Du kan laste ned all firmware under i arkivet (de er alle signert), i arkivet finner du også en simulering av kretser i Proteus, som gjør at du etter å ha hørt på alle låtene kan velge fra listen det du liker best .

    Nedenfor er signaleringsdiagrammet for Atmega8

    Liste over radiokomponenter som brukes i Atmega8-kretsen

    U1- AVR mikrokontroller 8-biters ATmega8-16PU, antall. 1,
    R1- Motstand med en nominell verdi på 47 ohm, nr. 1,
    R2, R3 - Motstand med en nominell verdi på 270 Ohm, nr. 2,
    D2,D3-LED, nr. 2,
    LS1-høyttaler, nr. 1,
    S1-sensor.

    Og i signalkretsen på Attiny2313 er det kun MK som er endret.
    U1- Mikrokontroller AVR 8-bit ATtiny2313-20PU, nr. 1.

    Trykt kretskort for Atmega8 ser slik ut:

    Som du kan se, er kretsen veldig enkel, det er bare en mikrokontroller, 3 motstander, 2 lysdioder og en høyttaler til. I stedet for en knapp kan du bruke en reed-bryter eller annen kontakt.

    Driftsprinsippet er som følger. Så snart vi setter på strøm, lyser LED-en (i krets D3) umiddelbart eller begynner å blinke (avhengig av fastvaren), og hvis vi ikke berører sensoren, vil alarmen være stille. Nå, hvis sensoren utløses, vil sirenen også fungere, LED vil også blinke, men D2.

    Hvis du vil at bilens frontlykter skal blinke når alarmen fungerer, må du for å gjøre dette koble pinnen til mikrokontrolleren 24 PC1 til releet gjennom en transistor, og selve reléet til frontlysene. For å slå av sirenen må du slå av og på enheten igjen, eller bare trykke på knappen. For å betjene mikrokontrolleren trenger du en intern 8 MHz oscillator,

    Hvis du på en eller annen måte vil forbedre lyden av alarmen, kan du sette sammen en forsterker med transistorer og koble den til kretsen. Det var akkurat det jeg gjorde, men jeg skildret det ikke i dette diagrammet.

    La oss gå videre til kretsen på Attiny 2313, som jeg sa tidligere, den har alle de samme detaljene og det samme operasjonsprinsippet, bare MK har blitt endret, og som et resultat, de tilkoblede pinnene. Denne mikrokontrolleren opererer fra en intern 4 MHz oscillator, selv om den kan blinke ved 1 MHz.

    Nedenfor er koblingsskjemaet allerede på Attiny2313

    For denne MK skrev jeg bare én versjon av fastvaren, monterte alt på kretskortet, sjekket det, alt fungerer bra.
    Og sikringene må stilles inn som vist nedenfor:





Topp