collapse

* Posts Recentes

Emulador NES em ESP32 por dropes
[22 de Abril de 2024, 14:14]


Arame de Estendal por almamater
[18 de Abril de 2024, 16:16]


O que é isto ? por SerraCabo
[12 de Abril de 2024, 14:20]


Amplificador - Rockboard HA 1 In-Ear por almamater
[11 de Abril de 2024, 20:46]


Meu novo robô por josecarlos
[29 de Março de 2024, 18:30]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]

Autor Tópico: VU meter com Atmega328p e lcd16x2  (Lida 44591 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline andre_f_carvalho

  • Mini Robot
  • *
  • Mensagens: 1.469
    • Pro - andrefcarvalho
Re: VU meter com Atmega328p e lcd16x2
« Responder #45 em: 13 de Março de 2011, 19:33 »
boas,


e que tal um destes, onde ele já filtra as frequências e mas usar como multiplexer para muda entre as varias frequências que ele dispõe

http://www.sparkfun.com/products/10024

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: VU meter com Atmega328p e lcd16x2
« Responder #46 em: 28 de Março de 2011, 21:51 »
Já não postava aqui novidades á algum tempo, mas o projecto este efectivamente parado, mas tenho muitas novidades.

Primeiro, respondo ao André, não uso esse chip porque é limitado, pois só me dá 7 frequências e porque deste modo tenho muito mais flexibilidade e como é feito em software o custo é nulo.

Actualmente tenho um novo filtro de entrada, muito mais simples que o anterior, é simplesmente um condensador no sinal de entrada para bloquear o sinal dc e depois duas resistências, uma liga o sinal de entrada aos 5v e outra á massa, assim quanto não tenho sinal tenho 2.5v na entrada dos adc's.

Estou actualmente a usar um adc externo da microchip de 12 bits, interface SPI e capaz de ler 100k samples por segundo, bastante mais rápido que as 16K samples que o adc interno do avr.

Por agora o modo fft precisa de umas limadelas para ficar em condições, o modo VU está muito melhor, mas apesar disso segue a musica durante 7 ou 8 segundos e depois por 1s parece que satura e fica praticamente a zeros, já com o antigo filtro de entrada acontecia o mesmo, ainda não percebi bem porque, e não tenho máquina aqui para filmar, mas vou tentar com o telemovel.

Estou mesmo assim pensar em adicionar um op-amp para fazer de buffer porque quanto mais aumento o som nas colunas menor é o sinal que o adc lê.
O código actualmente está assim, com alguns comentários em ingles, outros em português, precisa de uma certa limpeza e tem já funções para controlar o contraste e o brilho por pwm, mas ainda não tenho isso ligado, falta tambem um sistema de menus para altenar entre modo fft e modo vu e para controlar brilho e contraste.
Código: [Seleccione]
/*
*****************************************************************************
** LCD VU meter and FFT spectrum analyser *
** Using Peter Fleury lcd lib and el-chan fft engine for avr *
** Made for Atmega328p/Arduino Duemilanove *
** Tiago Angelo 12/01/2011 *
** Stable working version *
**
**  -Added SPI lcd
**  -Atomic execution of the fft
** *
*****************************************************************************

****************************************************************************
**
** Pinos do lcd - 16x2
** 1 2 3 4 5 6 7 8 9 10 11   12   13   14 15   16
** Gnd Vcc Ctr RS RW En D0 D1 D2 D3 D4   D5   D6 D7 An   Cat
**PC 5 4 3   2    1    0
**PD 7
**
** Ctr - Contrast
** An - Anode(+)
** Cat - Cathode(-)
****************************************************************************
**
** ADC pins
** Clock(13) - PB5
** Dout(12) - PB4
** Din(11)  - PB3
** CS/SHDN(10) - PB2
*/

#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <math.h>
#include <inttypes.h>
#include <avr/pgmspace.h>

#include "lcd.h"
#include "ffft.h"

/*
** Defines usados no programa
*/

#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

#define NUM_SAMPLES 64 //Samples usadas para calcular o FFT
#define FFT_SIZE (64/2) //Numero de valores devolvidos pelo FFT

#define FULL 0xFF //Caracter "cheio", consultar datasheet para perceber
#define BLANK 0xFE //Caracter em branco

#define MENUBT PB4 //Botão usado para chamar o menu
#define VU 1
#define FFT 2

#define MOSI PB3
#define MISO PB4
#define SCK PB5
#define SS PB2
#define ADDR 0x06 //Address/configuration byte for the spi ADC
#define DUMMY 0x00 //Dummy byte, because in each SPI comm we must send data
#define DATA_MASK 0x0F //Mask used to extract the first 4 bits that arrive in the second byte received


/*
***********************************************************************
** Constantes globais usadas no programa
***********************************************************************
*/

static const PROGMEM unsigned char vuChars[] = { //Dados na flash que não são precisos na Ram para nada
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 1 linha
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 2 linhas
0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, // 3 linhas
0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, // 4 linhas
0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x00, 0x00, //simbolo L
0x00, 0x00, 0x1F, 0x05, 0x0D, 0x12, 0x00, 0x00, //Simbolo R
};
static const PROGMEM unsigned char fftChars[] = { //Dados na flash que não são precisos na Ram para nada
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, //1 coluna
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, //2 colunas
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, //3 colunas
0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, //4 colunas
0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, //5 colunas
0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, //6 colunas
0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, //7 colunas
};


/*
**
*/

uint8_t i,k; //Variaveis de iterações
uint8_t sector2 = 0; //Numero de colunas para o vu meter, linha 2
uint8_t sectorRest2 = 0; //Numero de colunas para o vu meter, linha 2
uint8_t sector1 = 0; //Numero de colunas para o vu meter, linha 1
uint8_t sectorRest1 = 0; //Numero de colunas para o vu meter, linha 1
uint8_t pressed=0; //Usado para contar o tempo que o botão está premido
uint8_t count = 0;
uint8_t last_time=0;
uint8_t mode=0;
volatile uint8_t j=0; //variavel de iterações (só para a ISR)
volatile uint8_t time=0; //Uma espécie de milis para fazer deboucing não bloqueante
volatile uint8_t lcd_linha1[16]; //Dados da linha 1 do lcd
volatile uint8_t lcd_linha2[16]; //Dados da linha 2 do lcd
volatile uint8_t flag = 0;
uint16_t newReading1 = 0; //Variavel para guardar o valor lido pelo ADC
uint16_t newReading2 = 0; //Variavel para guardar o valor lido pelo ADC
uint16_t lastReading1 = 0;
uint16_t lastReading2 = 0;
uint16_t counter = 0;
uint16_t adcVal= 0; //Usado para guardar o valor lido pelo adc no modo fft
uint32_t mapped1 = 0; //Variavel para guardar o valor de adc_var_1*map
uint32_t mapped2 = 0; //Variavel para guardar o valor de adc_var_2*map


//Estas 3 são especificas para o FFT
int16_t capture[FFT_N]; //Buffer de captura
complex_t bfly_buff[FFT_N]; //Buffer do FFT
uint16_t spectrum[(FFT_N/2)]; //Buffer de saida do FFT


/*
***********************************************************************
** Declarações dos protótipos das funções
***********************************************************************
*/

void vu_mode(void);
void vu_mode_init(void); //Inicialização do modo VU meter
void fft_mode_init(void);
void fft_mode(void);
void timer1_init(void); //Inicialização do Timer1
void timer0_init(void); //Inicialização do Timer0
void update_pwm(uint8_t brightness, uint8_t contrast);
void SPI_init(void);
uint8_t SPI_Write(uint8_t data);
uint16_t Read_ADC(uint8_t channel);
void USART_init();
unsigned char USART_receive();
void USART_putchar(unsigned char);
void USART_putstring(char* StringPtr);

/*
***********************************************************************
** Inicio do main
***********************************************************************
*/

int main(void){

//DDRB &= ~(1<<MENUBT); //Coloca botão do menu como entrada

USART_init();
SPI_init();
lcd_init(LCD_DISP_ON); //Inicializa o LCD, sem cursor visivel
lcd_clrscr(); //Limpa o lcd e coloca o cursor em (0,0)
lcd_home();
fft_mode_init(); //Inicialização do modo fft
//vu_mode_init(); //Inicialização do modo vu meter
timer1_init(); //Inicialização/configuração do timer para gerar as interrupções
sei(); //Inicia as interrupções

while(1){ //Loop infinito

if(flag == 1){
//vu_mode();
flag = 0; //Modo vu meter
fft_mode(); //Modo fft
}

}

return 1;
}

/*
***********************************************************************
** ISR
** Corre todo o vu_mode/fft e faz o refresh do display.
** Todo o trabalho é feito por interrupção, deixando o CPU livre
** entre interrupções.
** Actualiza as duas linhas na totalidade.
***********************************************************************
*/

ISR(TIMER1_COMPA_vect){

lcd_gotoxy(0,0);
for(j=0; j<16; j++){
lcd_putc(lcd_linha1[j]); }

lcd_gotoxy(0,1);
for(j=0; j<16; j++){
lcd_putc(lcd_linha2[j]); }

flag = 1;
}


/*
***********************************************************************
** Funções usadas
***********************************************************************
*/



/*
***********************************************************************
** Le o canal 0 e 1 do adc, faz uma detecção de pico e depois mapeia
** o valor 0..1023 do adc para 0..75 barras no display 16x2
***********************************************************************
*/

void vu_mode(void){

/*
counter++;
itoa(counter, buffer, 10);
USART_putstring(buffer);
USART_putstring(" , ");
itoa(newReading1, buffer, 10);
USART_putstring(buffer);
USART_putchar('\n');
*/


newReading1 = abs(Read_ADC(0)-2048);
newReading2 = abs(Read_ADC(1)-2048);

if(newReading1 >= lastReading1){
lastReading1 = newReading1; }
else{
lastReading1 = (lastReading1*7 + newReading1)/8; } //Decaimento "suave"

mapped1 = ((uint32_t)((uint32_t)lastReading1 * 75)/2048); //Pega nos 0..1023 e devolve 0..75
sector1 = mapped1/5; //Segmentos FULL na linha 0
sectorRest1 = mapped1 % 5; //Segmento final da linha 0

if(newReading2 >= lastReading2){
lastReading2 = newReading2; }
else{
lastReading2 = ((uint32_t)lastReading2*7 + newReading2)/8; } //Decaimento "suave"

mapped2 = ((uint32_t)((uint32_t)lastReading2 * 75)/2048); //Pega nos 0..1023 e devolve 0..75
sector2 = mapped2/5; //Segmentos FULL na linha 1
sectorRest2 = mapped2 % 5; //Segmento final da linha 1

//Linha 0
for(i=0; i<(sector1); i++){
lcd_linha1[i+1] = FULL; }
if(sectorRest1>=1){
lcd_linha1[i+1] = ((sectorRest1-1)); }
for(i=(sector1 + 1);i<15; i++){
lcd_linha1[i+1] = BLANK; }

//Linha 1
for(i=0; i<(sector2); i++){
lcd_linha2[i+1] = FULL; }
if(sectorRest2>=1){
lcd_linha2[i+1] = ((sectorRest2-1)); }
for(i=(sector2 + 1);i<15; i++){
lcd_linha2[i+1] = BLANK; }

}

/*
***********************************************************************
** Le o canal 0 do adc, ao subtrair 512 á sample de 1023 bits cria um
** sinal positivo ou negativo centrado em 0, é preciso para o fft
** usando o FFT feito pelo elm-chan calcula um FFT de 64 pontos
** e preenche as duas linhas do lcd com barras
***********************************************************************
*/

void fft_mode(void){
count = 0;
cli();
while(count != NUM_SAMPLES){
adcVal = abs(Read_ADC(0)-2048);
capture[count] = ((int16_t)(adcVal)-1024);
count++;
}

fft_input(capture,bfly_buff);
fft_execute(bfly_buff);
fft_output(bfly_buff,spectrum);

k=0;
for(i=1; i<17; i++){
sector1 = spectrum[i]/8;

if((sector1>=0) & (sector1<7)){
lcd_linha2[k]=sector1;
lcd_linha1[k]=BLANK;
}

if((sector1>=7) & (sector1<15)){
lcd_linha2[k]=FULL;
lcd_linha1[k]=(sector1-8);
}

if(sector1>16){
lcd_linha2[k]=FULL;
lcd_linha1[k]=FULL;
}

k++;

}
sei();
}

/*
***********************************************************************
** Carrega da flash os caracteres especiais para fazer as barras e as
** letras L e R na CGRAM do display
***********************************************************************
*/

void vu_mode_init(void){

lcd_command(_BV(LCD_CGRAM)); //Coloca CG RAM no endereço 0
for(i=0; i<48; i++){
lcd_data(pgm_read_byte_near(&vuChars[i])); } //Lê os dados da flash e carrega na Ram do LCD

lcd_gotoxy(0,0); //Linha 0 coluna 0
lcd_putc(4); //Escreve L na esquerda
lcd_gotoxy(0,1); //Linha 1 coluna 0
lcd_putc(5); //Escreve R na direita
lcd_linha1[0]=4;
lcd_linha2[0]=5;
}

/*
***********************************************************************
** Carrega da flash os caracteres especiais para fazer as barras e as
** na CGRAM do display
***********************************************************************
*/

void fft_mode_init(void){

lcd_command(_BV(LCD_CGRAM)); //Coloca CG RAM no endereço 0
for(i=0; i<56; i++){
lcd_data(pgm_read_byte_near(&fftChars[i])); } //Lê os dados da flash e carrega na Ram do LCD

lcd_clrscr();
}

/*
***********************************************************************
** Inicializa o timer1(16 bits) no modo CTC com prescaller de 1024
***********************************************************************
*/

void timer1_init(void){

TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
OCR1A = 600; //Para gerar interrupções a 14Hz para o refresh do display, valor obtido experimentalmente
TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
TCCR1B |= ((1<<CS12)|(1<<CS10));//Inicia timer 1 com clock div de 1024
}

/*
***********************************************************************
** Inicializa o timer0(8 bits) no modo PWM phase correct
** Usado para gerar o pwm para o controlo do contraste e do brilho
** do lcd
***********************************************************************
*/
void timer0_init(void){
TCCR0A |= ((1<<COM0B1)|(1<<WGM00)); //Phase correct pwm
TCCR0B |= ((1<<CS01)|(1<<CS00));

}


void update_pwm(uint8_t brightness, uint8_t contrast){

OCR0A = brightness;
OCR0B = contrast;

}


void SPI_init(void){

DDRB |= ((1<<MOSI)|(1<<SCK)|(1<<SS)); //Mosi, sck and ss are outputs
DDRB &= (~(1<<MISO)); //Miso is input
PORTB |= (1<<SS); //Start with SS at 1 (HIGH)

//Enable SPI, Master mode
//MSB first
//CPOL=0
//CPHA=0
//SPI mode 0
//sck = F_CPU/8 = 2Mhz
//SPSR = (1<<SPI2X); //SPI clock x2
SPCR = ((1<<SPE)|(1<<MSTR)|(1<SPR0));

}

uint8_t SPI_Write(uint8_t data){

SPDR = data; //Start data transfer
while(!(SPSR & (1<<SPIF))); //Wait for the end of the transmission

return SPDR; //Return the received data

}

uint16_t Read_ADC(uint8_t channel){
uint8_t upper_addr, lower_addr, upper_data, lower_data;

if(channel > 3){
upper_addr = ADDR | 0x01; }
else{
upper_addr = ADDR; }
lower_addr = channel<<6;

PORTB &= (~(1<<SS)); //Put SS at 0 (LOW), to start the data transfer

SPI_Write(upper_addr);
upper_data = SPI_Write(lower_addr);
lower_data = SPI_Write(DUMMY);
upper_data &= DATA_MASK;

PORTB |= (1<<SS); //Puts SS at 1 (HIGH), because we already stoped all the data transfer

return ((upper_data<<8)|lower_data);


}

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}


unsigned char USART_receive(void){

while(!(UCSR0A & (1<<RXC0)));
return UDR0;

}


void USART_putchar( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}


void USART_putstring(char* StringPtr)
{
   while (*StringPtr != 0x00) {
      USART_putchar(*StringPtr);
      StringPtr++;
   }
}

Avr fanboy

Offline andre_f_carvalho

  • Mini Robot
  • *
  • Mensagens: 1.469
    • Pro - andrefcarvalho
Re: VU meter com Atmega328p e lcd16x2
« Responder #47 em: 28 de Março de 2011, 22:25 »
bem, sendo algum dinheiro investido ou n com este chip ja se tem as frequencias definidas e pouco em algum codigo, e se calhar resolve esse teu problema depois dos 7 ou 8s mas pts, achar uma solução diferente é meio caminho andado para obter conhecimentos:D

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: VU meter com Atmega328p e lcd16x2
« Responder #48 em: 28 de Março de 2011, 22:39 »
Mas esse chip só serve para a parte do spectrum analyzer, o VU meter não funciona com esses chips.
Tenho ideia que o problema ou é um overflow, que já detectei uma variavel que fazia overflow, provavelmente é o mesmo problema, ou então é uma race condition entre o tempo de update do lcd e as interrupções, mas tenho que analizar isso, provavelmente hoje.

E estou a ponderar mudar para um lcd gráfico, nada de exótico, os simples e mais que provados 128x64 com o controlador KS0018 que tenho aqui um belo pisa papeis de 50€ que nem a Sparkfun sabe porque é que não funciona, provavelmente estragado, mas quem tem a factura é o TigPt...
Avr fanboy

Offline andre_f_carvalho

  • Mini Robot
  • *
  • Mensagens: 1.469
    • Pro - andrefcarvalho
Re: VU meter com Atmega328p e lcd16x2
« Responder #49 em: 28 de Março de 2011, 22:57 »
sim eu sei que é para spectrum analyzer, mas sempre podes deitar o lcd e fazer um SA, e relação ao tiago, acho mais provavelmente ele emigrou:P, se alguem sober a morada dele é que podia falar com ele, é que uma das coisas que pode acontecer se ele n se interessar por isto é o forum ficar desligado por falta de pagamento:S

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: VU meter com Atmega328p e lcd16x2
« Responder #50 em: 28 de Abril de 2011, 22:11 »
Bem...
Tanta volta que dei com isto para descobrir que as pontas que eu comprei fazem mau contacto com o jack do portatil, bem sabia que ainda ia ter problemas por ter comprado material tão barato....
Tenho de ir atravessar a cidade para comprar mais meia duzia de breadboards que estão sempre todas ocupadas, que amanha devem chegar brinquedos novos e não tenho sitio onde os montar lol, aproveitar e comprar cabos de audio decentes para depois os cortar e meter uns headers lol.

Fica o abre olhos que material barato só dá chatice.
Avr fanboy

Offline vsta41

  • Mini Robot
  • *
  • Mensagens: 1
Re: VU meter com Atmega328p e lcd16x2
« Responder #51 em: 02 de Abril de 2013, 05:29 »
Por favor, onde eu posso obter o ffft.h biblioteca?