Სარჩევი:

DTMF დეტექტორი: 4 ნაბიჯი
DTMF დეტექტორი: 4 ნაბიჯი

ვიდეო: DTMF დეტექტორი: 4 ნაბიჯი

ვიდეო: DTMF დეტექტორი: 4 ნაბიჯი
ვიდეო: Smart home with SIM800 modem and NRF24L01 2024, ნოემბერი
Anonim
Image
Image

მიმოხილვა

მე შთაგონებული ვიყავი ამ მოწყობილობის ასაშენებლად ციფრული სიგნალის დამუშავების ონლაინ კურსზე საშინაო დავალებით. ეს არის DTMF დეკოდი, რომელიც განხორციელებულია Arduino UNO– სთან ერთად, ის ამოიცნობს ტელეფონის კლავიატურაზე დაჭერილ ციფრს ტონის რეჟიმში მისი წარმოქმნილი ხმით.

ნაბიჯი 1: ალგორითმის გაგება

Კოდი
Კოდი

DTMF– ში თითოეული სიმბოლო დაშიფრულია ორი სიხშირით სურათის ცხრილის მიხედვით.

მოწყობილობა იღებს მიკროფონიდან შეყვანას და ითვლის რვა სიხშირის ამპლიტუდას. ორი სიხშირე მაქსიმალური ამპლიტუდით იძლევა დაშიფრული სიმბოლოს მწკრივსა და სვეტს.

მონაცემთა მოპოვება

სპექტრის ანალიზის შესასრულებლად ნიმუშები უნდა იქნას აღებული გარკვეული პროგნოზირებადი სიხშირით. ამის მისაღწევად მე გამოვიყენე ADC რეჟიმი თავისუფალი სიზუსტით მაქსიმალური სიზუსტით (prescaler 128), რაც იძლევა შერჩევის სიჩქარეს 9615 Hz. ქვემოთ მოყვანილი კოდი გვიჩვენებს, თუ როგორ უნდა მოხდეს Arduino– ს ADC კონფიგურაცია.

void initADC () {

// ინიცირება ADC; f = (16MHz/prescaler)/13 ციკლი/კონვერტაცია ADMUX = 0; // არხი sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC ჩართვა _BV (ADSC) | // ADC დაწყება _BV (ADATE) | // ავტომატური გამშვები _BV (ADIE) | // შეწყვეტის ჩართვა _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 ჰც ADCSRB = 0; // თავისუფალი გაშვების რეჟიმი DIDR0 = _BV (0); // გამორთეთ ციფრული შეყვანა ADC pin TIMSK0 = 0; // ტაიმერი 0 გამორთულია} და შეფერხების დამმუშავებელი ასე გამოიყურება ISR (ADC_vect) {uint16_t ნიმუში = ADC; ნიმუშები [samplePos ++] = ნიმუში - 400; თუ (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // ბუფერი სავსეა, შეწყვეტა გამორთულია}}

სპექტრის ანალიზი

ნიმუშების შეგროვების შემდეგ ვიანგარიშებ სიმბოლოების კოდირების 8 სიხშირის ამპლიტუდას. მე არ მჭირდება ამის სრული FFT გაშვება, ამიტომ გამოვიყენე გოერცელის ალგორითმი.

void goertzel (uint8_t *ნიმუშები, float *სპექტრი) {

float 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])); float 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 = (float) (ნიმუშები ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); სპექტრი [k] = გამაძლიერებელი; }}

ნაბიჯი 2: კოდი

ზემოთ მოყვანილი სურათი გვიჩვენებს ციფრის კოდირების მაგალითს, სადაც მაქსიმალური ამპლიტუდა შეესაბამება სიხშირეებს 697Hz და 1477Hz.

სრული ესკიზი შემდეგნაირად გამოიყურება

/** * კავშირები: * [Mic to Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [ჩვენება Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #მოიცავს #მოიცავს

#ჩართეთ

#განსაზღვრეთ CS_PIN 9

#განსაზღვრეთ N 256

#განსაზღვრეთ IX_LEN 8 #განსაზღვრეთ THRESHOLD 20

LEDMatrixDriver lmd (1, CS_PIN);

uint8_t ნიმუშები [N];

არასტაბილური uint16_t samplePos = 0;

მცურავი სპექტრი [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.6343963985, 0.6343963985, 0.6343963985, 0.63439639885, 0.63439.396393, 0.6343 çawa const float sin_t [IX_LEN] PROGMEM = {0,44961132965460654, 0,49289819222978404, 0,5349976198870972, 0,5956993044924334, 0,7242470829514669, 0,7730104533627369, 0,8314696123025451, 0,8819212643483549}

typedef სტრუქტურა {

char სიმბოლო; uint8_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} };

ბაიტის შრიფტი [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 }, // 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 () {

// ინიცირება ADC; f = (16MHz/prescaler)/13 ციკლი/კონვერტაცია ADMUX = 0; // არხი sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC ჩართვა _BV (ADSC) | // ADC დაწყება _BV (ADATE) | // ავტომატური გამშვები _BV (ADIE) | // შეწყვეტის ჩართვა _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 ჰც ADCSRB = 0; // თავისუფალი გაშვების რეჟიმი DIDR0 = _BV (0); // გამორთეთ ციფრული შეყვანა ADC pin TIMSK0 = 0; // ტაიმერი 0 გამორთულია}

void goertzel (uint8_t *ნიმუშები, float *სპექტრი) {

float 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])); float 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 = (float) (ნიმუშები ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); სპექტრი [k] = გამაძლიერებელი; }}

float avg (float *a, uint16_t len) {

float შედეგი =.0; for (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; for (uint16_t i = 0; i ბარიერი) {if (ix == -1) {ix = i; } else {დაბრუნება -1; }}} დაბრუნება ix; }

void dete_digit (float *spectrum) {

float avg_row = avg (სპექტრი, 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 (& spectrum [4], 4, avg_col); if (row! = -1 && col! = -1 && avg_col> 200) {dete_digit.digit = pgm_read_byte (& (მაგიდა [რიგი] [col])); აღმოჩენილი_დიგიტი.ინდექსი = pgm_read_byte (& (char_indexes [row] [col])); } else {detect_digit.digit = 0; }}

void drawSprite (ბაიტი* Sprite) {

// ნიღაბი გამოიყენება სვეტის ბიტის მისაღებად Sprite row byte mask = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));

// გადაიტანეთ ნიღაბი ერთი პიქსელით მარჯვნივ

ნიღაბი = ნიღაბი >> 1; }

// სვეტის ნიღბის გადატვირთვა

ნიღაბი = B10000000; }}

void setup () {

cli (); initADC (); სეი ();

Serial.begin (115200);

lmd.setEnabled (ჭეშმარიტი); lmd.setIntensity (2); lmd. წმინდა (); lmd. ჩვენება ();

აღმოჩენილი_დიგიტი.დიგიტი = 0;

}

ხელმოუწერელი გრძელი z = 0;

ბათილი მარყუჟი () {

ხოლო (ADCSRA & _BV (ADIE)); // დაელოდეთ აუდიო შერჩევის დასრულებას goertzel (ნიმუშები, სპექტრი); detective_digit (სპექტრი);

თუ (აღმოჩენილი_დიგიტი.დიგიტი! = 0) {

drawSprite (შრიფტი [აღმოჩენილი_დიგიტი.ინდექსი]); lmd. ჩვენება (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (სპექტრი ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) found_digit.digit); } z ++;

samplePos = 0;

ADCSRA | = _BV (ADIE); // შერჩევის შეწყვეტის განახლება

}

ISR (ADC_vect) {

uint16_t ნიმუში = ADC;

ნიმუშები [samplePos ++] = ნიმუში - 400;

თუ (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // ბუფერი სავსეა, შეწყვეტა გამორთულია}}

ნაბიჯი 3: სქემა

სქემატიკა
სქემატიკა

შემდეგი კავშირები უნდა შეიქმნას:

მიკროფონი არდუინოსთან

გარეთ -> A0

Vcc -> 3.3V Gnd -> Gnd

მნიშვნელოვანია AREF- ის დაკავშირება 3.3V– თან

არდუინოს ჩვენება

Vcc -> 5V

Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9

ნაბიჯი 4: დასკვნა

რა შეიძლება გაუმჯობესდეს აქ? მე გამოვიყენე N = 256 ნიმუში 9615Hz სიჩქარით, რომელსაც აქვს სპექტრის გაჟონვა, თუ N = 205 და მაჩვენებელი 8000Hz მაშინ სასურველი სიხშირეები ემთხვევა დისკრეტიზაციის ქსელს. ამისათვის ADC უნდა იქნას გამოყენებული ტაიმერის გადატვირთვის რეჟიმში.

გირჩევთ: