//ATmega2560
#include <avr/io.h> //definições do componente especificado
#include <util/delay.h> //biblioteca para o uso das rotinas de _delay_ms e _delay_us(), biblioteca de atraso incluída no AVR Libc
#include <avr/pgmspace.h> //biblioteca para o uso dos DDRAM e DDROM
//===============================================//
// DEFINICAO //
//===============================================//
//Atmega 2560 clk
#define F_CPU 16000000UL // Frequência do clock do microcontrolador (16 MHz para Arduino Mega)
//POTENCIOMENTRO
#define knob_POTENCIOMETRO A0 //porta analogica
//LCD -> CONTROLE e DADOS
#define CONTR_LCD PORTA //PORT com os pinos de controle do LCD (pino R/W em 0).
#define RS PA1 //pino para informar se o dado é uma instrução ou caractere
#define RW PA3 //pino de habilitação do LCD (RW)
#define E PA5 //pino de habilitação do LCD (enable)
#define DADOS_LCD PORTC //4 bits de dados do LCD no PORTa
#define nibble_dados 1
#define LCD_ANODO PH3
//LED VERDE
#define LED_VERDE_PIN PJ1
//BUZZER
#define NOTAS_POR_OITAVA 12 // Definindo a quantidade de notas em uma oitava
#define NUM_OITAVAS 9// Número de oitavas
#define BUZZER_PIN PE3
//DHT
#define DHT_PIN PB7 // Pino ao qual o sensor DHT22 está conectado
#define DHT_TYPE DHT22 // Tipo do sensor DHT (DHT11 ou DHT22)
//Botoes -> Modos
#define botao_TEMPERATURA_INST PD0
#define botao_TEMPERATURA_MED PD1
#define botao_TEMPERATURA_CLR PD2
#define botao_TEMPERATURA_minMAX PD3
#define botao_On_Off PE4
//eeprom
#define temp_max 10 // Número máximo de temperaturas a serem consideradas
//sinal de habilitação para o LCD
#define pulso_enable() _delay_us(1); set_bit(CONTR_LCD, E); _delay_us(1); clr_bit(CONTR_LCD, E); _delay_us(45);
//Definições de macros para o trabalho com bits
#define set_bit(y,bit) (y|=(1<<bit)) //coloca em 1 o bit x da variável Y
#define clr_bit(y,bit) (y&=~(1<<bit)) //coloca em 0 o bit x da variável Y
#define cpl_bit(y,bit) (y^=(1<<bit)) //troca o estado lógico do bit x da variável Y
#define tst_bit(y,bit) (y&(1<<bit)) //retorna 0 ou 1 conforme leitura do bit
//------------------------------------------------------------------------------------
//===============================================//
// NUMERACAO //
//===============================================//
//dht
enum tipo_sensor{
DHT22,
DHT11
};
//eeprom
enum tipo_dados{
Temperatura,
Umidade
};
//buzzer
enum tom{
NOTA_DO = 0 ,
NOTA_DO_SUSTENIDO = 1,
NOTA_RE = 2,
NOTA_RE_SUSTENIDO = 3,
NOTA_MI = 4,
NOTA_FA = 5,
NOTA_FA_SUSTENIDO = 6,
NOTA_SOL = 7,
NOTA_SOL_SUSTENIDO = 8,
NOTA_LA = 9,
NOTA_LA_SUSTENIDO = 10,
NOTA_SI = 11
};
//buzzer
enum faixa{
ligando,
beep,
alarme,
desligando
};
//LCD
enum modo{
modo_PADRAO, modo_TEMPERATURA_INST, modo_TEMPERATURA_MED, modo_TROCAR_ESCALA, modo_TEMPERATURA_MinMax
};
//---------------------------------------------------------------------------
//===============================================//
// VARIAVEIS GLOBAIS //
//===============================================//
volatile float temperatura;
volatile float umidade;
volatile enum modo m; // Controle de modos
volatile bool flag_temperatura = true; //se a temperatura chegou na faixa entao false, se nao true
volatile uint8_t cont_bip;
volatile uint16_t endereco = 0;
volatile float media_temp = 0;
volatile float inst_temp = 0;
volatile float min_temp = 6000.00;
volatile float max_temp = -6000.00;
volatile char tempString[16];
volatile char mediaString[16];
volatile char minString[16];
volatile char maxString[16];
volatile uint16_t valor_ADC;
volatile bool timer_flag = false;
volatile bool init_ = true;
volatile bool OnOff = false;
volatile float FREQUENCIA_PWM; // Frequência desejada do PWM em Hz
//------------------------------------------------
//===============================================//
// EEPROM //
//===============================================//
void escrita_EEPROM_byte(uint16_t uiEndereco, uint8_t ucDado){
while(EECR & (1<<EEPE)); //espera completar um escrita prévia
EEAR = uiEndereco; //carrega o endereço para a escrita EEAR =>
EEDR = ucDado; //carrega o dado a ser escrito EEDR -> EEPROM Data Register
EECR |= (1<<EEMPE); //permite a escrita
EECR |= (1<<EEPE); //inicia a escrita ativando EEPE
}
unsigned char leitura_EEPROM_byte(uint16_t uiEndereco){
while(EECR & (1<<EEPE)); //espera completar um escrita prévia
EEAR = uiEndereco; //escreve o endereço de leitura
EECR |= (1<<EERE); //inicia a operação de leitura da EEPROM
return EEDR; //retorna o valor lido do registrador de dados
}
//tratamento dos dados de temperatura por casting
void escrita_EEPROM_float(uint16_t uiEndereco, float valor) {
byte* ptr = (byte*) &valor; // Ponteiro para o valor float
//Serial.println("Enderecos e bytes escritos:");
for (int i = 0; i < sizeof(float); i++) {
uint16_t endereco_atual = uiEndereco + i;
// Imprimir o endereço atual e o byte correspondente
//Serial.print("Endereco ");
//Serial.print(endereco_atual);
//Serial.print(": ");
//Serial.println(*(ptr + i));
// Escrever o byte na EEPROM
escrita_EEPROM_byte(endereco_atual, *(ptr + i));
}
//Serial.print("Escrita da temperatura: ");
//Serial.println(valor);
}
float leitura_EEPROM_float(uint16_t uiEndereco) {
float valor;
byte* ptr = (byte*) &valor; // Ponteiro para o valor float
//Serial.println("Enderecos e bytes lidos:");
// Lê os bytes da EEPROM na ordem correta
for (int i = 0; i < sizeof(float); i++) {
// Ler o byte da EEPROM e imprimir
uint16_t endereco_atual = 4 * uiEndereco + i;
// Imprimir o endereço atual
//Serial.print("Endereco ");
//Serial.print(endereco_atual);
//Serial.print(": ");
// Ler o byte da EEPROM e imprimir
*(ptr + i) = leitura_EEPROM_byte(endereco_atual);
//Serial.println(*(ptr + i));
}
//Serial.print("Endereco da leitura: ");
//Serial.println(uiEndereco);
//Serial.print("Leitura da temperatura: ");
//Serial.println(valor);
//Serial.println("=======================================");
return valor;
}
void armazenar_EEPROM(float temperatura){
escrita_EEPROM_float(4*endereco, temperatura);
}
void circular_EEPROM(){
//temperatura armazenada circularmente
if(4 * endereco <= 32){
endereco++;
}
else{
endereco = 0;
}
}
float media() {
float somaAfericoes = 0.0; // Variável para armazenar a soma das aferições
int numAfericoesValidas = 0; // Contador para o número de aferições válidas
// Loop para ler as aferições armazenadas no buffer circular da EEPROM
for(int i = 0; i < 10; i++) {
float afericao = leitura_EEPROM_float(i); // Lê a aferição na posição de memória
// Verifica se a aferição é válida (não é NaN)
if (!isnan(afericao)) {
somaAfericoes += afericao; // Adiciona a aferição à soma
numAfericoesValidas++; // Incrementa o contador de aferições válidas
}
}
//Serial.print("Na media aparece:");
//Serial.println(somaAfericoes / numAfericoesValidas);
//Serial.println(" ");
// Verifica se há pelo menos uma aferição válida antes de calcular a média
if (numAfericoesValidas > 0) {
return somaAfericoes / numAfericoesValidas; // Retorna a média calculada
} else {
return NAN; // Se não houver aferições válidas, retorna NaN
}
}
//ler na memoria EEPROM as ultimas 10 medicoes para escolher os tronos
void min_max_TEMPERATURA(float temp){
if(temp > max_temp){
max_temp = temp;
}
if(temp < min_temp){
min_temp = temp;
}
}
//--------------------------------------------------
//================================================//
// SENSOR DHT22 //
//================================================//
/*
The data from the DHT11 and DHT22 sensor consists of 40 bits and the format is as follows:
8 – Bit data for integral part of RH value, bt[0] -> high
8 – Bit data for decimal part of RH value, bt[1] -> low
8 – Bit data for integral part of Temperature value, bt[2] -> high
8 – Bit data for decimal part of Temperature value and bt[3] -> low
8 – Bit data for checksum.
*/
void sinc_MCU_() {
DDRB |= (1 << DHT_PIN); // Configura o pino de comunicação como saída
switch(DHT_TYPE) {
case DHT11:
PORTB &= ~(1 << DHT_PIN);
_delay_ms(18);
PORTB |= (1 << DHT_PIN);
_delay_us(20);
break;
case DHT22:
PORTB &= ~(1 << DHT_PIN);
_delay_us(1000);
PORTB |= (1 << DHT_PIN);
_delay_us(40);
break;
}
}
void sinc_DHT() {
DDRB &= ~(1 << DHT_PIN); // Configura o pino de comunicação como entrada
while(PINB & (1 << DHT_PIN)); // Aguarda o pino ficar alto
while(!(PINB & (1 << DHT_PIN))); // Aguarda o pino ficar baixo
while(PINB & (1 << DHT_PIN)); // Aguarda o pino ficar alto
}
//funcao secundaria
float calcular_temperatura(uint8_t dados[]) {
float temperatura = 0.0;
switch(DHT_TYPE) {
case DHT22:
temperatura = ((dados[2] & 0x7F) << 8 | dados[3]) / 10.0;
if (dados[2] & 0x80) {
temperatura *= -1;
}
break;
case DHT11:
temperatura = dados[2];
if (dados[2] & 0x80) temperatura = -1-temperatura;
temperatura += (dados[3] & 0x0f) * 0.1;
break;
}
return temperatura;
}
//funcao pai
float DHT(enum tipo_dados dados, enum tipo_sensor sensor){
sinc_MCU_();
sinc_DHT();
uint8_t bt[5] = {0};
for(uint8_t j = 0; j < 5; j++) {
uint8_t b = 0x0; //bits tudo zerado
for(uint8_t i = 0; i < 8; i++) {
while(!(PINB & (1 << DHT_PIN))); //enquanto baixo
switch(sensor){
case DHT22:
_delay_us(50);
break;
case DHT11:
_delay_us(30);
break;
}
if(PINB & (1 << DHT_PIN)) b |= (1 << (7 - i));
while(PINB & (1 << DHT_PIN));
}
bt[j] = b;
}
if(dados == Temperatura) {
float temp = calcular_temperatura(bt);
return temp;
}
return 0.0; // Retorno padrão caso o tipo de dado não seja suportado
}
//----------------------------------------------------------------------------------
//================================================================================ //
// ACIONANDO UM DISPLAY DE CRISTAL LIQUIDO DE 16x2 //
// Interface de dados de 4 bits //
//================================================================================ //
//c é o dado e cd indica se é instrução ou caractere (0 ou 1)
void cmd_LCD(unsigned char c, char cd){
if(cd==0)
clr_bit(CONTR_LCD,RS); //instrução
else
set_bit(CONTR_LCD,RS); //caractere
//primeiro nibble de dados - 4 MSB
#if (nibble_dados) //compila o código para os pinos de dados do LCD nos 4 MSB do PORT
DADOS_LCD = (DADOS_LCD & 0x0F)|(0xF0 & c);
#else
//compila o código para os pinos de dados do LCD nos 4 LSB do PORT
DADOS_LCD = (DADOS_LCD & 0xF0)|(c>>4);
#endif
pulso_enable();
//segundo nibble de dados - 4 LSB
#if (nibble_dados)
//compila o código para os pinos de dados do LCD nos 4 MSB do PORT
DADOS_LCD = (DADOS_LCD & 0x0F) | (0xF0 & (c<<4));
#else
//compila o código para os pinos de dados do LCD nos 4 LSB do PORT
DADOS_LCD = (DADOS_LCD & 0xF0) | (0x0F & c);
#endif
pulso_enable();
if((cd==0) && (c<4)) _delay_ms(2); //se for instrução de retorno ou limpeza espera LCD estar pronto
}
//sequência ditada pelo fabricando do circuito integrado HD44780
void inic_LCD_4bits(){
//o LCD será só escrito. Então, R/W é sempre zero.
clr_bit(CONTR_LCD,RS);//RS em zero indicando que o dado para o LCD será uma instrução
clr_bit(CONTR_LCD,E);//pino de habilitação em zero
_delay_ms(20); /*tempo para estabilizar a tensão do LCD, após VCC
ultrapassar 4.5 V (na prática pode ser maior).*/
//interface de 8 bits
#if (nibble_dados)
DADOS_LCD = (DADOS_LCD & 0x0F) | 0x30;
#else
DADOS_LCD = (DADOS_LCD & 0xF0) | 0x03;
#endif
pulso_enable(); //habilitação respeitando os tempos de resposta do LCD
_delay_ms(5);
pulso_enable();
_delay_us(200);
pulso_enable(); //até aqui ainda é uma interface de 8 bits.
//interface de 4 bits, deve ser enviado duas vezes (a outra está abaixo)
#if (nibble_dados)
DADOS_LCD = (DADOS_LCD & 0x0F) | 0x20;
#else
DADOS_LCD = (DADOS_LCD & 0xF0) | 0x02;
#endif
pulso_enable();
cmd_LCD(0x28,0);
//interface de 4 bits 2 linhas (aqui se habilita as 2 linhas)
//são enviados os 2 nibbles (0x2 e 0x8)
cmd_LCD(0x08,0); //desliga o display
cmd_LCD(0x01,0); //limpa todo o display
cmd_LCD(0x0C,0); //mensagem aparente cursor inativo não piscando
cmd_LCD(0x80,0); //inicializa cursor na primeira posição a esquerda - 1a linha
}
//escreve no LCD
void escreve_LCD(char *c){
for (; *c!=0;c++) cmd_LCD(*c,1);
}
//informação para criar caracteres novos armazenada na memória flash
const unsigned char carac1[] PROGMEM = {0b00011,//GRAU
0b00011,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000};
const unsigned char carac2[] PROGMEM = {0b00000,//M
0b00000,
0b10001,
0b11011,
0b10101,
0b10001,
0b10001};
const unsigned char carac3[] PROGMEM = {0b00000,//A
0b00000,
0b01110,
0b10001,
0b11111,
0b10001,
0b10001};
const unsigned char carac4[] PROGMEM = {0b00000,//X
0b00000,
0b10001,
0b01010,
0b00100,
0b01010,
0b10001};
const unsigned char carac5[] PROGMEM = {0b00000,//I
0b00000,
0b00100,
0b00100,
0b00100,
0b00100,
0b00100};
const unsigned char carac6[] PROGMEM = {0b00000,//N
0b00000,
0b10001,
0b11001,
0b10101,
0b10011,
0b10001};
const unsigned char carac7[] PROGMEM = {0b00000,
0b00100,
0b01010,
0b10001,
0b10101,
0b01110,
0b00000};
const unsigned char carac8[] PROGMEM = {0b00000,
0b10101,
0b01110,
0b11011,
0b01110,
0b10101,
0b00000};
void gerar_caracteres(){
//Gera grau
cmd_LCD(0x40,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x40
cmd_LCD(pgm_read_byte(&carac1[k]),1);
cmd_LCD(0x00,1); /*apaga última posição do end. da CGRAM para evitar algum dado espúrio*/
//gera M
cmd_LCD(0x48,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x48
cmd_LCD(pgm_read_byte(&carac2[k]),1);
cmd_LCD(0x00,1);
//Gera A
cmd_LCD(0x50,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x50
cmd_LCD(pgm_read_byte(&carac3[k]),1);
cmd_LCD(0x00,1);
//gera X
cmd_LCD(0x58,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x58
cmd_LCD(pgm_read_byte(&carac4[k]),1);
cmd_LCD(0x00,1);
//gera I
cmd_LCD(0x60,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x60
cmd_LCD(pgm_read_byte(&carac5[k]),1);
cmd_LCD(0x00,1);
//Gera N
cmd_LCD(0x68,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x68
cmd_LCD(pgm_read_byte(&carac6[k]),1);
cmd_LCD(0x00,1);
//Gera fogo
cmd_LCD(0x70,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x68
cmd_LCD(pgm_read_byte(&carac7[k]),1);
cmd_LCD(0x00,1);
//Gera neve
cmd_LCD(0x78,0); //endereço base para gravar novo segmento
for(int k=0;k<7;k++) //grava 8 bytes na DDRAM começando no end. 0x68
cmd_LCD(pgm_read_byte(&carac8[k]),1);
cmd_LCD(0x00,1);
/*
cmd_LCD(0x00,1); //apresenta segundo caractere 0x00 -> grau
cmd_LCD(0x01,1); //apresenta segundo caractere 0x01 -> M
cmd_LCD(0x02,1); //apresenta segundo caractere 0x02 -> A
cmd_LCD(0x03,1); //apresenta segundo caractere 0x03 -> X
cmd_LCD(0x04,1); //apresenta segundo caractere 0x04 -> I
cmd_LCD(0x05,1); //apresenta segundo caractere 0x05 -> N
...
*/
}
void modo_LCD(enum modo m){
//if(m != modo_PADRAO){
//brilho LCD
ler_potenciometro(); //para o brilho LCD
lcd_brilho_potenciometro(valor_ADC); //brilho LCD
//Lê a temperatura em Celsius
temperatura = DHT(Temperatura, DHT22);
//Adicionar novos caracteres na memoria DDRAM
gerar_caracteres();
//armazenamento
armazenar_EEPROM(temperatura);
//passagem das funcoes
inst_temp = leitura_EEPROM_float(endereco);
min_max_TEMPERATURA(inst_temp);
media_temp = media();
// Buffer converte os valores de temperatura e umidade para strings
dtostrf(inst_temp, 6, 2, tempString);
dtostrf(media_temp, 6, 2, mediaString);
dtostrf(min_temp, 6, 2, minString);
dtostrf(max_temp, 6, 2, maxString);
//circulando
circular_EEPROM();
//}
// Limpar display
cmd_LCD(0x01,0);
switch(m){
//Modo padrao
case modo_PADRAO:
cmd_LCD(0x81, 0); // Posiciona o cursor na segunda linha, terceira coluna
escreve_LCD("AquaWatch Kids");// Escreve no LCD
cmd_LCD(0xC2, 0);
escreve_LCD("JK Care LTDA");
break;
//Modo temperatura instantenea
case modo_TEMPERATURA_INST:
cmd_LCD(0x80, 0); // Posiciona o cursor na segunda linha, terceira coluna
escreve_LCD("Temperatura Inst."); // Escreve no LCD
cmd_LCD(0xC4, 0);
escreve_LCD(tempString);
cmd_LCD(0xCB, 0); // Posiciona o cursor na segunda linha, terceira coluna
escreve_LCD("C"); // Escreve no LCD
cmd_LCD(0xCA, 0);
cmd_LCD(0x00,1); //apresenta primeiro caractere 0x00
break;
//Modo temperatura min/max
case modo_TEMPERATURA_MinMax:
cmd_LCD(0x81, 0);
cmd_LCD(0x06,1);
cmd_LCD(0x83, 0);
escreve_LCD("T"); // Escreve no LCD
cmd_LCD(0x01,1); //apresenta segundo caractere 0x01 -> M
cmd_LCD(0x02,1); //apresenta segundo caractere 0x02 -> A
cmd_LCD(0x03,1); //apresenta segundo caractere 0x03 -> X
cmd_LCD(0xC1, 0);
cmd_LCD(0x07,1);
cmd_LCD(0xC3, 0);
escreve_LCD("T"); // Escreve no LCD
cmd_LCD(0x01,1); //apresenta segundo caractere 0x01 -> M
cmd_LCD(0x04,1); //apresenta segundo caractere 0x02 -> I
cmd_LCD(0x05,1); //apresenta segundo caractere 0x03 -> N
//MAXIMA
cmd_LCD(0x87, 0);
escreve_LCD(maxString);
cmd_LCD(0x00,1); //apresenta primeiro caractere 0x00
escreve_LCD("C");
//MINIMA
cmd_LCD(0xC7, 0);
escreve_LCD(minString);
cmd_LCD(0x00,1); //apresenta primeiro caractere 0x00
escreve_LCD("C"); // Escreve no LCD
break;
//Modo temperatura media
case modo_TEMPERATURA_MED:
cmd_LCD(0x80, 0); // Posiciona o cursor na segunda linha, terceira coluna
escreve_LCD("Temperatura Med"); // Escreve no LCD
cmd_LCD(0xC4, 0);
escreve_LCD(mediaString);
cmd_LCD(0xCB, 0); // Posiciona o cursor na segunda linha, terceira coluna
escreve_LCD("C"); // Escreve no LCD
cmd_LCD(0xCA,0); //endereça a posição para escrita dos caracteres
cmd_LCD(0x00,1); //apresenta primeiro caractere 0x00
break;
}
//bip se temperatura 36<t<37
beep_beep_beep_buzzer();
}
//---------------------------------------------------------------------------
//================================================================================ //
// Acionamento do POTENCIOMETRO //
//================================================================================ //
void ler_potenciometro(){ //POTENCIOMETRO
ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC)); // Aguardar a conversão ser concluída
valor_ADC = ADC; //Novo valor capturado
//Serial.print("Potenciometro: ");
//Serial.println(valor_ADC); // Imprimir o valor capturado do potenciômetro
}
void lcd_brilho_potenciometro(uint16_t val_adc){
DDRH |= (1 << LCD_ANODO); //saida
if(val_adc <= 500 & OnOff == true){
PORTH &= ~(1 << LCD_ANODO);
}
else{
PORTH |= (1 << LCD_ANODO);
}
}
//---------------------------------------------------------------------------
//================================================================================ //
// Acionamento do BUZZER //
//================================================================================ //
/*tipos de audio
tocar_faixa_musical(ligando);
tocar_faixa_musical(beep);
alarme_buzzer();
tocar_faixa_musical(desligando);
*/
// Frequências das notas em Hz para a oitava 0 até a oitava 8 (Universal)
float frequencias_notas[NUM_OITAVAS][NOTAS_POR_OITAVA] = {
// Oitava 0
{16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.50, 25.96, 27.50, 29.14, 30.87},
// Oitava 1
{32.70, 34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00, 58.27, 61.74},
// Oitava 2
{65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47},
// Oitava 3
{130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94},
// Oitava 4
{261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88},
// Oitava 5
{523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77},
// Oitava 6
{1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760.00, 1864.66, 1975.53},
// Oitava 7
{2093.00, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520.00, 3729.31, 3951.07},
// Oitava 8
{4186.01, 4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040.00, 7458.62, 7902.13}
}; //obs: o buzzer opera em 32hz-10khz
//init buzzer
void inicializar_pwm_buzzer(){
//se o dispositivo estiver ligado, entao pode tocar o som dj
if(OnOff == true){
// Configura o pino 13 (ou qualquer pino que deseje) como saída
DDRE |= (1 << BUZZER_PIN); // PB5 corresponde ao pino 13 no Arduino Mega
//PORTB |= (1 << PB5); //SAIDA
// Configura o Timer1 para PWM
TCCR3A |= (1 << COM3A1) | (1 << WGM31); // Configura o modo de saída não invertido (OC2A) e o modo de contagem PWM de 10 bits
TCCR3B |= (1 << WGM33) | (1 << WGM32) | (1 << CS31) | (1 << CS30); // Configura o pré-scaler para 64 (frequência do clock / 64)
ICR3 = F_CPU / 64 / FREQUENCIA_PWM - 1; // Configura o TOP para obter a frequência desejada
// O PWM está configurado, você pode ajustar o ciclo de trabalho alterando o valor do registrador OCR1A
// Exemplo: 50% de ciclo de trabalho (eficiente e audivel)
OCR3A = ICR3 / 2; //duty cyle (INMPORTANTE)
}
}
//1 beep -> PADRAO para qualquer som, entao se a frequencia muda -> a freq. do pwm deve mudar em ICR3 (TOP)
void beep_buzzer(int oitava, enum tom nota){
FREQUENCIA_PWM = frequencias_notas[oitava][nota];
ICR3 = F_CPU / 64 / FREQUENCIA_PWM - 1; // valor limite do temporizado TCN1 -> (TOP)
}
//padrao duracao = 250
void tocar_faixa_musical(enum faixa fx) {
//inicializa os registradores para fast pwm
inicializar_pwm_buzzer();
// Duração de cada nota em milissegundos
int duracao_nota = 250; // 0.250 segundos
// Sequência de notas para uma música simples (por exemplo)
enum tom notas_musica[] = {NOTA_DO, NOTA_RE, NOTA_MI};
//ligando
if(fx == ligando){
// Tocar cada nota na sequência
for (int i = 0; i < sizeof(notas_musica) / sizeof(notas_musica[0]); i++) {
beep_buzzer(5, notas_musica[i]); // Toca a nota
_delay_ms(300); // Aguarda a duração da nota
}
}
//beep
if(fx == beep){
// Duração de cada nota em milissegundos
beep_buzzer(5, NOTA_FA);
_delay_ms(333);
}
//alarme
if(fx == alarme){
beep_buzzer(7, NOTA_SI); // Toca a nota
_delay_ms(duracao_nota); // Aguarda a duração da nota
}
//desligando
if(fx == desligando){
// Tocar cada nota na sequência
for (int i = 3; i >= 0; i--) {
beep_buzzer(5, notas_musica[i]); // Toca a nota
_delay_ms(duracao_nota); // Aguarda a duração da nota
}
}
//parar a musica e PWM no pino
parar_musica();
}
//parar pwm basicamente
void parar_musica() {
// Desativa o timer para parar completamente o sinal PWM
TCCR3B = 0x00; // Desativa o clock do timer
// Desativa a saída PWM
TCCR3A = 0x00;
// Zera o registrador de comparação para manter o pino em nível baixo
OCR3A = 0;
// Define o pino como entrada
DDRE |= (0 << BUZZER_PIN);
}
//2 beeps
void alarme_buzzer(){
tocar_faixa_musical(alarme);
_delay_ms(333);
tocar_faixa_musical(alarme);
_delay_ms(333);
tocar_faixa_musical(alarme);
_delay_ms(666);
}
//3 sequecias de beeps e tratamentos
void beep_beep_beep_buzzer(){
if (media_temp >= 35.00 && media_temp <= 37.00 && m != modo_PADRAO){
if(cont_bip < 1 && flag_temperatura == false){
PORTJ |= (1 << LED_VERDE_PIN);
alarme_buzzer();
cont_bip++;
}
}
else{
flag_temperatura = true;
PORTJ &= ~(1 << LED_VERDE_PIN);
if(media_temp < 35.00 or media_temp > 37.00){
flag_temperatura = false;
cont_bip = 0;
}
}
}
//---------------------------------------------------------------------------
//================================================================================ //
// WATCHDOG //
//================================================================================ //
void reset() {
// Desabilitar interrupções globalmente
cli();
// Configurar o registrador WDTCSR para habilitar o watchdog (WDTCSR == WDRCR)
WDTCSR |= ( 1 << WDCE) | (1 << WDE);
// Configurar o watchdog para um tempo de reinicialização curto
WDTCSR = (1 << WDE);
// Entrar em loop infinito até o reinício ocorrer
while(1);
}
//---------------------------------------------------------------------------
//================================================================================//
// MAIN //
//================================================================================//
int main(){
cli(); //desabilita interrupcao global
//alimentacao 5v
DDRH |= (1 << PH5); //saida
//Botoes
DDRD &= ~(1 << botao_TEMPERATURA_INST); //Direcionando bit do DDRD como entrada
DDRD &= ~(1 << botao_TEMPERATURA_MED); //Direcionando bit do DDRD como entrada
DDRD &= ~(1 << botao_TEMPERATURA_minMAX); //Direcionando bit do DDRD como entrada
DDRD &= ~(1 << botao_TEMPERATURA_CLR);
DDRC &= ~(1 << knob_POTENCIOMETRO); // Configurar o pino A0 como entrada para o ADC
PORTD |= (1 << botao_TEMPERATURA_INST) | (1 << botao_TEMPERATURA_MED) | (1 << botao_TEMPERATURA_minMAX) | (1 << botao_TEMPERATURA_CLR); //ATIVA O PULL UP INTERNO
PORTC |= (1 << knob_POTENCIOMETRO); // ATIVA O PULL UP INTERNO
PORTE |= (1 << botao_On_Off); //Ativa o pull up interno
//LED controle
DDRJ |= (1 << LED_VERDE_PIN); // saida
//LCD 16x2
DDRA = 0xFF; // PORTD como saída (CONTROLE)
DDRC = 0xFF; // PORTB como saída (DADOS)
inic_LCD_4bits(); // Inicializa o LCD
//Interrupcoes (Externas)
EICRA |= (0 << ISC00) | (0 << ISC01); //Tipo de descida do INT0 inst
EICRA |= (0 << ISC10) | (0 << ISC11); //Tipo de descida do INT1 min/max
EICRA |= (0 << ISC20) | (0 << ISC21); //Tipo de descida do INT2 clr
EICRA |= (0 << ISC30) | (0 << ISC31); //Tipo de descida do INT3 med
EICRB |= (0 << ISC40) | (0 << ISC41); //Tipo de descida do INT3 med
EIMSK |= (1 << INT0); //habilita INT0
EIMSK |= (1 << INT1); //habilita INT1
EIMSK |= (1 << INT2); //habilita INT2
EIMSK |= (1 << INT3); //habilita INT3
EIMSK |= (1 << INT4); //habilita INT4
//ADC
ADCSRA |= (1 << ADEN); //ADC habilitado
ADMUX |= (1 << REFS0); //AVCC -> 5V como referencia para o ADC
ADMUX |= (0 << MUX0); //canal 0
ADCSRA |= (1 << ADSC); //Comecanco a conversao (podemos mudar aqui para o modo)
ADCSRA |= (1 << ADPS1) | (1 << ADPS2); //Prescale de 64
ADCSRA |= (1 << ADIF); //Mudancas salva no registrador
//Temporizador 1 (Interno)
TCCR1B |= (1 << WGM12); // ativa o modo CTC
OCR1A = 15624; // Define o valor de comparação para 1 segundo a uma frequência de 16MHz //OCR1A = 7812 para 0.5, 15624 para 1s
TIMSK1 |= (1 << OCIE1A); // ativa a interrupção de comparação A
TCCR1B |= (1 << CS10) | (1 << CS12); // Configura o prescaler para 1024
sei(); //Habilita interrupcao global
while(1){
if(timer_flag==true & OnOff == true){
timer_flag=false;
modo_LCD(m); // Chama a função para atualizar o LCD
}
}
return 0;
}
//---------------------------------------------------------------------------
//================================================================================ //
// INTERRUPCOES //
//================================================================================ //
//modo instantanea rotina
ISR(INT0_vect){
// Limpar display
cmd_LCD(0x01,0);
_delay_ms(200);
flag_temperatura = false; cont_bip = 0;
m = modo_TEMPERATURA_INST;
tocar_faixa_musical(beep);
}
//modo media rotina
ISR(INT1_vect){
//Limpar display
cmd_LCD(0x01,0);
_delay_ms(200);
flag_temperatura = false; cont_bip = 0;
m = modo_TEMPERATURA_MED;
tocar_faixa_musical(beep);
}
//modo clear (clr) rotina
ISR(INT2_vect){
//Limpar display
cmd_LCD(0x01,0);
_delay_ms(200);
endereco = 0; cont_bip = 0; flag_temperatura = false; media_temp = 0; inst_temp = 0; max_temp = -6000.00; min_temp = 6000.00;
tocar_faixa_musical(beep);
}
//modo temperatura min/max rotina
ISR(INT3_vect){
// Limpar display
cmd_LCD(0x01,0);
_delay_ms(200);
if(init==true){
max_temp = -6000.00; min_temp = 6000.00;
init_ = false;
}
flag_temperatura = false; cont_bip = 0;
m = modo_TEMPERATURA_MinMax;
tocar_faixa_musical(beep);
}
//On e Off rotina
ISR(INT4_vect){
if(OnOff == false){ //ligar
valor_ADC = 0;
_delay_ms(333);
m = modo_PADRAO;
PORTH |= (1 << PH5); //Ligar alimentacao de 5v
modo_LCD(m);
OnOff = true;
tocar_faixa_musical(ligando);
}
else{
tocar_faixa_musical(desligando);
parar_musica(); //parar a musica e PWM no pino
PORTH &= ~(1 << LCD_ANODO);
OnOff = false;
cmd_LCD(0x01,0); // Limpar display
PORTH &= ~(1 << PH5); //desligar alimentacao de 5v
reset(); // Resetar a placa por software
}
_delay_ms(500);
}
//atualizar a cada 1s rotina
ISR(TIMER1_COMPA_vect) {
timer_flag = true;
}
//---------------------------------------------------------------------------
/*
obs: pode ocorrer problema ao medir a temperatura negativa se o sensor for DHT11.
*/