Sisällysluettelo:
Video: DTMF -ilmaisin: 4 vaihetta
2024 Kirjoittaja: John Day | [email protected]. Viimeksi muokattu: 2024-01-30 09:02
Yleiskatsaus
Sain innoitukseni rakentaa tämä laite kotitehtävästä digitaalisen signaalin käsittelyn verkkokurssilla. Tämä on DTMF -dekooderi, joka on toteutettu Arduino UNO: lla, ja se tunnistaa numeron, jota puhelimen näppäimistö painaa äänitilassa sen tuottaman äänen perusteella.
Vaihe 1: Algoritmin ymmärtäminen
DTMF: ssä jokainen symboli on koodattu kahdella taajuudella kuvan taulukon mukaisesti.
Laite kerää mikrofonista tuloa ja laskee kahdeksan taajuuden amplitudit. Kaksi taajuutta, joilla on suurin amplitudi, antavat rivin ja sarakkeen koodatusta symbolista.
Tiedonkeruu
Spektrianalyysin suorittamiseksi näytteet on otettava tietyllä ennustettavalla taajuudella. Tämän saavuttamiseksi käytin vapaasti suoritettavaa ADC-tilaa mahdollisimman tarkasti (esiasetin 128), ja se antaa näytteenottotaajuuden 9615 Hz. Alla oleva koodi näyttää, miten Arduinon ADC määritetään.
void initADC () {
// Alkuperäinen ADC; f = (16 MHz/esiskaalain)/13 sykliä/muunnos ADMUX = 0; // Kanava sel, oikea-adj, käytä AREF-nastaista ADCSRA = _BV (ADEN) | // ADC käyttöön _BV (ADSC) | // ADC -aloitus _BV (ADATE) | // Automaattinen liipaisin _BV (ADIE) | // Keskeytyksen käyttöönotto _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Vapaakäyntitila DIDR0 = _BV (0); // Sammuta digitaalinen tulo ADC -nastalle TIMSK0 = 0; // Ajastin0 pois} Ja keskeytyksenkäsittelijä näyttää tältä: ISR (ADC_vect) {uint16_t sample = ADC; sample [samplePos ++] = sample - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Puskuri täynnä, keskeytys pois päältä}}
Spektrianalyysi
Näytteiden keräämisen jälkeen lasken symboleja koodaavien 8 taajuuden amplitudit. Minun ei tarvitse suorittaa täyden FFT: n tätä varten, joten käytin Goertzelin algoritmia.
void goertzel (uint8_t *näytteet, float *spektri) {
kellua v_0, v_1, v_2; float re, im, amp; for (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); float s = pgm_read_float (& (sin_t [k]))); kellua a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (kelluva) (näytteet ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektri [k] = amp; }}
Vaihe 2: Koodi
Yllä oleva kuva esittää esimerkin numeron 3 koodauksesta, jossa suurin amplitudi vastaa taajuuksia 697 Hz ja 1477 Hz.
Koko luonnos näyttää tältä
/** * Liitännät: * [Mic to Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Display to Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#sisältää
#define CS_PIN 9
#määrittele N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t näytteet [N];
haihtuva uint16_t samplePos = 0;
kelluva spektri [IX_LEN];
// Taajuudet [697,0, 770,0, 852,0, 941,0, 1209,0, 1336,0, 1477,0, 1633,0]
// Laskettu 9615 Hz: lle 256 näytteelle const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.63439328416364561956605, 5656 const float sin_t [IX_LEN] OHJELMA = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025456 0.48
typedef structure {
char -numero; uint8_t -indeksi; } numero_t;
digit_t havaittu_numero;
const char -taulukko [4] [4] OHJELMA = {
{'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', ' C '}, {'*',' 0 ','#',' D '}};
const uint8_t char_indexes [4] [4] PROGMEM = {
{1, 2, 3, 10}, {4, 5, 6, 11}, {7, 8, 9, 12}, {15, 0, 14, 13} };
tavu fontti [16] [8] = {
{0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38}, // 0 {0x04, 0x0c, 0x14, 0x24, 0x04, 0x04, 0x04, 0x04}, // 1 {0x00, 0x30, 0x48, 0x04, 0x04, 0x38, 0x40, 0x7c}, // 2 {0x00, 0x38, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38}, // 3 {0x00, 0x04, 0x0c, 0x14, 0x24, 0x7e, 0x04, 0x04 }, // 4 {0x00, 0x7c, 0x40, 0x40, 0x78, 0x04, 0x04, 0x38}, // 5 {0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38}, // 6 {0x00, 0x7c, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10}, // 7 {0x00, 0x3c, 0x44, 0x44, 0x38, 0x44, 0x44, 0x78}, // 8 {0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x04, 0x78}, // 9 {0x00, 0x1c, 0x22, 0x42, 0x42, 0x7e, 0x42, 0x42}, // A {0x00, 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x7c}, / / B {0x00, 0x3c, 0x44, 0x40, 0x40, 0x40, 0x44, 0x7c}, // C {0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78}, // D {0x00, 0x0a, 0x7f, 0x14, 0x28, 0xfe, 0x50, 0x00}, // # {0x00, 0x10, 0x54, 0x38, 0x10, 0x38, 0x54, 0x10} // *};
void initADC () {
// Alkuperäinen ADC; f = (16 MHz/esiskaalain)/13 sykliä/muunnos ADMUX = 0; // Kanava sel, oikea-adj, käytä AREF-nastaista ADCSRA = _BV (ADEN) | // ADC käyttöön _BV (ADSC) | // ADC -aloitus _BV (ADATE) | // Automaattinen liipaisin _BV (ADIE) | // Keskeytyksen käyttöönotto _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Vapaakäyntitila DIDR0 = _BV (0); // Sammuta digitaalinen tulo ADC -nastalle TIMSK0 = 0; // Ajastin0 pois päältä}
void goertzel (uint8_t *näytteet, float *spektri) {
kellua v_0, v_1, v_2; float re, im, amp; for (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); float s = pgm_read_float (& (sin_t [k]))); kellua a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (kelluva) (näytteet ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektri [k] = amp; }}
float avg (float *a, uint16_t len) {
float -tulos =.0; for (uint16_t i = 0; i <len; i ++) {tulos+= a ; } palautustulos / len; }
int8_t get_single_index_above_threshold (kelluva *a, uint16_t len, kellukynnys) {
if (kynnys <THRESHOLD) {return -1; } int8_t ix = -1; (uint16_t i = 0; i kynnys) {if (ix == -1) {ix = i; } else {return -1; }}} return ix; }
void detect_digit (float *spektri) {
float avg_row = avg (spektri, 4); float avg_col = keskiarvo (& spektri [4], 4); int8_t rivi = get_single_index_above_threshold (spektri, 4, keskiarvo); int8_t col = get_single_index_above_threshold (& spektri [4], 4, keskim.) if (rivi! = -1 && col! = -1 && avg_col> 200) {havaittu_digit.digit = pgm_read_byte (& (taulukko [rivi] [sarake])); havaittu_dig.index = pgm_read_byte (& (char_indexes [rivi] [col])); } else {havaittu_numero.numero = 0; }}
void drawSprite (tavu* sprite) {
// Maskia käytetään sarakkeen bitin hakemiseen sprite -rivin tavumastista = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));
// siirrä naamio yhden pikselin verran oikealle
maski = maski >> 1; }
// nollaa pylväsmaski
naamio = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Sarja.alku (115200);
lmd.setEnabled (true); lmd.setIntensity (2); lmd.clear (); lmd.display ();
havaittu_numero.numero = 0;
}
allekirjoittamaton pitkä z = 0;
void loop () {
kun taas (ADCSRA & _BV (ADIE)); // Odota ääninäytteenoton päättymistä goertzeliin (näytteet, spektri); tunnista_numero (spektri);
jos (havaittu_numero.luku! = 0) {
drawSprite (fontti [tunnistettu_numero.index]); lmd.display (); } jos (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (spektri ); Serial.print ("\ t"); } Sarja.println (); Sarja.println ((int) havaittu_numero.numero); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Jatka näytteenoton keskeytystä
}
ISR (ADC_vect) {
uint16_t näyte = ADC;
näytteet [samplePos ++] = näyte - 400;
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Puskuri täynnä, keskeytys pois päältä}}
Vaihe 3: Kaaviot
Seuraavat liitännät on tehtävä:
Mikrofoni Arduinolle
Ulos -> A0
Vcc -> 3.3V Gnd -> Gnd
On tärkeää liittää AREF 3,3 V: n jännitteeseen
Näytä Arduinolle
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Vaihe 4: Johtopäätös
Mitä tässä voisi parantaa? Käytin N = 256 näytettä taajuudella 9615 Hz, jolla on jonkin verran spektrivuotoa, jos N = 205 ja nopeus on 8000 Hz, niin halutut taajuudet vastaavat diskreetointiruudukkoa. Tätä varten ADC: tä tulisi käyttää ajastimen ylivuototilassa.
Suositeltava:
DTMF VIDEO STREAMING ROVER: 3 vaihetta
DTMF VIDEO STREAMING ROVER: hei LINUX TERMINAL CONTROLLED ROVERin ja WIFI DTMF PC OHJAAMAN ROBOTIN jälkeen tämä on kolmas robotti. ja kuten muut kaksi täällä, en myöskään käyttänyt mitään mikro -ohjainta tai ohjelmointia pitääksesi sen yksinkertaisena ja helpoksi tehdä. se myös suoratoistaa suoraa videota wifi -yhteyden kautta
Yksinkertaisen DTMF (ääni) -puhelinlinjan dekooderin tekeminen: 3 vaihetta
Yksinkertaisen DTMF (ääni) -puhelinlinjan dekooderin tekeminen: Tämä on yksinkertainen projekti, jonka avulla voit purkaa DTMF -signaalit periaatteessa millä tahansa puhelinlinjalla. Tässä opetusohjelmassa käytämme dekooderia MT8870D. Käytämme esivalmistettua äänidekooderia, koska usko minua, takana on kipua yrittää tehdä se
WIFI DTMF ROBOT: 5 vaihetta
WIFI DTMF ROBOT: Hei tässä opetusohjelmassa aion näyttää sinulle, kuinka voit tehdä tietokoneella ohjatun roverin ilman mikro -ohjainta, tämä tarkoittaa, että tässä projektissa ei ole mukana korkean tason koodia, tarvitset vain perustiedot html -sivun tekemisestä. voi katsoa koko
Kuinka tehdä mobiiliohjattu robotti - DTMF -pohjainen - Ilman mikrokontrolleria ja ohjelmointia - Ohjaus mistä tahansa maailmasta - RoboGeeks: 15 vaihetta
Kuinka tehdä mobiiliohjattu robotti | DTMF -pohjainen | Ilman mikrokontrolleria ja ohjelmointia | Ohjaus mistä tahansa maailmasta | RoboGeeks: Haluatko tehdä robotin, jota voidaan ohjata mistä päin maailmaa tahansa, tee se
DTMF- ja eleohjattu robottipyörätuoli: 7 vaihetta (kuvilla)
DTMF ja eleohjattu robottipyörätuoli: Tässä maailmassa monet ihmiset ovat vammaisia. Heidän elämänsä pyörii pyörien ympärillä. Tämä projekti esittelee lähestymistavan pyörätuolin liikkeen ohjaamiseen käsieleiden tunnistuksella ja älypuhelimen DTMF: llä