Advertisement
paulogp

ATmega128: T5 - Voltímetro

Jul 23rd, 2011
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.10 KB | None | 0 0
  1. /* Pretende-se implementar um voltímetro digital que apresente, nos display de 7 segmentos,
  2. o resultado da medida de uma tensão analógica em mV. A simulação da tensão de entrada do
  3. voltímetro será feita através de um potenciómetro ligado a um canal de entrada do conversor
  4. digital-analógico existente no ATmega128.
  5.  
  6. O sinal em tensão do potenciómetro pode ser amostrado utilizando o canal ADC0 (PF0).
  7.  
  8. Para que possa ser implementado um filtro de média (passa-baixo), o switches SW1, ..., SW4
  9. permitem definir o número de amostras que devem ser obtidas do sinal analógico (1, 8, 16 ou
  10. 32 amostras). O resultado final da conversão será calculado através da média aritmética dos
  11. resultados das n amostragens.
  12.  
  13. Pretende-se que o processo de aquisição (obtenção das 1, 8, 16 ou 32 amostras e cálculo da
  14. respectiva média) seja feito a uma taxa de 2Hz.
  15.  
  16. Implementação:
  17. A função que faz a leitura do conversor A/D, a acumulação das diferentes medidas e o cálculo
  18. final da média, deve ser implementada utilizando linguagem Assembly. */
  19.  
  20. // ATmega128 - Voltimetro
  21. // paulogp
  22.  
  23. // ficheiro C
  24. /*
  25.  Timer/Counter 0:
  26.  
  27.  Base de tempo de 5ms
  28.  
  29.  t = 5ms
  30.  frequencia oscilacao = 16 MHz
  31.  pre-scaler = 1024
  32.  
  33.  t = (preScaler / frequenciaOscilacao) * (OCR0 + 1)
  34.  
  35.  OCR0 -> 78
  36.  
  37.  Modo 2 (CTC - clear timer on compare)
  38.  
  39.  
  40.  Conversor AD
  41.  ADMUX
  42.  - bit 7:6 (01) - AVcc (5V)
  43.  - bit 5 (0) - ajustado a esquerda
  44.  - bit 4:0 (00000) - ADC0
  45.  
  46.  ADCSRA
  47.  - bit 7 (1) - liga conversor
  48.  - bit 6 (0) - comeca conversao
  49.  - bit 5 (0) - free-running mode
  50.  - bit 4 (0) - vai a 1 quando acaba uma conversao
  51.  - bit 3 (1) - activa interrupcao
  52.  - bit 2:0 (111) - determina pre-scaler (128 - 16MHz / 128 = 125kHz)
  53.  */
  54.  
  55. #include <avr/interrupt.h>
  56. #include <stdlib.h>
  57.  
  58.  
  59.  
  60. unsigned char the_new_sample[3];
  61. unsigned char the_flag = 0;
  62. //unsigned char the_cnt_rx = 0;
  63.  
  64.  
  65. void inic();
  66. void display();
  67.  
  68.  
  69. // valor a colocar no display
  70. unsigned long int THE_DISP_VALUE = 0;
  71.  
  72.  
  73. // assembly file: calc.s
  74. extern void func_voltage_calc();
  75.  
  76. // quantas amostras a obter
  77. int NO_SAMPLES = 1;
  78.  
  79. // contador de amostras ja obtidas
  80. int COUNT_SAMPLES = 0;
  81.  
  82. unsigned char VALUE_H = 0;
  83. unsigned char VALUE_L = 0;
  84.  
  85. unsigned char AVG_L = 0;
  86. unsigned char AVG_H = 0;
  87.  
  88.  
  89.  
  90. char the_msg[3];
  91. int the_flag_msg = 0;
  92.  
  93.  
  94.  
  95. int main() {
  96.     inic();
  97.  
  98.     int the_input;
  99.  
  100.     while (1) {
  101.         the_input = PINA;
  102.  
  103.         // switch 1 (1 amostra obtida)
  104.         if ((the_input & 0x01) == 0) {
  105.             NO_SAMPLES = 1;
  106.         }
  107.  
  108.         // switch 2 (8 amostras obtidas)
  109.         else if ((the_input & 0x02) == 0) {
  110.             NO_SAMPLES = 8;
  111.         }
  112.  
  113.         // switch 3 (16 amostras obtidas)
  114.         else if ((the_input & 0x04) == 0) {
  115.             NO_SAMPLES = 16;
  116.         }
  117.  
  118.         // switch 4 (32 amostras obtidas)
  119.         else if ((the_input & 0x08) == 0) {
  120.             NO_SAMPLES = 32;
  121.         }
  122.  
  123.         UDR0 = the_msg[0];
  124.  
  125.         if (the_flag_msg == 1) {
  126.             while (!(UCSR0A & 0x20));
  127.  
  128.             UDR0 = 'A';
  129.         }
  130.     }
  131.  
  132.     return 0;
  133. }
  134.  
  135.  
  136. void inic() {
  137.     // define limite ate onde o timer 0 conta
  138.     OCR0 = 78;
  139.  
  140.     // configura o timer 0
  141.     TCCR0 = 0x0F; // 0b00001111;
  142.  
  143.  
  144.     // activa a interrupcao do timer 0 (bit 1)
  145.     TIMSK |= 0x02; // 0b00000010
  146.  
  147.     // activa interrupcoes globais
  148.     SREG |= 0x80; // 0b10000000
  149.  
  150.     // configura o conversor AD (ADC)
  151.     ADMUX = 0x40; // 0b01000000;
  152.  
  153.     ADCSRA = 0x8F; // 0b10001111;
  154.  
  155.  
  156.     // PORTA - switches/display
  157.     // PORTC - display
  158.     // PORTF - potenciometro
  159.  
  160.     // switches e display
  161.     DDRA = 0xC0; // 0b11000000
  162.     PORTA = 0xC0; // 0b11000000
  163.  
  164.     // display
  165.     DDRC = 0xFF; // 0b11111111
  166.  
  167.     // potenciometro
  168.     DDRF = 0;
  169. }
  170.  
  171.  
  172. // rotina de interrupcao do timer/counter 0
  173. ISR(TIMER0_COMP_vect) {
  174.     // conta 500ms (T = 1 / 2 Hz = 500ms)
  175.     static int the_count = 0;
  176.  
  177.     // 5 ms
  178.     the_count += 5;
  179.  
  180.     // >= 500ms - realiza amostra
  181.     if (the_count == 500) {
  182.     // comeca uma conversão (activar ADC)
  183.     // Analog to Digital Converter (ADC) Control and Status Register A
  184.         ADCSRA |= 0x40; // set bit 6 (inicio conversao)
  185.  
  186.     // reset contagem
  187.         the_count = 0;
  188.     }
  189.  
  190.     // refresh ao display a cada 5ms
  191.     display();
  192. }
  193.  
  194.  
  195. /* O sinal e obtido no pin 0 do PORTF (PF0)
  196.  (ADC0)
  197.  - apos cada conversao -> interrupcao chamada
  198.  - ler os registos ADCH e ADCL (o resultado separado em 2 bytes) */
  199. ISR(ADC_vect) {
  200.     // chamada assembly
  201.     func_voltage_calc();
  202. }
  203.  
  204.  
  205. // PORTC - display
  206. void display() {
  207.     static int the_display_number = -1;
  208.  
  209.     the_display_number++;
  210.  
  211.     if (the_display_number == 4) {
  212.         the_display_number = 0;
  213.     }
  214.  
  215.     // seleciona o display a mostrar
  216.     PORTA = the_display_number << 6;
  217.  
  218.     // converte numero para codigo display de 7 segmentos
  219.     int the_display_code[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
  220.  
  221.  
  222.     // converte VALUE_L e VALUE_H em VALOR
  223.     THE_DISP_VALUE = VALUE_L;
  224.  
  225.     // tem um 1 no primeiro bit (+256)
  226.     if ((VALUE_H & 0x01) != 0) {
  227.         THE_DISP_VALUE += 256;
  228.     }
  229.  
  230.     // tem um 1 no segundo bit (+512)
  231.     if ((VALUE_H & 0x02) != 0) {
  232.         THE_DISP_VALUE += 512;
  233.     }
  234.  
  235.     THE_DISP_VALUE = THE_DISP_VALUE * 5000 / 1023;
  236.  
  237.     int the_value;
  238.  
  239.     switch(the_display_number) {
  240.         case 0:
  241.             // display mais a esquerda
  242.             the_value = (THE_DISP_VALUE / 1000);
  243.             break;
  244.  
  245.         case 1:
  246.             the_value = (THE_DISP_VALUE / 100) % 10;
  247.             break;
  248.  
  249.         case 2:
  250.             the_value = (THE_DISP_VALUE / 10) % 10;
  251.             break;
  252.  
  253.         case 3:
  254.             // display mais a direita
  255.             the_value = (THE_DISP_VALUE % 10);
  256.             break;
  257.  
  258.         default:
  259.             the_value = 0;
  260.             break;
  261.     }
  262.  
  263.     PORTC = the_display_code[the_value];
  264. }
  265.  
  266.  
  267.  
  268. // ficheiro asm: calc.s
  269. #include <avr/io.h>
  270.  
  271. .global func_voltage_calc
  272.  
  273. .extern NO_SAMPLES
  274. .extern COUNT_SAMPLES
  275. .extern VALUE_H
  276. .extern VALUE_L
  277. .extern AVG_L
  278. .extern AVG_H
  279.  
  280.  
  281.  
  282. func_voltage_calc:
  283.     // grava os valores que estavam anteriormente nestes registos
  284.     push r17
  285.     push r18
  286.     push r19
  287.     push r20
  288.     push r21   
  289.     push r22
  290.     push r23
  291.  
  292.     // carrega variaveis
  293.     lds r17, AVG_L
  294.     lds r18, AVG_H
  295.  
  296.     lds r19, ADCL
  297.     lds r20, ADCH
  298.  
  299.     // soma as varias amostras
  300.     add r17, r19
  301.     adc r18, r20
  302.  
  303.     lds r22, NO_SAMPLES
  304.  
  305.     cpi r22, 1
  306.  
  307.     breq reset
  308.  
  309.     // mais uma amostra
  310.     lds r21, COUNT_SAMPLES
  311.     inc r21
  312.  
  313.     cp r21, r22
  314.  
  315.     BRLO exit
  316.     // se for igual, executar este codigo
  317.     // faz a media
  318.     mov r23, r22
  319.  
  320.  
  321. reset:
  322.     // copia para outra variavel
  323.     sts VALUE_H, r18
  324.     sts VALUE_L, r17
  325.  
  326.     ldi r21, 0
  327.     ldi r17, 0
  328.     ldi r18, 0
  329.  
  330.  
  331. exit:
  332.     sts AVG_H, r18
  333.     sts AVG_L, r17
  334.     sts COUNT_SAMPLES, r21
  335.  
  336.     // repoe os valores nos registos
  337.     pop r23
  338.     pop r22
  339.     pop r21
  340.     pop r20
  341.     pop r19
  342.     pop r18
  343.     pop r17
  344. ret
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement