Innehållsförteckning:
Video: DTMF -detektor: 4 steg
2024 Författare: John Day | [email protected]. Senast ändrad: 2024-01-30 12:45
Översikt
Jag inspirerades att bygga den här enheten genom ett hemuppdrag på onlinekurs för digital signalbehandling. Detta är en DTMF -avkodare implementerad med Arduino UNO, den känner av en siffra som trycks på en knappsats på telefonen i tonläget av det ljud som den producerar.
Steg 1: Förstå algoritmen
I DTMF kodas varje symbol med två frekvenser enligt tabellen på bilden.
Enheten fångar inmatning från mikrofonen och beräknar amplituder på åtta frekvenser. Två frekvenser med maximala amplituder ger en rad och en kolumn med den kodade symbolen.
Datainsamling
För att kunna utföra spektrumanalys bör prover tas med en viss förutsägbar frekvens. För att uppnå detta använde jag frikörning ADC-läge med maximal precision (förskalare 128) det ger samplingshastighet 9615Hz. Koden nedan visar hur du konfigurerar Arduinos ADC.
ogiltig initADC () {
// Init ADC; f = (16MHz/förkalkning)/13 cykler/konvertering ADMUX = 0; // Channel sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC aktivera _BV (ADSC) | // ADC start _BV (ADATE) | // Auto trigger _BV (ADIE) | // Avbryt aktivering _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Free-run mode DIDR0 = _BV (0); // Stäng av digital ingång för ADC -stift TIMSK0 = 0; // Timer0 av} Och avbrottshanteraren ser ut så här ISR (ADC_vect) {uint16_t sample = ADC; samples [samplePos ++] = sample - 400; om (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffert full, avbryt}}
Spektrumanalys
Efter att ha samlat in prover beräknar jag amplituder på 8 frekvenser som kodar symboler. Jag behöver inte köra full FFT för detta, så jag använde Goertzels algoritm.
void goertzel (uint8_t *samples, float *spectrum) {
float v_0, v_1, v_2; float re, im, amp; för (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); flyta a = 2. * c; v_0 = v_1 = v_2 = 0; för (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (prover ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrum [k] = amp; }}
Steg 2: Koden
Bilden ovan visar exemplet på kodning av siffra 3 där maximal amplitud motsvarar frekvenserna 697Hz och 1477Hz.
Hela skissen ser ut så här
/** * Anslutningar: * [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
#omfatta
#define CS_PIN 9
#definiera N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t prover [N];
flyktigt uint16_t samplePos = 0;
flottörspektrum [IX_LEN];
// Frekvenser [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// Beräknat för 9615Hz 256 sampel const float cos_t [IX_LEN] PROGMEM = {0,8932243011955153, 0,877869911087115, 0,8448535652497071, 0,8032075314806449, 0,6895405447370669, 0,6343932841636456, 0,5555; const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025451, 0.88
typedef struct {
rödningssiffra; uint8_t index; } digit_t;
digit_t detekterade_siffran;
const char tabell [4] [4] PROGMEM = {
{'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} };
byte font [16] [8] = {
{0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38}, // 0 {0x04, 0x0c, 0x14, 0x24, 0x04, 0x04, 0x04, 0x04}, // 1 {0x00, 0x30, 0x48, 0x0, 0x04, 0x38, 0x40, 0x7c}, // 2 {0x00, 0x38, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38}, // 3 {0x00, 0x04, 0x0c, 0x14, 0x24, 0x7e, 0x04, 0x0 }, // 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} // *};
ogiltig initADC () {
// Init ADC; f = (16MHz/förkalkning)/13 cykler/konvertering ADMUX = 0; // Channel sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC aktivera _BV (ADSC) | // ADC start _BV (ADATE) | // Auto trigger _BV (ADIE) | // Avbryt aktivering _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Free-run mode DIDR0 = _BV (0); // Stäng av digital ingång för ADC -stift TIMSK0 = 0; // Timer0 av}
void goertzel (uint8_t *samples, float *spectrum) {
float v_0, v_1, v_2; float re, im, amp; för (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); flyta a = 2. * c; v_0 = v_1 = v_2 = 0; för (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (prover ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrum [k] = amp; }}
float avg (float *a, uint16_t len) {
float resultat =.0; för (uint16_t i = 0; i <len; i ++) {resultat+= a ; } returresultat / len; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float tröskel) {
if (tröskel <THRESHOLD) {return -1; } int8_t ix = -1; för (uint16_t i = 0; i tröskel) {if (ix == -1) {ix = i; } annat {return -1; }}} returnera ix; }
void detect_digit (float *spectrum) {
float avg_row = avg (spektrum, 4); float avg_col = avg (& spektrum [4], 4); int8_t rad = get_single_index_above_threshold (spektrum, 4, avg_row); int8_t col = get_single_index_above_threshold (& spektrum [4], 4, avg_col); if (rad! = -1 && col! = -1 && avg_col> 200) {detect_digit.digit = pgm_read_byte (& (tabell [rad] [col])); detekterad_digit.index = pgm_read_byte (& (char_indexes [rad] [kol])); } annat {detect_digit.digit = 0; }}
void drawSprite (byte* sprite) {
// Masken används för att få kolumnbiten från sprite row byte mask = B10000000; för (int iy = 0; iy <8; iy ++) {för (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));
// flytta masken med en pixel åt höger
mask = mask >> 1; }
// återställ kolumnmask
mask = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (true); lmd.setIntensity (2); lmd.clear (); lmd.display ();
detekterad_digit.digit = 0;
}
osignerad lång z = 0;
void loop () {
medan (ADCSRA & _BV (ADIE)); // Vänta på ljudsampling för att slutföra goertzel (samplingar, spektrum); detect_digit (spektrum);
om (detect_digit.digit! = 0) {
drawSprite (font [detekterad_digit.index]); lmd.display (); } if (z % 5 == 0) {för (int i = 0; i <IX_LEN; i ++) {Serial.print (spektrum ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) detect_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Återuppta provtagningsavbrott
}
ISR (ADC_vect) {
uint16_t sample = ADC;
prover [samplePos ++] = prov - 400;
om (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffert full, avbryt}}
Steg 3: Scheman
Följande anslutningar bör göras:
Mic till Arduino
Ut -> A0
Vcc -> 3.3V Gnd -> Gnd
Det är viktigt att ansluta AREF till 3,3V
Display till Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Steg 4: Slutsats
Vad kan förbättras här? Jag använde N = 256 sampler med en hastighet av 9615Hz som har ett visst spektrumläckage, om N = 205 och hastigheten är 8000Hz sammanfaller de önskade frekvenserna med diskretiseringsnätet. För att ADC ska användas i timeröverflödesläge.
Rekommenderad:
DTMF VIDEO STREAMING ROVER: 3 steg
DTMF VIDEO STREAMING ROVER: hej efter min LINUX TERMINAL CONTROLLED ROVER och WIFI DTMF PC CONTROLLED ROBOT detta är min tredje robot. och som andra två här använde jag inte någon mikrokontroller eller programmering för att hålla det enkelt och enkelt att göra. det strömmar också livevideo över wifi
Hur man gör en enkel DTMF (ton) telefonlinjeavkodare: 3 steg
Hur man gör en enkel DTMF (ton) telefonlinjeavkodare: Detta är ett enkelt projekt som låter dig avkoda DTMF -signaler på i princip vilken telefonlinje som helst. I denna handledning använder vi avkodaren MT8870D. Vi använder en förbyggd tonavkodare eftersom, tro mig, det är ont i baksidan att försöka göra det med
WIFI DTMF ROBOT: 5 steg
WIFI DTMF ROBOT: hej i den här självstudien kommer jag att visa dig hur du kan göra en datorstyrd rover utan att använda mikrokontroller, det betyder i detta projekt att ingen högnivåkod är involverad, du behöver bara grundläggande kunskap om html -sida som gör det. Det är du kan se hela
Hur man gör en mobilstyrd robot - DTMF -baserad - Utan mikrokontroller och programmering - Kontroll överallt i världen - RoboGeeks: 15 steg
Hur man gör en mobilstyrd robot | DTMF -baserad | Utan mikrokontroller och programmering | Kontroll överallt i världen | RoboGeeks: Vill du göra en robot som kan styras var som helst i världen, låt oss göra det
DTMF och gestkontrollerad robotrullstol: 7 steg (med bilder)
DTMF och geststyrd robotrullstol: I denna värld är ett antal människor handikappade. Deras liv kretsar kring hjul. Detta projekt presenterar ett tillvägagångssätt för att kontrollera rullstolsrörelser med hjälp av handrörelseigenkänning och DTMF för en smartphone