Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Pretende-se implementar um voltímetro digital que apresente, nos display de 7 segmentos,
- o resultado da medida de uma tensão analógica em mV. A simulação da tensão de entrada do
- voltímetro será feita através de um potenciómetro ligado a um canal de entrada do conversor
- digital-analógico existente no ATmega128.
- O sinal em tensão do potenciómetro pode ser amostrado utilizando o canal ADC0 (PF0).
- Para que possa ser implementado um filtro de média (passa-baixo), o switches SW1, ..., SW4
- permitem definir o número de amostras que devem ser obtidas do sinal analógico (1, 8, 16 ou
- 32 amostras). O resultado final da conversão será calculado através da média aritmética dos
- resultados das n amostragens.
- Pretende-se que o processo de aquisição (obtenção das 1, 8, 16 ou 32 amostras e cálculo da
- respectiva média) seja feito a uma taxa de 2Hz.
- Implementação:
- A função que faz a leitura do conversor A/D, a acumulação das diferentes medidas e o cálculo
- final da média, deve ser implementada utilizando linguagem Assembly. */
- // ATmega128 - Voltimetro
- // paulogp
- // ficheiro C
- /*
- Timer/Counter 0:
- Base de tempo de 5ms
- t = 5ms
- frequencia oscilacao = 16 MHz
- pre-scaler = 1024
- t = (preScaler / frequenciaOscilacao) * (OCR0 + 1)
- OCR0 -> 78
- Modo 2 (CTC - clear timer on compare)
- Conversor AD
- ADMUX
- - bit 7:6 (01) - AVcc (5V)
- - bit 5 (0) - ajustado a esquerda
- - bit 4:0 (00000) - ADC0
- ADCSRA
- - bit 7 (1) - liga conversor
- - bit 6 (0) - comeca conversao
- - bit 5 (0) - free-running mode
- - bit 4 (0) - vai a 1 quando acaba uma conversao
- - bit 3 (1) - activa interrupcao
- - bit 2:0 (111) - determina pre-scaler (128 - 16MHz / 128 = 125kHz)
- */
- #include <avr/interrupt.h>
- #include <stdlib.h>
- unsigned char the_new_sample[3];
- unsigned char the_flag = 0;
- //unsigned char the_cnt_rx = 0;
- void inic();
- void display();
- // valor a colocar no display
- unsigned long int THE_DISP_VALUE = 0;
- // assembly file: calc.s
- extern void func_voltage_calc();
- // quantas amostras a obter
- int NO_SAMPLES = 1;
- // contador de amostras ja obtidas
- int COUNT_SAMPLES = 0;
- unsigned char VALUE_H = 0;
- unsigned char VALUE_L = 0;
- unsigned char AVG_L = 0;
- unsigned char AVG_H = 0;
- char the_msg[3];
- int the_flag_msg = 0;
- int main() {
- inic();
- int the_input;
- while (1) {
- the_input = PINA;
- // switch 1 (1 amostra obtida)
- if ((the_input & 0x01) == 0) {
- NO_SAMPLES = 1;
- }
- // switch 2 (8 amostras obtidas)
- else if ((the_input & 0x02) == 0) {
- NO_SAMPLES = 8;
- }
- // switch 3 (16 amostras obtidas)
- else if ((the_input & 0x04) == 0) {
- NO_SAMPLES = 16;
- }
- // switch 4 (32 amostras obtidas)
- else if ((the_input & 0x08) == 0) {
- NO_SAMPLES = 32;
- }
- UDR0 = the_msg[0];
- if (the_flag_msg == 1) {
- while (!(UCSR0A & 0x20));
- UDR0 = 'A';
- }
- }
- return 0;
- }
- void inic() {
- // define limite ate onde o timer 0 conta
- OCR0 = 78;
- // configura o timer 0
- TCCR0 = 0x0F; // 0b00001111;
- // activa a interrupcao do timer 0 (bit 1)
- TIMSK |= 0x02; // 0b00000010
- // activa interrupcoes globais
- SREG |= 0x80; // 0b10000000
- // configura o conversor AD (ADC)
- ADMUX = 0x40; // 0b01000000;
- ADCSRA = 0x8F; // 0b10001111;
- // PORTA - switches/display
- // PORTC - display
- // PORTF - potenciometro
- // switches e display
- DDRA = 0xC0; // 0b11000000
- PORTA = 0xC0; // 0b11000000
- // display
- DDRC = 0xFF; // 0b11111111
- // potenciometro
- DDRF = 0;
- }
- // rotina de interrupcao do timer/counter 0
- ISR(TIMER0_COMP_vect) {
- // conta 500ms (T = 1 / 2 Hz = 500ms)
- static int the_count = 0;
- // 5 ms
- the_count += 5;
- // >= 500ms - realiza amostra
- if (the_count == 500) {
- // comeca uma conversão (activar ADC)
- // Analog to Digital Converter (ADC) Control and Status Register A
- ADCSRA |= 0x40; // set bit 6 (inicio conversao)
- // reset contagem
- the_count = 0;
- }
- // refresh ao display a cada 5ms
- display();
- }
- /* O sinal e obtido no pin 0 do PORTF (PF0)
- (ADC0)
- - apos cada conversao -> interrupcao chamada
- - ler os registos ADCH e ADCL (o resultado separado em 2 bytes) */
- ISR(ADC_vect) {
- // chamada assembly
- func_voltage_calc();
- }
- // PORTC - display
- void display() {
- static int the_display_number = -1;
- the_display_number++;
- if (the_display_number == 4) {
- the_display_number = 0;
- }
- // seleciona o display a mostrar
- PORTA = the_display_number << 6;
- // converte numero para codigo display de 7 segmentos
- int the_display_code[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
- // converte VALUE_L e VALUE_H em VALOR
- THE_DISP_VALUE = VALUE_L;
- // tem um 1 no primeiro bit (+256)
- if ((VALUE_H & 0x01) != 0) {
- THE_DISP_VALUE += 256;
- }
- // tem um 1 no segundo bit (+512)
- if ((VALUE_H & 0x02) != 0) {
- THE_DISP_VALUE += 512;
- }
- THE_DISP_VALUE = THE_DISP_VALUE * 5000 / 1023;
- int the_value;
- switch(the_display_number) {
- case 0:
- // display mais a esquerda
- the_value = (THE_DISP_VALUE / 1000);
- break;
- case 1:
- the_value = (THE_DISP_VALUE / 100) % 10;
- break;
- case 2:
- the_value = (THE_DISP_VALUE / 10) % 10;
- break;
- case 3:
- // display mais a direita
- the_value = (THE_DISP_VALUE % 10);
- break;
- default:
- the_value = 0;
- break;
- }
- PORTC = the_display_code[the_value];
- }
- // ficheiro asm: calc.s
- #include <avr/io.h>
- .global func_voltage_calc
- .extern NO_SAMPLES
- .extern COUNT_SAMPLES
- .extern VALUE_H
- .extern VALUE_L
- .extern AVG_L
- .extern AVG_H
- func_voltage_calc:
- // grava os valores que estavam anteriormente nestes registos
- push r17
- push r18
- push r19
- push r20
- push r21
- push r22
- push r23
- // carrega variaveis
- lds r17, AVG_L
- lds r18, AVG_H
- lds r19, ADCL
- lds r20, ADCH
- // soma as varias amostras
- add r17, r19
- adc r18, r20
- lds r22, NO_SAMPLES
- cpi r22, 1
- breq reset
- // mais uma amostra
- lds r21, COUNT_SAMPLES
- inc r21
- cp r21, r22
- BRLO exit
- // se for igual, executar este codigo
- // faz a media
- mov r23, r22
- reset:
- // copia para outra variavel
- sts VALUE_H, r18
- sts VALUE_L, r17
- ldi r21, 0
- ldi r17, 0
- ldi r18, 0
- exit:
- sts AVG_H, r18
- sts AVG_L, r17
- sts COUNT_SAMPLES, r21
- // repoe os valores nos registos
- pop r23
- pop r22
- pop r21
- pop r20
- pop r19
- pop r18
- pop r17
- ret
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement