Mục lục:
Video: DTMF Detector: 4 bước
2024 Tác giả: John Day | [email protected]. Sửa đổi lần cuối: 2024-01-30 13:34
Tổng quat
Tôi được truyền cảm hứng để chế tạo thiết bị này nhờ một bài tập về nhà trong khóa học trực tuyến Xử lý tín hiệu kỹ thuật số. Đây là bộ giải mã DTMF được triển khai với Arduino UNO, nó phát hiện một chữ số được nhấn trên bàn phím điện thoại ở chế độ âm báo bằng âm thanh mà nó tạo ra.
Bước 1: Tìm hiểu thuật toán
Trong DTMF mỗi ký hiệu được mã hóa với hai tần số theo bảng trên hình.
Thiết bị thu nhận đầu vào từ micrô và tính toán biên độ của tám tần số. Hai tần số có biên độ cực đại cho một hàng và một cột của biểu tượng được mã hóa.
Thu thập dữ liệu
Để thực hiện phân tích phổ, các mẫu cần được thu nhận ở một tần số có thể dự đoán được. Để đạt được điều này, tôi đã sử dụng chế độ ADC chạy tự do với độ chính xác tối đa (bộ định mức 128), nó cho tốc độ lấy mẫu 9615Hz. Đoạn mã dưới đây cho biết cách định cấu hình Arduino’s ADC.
void initADC () {
// Nhập ADC; f = (16MHz / bộ định mức) / 13 chu kỳ / chuyển đổi ADMUX = 0; // Kênh sel, right-adj, sử dụng chân AREF ADCSRA = _BV (ADEN) | // Kích hoạt ADC _BV (ADSC) | // ADC start _BV (ADATE) | // Tự động kích hoạt _BV (ADIE) | // Kích hoạt ngắt _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Chế độ chạy tự do DIDR0 = _BV (0); // Tắt đầu vào số cho chân ADC TIMSK0 = 0; // Timer0 tắt} Và trình xử lý ngắt có dạng như sau ISR (ADC_vect) {uint16_t sample = ADC; samples [samplePos ++] = sample - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Bộ đệm đầy, ngắt}}
Phân tích phổ
Sau khi thu thập mẫu, tôi tính toán biên độ của ký hiệu mã hóa 8 tần số. Tôi không cần chạy FFT đầy đủ cho việc này, vì vậy tôi đã sử dụng thuật toán của Goertzel.
void goertzel (uint8_t * mẫu, float * phổ) {
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) (mẫu ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); quang phổ [k] = amp; }}
Bước 2: Mã
Hình trên cho thấy ví dụ về mã hóa của chữ số 3 trong đó biên độ tối đa tương ứng với các tần số 697Hz và 1477Hz.
Bản phác thảo hoàn chỉnh trông như sau
/ ** * Kết nối: * [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
#bao gồm
#define CS_PIN 9
#define N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t mẫu [N];
dễ bay hơi uint16_t samplePos = 0;
phổ float [IX_LEN];
// Tần suất [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// Được tính cho 9615Hz 256 mẫu const float cos_t [IX_LEN] PROGMEM = {0,8932243011955153, 0,8700869911087115, 0,8448535652497071, 0,8032075314806449, 0,6895405447370669, 0,634399978841636456, 0,5555702347991960} 0,5555702347991960} 0,55557023 const float sin_t [IX_LEN] PROGMEM = {0,44961132965460654, 0,49289819222978404, 0,5349976198870972, 0,5956993044924334, 0,7242470829514669, 0,7730104533627369, 0,8314696123025451, 0,883549126434835491264348354912643;
typedef struct {
ký số char; chỉ mục uint8_t; } số_t;
số_t phát hiện_digit;
bảng 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} };
phông chữ byte [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 () {
// Nhập ADC; f = (16MHz / bộ định mức) / 13 chu kỳ / chuyển đổi ADMUX = 0; // Kênh sel, right-adj, sử dụng chân AREF ADCSRA = _BV (ADEN) | // Bật ADC _BV (ADSC) | // ADC start _BV (ADATE) | // Tự động kích hoạt _BV (ADIE) | // Kích hoạt ngắt _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Chế độ chạy tự do DIDR0 = _BV (0); // Tắt đầu vào số cho chân ADC TIMSK0 = 0; // Timer0 tắt}
void goertzel (uint8_t * mẫu, float * phổ) {
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) (mẫu ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); quang phổ [k] = amp; }}
float avg (float * a, uint16_t len) {
kết quả float =.0; for (uint16_t i = 0; i <len; i ++) {result + = a ; } trả về kết quả / len; }
int8_t get_single_index_above_threshold (float * a, uint16_t len, float ngưỡng) {
if (ngưỡng <THRESHOLD) {return -1; } int8_t ix = -1; for (uint16_t i = 0; i ngưỡng) {if (ix == -1) {ix = i; } else {return -1; }}} trả về ix; }
void explore_digit (float * phổ) {
float avg_row = avg (phổ, 4); float avg_col = avg (& phổ [4], 4); int8_t row = get_single_index_above_threshold (phổ, 4, avg_row); int8_t col = get_single_index_above_threshold (& phổ [4], 4, avg_col); if (row! = -1 && col! = -1 && avg_col> 200) {secure_digit.digit = pgm_read_byte (& (table [row] [col])); Discover_digit.index = pgm_read_byte (& (char_indexes [row] [col])); } else {secure_digit.digit = 0; }}
void drawSprite (byte * sprite) {
// Mặt nạ được sử dụng để lấy bit cột từ sprite hàng 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));
// di chuyển mặt nạ một pixel sang bên phải
mask = mặt nạ >> 1; }
// đặt lại mặt nạ cột
mặt nạ = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (true); lmd.setIntensity (2); lmd.clear (); lmd.display ();
phát hiện_digit.digit = 0;
}
dài không dấu z = 0;
void loop () {
trong khi (ADCSRA & _BV (ADIE)); // Chờ lấy mẫu âm thanh kết thúc goertzel (mẫu, phổ); dò_dấu (quang phổ);
if (secure_digit.digit! = 0) {
drawSprite (font [found_digit.index]); lmd.display (); } if (z% 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (phổ ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) found_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Tiếp tục ngắt lấy mẫu
}
ISR (ADC_vect) {
uint16_t mẫu = ADC;
mẫu [samplePos ++] = mẫu - 400;
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Bộ đệm đầy, ngắt}}
Bước 3: Sơ đồ
Các kết nối sau nên được thực hiện:
Mic để Arduino
Hết -> A0
Vcc -> 3.3V Gnd -> Gnd
Điều quan trọng là phải kết nối AREF với 3.3V
Hiển thị với Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Bước 4: Kết luận
Điều gì có thể được cải thiện ở đây? Tôi đã sử dụng N = 256 mẫu ở tốc độ 9615Hz có một số rò rỉ phổ, nếu N = 205 và tốc độ là 8000Hz thì các tần số mong muốn trùng với lưới tùy ý. Đối với ADC đó nên được sử dụng trong chế độ tràn bộ hẹn giờ.
Đề xuất:
DTMF VIDEO STREAMING ROVER: 3 bước
DTMF VIDEO STREAMING ROVER: xin chào sau ROVER ĐIỀU KHIỂN LINUX TERMINAL và ROBOT MÁY TÍNH CÓ ĐIỀU KHIỂN WIFI DTMF đây là robot thứ ba của tôi. và giống như hai phần khác ở đây, tôi cũng không sử dụng bất kỳ bộ vi điều khiển hoặc lập trình nào để giữ cho nó đơn giản và dễ thực hiện. nó cũng phát trực tiếp video qua wifi
Cách tạo bộ giải mã đường dây điện thoại DTMF (âm báo) đơn giản: 3 bước
Cách tạo bộ giải mã đường dây điện thoại DTMF (âm báo) đơn giản: Đây là một dự án đơn giản cho phép bạn giải mã tín hiệu DTMF về cơ bản trên bất kỳ đường dây điện thoại nào. Trong hướng dẫn này, chúng tôi đang sử dụng bộ giải mã MT8870D. Chúng tôi đang sử dụng một bộ giải mã giai điệu dựng sẵn bởi vì, tin tôi đi, việc thử và làm điều đó với
WIFI DTMF ROBOT: 5 bước
WIFI DTMF ROBOT: xin chào, trong hướng dẫn này, tôi sẽ chỉ cho bạn cách bạn có thể tạo một thiết bị di động điều khiển bằng máy tính mà không cần sử dụng bộ điều khiển vi mô, điều này có nghĩa là trong dự án này không liên quan đến mã cấp cao, bạn chỉ cần kiến thức cơ bản về trang html tạo ra nó. có thể xem đầy đủ
Cách chế tạo Robot điều khiển di động - Dựa trên DTMF - Không có Vi điều khiển & Lập trình - Kiểm soát từ mọi nơi trên thế giới - RoboGeeks: 15 bước
Cách chế tạo Robot điều khiển di động | Dựa trên DTMF | Không có Vi điều khiển & Lập trình | Kiểm soát từ mọi nơi trên thế giới | RoboGeeks: Muốn tạo ra một robot có thể được điều khiển từ mọi nơi trên thế giới, Hãy làm điều đó
DTMF và Xe lăn rô bốt điều khiển bằng cử chỉ: 7 bước (có hình ảnh)
DTMF và Xe lăn điều khiển bằng cử chỉ: Trên thế giới này có rất nhiều người bị tàn tật. Cuộc sống của họ xoay quanh những bánh xe. Dự án này trình bày một cách tiếp cận để kiểm soát chuyển động của xe lăn bằng cách sử dụng nhận dạng cử chỉ tay và DTMF của điện thoại thông minh