Página 1 de 1

Gerar 60Hz com cristal de 8MHz?

MensagemEnviado: 11 Ago 2009 00:29
por zazulak
Olá pessoal,

estou tentando bolar um inversor simples de onda quadrada, em meia ponte. Um conversor DC-DC fornecerá +180 e -180V (valor de pico de uma rede de 127VAC), e o chaveamento será feito por um par de FETs. A largura de pulso será fixa, controlada via contagens do timer0 + uma rotina de interrupção, sem controle PWM.

Aí é que entra a dúvida: Se usar um cristal de 4 ou 8MHz, ou mesmo o clock RC interno, o valor não é multiplo dos 60Hz.. a divisão dá um numero quebrado. Mas, a maioria dos nobreaks comuns que vejo usam cristais dessas frequencias, ou de outras que não são diretamente multiplas de 60.

Resumindo: Qual artificio costuma-se usar para gerar esta base de tempo com uma precisão aceitável?

ps. o micro usado é o ATMEGA8.

MensagemEnviado: 11 Ago 2009 01:26
por Djalma Toledo Rodrigues
Diversos
Pode carregar um valor no Timer, de modo que a contagem sera menor.
(Ver Datasheet do Contador Programável HFE4059B Div por N)
Pode incluir Instruções NOP
.

MensagemEnviado: 11 Ago 2009 01:58
por msamsoniuk
mas vc precisa mesmo de tanta precisao? 8MHz dividido por 133333 inteiro jah dah 60.000Hz. o erro na verdade eh de 150x10^-6Hz, algo em torno de 1Hz extra a cada 2h e depois vc consegue ateh resolver isso facil! por exemplo, uma abordagem trivial seria usar 133333 por dois segundos e 133334 por um segundo, assim a cada 3 segundos a sua media eh 60Hz certinho. claro que isso depende da qualidade do seu oscilador e da precisao que vc quer... precisao perfeita soh se vc sincronizar com a rede externa simulando por software um DPLL.

obviamente 133333 eh um divisor horrivel por si mesmo, ficando as duas unicas opcoes possiveis:

- timer com valor 883 sem prescaler (9060Hz) e contador por software com valor 151
- timer com valor 151 sem prescaler (52980Hz) e contador por software com valor 883

se vc fosse gerar um pulse shape de 60Hz, vc conseguiria apenas 151 amostras no primeiro caso e 883 no segundo caso, com DAs de 8 e 10 bits, respectivamente. o segundo caso teria qualidade maior, mas seria computacionalmente pesado para um mcu de 8 bits.

e para trabalhar com 133334, teria que trocar o par 151x883 pelo par 163x818 ou calcular algum outro mecanismo de compensacao dinamica :)

MensagemEnviado: 11 Ago 2009 10:38
por Djalma Toledo Rodrigues
Outra opção seria encomendar Cistal multiplo de 60 Hz .

É barato o xtal, e a sobretom aqui do rio faz.

http://www.sobretom.com.br/
.

MensagemEnviado: 20 Ago 2009 21:11
por zazulak
Buenas,

obrigado pelas dicas, pessoal. Pesquisando nos esquemas de alguns nobreaks, descobri um modelo da NHS que usa cristal de 3.072MHz, e que este cristal não é dos mais difíceis de obter. Quando conseguir adquirir um ATMega8 'de verdade' (por enquanto, só simulação no Proteus), farei o primeiro protótipo com este cristal.

Informação inútil.. tenho visto que a preferência dos fabricantes por uma ou outra família de uC muda ao longo do tempo. Por exemplo:

Os NHS começaram com a linha 51 Atmel, depois passaram aos PIC, e atualmente usam 68HC.

SMS, iniciaram com ST62, depois AVR por pouco tempo e depois passaram pros PIC. Os AVR ainda são usados em alguns modelos de grande porte.

APC, os modelos clássicos usam 87C51, os mais novos (pelo menos os feitos para o mercado brasileiro), PIC.

Engetron, geralmente usam um microprocessador National (não é COP8, é processador mesmo), com eprom e ram externa.

TS-Shara, aparentemente nunca saíram dos 68HC, desde o tempo em que ainda era Motorola.

Powerware/Invensys/Eaton, igualmente parecem ter preferência por 68HC.


Se existe algum que usa Holtek, nunca vi...

MensagemEnviado: 20 Ago 2009 21:17
por proex
Bom, tem um fabricante ai que usava PIC, Atmel e 8051.

Agora usa ARM, não sei quem fiz !! :lol:

Bom, eu faço gerador de 60Hz com qualquer valor de cristal, isso na realidade não importa.

O problema é que vc esta usando ATMEGA, e eu não mexo com isso.
Não saberia te explicar.

.

MensagemEnviado: 20 Ago 2009 21:25
por zazulak
Não seria por acaso uma tal de CS?

É, uma opção seria fazer uma rotina que a cada tantos ciclos, compensa o erro aumentando ou diminuindo em 1 o valor da contagem, como o pessoal sugeriu. Aliás, terei que usar este recurso, mesmo com cristal multiplo: Na hora de sincronizar com a rede, o inversor dará uma levíssima 'acelerada', até que a passagem por zero coincida.

ARM nunca vi pessoalmente em nobreak. É fácil achar por aí este uC em invólucro DIP??


ps. Você não é o mesmo que, nos idos tempos das conversas via ICQ, usava o nick "PIC a pau"?

MensagemEnviado: 07 Nov 2009 03:28
por Jozias del Rios
Bom, eu costumo implementar um low-cost, low-overhead Real Time Clock nos AVR8 através do código abaixo que desenvolvi faz um tempo. Estou supondo que o AVR ATMEGA8 esteja rodando a 8MHz e disso consigo extrair 1Hz, mas a princípio qualquer frequencia de entrada poderia ser usada...

Obs:
ml = r14
al = r16
ah = r17
ol = r2 = 0x00 constante
oh = r3 = 0xFF constante



Configuração:

Código: Selecionar todos
.dseg
TimerError:     .byte 2

rtc:
rtcSecond:      .byte 1
rtcMinute:      .byte 1
rtcHour:        .byte 1
rtcDay:         .byte 1
rtcMonth:       .byte 1
rtcYear:        .byte 1

.cseg
MonthTable:
    .db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    ;   jan fev mar apr may jun jul aug sep oct nov dec


rtcSetup:

    ;]-- set initial value of DDA (Digital Differential Analyzer)
    sts TimerError+1, oh

    ;]-- setup timer0 interrupt for 128us periods increment (7.8125kHz)
    ldi al, (1 << CS02)|(1 << CS00)
    out TCCR0, al

    ret


Interrupção OVF0:

Código: Selecionar todos
TimerHandler:

; This handler is called at ~30.5 Hz (32768us)
; We pursuit 1Hz with a zero-error Bresenham DDA algorithm
;
; Dx = 15625            Dy = 15625 * 0.032768 = 512
; 2*(Dx-Dy) = 30226     2*Dy = 1024
;
; For each interrupt...
;    if Error > 0
;       Error -= 30226
;       and execute RTC code to update to next second
;    else
;       Error += 1024

    push ml

    push al
    push ah
       
    push xl
    push xh

    push yl
    push yh

        in ml, SREG
       
        ;]-- each 32768us here.
       
        ;]-- check the TimerError signal
        lds yh, TimerError+1
        tst yh
        brpl th_ddaPositive
           
            ;]-- TimerError negative, add 1024 to it and exit
            subi yh, high(-1024)
            sts TimerError+1, yh
            rjmp th_ddaDone
       
        th_ddaPositive:
           
            ;]-- TimerError positive, subtract 30226 from it and update RTC

            ;]--- read complete error value
            lds yl, TimerError+0
           
            ;]--- add 30226
            subi yl, low(30226)
            sbci yh, high(30226)
           
            ;]--- store it back
            sts TimerError+0, yl
            sts TimerError+1, yh
           
            ;]-- each second here
         
            ;]--- setup RTC data structure pointer
            ldi yl, low(rtc)
            ldi yh, high(rtc)
           
            ;]-- update seconds...
            ldi ah, 60
            rcall th_calendar
            brcs th_rtcDone

            ;]-- update minutes
            rcall th_calendar
            brcs th_rtcDone
           
            ;]-- update hours
            ldi bl, 24
            rcall th_calendar
            brcs th_rtcDone
           
            ;]-- update day, check for leap year
            push zl
            push zh

                ;]-- get number of days of current month
                ldi zl, low(MonthTable<<1)
                ldi zh, high(MonthTable<<1)
   
                lds al, rtcMonth

                add zl, al
                adc zh, ol
               
                lpm ah, z
               
                ;]-- if month is february(=1) and (year&3)!=0, then add 1
                cpi al, 1
                brne th_notLeapYear
               
                    lds al, rtcYear
                    andi al, 0x03
                    brne th_notLeapYear

                        ;]-- february and leap year, has 29 days
                        inc ah
                       
                th_notLeapYear:
               
            pop zh
            pop zl
               
            rcall th_calendar
            brcs th_rtcDone
           
            ;]-- month update
            ldi ah, 12
            rcall th_calendar
            brcs th_rtcDone
           
            ;]-- year update
            ldi ah, 100
            rcall th_calendar
       
            th_rtcDone:
           
        th_ddaDone:
       
        out SREG, ml
       
        pop yh
        pop yl
       
        pop xh
        pop xl

        pop ah
        pop al
    pop ml
    reti
       
    ;]-- calendar sub-function of timer interrupt handler.
    ;]-- it updates a field of the calendar.
   
    th_calendar:
        ;]-- load calendar field value
        ld al, y
       
        ;]-- increment value
        inc al
       
        ;]-- store it back
        st y, al
       
        ;]-- set carry flag...
        sec
       
        ;]-- return if the calendar field has'nt reached its maximum value
        cpse al, ah
            ret
           
        ;]-- or else, store zero and return carry clear
        st y+, ol
        clc
        ret
       


É isso aí. Tem teoria matemática envolvida bem interessante. Os segundos não tem todos a mesma duração, alguns durarão 0,98304s (30 interrupções) e outros durarão 1,015808s (31 interrupções). Mas na média você terá o tempo correto.

A solução que eu dei usa o TIMER0 do Atmega, que não tem funcionalidade CTC (Clear Timer on Compare Match) como é o caso do TIMER1A/B e do TIMER2. Este último é o mais indicado para a função de RTC, mas como eu trabalho com ATMEGA8 que tem poucos pinos, se não há cristal ganha-se 2 pinos para GPIO.

Se alguém implementar isso e achar um bug, dê um feedback!