Ik ben benieuwd of dat met een AVR lukt.
Ik ben nog niet zolang met PIC's bezig, en kies nu niet het meest makkelijk project geloof ik...
RES
RES
Op 4 december 2005 19:48:13 schreef MMSoft:
Ik ben benieuwd of dat met een AVR lukt.Ik ben nog niet zolang met PIC's bezig, en kies nu niet het meest makkelijk project geloof ik...

Ja klopt, meestal klinkt het simpel, en dan kom je erachter dat het toch pittig is om werkend te krijgen.
Op 4 december 2005 18:57:21 schreef MMSoft:
JoWi: Dus als ik het goed begrijp is dit niet mogelijk met alleen één PIC ?
Nee, dat heb ik niet gezegd. Ik zei:
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.
Alleen haal je met die hardware chips 100 MegaHertz en hoger als klok en en mag je blij zijn als je met software boven de enkele honderden kiloHertz komt.
Een timerloop met variabele delay (al dan niet met hardware en software) is leuk voor een bepaalde frequentie, maar een ramp als je een mooi verloopt wilt. Maar daar komt RES nog wel achter als ie het probeert te maken op zijn AVR 
Je moet dus een DDS, dat is een Direct Digital Synthesizer, maken. Zo'n ding bestaat uit een klok, een opteller (voor de faze van je signaal, een sinus ROM (voor de sinus, maar kan ook een driehoek, of zaagtand of welke golfvorm zijn) en een D/A converter.
Aangezien je een blokgolf wilt kan je de sinus tabel eruit gooien. En omdat je gewoon een binair signaal wilt ook de DA converter. Blijft dus over een klok en een opteller.
Voor de klok gebruik je dus een timer, voor het optellen wat registers en de ADD instructie. Om de output hoog of laag te maken kijk je of de faze groter of kleiner dan 180 graden is. (Dus de helft hoog en de helft laag).
Dat is dus alles. Het onderstaande is een 16 bit software DDS die je kan gebruiken om een blokgolf van 0 tot een paar kiloHertz te maken. Theoretisch gaat deze tot 32 kHz maar dat moet je niet proberen ivm fazeruis en alias frequenties. Wat dat is moet je maar opzoeken op het net. Praktisch kan je dit ding gebruiken tot een paar kiloHertz.
Het programma is voor een 16F819 maar werkt op elke 16F pic met TMR2 aan boord (zoals de 16F628, 16F876 etc.) Je specificeert de frequentie in Hz en hij draait in de achtergrond (op de timer interrupt). Het kristal moet 10 MHz zijn, dan klopt de waarde in het getal ongeveer met de frequentie. (Eigenlijk is de frequentie 1.003867701 maal het getal, dus bij het getal 4000 doet ie 4015 Hz). Je kan dus ook de frequentie in stapjes van 1 Hz instellen.
; SOFTDDS.ASM
; Current Version: 0.00
;
; Experiment with a PIC based software DDS generator
; Stripped for square waves only !!!!!!!!!!!!!!!!!!!
;
LIST P=16F819
ERRORLEVEL -302
include <p16f819.inc>
__config _CP_OFF & _WDT_OFF & _HS_OSC & _LVP_OFF
CBLOCK 0x20
DDSFlags ; various flag bits,see defines below
PhaseRegLo,PhaseRegHi ; phase reg lo & hi
PhaseIncLo,PhaseIncHi ; phase inc lo * hi
PhaseIncLoN,PhaseIncHiN ; New phase inc lo & hi
ENDC
; Some allocations in "shared" memory
temp_S equ 0x7F
temp_W equ 0x7E
#define DDS_NEWFREQ DDSFlags,1 ; Load a new FREQ
#define DDSOUTPUT PORTB,3 ; Here we get the output signal
; Each step is 1.0038677 Hz, round to 1 Hz
#define FREQUENTIE .1000 ; Frequentie in Hz (1003.87 Hz)
ORG 0
RESET goto Init ; Restart vector
ORG 4
INTERRUPT movwf temp_W ; Interrupt vector
swapf STATUS,W ; Save W and STATUS
movwf temp_S
bcf STATUS,RP0 ; ensure bank 0
bcf PIR1,TMR2IF ; Clr Timer2 interrupt
btfss DDS_NEWFREQ ; Should we load a new frequency ?
goto inc_phase ; No, increment phase
movfw PhaseIncLoN ; Yes, Load the new frequency
movwf PhaseIncLo
movfw PhaseIncHiN
movwf PhaseIncHi
bcf DDS_NEWFREQ
inc_phase movfw PhaseIncLo
addwf PhaseRegLo,F
skpnc
incf PhaseRegHi,F
movfw PhaseIncHi
addwf PhaseRegHi,F
btfss PhaseRegHi,7 ; 50 % low, 50 % high
bcf DDSOUTPUT
btfsc PhaseRegHi,7
bsf DDSOUTPUT
IntDone swapf temp_S,W ; Restore registers
movwf STATUS
swapf temp_W,F
swapf temp_W,W
retfie
Init clrf PIR1 ; reset perif int
clrf T2CON ; Stop Timer2, Prescaler = 1:1, Postscaler = 1:1
bsf STATUS,RP0 ; BANK1
movlw b'11110000' ; port B in/outputs
movwf TRISB
movlw .37 ; DDSclock (65.789 kHz @ 10 MHz)
movwf PR2 ; Set period for DDS
bsf PIE1,TMR2IE ; Timer 2 interrupt enabled
bcf STATUS,RP0 ; BANK0
bsf INTCON,PEIE ; Pheriperal interrupts enabled
bsf INTCON,GIE ; Global interrupts enabled
bsf T2CON, TMR2ON ; Timer2 starts to increment
movlw low FREQUENTIE ; Load frequency
movwf PhaseIncLoN
movlw high FREQUENTIE
movwf PhaseIncHiN
bsf DDS_NEWFREQ
btfsc DDS_NEWFREQ ; Wait until frequency is latched
goto $-1 ; otherwise you get funny glitches
MAIN goto $ ; Main program, do nothing
end
Ziet er veel belovend uit !
Morgen een 10 Mhz kristal halen...
Hopelijk stoort de AD Converter deze DDS niet.
Op 4 december 2005 22:17:20 schreef MMSoft:
Ziet er veel belovend uit !
Morgen een 10 Mhz kristal halen...
Uh ? op 20 Mhz komt er gewoon 2* de frequentie uit, op 4 MHz de frequentie gedeeld door 2.5.
Hopelijk stoort de AD Converter deze DDS niet.
Misschien moet je je kennis qua ISRs (Interrupt Service Routines) maar eens bijspijkeren.
RES
RES
De AVR kan op max. 1MHz snelheid samplen (8bit)
Elke ADC conversie duurt 13 ck, dus 1/1MHz*13 = 13usec.
Dus een periodetijd van max. 26usec, dus een output frekwentie van max. 38.46kHz. Maar dit zal nog wat lager liggen, want er moeten nog wat instructies worden uitgevoerd. (pin omschakelen)
Voor de PIC zal dit denk ik komen op zeg 35kHz/4=8500Hz, dus het lijkt toch te kunnen. Weet alleen niet of de PIC zo snel kan converteren?
[Bericht gewijzigd door RES op ]
SOFTDDS: 1004 Hz, dat zit er goed uit !
Als ik de ADC heb toegevoegd, waaruit ik de 2 lage bits laat vervallen geeft dit een waarde van 0....255
Nu moet deze waarde omgezet worden in een Freq. waarde.
Ik denk eraan om deze in een Tabel te zetten, zouden jullie dat ook zo doen ?
Vraagje: 'FREQUENTIE .1000'
Is een groter getal dan een 8 bits getal, kan dat zo makkelijk worden opgesplitst in een Hoog en een Laag deel ?
Yep met high en low krijg het hoge en lage byte van een getal. Dat puntje staat trouwens voor "decimaal", vind ik leesbaarder als die andere constructies (met een D en quotes geloof ik). De default staat bij mij altijd op hexadecimaal.
Heb je een 10 MHz kristal ? In dat geval kan je het getal uit de AD met 16 vermenigvuldigen. Kom je aardig in de buurt van de 4000. (x16 kan je met swap,and en or instructies doen)
Kristal is 10 Mhz.
Hoe vermenigvuldig ik precies met swap, and en or
en dan ook nog eens met grotere getalen ?
Op 5 december 2005 22:15:01 schreef MMSoft:
Hoe vermenigvuldig ik precies met swap, and en or
en dan ook nog eens met grotere getalen ?
Wil je leren programmeren of alleen maar leren knippen en plakken ?? 
Je hebt een 8 bit getal b.v. 0x12 en na afloop wil je 16 keer dat getal. Dat past niet in 8bit dus heb je een 16 bit getal nodig (2bytes) 0x120, dus 0x01 in het ene en 0x20 in het ander byte. Dat is 16 keer het oorspronkelijke getal. D'r zijn meerdere manieren om dat te doen maar het kan met o.a. met 1 swap, 2 ands en 3 moves. OR is niet eens nodig.
Ik ga hier vanavond mee aan de slag...
De Freq. mag alleen wijzigen als de uitgang laag is !
Ook mogen er geen spikes ontstaan !
Dus de freq. moet geleidelijk wijzigen en altijd in een nul doorgang.
Werkt deze SOFTDDS code zo ?
Edit:
De ingangs spanning regelt heel geleidelijk.
[Bericht gewijzigd door MMSoft op ]
Dit heb ik er van gemaakt:
LIST P=16F876A ;Processor type
include <P16F876A.INC> ;Register en poort definities
include "if_then.inc" ;Vergelijk functie's
__CONFIG B'11111101111010'
DDSFlags EQU 0x20 ;various flag bits,see defines below
PhaseRegLo EQU 0x21 ;phase reg lo
PhaseRegHi EQU 0x22 ;phase reg hi
PhaseIncLo EQU 0x23 ;phase inc lo
PhaseIncHi EQU 0x24 ;phase inc hi
PhaseIncLoN EQU 0x25 ;New phase inc 'low'
PhaseIncHiN EQU 0x26 ;New phase inc 'Hi'
Cntr1 EQU 0x30 ;
Cntr2 EQU 0x31 ;
Cntr3 EQU 0x32 ;
Cnt EQU 0x33 ;
BACKUP_S EQU 0x34 ;
AD_W EQU 0x35 ;
D_Cntr1 EQU 0x36 ;
D_Cntr2 EQU 0x37 ;
D_Cntr3 EQU 0x38 ;
Bin EQU 0x39 ;
Bcd001 EQU 0x3A ;
Bcd010 EQU 0x3B ;
Bcd100 EQU 0x3C ;
AD_Waarde_N EQU 0x3D ;
Register_1 EQU 0x3E ;
Register_2 EQU 0x3F ;
BACKUP_W EQU 0x40 ;
AD_Waarde_O EQU 0x41 ;
Tyd EQU 0x42 ;
; Some allocations in "shared" memory
temp_S equ 0x7F
temp_W equ 0x7E
#Define DDS_NEWFREQ DDSFlags,1 ;Load a new FREQ
#Define DDSOUTPUT PORTB,3 ;Here we get the output signal
;Each step is 1.0038677 Hz, round to 1 Hz
#Define FREQUENTIE .1000 ;Frequentie in Hz (1003.87 Hz)
;** Start adressen *************************************************************
ORG 00h ;Start adres
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 PIR1 ;reset perif int
clrf T2CON ;Stop Timer2, Prescaler = 1:1, Postscaler = 1:1
bsf STATUS,RP0 ;BANK1
movlw b'11110000' ;port B in/outputs
movwf TRISB ;
movlw .37 ;DDSclock (65.789 kHz @ 10 MHz)
movwf PR2 ;Set period for DDS
bsf PIE1,TMR2IE ;Timer 2 interrupt enabled
bcf STATUS,RP0 ;BANK0
bsf INTCON,PEIE ;Pheriperal interrupts enabled
bsf INTCON,GIE ;Global interrupts enabled
bsf T2CON, TMR2ON ;Timer2 starts to increment
movlw low FREQUENTIE ;Load frequency
movwf PhaseIncLoN ;
movlw high FREQUENTIE ;
movwf PhaseIncHiN ;
bsf DDS_NEWFREQ ;
btfsc DDS_NEWFREQ ;Wait until frequency is latched
goto $-1 ;otherwise you get funny glitches
GOTO MAIN ;
;** Hoofd Programma ************************************************************
MAIN CALL AD_1 ;
;AD_1 waarde gewijzigd ? ;AD_1 waarde gewijzigd ?
IREQRT AD_Waarde_O,AD_Waarde_N ;Gewijzigd ?
GOTO MAIN ;Nee -> Geen actie
NOP ;JA -> Freq. wijzigen
;Bereken nieuwe Freq.
;AD Waarde * 16
MOVLW B'00001111' ;
ANDWF AD_W,W ;Alleen bits 0 t/m 3 van AD waarde
MOVWF Tyd ;
SWAPF Tyd,W ;Verwissel bits 0..3 met 4..7
MOVWF PhaseIncLoN ;Naar Lo Byte
MOVLW B'11110000' ;
ANDWF AD_W,W ;Alleen bits 4 t/m 7 van AD waarde
MOVWF PhaseIncHiN ;Naar Hi Byte
SWAPF PhaseIncHiN,W ;Verwissel bits 0..3 met 4..7
MOVWF PhaseIncHiN
BSF DDS_NEWFREQ ;Nieuwe Freq. aanwezig
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
MOVFW ADRESH ;Waarde Uitlezen (in hoog adres)
MOVWF AD_W ;Getal opslaan
MOVFW AD_Waarde_N ;
MOVWF AD_Waarde_O ;Oude waarde
MOVFW AD_W ;
MOVWF AD_Waarde_N ;Nieuwe waarde
Return
;** Interrupt Afhandeling ****************************************************
INTERR movwf temp_W ;Interrupt vector
swapf STATUS,W ;Save W and STATUS
movwf temp_S ;
bcf STATUS,RP0 ;ensure bank 0
bcf PIR1,TMR2IF ;Clr Timer2 interrupt
;Waarde <> 0 ?
IRNEQZT AD_Waarde_N ;AD Waarde <> 0
GOTO X1 ;<> 0
bcf DDSOUTPUT ;= 0
GOTO IntDone
X1 btfss DDS_NEWFREQ ;Should we load a new frequency ?
goto inc_phase ;No, increment phase
movfw PhaseIncLoN ;Yes, Load the new frequency
movwf PhaseIncLo ;
movfw PhaseIncHiN ;
movwf PhaseIncHi ;
bcf DDS_NEWFREQ ;
inc_phase movfw PhaseIncLo ;
addwf PhaseRegLo,F ;
skpnc ;
incf PhaseRegHi,F ;
movfw PhaseIncHi ;
addwf PhaseRegHi,F ;
btfss PhaseRegHi,7 ;50 % low, 50 % high
bcf DDSOUTPUT
btfsc PhaseRegHi,7 ;
bsf DDSOUTPUT ;
IntDone swapf temp_S,W ;Restore registers
movwf STATUS ;
swapf temp_W,F ;
swapf temp_W,W ;
retfie ;
;** einde van het programma ****************************************************
END
Ik ben benieuwd of het werkt, ga er zo de scoop bij pakken.
Edit:
Is en blijft 0 Hz. (continu laag signaal)
Ben al even naar de fout aan het zoeken geweest, maar heb deze nog niet gevonden.
Wie ziet de fout(en) ?
Edit:
Code is gewijzigd op 10-12-2005
free_electron
Silicon Member
Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM
Op 2 december 2005 00:42:01 schreef lucy:
is een ILC-8038 niet simpeler ?
dood en begraven.
Tja, je hebt helemaal gelijk !
Omdat ik pas met PICs begonnen ben, probeer ik nu alles met deze dingen op te lossen.
Ik heb het idee dat ik er nu ook bijna ben...
Als het met de PIC niet lukt, dan wordt het hoogst waarschijnlijk een ILC-8038 
Eindelijk tijd gehad om de fout te zoeken.
Het (1e) probleem zat in het configuratie word
Nadat deze gewijzigd had in:
__CONFIG B'11111101111010'
Werkt de code.
Helaas klopt de freq. nog niet:
0 Volt = 22 Hz
~ 2,5 v = 16666 Hz
5 v = 250 Hz
Wie ziet de fout ?
Op 9 december 2005 21:46:54 schreef MMSoft:
Wie ziet de fout ?
In ieder geval dit:
SWAPF W,W ;Verwissel bits 0..3 met 4..7
Ga maar eens in de simulator kijken wat er gebeurd.
En denk je dat dit voor jan doedel in de oorspronkelijke code zit ?
btfsc DDS_NEWFREQ ;Wait until frequency is latched
goto $-1 ;otherwise you get funny glitchesCode is nu gewijzigd !
Helaas werkt het nog niet goed...
Wie ziet er nog een fout ?
[Bericht gewijzigd door MMSoft op ]
Het werkt !
(Code is aangepast !)
De fout zat in het gedeelte: 'AD Waarde * 16'
Deze kan waarschijnlijk met minder instrukties !
Ook zit er nog een klein foutje in, als de ingangs spanning 0 volt wordt, dan moet de uitgang Laag zijn !
Deze blijft nu ook nog wel eens Hoog bij een ingangs waarde van 0 volt.
Edit:
Code gewijzigd, de uitgang is nu altijd Laag bij een ingangs spanning van 0 volt.
0v = 0 Hz (Laag)
>0v = 16,7 Hz
1,25v = 1020 Hz
2,5v = 2045 Hz
3,75v = 3065 Hz
5v = 4090 Hz
[Bericht gewijzigd door MMSoft op ]
Op 4 december 2005 19:23:23 schreef RES:
...zal eens kijken of het met een AVR wel lukt, dan kan ...
Lukt het met een AVR ?
Kan de code waar de AD waarde wordt vermenigvuldigd met 16 korter ?
Iedereen die meegedacht heeft Bedankt !
RES
RES
Op 12 december 2005 20:01:38 schreef MMSoft:
[...]Lukt het met een AVR ?Kan de code waar de AD waarde wordt vermenigvuldigd met 16 korter ?
Iedereen die meegedacht heeft Bedankt !
Een jaartje later... 
Weet iemand hoe ik die 0-10V om kan zetten naar 0-3.9V?
Ga hier weer even mee aan de slag.
Een jaartje later...
Weet iemand hoe ik die 0-10V om kan zetten naar 0-3.9V?
Ga hier weer even mee aan de slag.
Door de Vref ingangen te gebruiken.
Altans bij een PIC, of een AVR deze mogelijkheid ook heeft weet ik niet.
Edit:
De 0..10 volt wordt gedeeld, dit is nu niet nodig, het wordt dus 0...5 volt.
Als je nu bij 3.9 volt toch de maximale waarde wilt, dan verlaag je de boven grens (Vref+) van de DA converter.
[Bericht gewijzigd door MMSoft op ]
RES
RES
Op 18 januari 2007 19:06:24 schreef MMSoft:
[...]
Door de Vref ingangen te gebruiken.Altans bij een PIC, of een AVR deze mogelijkheid ook heeft weet ik niet.
Ja zit erop een Vref.
Edit:
De 0..10 volt wordt gedeeld, dit is nu niet nodig, het wordt dus 0...5 volt.
Als je nu bij 3.9 volt toch de maximale waarde wilt, dan verlaag je de boven grens (Vref+) van de DA converter.
Dus ik kan een potmeter aan die Vref hangen? Want ik wil exact 1000 zien te halen bij 3.9V. (geen 1024)
Weet ook niet of die 0-10V zo exact is? Stel het is 0-9.9V, dan wordt het bereik van 4000 Hz niet gehaald.
Dus ik kan een potmeter aan die Vref hangen? Want ik wil exact 1000 zien te halen bij 3.9V
Ik bedoel eigenlijk een vaste spanning van 3.9 volt op de Vref+ ingang.
Als je exact 1000 wilt halen, dan kan je waarschijnlijk het beste de waarde uit de ADC begrenzen op een bepaalde maximale waarde.
0....1024, begrenzen op bijvoorbeeld 1022.
IF waarde > 1022 then waarde = 1022.
[Bericht gewijzigd door MMSoft op ]
