Op 29 november 2005 13:55:07 schreef RES:
Is er geen PIC met een fast PWM aan boord?
Een AVR kan bijv. een PWM van 250kHz eruit gooien met de fast PWM functie, zou toch denken dat er ook een PIC is die dit aan boord heeft?
Het probleem is niet fast PWM, maar slow PWM. Je kan er geen 10Hz uitgooien , 250 kHz kan weer wel.
RES
RES
Misschien is dit te omzeilen door de xtal heel laag te kiezen, zeg 100kHz zodat de hele processor heel traag gaat werken.
Mits er een minimum aan clocksnelheid staat vermeld in de datasheet, dan houdt het op.
Ik kom nog 2 problemen tegen:
1: Ik heb een Inverse AD waarde nodig.
Nu loop de waarde op als de ingangs spanning stijgt.
0...5 volt = 0...255 moet worden 255...0
Ik kan dit natuurlijk berekenen 255 - X = Waarde.
Maar hoe kan ik een 8 bits getal makkelijk aftrekken ?
2: Hoe lang duurt een AD Conversie ?
Dit kan ik met MPLAB niet bepalen, omdat deze niet met
analoge waardes kan werken (is mij verteld).
Ik start de AD conversie, en wacht tot deze klaar is.
Deze tijd is belangrijk, omdat de uitgangs freq.
niet verstoord mag worden.
Wie kan hier iets over vertellen ?
Edit:
Gegevens:
Xtal: 4 Mhz
Fosc/32
PIC16F876A
Ben alweer een stukje verder, en zit met het volgende probleem.
Het programma ziet er nu zo uit:
-AD Converter starten, Spanning -> getal 0...255
-Wachten tot AD Converter klaar is.
-Bereken 255 - AD waarde = Nieuwe waarde
-Uitgang Setten
-Waarde afhankelijk een x aantal keer een wacht routine doorlopen
-Uitgang Resetten
-Waarde afhankelijk een x aantal keer een wacht routine doorlopen
-Terug naar 1e regel
Hiermee krijg ik een uitgangs freq. van 16...2174 Hz.
Dit werkt helaas heel erg logeritmische
0V = 16,1 Hz.
5V = 31 Hz.
10V = 2174 Hz.
Hoe kan ik dit beter liniaar krijgen ?
Omdat ik niet zo gelukkig was met de vorige oplossing,
ziet het programma er nu zo uit:
-Timer2 genereerd elke 125us een interrupt
-AD Converter starten, Spanning -> getal 0...255
-Wachten tot AD Converter klaar is.
-Bereken 255 - AD waarde = Nieuwe waarde
Interrupt afhandeling:
-Teller verhogen met 1
-Vergelijk: AD waarde <= Teller
-Teller is gelijk of hoger: Uitgang toestand wijzigen, en
teller op 0 zetten (einde Interrupt)
-Teller is lager: Einde Interrupt
Dit werkt prima, er is nu een uitgangs Freq. van 16...4000Hz
Helaas werkt deze opzet niet Liniaar !
AD Waarde Freq.
0 4000
5 800
10 400
20 200
64 63
128 31
255 16
Hoe kan ik dit (beter) Liniaar krijgen ?
RES
RES
4000 / 256 is denk ik de enige manier om het linear te krijgen, want elk stapje is dan exact 15 5/8 Hz.
Denk eerst de nieuwe frekwentie laten berekenen en dan pas uitsturen. (bij verderdraaien stopt de uitgang met uitsturen heel even.)
Hier wordt een fundamenteel foutje gemaakt: Linear in tijd is niet linear in frequentie P = 1 / F.
En de periode is wat je programmeert in een timer !!!
RES
RES
Op 1 december 2005 16:44:59 schreef JoWi:
Hier wordt een fundamenteel foutje gemaakt: Linear in tijd is niet linear in frequentie P = 1 / F.
En de periode is wat je programmeert in een timer !!!
Dat klopt.
100Hz T=10msec
200Hz T=5msec
300Hz T=3.33msec
Anders een tabel maken met 256 T getallen en daar doorheen lopen, met dat getal telkens de timer presetten.
Ik voorzie 2 problemen:
Een tabel moet toch in de zelfde memory deel staan, als ik mij niet vergis, dan zijn dat telkens delen van 256 Bytes
Dus dan moet wel heel erg precies gebeuren.
Graag had ik hier iets meer info over.
Het uitgangs signaal mag zeer zeker niet haperen, dit moet te alle tijden zo vloeiend mogelijk blijven.
Door nu plotseling de timer te presetten (dat is toch opnieuw starten ?) kan dit signaal naar mijn mening even raar gaan doen...
RES
RES
Die presets zijn ten eerste halve tijden, dus T/2, want na T/2 moet je de pin omschakelen. Dan nog een keer T/2 laten wegticken. (interrupt op T/2 kan ook nog.)
0 = 0 (off) (0V) niks doen.
Als je begint bij 15Hz en telkens verdubbelt kom je uit op 3825 Hz. (15 Hz - 3825 Hz)
15Hz -> T/2 = 33.3 msec
30Hz -> T/2 = 16.6 msec
45Hz -> T/2 = 11.1 msec
60Hz -> T/2 = 8.3 msec
75Hz -> T/2 = 6.6 msec
etc
Totaal 255 getallen (zonder de 0)
Eigenlijk is de formule.
f = 1/T -> T = 1/f dus T/2 = (1/f)/2 = 1/2f.
Het is telkens 1 / 2x de frekwentie aan msec.
Zo te zien kan het dus ook zonder tabel en laten berekenen om linear te verkrijgen. Anders met de hand die getallen berekenen en de overeenkomstige getallen in 255 presets.
Weet alleen niet of de timer opzelfde instelling kan blijven met die zwaai van 15 - 3825 Hz.
Ik heb net even gezocht naar de ILC-8038 maar kan zo snel niets vinden, heb je daar meer gegevens over ?
RES: Ik ga morgen een poging doen.
Ik krijg het nog niet voor elkaar...
Dit is wat ik nu heb, deze Code werkt alleen niet linear.
LIST P=16F876A ;Processor type
include <P16F876A.INC> ;Register en poort definities
include "if_then.inc" ;Vergelijk functie's
__CONFIG B'11111101111001'
Cntr1 EQU 0x20 ;
BACKUP_S EQU 0x21 ;Backup van Status Register
AD_W EQU 0x22 ;
Register_1 EQU 0x23 ;
Register_2 EQU 0x24 ;
BACKUP_W EQU 0x25 ;Backup van W-Register
;** Start adressen *************************************************************
ORG 00h ;Start adres (Eerste instructie op deze locatie)
GOTO INIT ;Reset: 'Start regel'
NOP ;
NOP ;
NOP ;
GOTO INTERR ;Interrupt opgetreden -> Ga naar INTERR
;** Initalisatie ***************************************************************
INIT BCF STATUS,RP0 ;Select Bank 0
MOVLW B'00000000' ;Reset
MOVWF PORTA ;-PORTA
MOVWF PORTB ;-PORTB
MOVWF PORTC ;-PORTC
MOVWF STATUS ;-STATUS
BSF STATUS,RP0 ;Select Bank 1
MOVLW B'11111111' ;
MOVWF TRISA ;A Ingangen
MOVLW B'00000000' ;
MOVWF TRISB ;B Uitgangen
MOVLW B'00000000' ;
MOVWF TRISC ;C Uitgangen
;Analoge comperators instellen
MOVLW B'00000111' ;Bits naar tijdelijk register
MOVWF CMCON ;Comparators uitschakelen
;A/D Convertor instellen
BCF STATUS,RP0 ;Select Bank 0
MOVLW B'10000001' ;
MOVWF ADCON0 ;...
BSF STATUS,RP0 ;Select Bank 1
MOVLW B'00001110' ;Gemiddelde snelheid
MOVWF ADCON1 ;...
BCF STATUS,RP0 ;Select Bank 0
;Fosc/32
;AN0 = Analoog
;AN1...AN7 = Digitaal
;Hoge bits laten vervallen
CLRF T2CON ;Stop Timer2, Prescaler = 1:1, Postscaler = 1:1
CLRF TMR2 ;Clear Timer2 register
CLRF INTCON ;Disable interrupts
BSF STATUS,RP0 ;Select BANK1
CLRF PIE1 ;Disable peripheral interrupts
BCF STATUS,RP0 ;Select BANK0
CLRF PIR1 ;Clear peripheral interrupts Flags
;Configure timer 2 to generate a 50 Hz
;interrupt:
;CLK/4 = 1.000.000 Hz
;Prescaler 1:4 = 1.000.000 Hz
;PR2 value 125 = 8.000 Hz
;Postscaler 1:1 = 8.000 Hz
movlw b'00000000' ;Prescaler= 1:1, Postscaler 1:1
movwf T2CON ;Timer2 is off
bsf STATUS,RP0 ;Select BANK1
movlw .124 ;Timer 2, Counts to 125 (0..124) (Lager getal is sneller)
movwf PR2 ;
bsf PIE1,TMR2IE ;Timer 2, Interrupt on
bcf STATUS,RP0 ;Select BANK0
bsf INTCON,PEIE ;Pheriperal interrupts enabled
bsf INTCON,GIE ;Global interrupts enabled
bsf T2CON, TMR2ON ;Timer2 starts to increment
BSF INTCON,7 ;Interrupt toestaan
GOTO MAIN ;
;** Hoofd Programma ************************************************************
MAIN CALL AD_1 ;
GOTO MAIN
;** AD Convertor ***************************************************************
AD_1 ;1e Potmeter stand inlezen
BSF ADCON0,2 ;A/D Converter starten
;Wacht totdat AD Convertor klaar is
M1 BTFSC ADCON0,2 ;AD Convertor klaar ?
GOTO M1 ;Nee
NOP ;Ja
;255 - AD_Waarde = Waarde
MOVLW D'255' ;
MOVWF Register_1 ;
MOVFW ADRESH ;Waarde Uitlezen (in hoog adres)
MOVWF Register_2 ;
movf Register_2, w ;
subwf Register_1, w ;
MOVWF AD_W ;Getal opslaan
Return
;** Interrupt Afhandeling ****************************************************
;Deze Routine wordt 8000x per Sec opgeroepen
INTERR MOVWF BACKUP_W ;W-Reg bewaren
movf STATUS,W ;
movwf BACKUP_S ;
bcf STATUS, RP0 ; Select bank 0
bcf STATUS, RP1
BCF INTCON,2 ;Disable Intterrupt TMR0
bcf PIR1, TMR2IF ; Clr Timer2 interrupt
;------------------begin---------------------------
INCF Cntr1,F ;Teller verhogen (+1)
IRGEQRT Cntr1,AD_W ;<=
Goto Wissel
Goto IntEnd
Wissel ClrF Cntr1 ;Counter = 0
BTFSS PORTC,2 ;Uitgang Laag ?
GOTO L_H ;Ja
BTFSC PORTC,2 ;Uitgang Hoog ?
GOTO H_L ;Ja
;
L_H BSF PORTC,2 ;Setten
GOTO IntEnd ;Einde Interrupt Routine
H_L BCF PORTC,2 ;Resetten
GOTO IntEnd ;Einde Interrupt Routine
;-------------------end----------------------------
IntEnd movf BACKUP_W,w ;Restore W and STATUS
movwf BACKUP_S
swapf BACKUP_W,F
swapf BACKUP_W,W
RETFIE
;** einde van het programma ****************************************************
END
Opmerking:
IRGEQRT is een Vergelijk Macro ( <= )
Zie http://home.versatel.nl/edithenwilliam/william.htm
Sorry dat ik wat laat ben met reply.
http://www.williamson-labs.com/images/v-f-v.gif
Is een soort functiegenerator maar erg gevoelig.
met een beetje spelen met een spanningsdeler aan de ingang
moet je er best het gewenste uitkrijgen. Als je in de AVR wil weten wat er gebeurd kun je analoog de spanning inlezen of via een interrupt en timer de blokgolf die eruit komt of beide als je de chip wil controleren LOL
Zo'n oude XR2206 kan mischien ook al helpen.
Lucy: Bedankt, deze houdt ik even in het achterhoofd.
Ik probeer eerst nog even om dit in een PIC voor elkaar te krijgen (hopelijk met een beetje hulp hier
)
Het is voor mij ook een uitdaging omdat ik pas met PICs begonnen ben...
Op 26 november 2005 17:59:27 schreef JoWi:
[...]Jawel, dat is mogelijk.
Is het ook mogelijk om de verhouding linear te krijgen ?
Zoja: Hoe ?
RES
RES
Als 15Hz de stapgrootte is betekent dit telkens 15Hz hoger in frekwentie, dan is het linear.
Je krijgt dus 10V / 255 stapjes, dus elke 39.2mV zal de frekwentie 15Hz hoger worden.
Alleen de input loopt van 0V t/m 5V ADC gaat van, dus 5V / 255 = 19.6 mV, dus elke 19.6mV zal de frekwentie met 15Hz opgehoogt moeten worden.
Bij 0V = 0 (pin laag houden)
Bij 19.6mV moet er 15Hz vanaf komen, dus T = 66.7 msec
Bij 39.2mV moet er 30Hz vanaf komen, dus T = 33.3 msec
Bij 58.8mV moet er 45Hz vanaf komen, dus T = 22.2 msec
Bij 78.4mV moet er 60Hz vanaf komen, dus T = 16.7 msec
etc.
Je ziet dat de periodetijd niet linear verloopt, je ziet wel dat de spanning telkens 19.6mV ophoogt.
Als het goed is staat er in de datasheet een formule bij de ADC om een overeenkomstig getal uit de aangeboden spanning te halen.
ADC = (Vin * 1024)/ Vref.
Ik weet niet wat jouw referentiespanning is, ik neem aan 5V. (of 2.56V?)
ADC (15Hz) = (19.6mV * 1024) / 5V = 4 = 0b00000100
ADC (30Hz) = (2 * 19.6mV * 1024) / 5V = 8 = 0b00001000
etc.
Dit zijn afgeronde getallen.
Dus telkens 4 erbij optellen. 255 * 4 = 1020, dus dat klopt, want 0 was niks, dus geen 256, maar 255 stapjes.
Dus telkens als de ADC 4 hoger of 4 lager wordt moet je de periodetijd opnieuw laten berekenen (aanpassen), of uit een tabel halen (nieuwe timer laden, of zelf stukje code schrijven ipv de timer gebruiken.) en dan delen door 2 en daarop de pin schakelen, dan genereert ie f.
Be continued...
>Ik weet niet wat jouw referentiespanning is, ik neem aan 5V. (of 2.56V?)
Deze is 5 Volt.
Ik ga vannavond een poging doe om de Code om te bouwen...
Probeer dat maar niet, want dat gaat niet werken.
Het probleem is dat die tijd dus zo alinear is als je maar kunt bedenken. Het ziet er leuk uit voor 15/30/45 en 60 Hz.
Maar voor 4000 Hz, en bijvoorbeeld bij 3850Hz ? Voor 3850 Hz is de tijd bijvoorbeeld 0.25974 milliseconden. En je kan nooit 15.6 milliseconden (is trouwens 15.66666) en bovengenoemd getal uit een timer krijgen.
Wat als je later 10 bit A/D wilt gebruiken ?
Het magische woord is trouwens al genoemd door DC2PCC: Een DDS gebruiken. Dat kan met een extern chippie zoals hij zegt, maar voor lage frequenties kan je het ook met software doen.
RES
RES
Bij 3850Hz is de periodtijd 259.74 usec.
Ik weet niet hoe het zit bij de PIC, maar de AVR bijv. (ATtiny2313) kan de timer (op ck) op 50 nsec laten ticken, met een 20MHz xtal.
Ik weet niet wat een PIC doet op 20MHz? Was het niet 4x delen in verhouding tot een AVR? Dan nog altijd 200 nsec per tick.
259.74 usec / 200 nsec = 1298 ticks, dus je kan nog heel wat instructies uitvoeren.
PS. er blijft wel een probleem, dat is de snelheid van de ADC, die moet onder de 129usec liggen, om het zo snel om te zetten dat de frekwentie direct reageert op de spanningsverandering.
[Bericht gewijzigd door RES op ]
JoWi: Dus als ik het goed begrijp is dit niet mogelijk met alleen één PIC ?
RES: Ik heb geen idee hoeveel tijd de ADC nodig heeft.
RES
RES
Nu ik er nog eens over nadenk, moet direct invloedbaar volgens mij wel mogelijk zijn, maar dan alleen met de PWM/timer functie (alleen kon die bij de PIC niet zeg 10Hz aan, dus lage frekwenties. Bij de AVR weet ik dit nog niet.), aangezien die onder het samplen van de ADC blijft doordraaien.
Ik zal eens kijken of het met een AVR wel lukt, dan kan ik vertellen hoe ik het heb gedaan, zou voor een PIC dan ook moeten kunnen lijkt mij.