Índice:
2025 Autor: John Day | [email protected]. Última modificação: 2025-01-13 06:58
Olá pessoal!
Nesta seção, fazemos um dispositivo eletrônico simples para monitorar a temperatura e o nível de luz. As medições desses parâmetros são exibidas no LCD NOKIA 5110. O dispositivo é baseado no microcontrolador AVR ATMEGA328P. O dispositivo de monitoramento é equipado com termômetro digital DS18B20 e fotoresistor para medir o nível de luz.
Etapa 1: Descrição dos componentes
Componentes básicos do dispositivo de monitoramento:
- Microcontrolador AVR «ATMEGA328P»
- LCD gráfico monocromático «NOKIA 5110»
- Termômetro digital de 1 fio de resolução programável «DS18B20»
- Resistor dependente de luz
- Fios
Microcontrolador AVR «ATMEGA328P»
O dispositivo de monitoramento usa os seguintes recursos periféricos do microcontrolador:
- Interrupção do temporizador / contador de 16 bits
- ADC de 8 canais e 10 bits
- Interface serial SPI mestre / escravo
LCD gráfico monocromático «NOKIA 5110»
Especificações:
- Tela LCD de 48 x 84 pontos
- Interface de barramento serial com alta velocidade máxima de 4 Mbits / S
- Controlador / driver interno «PCD8544»
- Retroiluminação LED
- Funciona com tensão 2,7-5 volts
- Baixo consumo de energia; é adequado para aplicações de bateria
- Faixa de temperatura de -25˚C a + 70˚C
- Entrada de sinal CMOS de suporte
Tratamento do endereço LCD (endereçamento):
O arranjo de endereço da memória que é mostrado no display LCD (DDRAM) é a matriz que consiste em 6 linhas (endereço Y) do endereço Y 0 ao endereço Y 5 e 84 colunas (endereço X) do endereço X 0 ao X- Endereço 83. Se o usuário deseja acessar a posição de exibição do resultado no visor LCD, deve consultar a relação entre o endereço X e o endereço Y.
Os dados que serão enviados ao display são de 8 bits (1 Byte) e serão organizados como uma linha vertical; neste caso, o Bit MSB será inferior e o Bit LSB será superior, conforme mostrado na figura.
Termômetro digital de resolução programável com 1 fio DALLAS «DS18B20»
Recursos:
- Interface única de 1 fio® requer apenas um pino de porta para comunicação
- Reduza a contagem de componentes com sensor de temperatura integrado e EEPROM
- Mede temperaturas de -55 ° C a + 125 ° C (-67 ° F a + 257 ° F)
- ± 0,5 ° C Precisão de -10 ° C a + 85 ° C
- Resolução programável de 9 bits a 12 bits
- Nenhum componente externo necessário
- O modo de energia parasita requer apenas 2 pinos para operação (DQ e GND)
- Simplifica as aplicações distribuídas de detecção de temperatura com capacidade multiponto
- Cada dispositivo possui um código serial exclusivo de 64 bits armazenado na ROM on-board
- Configurações flexíveis de alarme não volátil (NV) definidas pelo usuário com o comando de pesquisa de alarme identifica dispositivos com temperaturas fora dos limites programados
Formulários:
- Controles termostáticos
- Sistemas Industriais
- Produtos de consumo
- Termômetros
- Sistemas termicamente sensíveis
Resistor dependente de luz
O Resistor Dependente de Luz (LDR) é um transdutor que muda sua resistência quando a luz incide em sua superfície.
Normalmente, um LDR terá de um megaOhms a dois megaOhms na escuridão total, de dez a vinte kiloOhms a dez LUX, de dois a cinco quiloohms a 100 LUX. A resistência entre os dois contatos do sensor diminui com a intensidade da luz ou a condutância entre os dois contatos do sensor aumenta.
Use o circuito divisor de tensão para converter a mudança na resistência em mudança na tensão.
Etapa 2: Código de firmware do microcontrolador
#ifndef F_CPU # define F_CPU 16000000UL // informando a frequência do cristal do controlador (16 MHz AVR ATMega328P) #endif
// INTERFACE SPI DEFINA # define MOSI 3 // MOSI é PORTA B, PIN 3 # define MISO 4 // MISO é PORTA B, PIN 4 # define SCK 5 // SCK é PORTA B, PIN 5 # define SS 2 // SS é PORTA B, PIN 2
// RESET O DISPLAY #define RST 0 // RESET é PORTA B, PIN 0
// DISPLAY MODE SELECT - Entrada para selecionar comando / endereço ou entrada de dados. # define DC 1 // DC é PORTA B, PIN 1
// array de códigos de signstatic negativo const unsigned char neg [4] = {0x30, 0x30, 0x30, 0x30};
// codes array of digits [0..9] static const unsigned char font6x8 [10] [16] = {{0xFC, 0xFE, 0xFE, 0x06, 0x06, 0xFE, 0xFE, 0xFC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 0 {0x00, 0x00, 0x18, 0x1C, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00}, // 1 { 0x0C, 0x8E, 0xCE, 0xE6, 0xE6, 0xBE, 0x9E, 0x0C, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 2 {0x00, 0x04, 0x06, 0x26, 0x76, 0xFE, 0xDE, 0x8C, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 3 {0x3C, 0x3E, 0x7C, 0x60, 0x60, 0xFC, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01}, // 4 {0x1C, 0x3E, 0x3E, 0x36, 0x36, 0xF6, 0xF6, 0xE4, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 5 {0xFC, 0xFE, 0xFE, 0x36, 0x36, 0xF6, 0xF6, 0xE4, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 6 {0x04, 0x06, 0x06, 0x86, 0xE6, 0xFE, 0x7E, 0x1C, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00}, // 7 {0xCC, 0xFE, 0xFE, 0x36, 0x36, 0xFE, 0xFE, 0xCC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0 3, 0x01}, // 8 {0x3C, 0x7E, 0x7E, 0x66, 0x66, 0xFE, 0xFE, 0xFC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01} // 9};
// codifica a matriz da palavra "TEMP:" static const unsigned char TEMP_1 [165] = {0x02, 0x06, 0x06, 0xFE, 0xFE, 0xFE, 0x06, 0x06, 0x02, 0x00, 0xFC, 0xFE, 0xFE, 0x26, 0x26, 0x24, 0x00, 0xFC, 0xFE, 0xFE, 0x1C, 0x38, 0x70, 0x38, 0x1C, 0xFE, 0xFE, 0xFC, 0x00, 0xFC, 0xFE, 0xFE, 0x66, 0x66, 0x7E, 0x7E, 0x3C, 0x00, 0x8C, 0x8C, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0C, 0x1E, 0x33, 0x33, 0x1E, 0x0C, 0x00, 0xF8, 0xFC, 0x0C, 0x9C, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x01,};
// codifica a matriz da palavra "LUX:" const unsigned char TEMP_2 [60] = {0xFC, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFE, 0xFC, 0x00, 0x00, 0xFC, 0xFE, 0xFC, 0x00, 0x04, 0x8E, 0xDE, 0xFC, 0xF8, 0xFC, 0xDE, 0x8E, 0x04, 0x00, 0x8C, 0x8C, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x01, 0x03, 0x03, 0x01, 0x00, 0x01, 0x03, 0x03, 0x01, 0x00, 0x01, 0x01};
#incluir
#include #include
// Inicialização da porta evita Port_Init () {DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS) | (1 << RST) | (1 << DC); // Definir MOSI, SCK, SS, RST, DC como saída, todas as outras entradas PORTB | = (1 << RST); // Definir pino RST como alto PORTB | = (1 << SS); // Definir pino SS como alto - Display é Desative DDRC = 0xFFu; // Defina todos os pinos do PORTC como saída. DDRC & = ~ (1 << 0); // Faz o primeiro pino de PORTC como Entrada PORTC = 0x00u; // Defina todos os pinos de PORTC para baixo, o que o desliga. }
// Inicialização ADC void ADC_init () {// Habilitar ADC, amostragem freq = osc_freq / 128 definir prescaler para valor máximo, 128 ADCSRA | = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); ADMUX = (1 << REFS0); // Selecione a referência de tensão para o ADC // Selecione o canal zero por padrão usando o registro ADC Multiplexer Select (ADC0). }
// Função para ler o resultado da conversão de analógico para digital uint16_t get_LightLevel () {_delay_ms (10); // Aguarde algum tempo até que o canal seja selecionado ADCSRA | = (1 << ADSC); // Inicie a conversão ADC definindo o bit ADSC. escreva 1 para ADSC enquanto (ADCSRA & (1 << ADSC)); // espera que a conversão seja concluída // ADSC torna-se 0 novamente até então, execute o loop continuamente _delay_ms (10); retorno (ADC); // Retorna o resultado de 10 bits}
// SPI Initialization void SPI_Init () {SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Habilitar SPI, definir como mestre, definir pré-escalador como Fosc / 16 no controle SPI registro }
// inicializa o Timer1 de 16 bits, interrupção e variável void TIMER1_init () {// configura o timer com prescaler = 256 e modo CTC TCCR1B | = (1 << WGM12) | (1 << CS12); // inicializa o contador TCNT1 = 0; // inicializa o valor de comparação - 1 s OCR1A = 62500; // habilita a interrupção de comparação TIMSK1 | = (1 << OCIE1A); // habilita interrupções globais sei (); }
// Exibir habilitar void SPI_SS_Enable () {PORTB & = ~ (1 << SS); // Habilite o pino SS para o lógico 0}
// Exibir Desabilitar void SPI_SS_Disable () {PORTB | = (1 << SS); // Desative o pino SS para lógica 1}
// Função para enviar dados para o buffer de exibição void SPI_Tranceiver (unsigned char data) {SPDR = data; // Carrega dados no buffer while (! (SPSR & (1 << SPIF))); // Espere até a transmissão terminar}
// Reinicia o display no início da inicialização void Display_Reset () {PORTB & = ~ (1 << RST); _delay_ms (100); PORTB | = (1 << RST); }
// Função de escrita do comando void Display_Cmnd (unsigned char data) {PORTB & = ~ (1 << DC); // torna o pino DC para o lógico 0 para operação de comando SPI_Tranceiver (dados); // envia dados no registro de dados PORTB | = (1 << DC); // torna o pino DC para a lógica alta para operação de dados}
// Inicialização do Display void Display_init () {Display_Reset (); // redefine o display Display_Cmnd (0x21); // comando definido no modo de adição Display_Cmnd (0xC0); // define a tensão enviando C0 significa VOP = 5V Display_Cmnd (0x07); // definir a temperatura. coeficiente para 3 Display_Cmnd (0x13); // definir o valor do sistema de polarização de tensão Display_Cmnd (0x20); // comando definido no modo básico Display_Cmnd (0x0C); // exibe o resultado no modo normal}
// Limpa a exibição void Display_Clear () {PORTB | = (1 << DC); // torna DC pin para lógica alta para operação de dados para (int k = 0; k <= 503; k ++) {SPI_Tranceiver (0x00);} PORTB & = ~ (1 << DC); // faz DC pin para lógica zero para operação de comando}
// define a coluna e linha para a posição de exibição do resultado no visor LCD void Display_SetXY (unsigned char x, unsigned char y) {Display_Cmnd (0x80 | x); // coluna (0-83) Display_Cmnd (0x40 | y); // linha (0-5)}
// Função para exibir o sinal negativo void Display_Neg (unsigned char neg) {Display_SetXY (41, 0); // Define o endereço da posição no display para (int index = 0; index0) {SPDR = 0x30;} // Carrega os dados no buffer do display (mostra o sinal negativo) else {SPDR = 0x00;} // Carrega os dados no o buffer de exibição (limpar o sinal negativo) enquanto (! (SPSR & (1 << SPIF))); // Espere até a transmissão terminar _delay_ms (100); }}
// Função para limpar o sinal digital void Off_Dig (unsigned char x, unsigned char y) {Display_SetXY (x, y); // Defina o endereço da posição no visor (linha superior) para (int índice = 0; índice <8; índice ++) {SPI_Tranceiver (0);} // Carregar dados no buffer do visor (limpar a parte superior do sinal digital) y ++; Display_SetXY (x, y); // Definir o endereço da posição no display (linha inferior) para (int índice = 0; índice <8; índice ++) {SPI_Tranceiver (0);} // Carregar dados no buffer do display (limpar a parte inferior do sinal digital)}
// Função para exibir o sinal digital void Display_Dig (int dig, unsigned char x, unsigned char y) {Display_SetXY (x, y); // Definir o endereço da posição no display (linha superior) para (int índice = 0; índice <16; índice ++) {if (índice == 8) {y ++; Display_SetXY (x, y);} // Define o endereço da posição no display (linha inferior) SPI_Tranceiver (font6x8 [dig] [índice]); // Carrega array de códigos de dados de dígitos no buffer de display _delay_ms (10); }}
// Inicialização do DS18B20 unsigned char DS18B20_init () {DDRD | = (1 << 2); // Define o pino PD2 do PORTD como saída PORTD & = ~ (1 << 2); // Defina o pino PD2 como baixo _delay_us (490); // Tempo de inicialização DDRD & = ~ (1 << 2); // Define o pino PD2 do PORTD como input _delay_us (68); // Tempo OK_Flag = (PIND & (1 << 2)); // obtém pulso do sensor _delay_us (422); return OK_Flag; // return 0-ok sensor is plug, 1-error sensor is unplug}
// Função para ler byte de DS18B20 unsigned char read_18b20 () {unsigned char i, data = 0; para (i = 0; i <8; i ++) {DDRD | = (1 << 2); // Define o pino PD2 do PORTD como output _delay_us (2); // Timing DDRD & = ~ (1 1; // Próximo bit if (PIND & (1 << 2)) data | = 0x80; // coloca o bit no byte _delay_us (62);} dados de retorno;}
// Função para escrever byte para DS18B20 void write_18b20 (unsigned char data) {unsigned char i; para (i = 0; i <8; i ++) {DDRD | = (1 << 2); // Define o pino PD2 do PORTD como output _delay_us (2); // Tempo se (dados & 0x01) DDRD & = ~ (1 << 2); // se quisermos escrever 1, libere a linha else DDRD | = (1 1; // Próximo bit _delay_us (62); // Timing DDRD & = ~ (1 << 2); // Defina o pino PD2 do PORTD como entrada _delay_us (2);}}
// Função para exibir o nível de luz void Read_Lux () {uint16_t buffer; sem sinal int temp_int_1, temp_int_2, temp_int_3, temp_int_0; // dígitos únicos, dígitos duplos, dígitos triplos, dígitos de um quarto buffer = get_LightLevel (); // lê o resultado do nível de luz de conversão de analógico para digital temp_int_0 = buffer% 10000/1000; // temp_int_1 de um quarto de dígito = buffer% 1000/100; // temp_int_2 de três dígitos = buffer% 100/10; // dois dígitos temp_int_3 = buffer% 10; // dígito único if (temp_int_0> 0) // se o resultado for um número de um quarto de dígito {Display_Dig (temp_int_0, 32, 2); // exibe 1 dígito do nível de luz Display_Dig (temp_int_1, 41, 2); // exibe 2 dígitos do nível de luz Display_Dig (temp_int_2, 50, 2); // exibe 3 dígitos do nível de luz Display_Dig (temp_int_3, 59, 2); // exibe 4 dígitos do nível de luz} else {if (temp_int_1> 0) // se o resultado é um número de três dígitos {Off_Dig (32, 2); // limpa 1 sinal de número Display_Dig (temp_int_1, 41, 2); // exibe 1 dígito do nível de luz Display_Dig (temp_int_2, 50, 2); // exibe 2 dígitos do nível de luz Display_Dig (temp_int_3, 59, 2); // exibe 3 dígitos do nível de luz} else {if (temp_int_2> 0) // se o resultado for um número de dois dígitos {Off_Dig (32, 2); // limpa 1 sinal do número Off_Dig (41, 2); // limpar 2 sinais de número Display_Dig (temp_int_2, 50, 2); // exibe 1 dígito do nível de luz Display_Dig (temp_int_3, 59, 2); // exibe 2 dígitos do nível de luz} else // se o resultado for um número de um dígito {Off_Dig (32, 2); // limpa 1 sinal do número Off_Dig (41, 2); // limpa o sinal 2 do número Off_Dig (50, 2); // limpar 3 sinais de número Display_Dig (temp_int_3, 59, 2); // exibe 1 dígito do nível de luz}}}}
// Função para exibir a temperatura void Read_Temp () {unsigned int buffer; sem sinal int temp_int_1, temp_int_2, temp_int_3; // dígitos únicos, dígitos duplos, dígitos triplos, dígitos sem sinal char Temp_H, Temp_L, OK_Flag, temp_flag; DS18B20_init (); // Inicialização do DS18B20 write_18b20 (0xCC); // Verificação do código do sensor write_18b20 (0x44); // Iniciar conversão de temperatura _delay_ms (1000); // Atraso na pesquisa do sensor DS18B20_init (); // Inicialização do DS18B20 write_18b20 (0xCC); // Verificação do código do sensor write_18b20 (0xBE); // Comando para ler o conteúdo do Sensor RAM Temp_L = read_18b20 (); // Lê os primeiros dois bytes Temp_H = read_18b20 (); temp_flag = 1; // temperatura 1-positiva, temperatura 0-negativa // Obtém temperatura negativa if (Temp_H & (1 << 3)) // Verificação do Bit de Sinal (se o bit está definido - temperatura negativa) {assinado int temp; temp_flag = 0; // sinalizador é definido como 0 - temperatura negativa temp = (Temp_H << 8) | Temp_L; temp = -temp; // Converta o código adicional em direto Temp_L = temp; Temp_H = temp >> 8; } buffer = ((Temp_H 4); temp_int_1 = buffer% 1000/100; // dígito triplo temp_int_2 = buffer% 100/10; // dígito duplo temp_int_3 = buffer% 10; // dígito único
// Se a temperatura for negativa, exibirá o sinal de temperatura, caso contrário, limpará
if (temp_flag == 0) {Display_Neg (1);} else {Display_Neg (0);} if (temp_int_1> 0) // se o resultado for um número de três dígitos {Display_Dig (temp_int_1, 45, 0); // exibe 1 dígito de temperatura Display_Dig (temp_int_2, 54, 0); // exibe 2 dígitos da temperatura Display_Dig (temp_int_3, 63, 0); // exibe 3 dígitos da temperatura} else {if (temp_int_2> 0) // se o resultado for um número de dois dígitos {Off_Dig (45, 0); // limpa 1 sinal de número Display_Dig (temp_int_2, 54, 0); // exibe 1 dígito de temperatura Display_Dig (temp_int_3, 63, 0); // exibe 2 dígitos de temperatura} else // se o resultado for um número de um dígito {Off_Dig (45, 0); // limpa 1 sinal do número Off_Dig (54, 0); // limpa 2 sinais de número Display_Dig (temp_int_3, 63, 0); // exibe 1 dígito de temperatura}}}
// Este ISR é disparado sempre que ocorre uma correspondência da contagem do cronômetro com o valor de comparação (a cada 1 segundo) ISR (TIMER1_COMPA_vect) {// Leitura, exibição de temperatura e nível de luz Read_Temp (); Read_Lux (); }
// Função para exibir as palavras "TEMP" e "LUX" void Display_label () {// Palavra "TEMP" Display_SetXY (0, 0); // Define o endereço da posição no display (linha acima) para (int index = 0; index <105; index ++) {if (index == 40) {Display_SetXY (0, 1);} // Define o endereço da posição no display (linha inferior) if (índice == 80) {Display_SetXY (72, 0);} // Define o endereço da posição no display (linha superior) if (índice == 92) {Display_SetXY (72, 1); } // Define o endereço da posição no display (linha inferior) SPDR = TEMP_1 [índice]; // Carrega os dados da matriz de códigos no buffer de exibição while (! (SPSR & (1 << SPIF))); // Espere até a transmissão terminar _delay_ms (10); } // Palavra "LUX" Display_SetXY (0, 2); // Define o endereço da posição no display (linha acima) para (int index = 0; index <60; index ++) {if (index == 30) {Display_SetXY (0, 3);} // Define o endereço da posição no display (linha inferior) SPDR = TEMP_2 [índice]; // Carrega os dados da matriz de códigos no buffer de exibição while (! (SPSR & (1 << SPIF))); // Espere até a transmissão terminar _delay_ms (10); }}
int main (vazio)
{Port_Init (); // Inicialização da porta ADC_init (); // Inicialização ADC SPI_Init (); // Inicialização SPI SPI_SS_Enable (); // Habilitar exibição DS18B20_init (); // Inicialização do DS18B20 Display_init (); // Exibir inicialização Display_Clear (); // Mostra clear Display_label (); // Mostra as palavras "TEMP" e "LUX" TIMER1_init (); // Inicialização Timer1. Comece a monitorar. Obtendo parâmetros a cada segundo. // Loop infinito enquanto (1) {}}
Etapa 3: Flashing Firmware to Microcontrolador
Carregando o arquivo HEX na memória flash do microcontrolador. Assista ao vídeo com uma descrição detalhada da gravação da memória flash do microcontrolador: Gravação da memória flash do microcontrolador…
Etapa 4: Montagem do circuito do dispositivo de monitoramento
Conecte os componentes de acordo com o diagrama esquemático.
Conecte a energia e está funcionando!