Πίνακας περιεχομένων:
Βίντεο: Ανιχνευτής DTMF: 4 βήματα
2024 Συγγραφέας: John Day | [email protected]. Τελευταία τροποποίηση: 2024-01-30 08:36
ΣΦΑΙΡΙΚΗ ΕΙΚΟΝΑ
Εμπνεύστηκα να δημιουργήσω αυτήν τη συσκευή από μια οικιακή εργασία στο διαδικτυακό μάθημα Digitalηφιακής επεξεργασίας σημάτων. Αυτός είναι ένας αποκωδικοποιητής DTMF που εφαρμόζεται με το Arduino UNO, ανιχνεύει ένα ψηφίο που πιέζεται σε ένα πληκτρολόγιο τηλεφώνου στη λειτουργία τόνου από τον ήχο που παράγει.
Βήμα 1: Κατανόηση του αλγορίθμου
Στο DTMF κάθε σύμβολο κωδικοποιείται με δύο συχνότητες σύμφωνα με τον πίνακα της εικόνας.
Η συσκευή καταγράφει την είσοδο από το μικρόφωνο και υπολογίζει πλάτη οκτώ συχνοτήτων. Δύο συχνότητες με μέγιστα πλάτη δίνουν μια γραμμή και μια στήλη του κωδικοποιημένου συμβόλου.
Απόκτηση δεδομένων
Για την εκτέλεση ανάλυσης φάσματος τα δείγματα πρέπει να λαμβάνονται σε μια συγκεκριμένη προβλέψιμη συχνότητα. Για να το πετύχω αυτό, χρησιμοποίησα τη λειτουργία ADC ελεύθερης λειτουργίας με μέγιστη ακρίβεια (προ-ζυγοστάτης 128) δίνει ρυθμό δειγματοληψίας 9615Hz. Ο παρακάτω κώδικας δείχνει πώς μπορείτε να διαμορφώσετε το ADC του Arduino.
void initADC () {
// Init ADC; f = (16MHz/prescaler)/13 κύκλοι/μετατροπή ADMUX = 0; // Πωλήσεις καναλιών, δεξιά-επέκταση, χρησιμοποιήστε καρφίτσα AREF ADCSRA = _BV (ADEN) | // ADC enable _BV (ADSC) | // ADC start _BV (ADATE) | // Αυτόματη σκανδάλη _BV (ADIE) | // Διακοπή ενεργοποίησης _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Λειτουργία ελεύθερης εκτέλεσης DIDR0 = _BV (0); // Απενεργοποίηση ψηφιακής εισόδου για καρφίτσα ADC TIMSK0 = 0; // Timer0 off} Και ο χειριστής διακοπών μοιάζει με αυτό το ISR (ADC_vect) {uint16_t sample = ADC; δείγματα [samplePos ++] = δείγμα - 400; εάν (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Η προσωρινή μνήμη είναι πλήρης, η διακοπή απενεργοποιείται}}
Ανάλυση φάσματος
Μετά τη συλλογή δειγμάτων υπολογίζω πλάτη 8 συχνοτήτων που κωδικοποιούν σύμβολα. Δεν χρειάζεται να εκτελέσω πλήρη FFT για αυτό, οπότε χρησιμοποίησα τον αλγόριθμο του Goertzel.
void goertzel (uint8_t *δείγματα, float *φάσμα) {
float v_0, v_1, v_2; float re, im, amp; για (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); float a = 2. * c; v_0 = v_1 = v_2 = 0; για (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (δείγματα ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); φάσμα [k] = ενισχυτής; }}
Βήμα 2: Ο κώδικας
Η παραπάνω εικόνα δείχνει το παράδειγμα της κωδικοποίησης του ψηφίου 3 όπου το μέγιστο πλάτος αντιστοιχεί σε συχνότητες 697Hz και 1477Hz.
Το πλήρες σκίτσο φαίνεται ως εξής
/** * Συνδέσεις: * [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
#περιλαμβάνω
#define CS_PIN 9
#define N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
δείγματα uint8_t [N];
πτητικό uint16_t samplePos = 0;
float φάσμα [IX_LEN];
// Συχνότητες [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// Υπολογίστηκε για 9615Hz 256 δείγματα const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.63439639885, 0.63439639885, 0.634393603, 0.634393603, 0.63439.396393 0.63439.393 0.8639.396393 0.6343.986393 0.6343 Six. const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.831924696, 0.831924986, 0.831924986, 0.83192496
typedef struct {
ψηφίο char? ευρετήριο uint8_t; } digit_t;
ψηφίο_αναγνωρισμένο_ψήφιο?
const char table [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, 0x04, 0x04, 0x38, 0x40, 0x7c}, // 2 {0x00, 0x38, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38}, // 3 {0x00, 0x04, 0x0c, 0x14, 0x24, 0x7e, 0x04, 0x04, 0x04, 0x04, 0x04, 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}, / / Β {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 () {
// Init ADC; f = (16MHz/prescaler)/13 κύκλοι/μετατροπή ADMUX = 0; // Πωλήσεις καναλιών, δεξιά-επέκταση, χρησιμοποιήστε καρφίτσα AREF ADCSRA = _BV (ADEN) | // ADC enable _BV (ADSC) | // ADC start _BV (ADATE) | // Αυτόματη σκανδάλη _BV (ADIE) | // Διακοπή ενεργοποίησης _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Λειτουργία ελεύθερης εκτέλεσης DIDR0 = _BV (0); // Απενεργοποίηση ψηφιακής εισόδου για καρφίτσα ADC TIMSK0 = 0; // Χρονοδιακόπτης 0 απενεργοποιημένος}
void goertzel (uint8_t *δείγματα, float *φάσμα) {
float v_0, v_1, v_2; float re, im, amp? για (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); float a = 2. * c; v_0 = v_1 = v_2 = 0; για (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (δείγματα ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); φάσμα [k] = ενισχυτής; }}
μέσο πλωτήρα (float *a, uint16_t len) {
float αποτέλεσμα =.0; για (uint16_t i = 0; i <len; i ++) {result+= a ; } αποτέλεσμα επιστροφής / len; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float threshold) {
εάν (κατώφλι <THRESHOLD) {επιστροφή -1; } int8_t ix = -1; για (uint16_t i = 0; i κατώφλι) {if (ix == -1) {ix = i; } else {return -1; }}} return ix; }
void dete_digit (float *spectrum) {
float avg_row = μέσο (φάσμα, 4); float avg_col = avg (& φάσμα [4], 4); int8_t row = get_single_index_above_threshold (φάσμα, 4, avg_row)? int8_t col = get_single_index_above_threshold (& φάσμα [4], 4, avg_col); if (row! = -1 && col! = -1 && avg_col> 200) {dete_digit.digit = pgm_read_byte (& (πίνακας [σειρά] [col])); Discover_digit.index = pgm_read_byte (& (char_indexes [σειρά] [col])); } else {dete_digit.digit = 0; }}
void drawSprite (byte* sprite) {
// Η μάσκα χρησιμοποιείται για να πάρει το bit της στήλης από τη μάσκα byte σειράς sprite = B10000000; για (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask)) ?
// μετακινήστε τη μάσκα κατά ένα pixel προς τα δεξιά
μάσκα = μάσκα >> 1; }
// επαναφορά μάσκας στήλης
μάσκα = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (true); lmd.setIntensity (2); lmd.clear (); lmd.display ();
Discover_digit.digit = 0;
}
ανυπόγραφο μακρύ z = 0;
void loop () {
ενώ (ADCSRA & _BV (ADIE)); // Περιμένετε να ολοκληρωθεί η δειγματοληψία ήχου για να τελειώσει το goertzel (δείγματα, φάσμα). dete_digit (φάσμα)?
εάν (dete_digit.digit! = 0) {
drawSprite (γραμματοσειρά [dete_digit.index]); lmd.display (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (φάσμα ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) detect_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Συνέχιση διακοπής δειγματοληψίας
}
ISR (ADC_vect) {
uint16_t δείγμα = ADC;
δείγματα [samplePos ++] = δείγμα - 400;
εάν (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Η προσωρινή μνήμη είναι πλήρης, η διακοπή απενεργοποιείται}}
Βήμα 3: Διαγράμματα
Πρέπει να γίνουν οι ακόλουθες συνδέσεις:
Μικρόφωνο στο Arduino
Έξω -> Α0
Vcc -> 3.3V Gnd -> Gnd
Είναι σημαντικό να συνδέσετε το AREF σε 3,3V
Εμφάνιση στο Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Βήμα 4: Συμπέρασμα
Τι θα μπορούσε να βελτιωθεί εδώ; Χρησιμοποίησα δείγματα Ν = 256 με ρυθμό 9615Hz που έχει κάποια διαρροή φάσματος, αν Ν = 205 και ρυθμός είναι 8000Hz τότε οι επιθυμητές συχνότητες συμπίπτουν με το πλέγμα διακριτικότητας. Για αυτό το ADC θα πρέπει να χρησιμοποιείται σε λειτουργία υπερχείλισης χρονοδιακόπτη.
Συνιστάται:
Ανιχνευτής στάθμης νερού: 7 βήματα
Ανιχνευτής στάθμης νερού: Ο αισθητήρας υπερήχων λειτουργεί στις ίδιες αρχές με το σύστημα ραντάρ. Ένας υπερηχητικός αισθητήρας μπορεί να μετατρέψει την ηλεκτρική ενέργεια σε ακουστικά κύματα και αντίστροφα. Ο διάσημος αισθητήρας υπερήχων HC SR04 παράγει υπερηχητικά κύματα σε συχνότητα 40kHz. Typica
Ανιχνευτής παρουσίας κρεβατιού Zigbee: 8 βήματα
Ανιχνευτής παρουσίας κρεβατιού Zigbee: Εδώ και λίγο καιρό έψαχνα έναν τρόπο να εντοπίσω πότε είμαστε στο κρεβάτι. Αυτό για τη χρήση αυτών των πληροφοριών στο Homeassistant. Με αυτές τις πληροφορίες θα μπορούσα να κάνω αυτοματισμούς για να σβήσω τα φώτα τη νύχτα ή για παράδειγμα να ενεργοποιήσω ένα σύστημα συναγερμού στο σπίτι μου
Ανιχνευτής καπνού: 13 βήματα
Ανιχνευτής καπνού: Γεια σας φίλοι σήμερα ας δούμε για τον ανιχνευτή καπνού Πολλοί από εσάς πήγατε σε εμπορικά κέντρα σε εμπορικά κέντρα, κυρίως μπορείτε να δείτε αυτή τη συσκευή που ονομάζεται ανιχνευτής καπνού, θα ανιχνεύσει τον καπνό και θα ενεργοποιήσει τον ψεκαστήρα και θα σταματήσει τη φωτιά. Αλλά σε αυτό το έργο αυτό είναι μια μικρή αλλαγή αντι αυτου
Digitalηφιακή πυξίδα και ανιχνευτής κατεύθυνσης: 6 βήματα
Digital Compass and Heading Finder: Συγγραφείς: Cullan Whelan Andrew Luft Blake Johnson Ευχαριστίες: California Maritime Academy Evan Chang-SiuΕισαγωγή: Η βάση αυτού του έργου είναι μια ψηφιακή πυξίδα με παρακολούθηση επικεφαλίδας. Αυτό επιτρέπει στον χρήστη να ακολουθήσει μια επικεφαλίδα σε μεγάλες αποστάσεις
Ανιχνευτής βροχής χρησιμοποιώντας αισθητήρα Arduino και σταγόνας βροχής: 8 βήματα
Ανιχνευτής βροχής χρησιμοποιώντας αισθητήρα Arduino και Raindrop: Σε αυτό το σεμινάριο θα μάθουμε πώς να ανιχνεύουμε μια βροχή χρησιμοποιώντας έναν αισθητήρα βροχής και να κάνουμε έναν ήχο χρησιμοποιώντας μια μονάδα βομβητή και OLED Display και Visuino. Δείτε το βίντεο