Página 1 de 1
Gerar 60Hz com cristal de 8MHz?

Enviado:
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.

Enviado:
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
.

Enviado:
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


Enviado:
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/
.

Enviado:
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...

Enviado:
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 !!
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.
.

Enviado:
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"?

Enviado:
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!