Съдържание:
Видео: DTMF детектор: 4 стъпки
2024 Автор: John Day | [email protected]. Последно модифициран: 2024-01-30 07:52
Общ преглед
Бях вдъхновен за изграждането на това устройство от домашна задача на онлайн курса за цифрова обработка на сигнали. Това е DTMF декодер, реализиран с Arduino UNO, той открива цифра, натисната върху клавиатурата на телефона в тонален режим от звука, който произвежда.
Стъпка 1: Разбиране на алгоритъма
В DTMF всеки символ е кодиран с две честоти според таблицата на картината.
Устройството улавя вход от микрофона и изчислява амплитуди от осем честоти. Две честоти с максимални амплитуди дават ред и колона от кодирания символ.
Събиране на данни
За да се извърши анализ на спектъра, пробите трябва да бъдат уловени с определена предсказуема честота. За да постигна това, използвах свободно работещ ADC режим с максимална прецизност (предусилвател 128), който дава честота на дискретизация 9615Hz. Кодът по -долу показва как да конфигурирате ADC на Arduino.
void initADC () {
// Init ADC; f = (16MHz/предусилвател)/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 Hz ADCSRB = 0; // режим на свободно движение DIDR0 = _BV (0); // Изключете цифровия вход за ADC извод TIMSK0 = 0; // Timer0 off} И манипулаторът на прекъсване изглежда така: ISR (ADC_vect) {uint16_t sample = ADC; sample [samplePos ++] = sample - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буферът е пълен, прекъсването е изключено}}
Анализ на спектъра
След събиране на проби изчислявам амплитуди от 8 честоти, кодиращи символи. Не е необходимо да изпълнявам пълен FFT за това, затова използвах алгоритъма на Goertzel.
void goertzel (uint8_t *проби, плаващ *спектър) {
поплавък 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])); поплавък 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 = (плаващ) (проби ) + 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.
Пълната скица изглежда по следния начин
/** * Връзки: * [Микрофон към Arduino] * - Изход -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Дисплей към Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#включва
#дефинирайте CS_PIN 9
#дефинирайте N 256
#define IX_LEN 8 #define 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] ПРОГРАМА = {0,8932243011955153, 0,8700869911087115, 0,8448535652497071, 0,8032075314806449, 0,6895405447370669, 0,634393284163645639, 0,56036, 0,353670; const float sin_t [IX_LEN] ПРОГРАМА = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025454, 0.8314696123025451, typedef struct {
цифра char; uint8_t индекс; } цифра_t;
digit_t открита_цифра;
таблица const char [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 }, // 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 () {
// Init ADC; f = (16MHz/предусилвател)/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 Hz ADCSRB = 0; // режим на свободно движение DIDR0 = _BV (0); // Изключете цифровия вход за ADC извод TIMSK0 = 0; // Таймер0 изключен}
void goertzel (uint8_t *проби, плаващ *спектър) {
поплавък 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])); поплавък 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 = (плаващ) (проби ) + 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) {
плаващ резултат =.0; for (uint16_t i = 0; i <len; i ++) {резултат+= a ; } връщане на резултат / len; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float праг) {
if (праг <THRESHOLD) {връщане -1; } int8_t ix = -1; за (uint16_t i = 0; i праг) {if (ix == -1) {ix = i; } else {връщане -1; }}} връщане ix; }
void detect_digit (плаващ *спектър) {
float avg_row = avg (спектър, 4); float avg_col = avg (& спектър [4], 4); int8_t ред = get_single_index_above_threshold (спектър, 4, avg_row); int8_t col = get_single_index_above_threshold (& спектър [4], 4, avg_col); if (ред! = -1 && col! = -1 && avg_col> 200) {открит_дигит.дигит = pgm_read_byte (& (таблица [ред] [колона])); открит_дигит.индекс = pgm_read_byte (& (char_indexes [ред] [колона])); } else {открит_дигит.дигит = 0; }}
void drawSprite (байт* спрайт) {
// Маската се използва за получаване на бита на колоната от спрайт байт маска = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & маска));
// изместване на маската с един пиксел надясно
маска = маска >> 1; }
// нулиране на маската на колоната
маска = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (вярно); lmd.setIntensity (2); lmd.clear (); lmd.display ();
открит_дигит.дигит = 0;
}
без знак дълга z = 0;
void loop () {
while (ADCSRA & _BV (ADIE)); // Изчакайте аудио семплирането да завърши goertzel (мостри, спектър); detect_digit (спектър);
if (открит_дигит.дигит! = 0) {
drawSprite (шрифт [открит_дигит.индекс]); lmd.display (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (спектър ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) открит_дигит.дигит); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Възобновяване на извадковото прекъсване
}
ISR (ADC_vect) {
uint16_t проба = ADC;
проби [samplePos ++] = проба - 400;
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буферът е пълен, прекъсването е изключено}}
Стъпка 3: Схеми
Трябва да се направят следните връзки:
Микрофон към Arduino
Изход -> A0
Vcc -> 3.3V Gnd -> Gnd
Важно е да свържете AREF към 3.3V
Показване на Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Стъпка 4: Заключение
Какво би могло да се подобри тук? Използвах N = 256 проби при честота 9615Hz, която има известно изтичане на спектър, ако N = 205 и честота е 8000Hz, тогава желаните честоти съвпадат с дискретизационната мрежа. За това ADC трябва да се използва в режим на препълване на таймера.
Препоръчано:
Raspberry Pi - TMD26721 Инфрачервен цифров детектор за близост Java Урок: 4 стъпки
Raspberry Pi-TMD26721 Инфрачервен цифров детектор за близост Java Урок: TMD26721 е инфрачервен цифров детектор за близост, който осигурява пълна система за откриване на близост и логика на цифров интерфейс в един 8-пинов модул за повърхностен монтаж. Откриването на близост включва подобрен сигнал към шум и точност. Професионалист
Детектор за нивото на водата: 7 стъпки
Детектор на нивото на водата: Ултразвуковият сензор работи на същите принципи като радарната система. Ултразвуков сензор може да преобразува електрическата енергия в акустични вълни и обратно. Известният ултразвуков сензор HC SR04 генерира ултразвукови вълни с честота 40 kHz
Детектор за наличие на легло Zigbee: 8 стъпки
Детектор за наличие на легло Zigbee: От известно време търсех начин да открия кога сме в леглото. Това за използване на тази информация в Homeassistant. С тази информация бих могъл да направя автоматизация за изключване на светлините през нощта или например да активирам алармена система в моя дом
Детектор за дим: 13 стъпки
Детектор на дим: Здравейте приятели, нека да видим за детектора на дим Много от вас са ходили по молове в молове, най -вече можете да видите това устройство, наречено детектор на дим, то ще открие дима и ще включи пръскачката и ще спре огъня. Но в този проект това е малка промяна вместо
IOT детектор за дим: Актуализирайте съществуващ детектор за дим с IOT: 6 стъпки (със снимки)
IOT Smote Detector: Актуализирайте съществуващия детектор на дим с IOT: Списък на сътрудниците, Изобретател: Tan Siew Chin, Tan Yit Peng, Tan Wee Heng Надзорник: Д -р Chia Kim Seng Катедра по мехатронно и роботизирано инженерство, Факултет по електротехника и електронно инженерство, Universiti Tun Хюсеин Он Малайзия. Разпространение