-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSound_monitor.c
More file actions
105 lines (79 loc) · 3.08 KB
/
Copy pathSound_monitor.c
File metadata and controls
105 lines (79 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <stdio.h>
#include <math.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/dma.h"
#include "inc\mqtt_lwip.h"
#include "Sound_monitor.h"
// Canal e configurações do DMA
uint dma_channel;
dma_channel_config dma_cfg;
// Buffer de amostras do ADC.
uint16_t adc_buffer[SAMPLES];
void init_mic_dma(){
// Preparação do ADC.
printf("Preparando ADC...\n");
adc_gpio_init(MIC_PIN);
adc_init();
adc_select_input(MIC_CHANNEL);
adc_fifo_setup(
true, // Habilitar FIFO
true, // Habilitar request de dados do DMA
1, // Threshold para ativar request DMA é 1 leitura do ADC
false, // Não usar bit de erro
false // Não fazer downscale das amostras para 8-bits, manter 12-bits.
);
adc_set_clkdiv(ADC_CLOCK_DIV);
printf("ADC Configurado!\n\n");
printf("Preparando DMA...");
// Tomando posse de canal do DMA.
dma_channel = dma_claim_unused_channel(true);
// Configurações do DMA.
dma_cfg = dma_channel_get_default_config(dma_channel);
channel_config_set_transfer_data_size(&dma_cfg, DMA_SIZE_16); // Tamanho da transferência é 16-bits (usamos uint16_t para armazenar valores do ADC)
channel_config_set_read_increment(&dma_cfg, false); // Desabilita incremento do ponteiro de leitura (lemos de um único registrador)
channel_config_set_write_increment(&dma_cfg, true); // Habilita incremento do ponteiro de escrita (escrevemos em um array/buffer)
channel_config_set_dreq(&dma_cfg, DREQ_ADC); // Usamos a requisição de dados do ADC
printf("Configuracoes completas!\n");
}
void Sound_level(char *buf, int len){
printf("\n----\nIniciando leitura...\n----\n");
// Realiza uma amostragem do microfone.
sample_mic();
float vrms = ADC_ADJUST(mic_power()); // converte RMS do ADC para volts (ajustado em relação a 1.65V)
vrms = fabsf(vrms); // pega apenas a magnitude (sem sinal)
float db = 20.0f * log10f(vrms / 3.3f); // dBFS(decibeis em full scale) usando a voltagem máxima como referencia
db = 1.1584f * db + 86.8105; //calibração empirica do dbFS, obtido com regressão linear(28 amostras)
printf("Vrms: %.4f V | dBV: %.2f dB\n", vrms, db);
char db_level[64];
sprintf(buf, "%.2f", db); //transforma variavel decibeis em uma string para ser publicada no mqtt
}
/**
* Realiza as leituras do ADC e armazena os valores no buffer.
*/
void sample_mic() {
adc_fifo_drain(); // Limpa o FIFO do ADC.
adc_run(false); // Desliga o ADC (se estiver ligado) para configurar o DMA.
dma_channel_configure(dma_channel, &dma_cfg,
adc_buffer, // Escreve no buffer.
&(adc_hw->fifo), // Lê do ADC.
SAMPLES, // Faz SAMPLES amostras.
true // Liga o DMA.
);
// Liga o ADC e espera acabar a leitura.
adc_run(true);
dma_channel_wait_for_finish_blocking(dma_channel);
// Acabou a leitura, desliga o ADC de novo.
adc_run(false);
}
/**
* Calcula a potência média das leituras do ADC. (Valor RMS)
*/
float mic_power() {
float avg = 0.f;
for (uint i = 0; i < SAMPLES; ++i){
avg += adc_buffer[i] * adc_buffer[i];
}
avg /= SAMPLES;
return sqrt(avg);
}