Sinteza Directa Digitala
Cuprins
1. Introducere
1.1 Sintetizoare de frecvență
1.2 Ce este sinteza directă digitală?
1.3 Ce face dispozitivul?
1.4 Scopul principal al DDS
2. Fundamente teoretice
2.1 Partea Hardware
2.1.1 Schema bloc5
2.1.2 Funcționare a acumulatorului de fază într-un sintetizator digitală directă
2.2 Partea Software (Limbajul de asamblare)
2.2.1 Ce este limbajul de asamblare
2.2.2 Caracteristici
2.2.3 Asamblarea
2.2.4 Avantajele limbajului de asamblare
2.3 Partea Microcontrolere
2.3.1 Generalități
2.3.2 Utilizarea microcontrolerelor
3. Echipamente hardware folosite
3.1 AD9835
3.1.1 Descriere generală
3.1.2 Schema bloc de funcționare
3.1.3 Configurarea pinilor
3.1.4 Descrierea circuitului
3.1.5 Teoria de operare
3.1.6 Aplicații
3.2 Microcontrolerul PIC16F84A
3.2.1 Descriere generală, schema bloc
3.2.2 CISC, RISC
3.2.3 Aplicații
3.2.4 Ciclul instrucțiune
3.2.5 Pipelining
3.2.6 Semnificația pinilor
3.3 Encoder-ul optic
3.3.1 Descriere generală
3.3.2 Schema generală
3.4 Amplificatorul MAX4012
3.4.1 Descriere generală
3.4.2 Schema bloc
3.4.3 Despre MAX4012
3.4.4 Configurarea pinilor
3.5 Display-ul LCD 2×16
3.5.1 Descriere generală
3.5.2 Schema LCD
3.5.3 Configurarea pinilor
4. Proiectarea sistemului propus
4.1 Proiectarea Hardware-lui propus
4.2 Proiectarea Software-lui propus
5. Rezultate experimentale
6. Concluzi
7. Bibliografie
8. Anexa
8.1 Anexa 1 Schema DDS
8.2 Anexa 2 Cod sursă
Introducere
Sintetizoare de frecvență
Un sintetizor de frecvență este definit ca un sistem care generează una sau mai multe frecvențe obținute de la o singură bază de timp (frecvență de referință), astfel încât raportul dintre frecvența semnalului de ieșire și cea a referinței este un număr rațional.
Există trei tehnologii convenționale principale care sunt în mod curent utilizate pentru un mecanism cu reacție negativă ce menține în fază frecvența semnalului de ieșire cu cea a referinței. Sintetizoarele de frecvență cu PLL s-au impus, atât datorită simplității, cât și a prețului de cost scăzut.
O altă tehnică de sinteză a frecvenței este cea care folosește metoda directă analogică (DA) la care un grup de frecvențe de referință este obținut de la o sursă principală de referință. Aceste frecvențe sunt mixate și filtrate, sumate, scăzute sau divizate în concordanță cu frecvența dorită la ieșire.
Cea de a treia tehnică, utilizată pe scară din ce în ce mai largă în ultimii ani, este cea care folosește metoda directă digitală (DDS). Aceasta este în fapt o procesare digitală a semnalului ce utilizează circuite și tehnici digitale pentru a crea, prelucra sau modula un semnal digital și apoi, eventual, a-l converti într-un semnal analogic cu ajutorul unui convertor digital-analog (DAC).
Este de remarcat faptul că în multe echipamente, cerințele impuse sintetizoarelor de frecvență depășesc performanțele optenabile prin utilizarea uneia sau alteia dintre metodele enumerate mai sus. În aceste cazuri se recurge la soluții hibride ce folosesc câte două sau chiar toate cele trei metode de bază.
Ce este sinteza directă digitală?
Sinteza digitală directă este o tehnica care este folosit în domeniul de generare semnale de frecvență radio pentru utilizare într-o varietate de aplicații de la receptoare de radio până la semnalele generatoare și multe altele. Tehnica a devenit mult mai răspândită în ultimii ani, cu progresele făcute în tehnologia de circuit integrat, care permite viteze mult mai repede să fie manipulate, care la rândul său permite mai mari de cipuri de frecvență DDS să fie făcute. Deși de multe ori este folosit pe cont propriu, DDS adesea este folosit în buclă sintetizator indirecte sau fază blocat. Prin combinarea celor două tehnologii este posibil pentru a profita de cele mai bune aspecte ale fiecărui.
Având în vedere faptul că circuitele integrate sunt acum disponibile pe scară largă, ceea ce face ușor de utilizat acestora.
Ce face dispozitivul?
Dispozitivul sinteza directă digitală adică Direct Digital Synthesis (DDS) este un dispozitiv care produce o formă de semnal analogică, de obicei un semnal sinusoidal sau dreptunghiular sau triunghiular. Prin generarea unui semnal, semnalul variază în timp în formă digitală și apoi efectuează o conversie digital-analogic. Deoarece operațiunile în dispozitivul DDS sunt în primul rând digitale, se poate oferi comutare rapidă între frecvențe de ieșire, rezoluția de frecvență fin și operarea pe un spectru larg de frecvențe. Cu progresele în design și tehnologie de proces, dispozitive DDS sunt foarte compacte și puterea pe care folosește este foarte redusă. Menținem că dispozitivul poate să fie un sintetizator de frecvență care este utilizat pentru crearea forme de undă arbitrare dintr-un singur ceas de referință cu frecvență fixă. Sinteza directă digitală include următoarele aplicațiile pe care folosește: generarea de semnal, oscilatoare locale în sistemele de comunicații, generatoare de funcții, mixere, modulatoare, sintetizatoare de sunet și ca parte a unui circuit de sincronizare pe fază digitală.
Scopul principal al DDS
Dispozitivele, cum ar fi DDS AD9833 sunt programate printr-o mare viteză de serie periferice-interfață (Serial Peripheral-Interface SPI), și au nevoie de doar un ceas extern pentru a genera valuri sinusoidale simple. Dispozitivele DDS sunt acum disponibile, care pot genera frecvențe de la mai puțin de 1 Hz pana la 400 MHz bazat pe un ceas 1GHz. Beneficiile dispozitivului este putere scăzut, costul redus, are un singur pachet mic, combinat cu performanțele lor excelente inerente și capacitatea s-a de a programa digital (sau să reprogrameze) forma de undă la ieșire, face dispozitivele DDS o soluție extrem de atractiv, ca preferat la soluții mai puțin flexibile care cuprind agregări de elemente discrete.
Fundamente teoretice
După cum sugerează și numele această formă de sinteză generează forma de undă direct, folosind tehnici digitale. Diferența dintre sintetizatoare directe și indirecte este că sintetizatorul indirect utilizează o buclă de fază închisă ca bază a funcționării ei. Un sintetizator digitală directă funcționează prin stocarea în format digital punctul formă de undă, și apoi returnarea acestora pentru a genera forma de undă. Rata la care sintetizatorul completează o formă de semnal reglementează apoi frecvența. Înainte de a examina detaliile funcționării sintetizatorului, este necesar să se examinăm conceptul de bază din spatele sistemului. Pe operația poate să observăm mai ușor în modul în care faza progresează de-a lungul unui ciclu de undă. Acest lucru poate fi avută în vedere ca fază progresează în jurul unui cerc. Așa cum faza avansează în jurul cercului, aceasta corespunde la progrese in forma de undă.
Partea Hardware
Schema bloc
Figura 1
Un DDS produce o undă sinusoidală la o frecvență dată. Frecvența depinde de două variabile. Primul este frecvența de referință de ceas și al doilea este numărul binar programat în registrul de frecvență. Numărul binar în registrul frecvență formează intrarea principală la acumulatorul de fază. Dacă se folosește un tabel de căutare sinusoidală, acumulatorul de fază calculează o adresă de fază pentru tabelul de căutare, care emite valoarea digitală a amplitudinii către convertorul digital analog. În fine convertorul digital analog se transformă acest număr la o valoare corespunzătoare de tensiune analog sau curent. Pentru a genera o frecvență fixă undă sinusoidală, este adăugată o valoare constantă la acumulatorul de fază, cu fiecare ciclu de ceas. Dacă incrementul de fază este mare, acumulatorul de fază se va intensifica rapid prin tabel de
căutare sinusoidală și astfel generează o înaltă frecvență sinusoidală. Dacă incrementul de fază este mic, acumulatorul de fază va avea mult mai multe etape, generând în consecință, o formă de undă mai lent.
Funcționare a acumulatorului de fază într-un sintetizator digitală directă
După cum am zis sintetizatorul funcționează prin stocarea diferite puncte în forma de undă în format digital și apoi returnează pentru a genera forma de undă. Funcționarea sa poate fi explicată în mai multe detaliu prin luarea în considerare avansurile fază jurul unui cerc așa cum se arată în figura 2.
Figura 2
Faza avansează în jurul cercului care corespunde progreselor în forma de undă, adică cu cât mai mare este numărul corespunzător fazei, cu atât mai mare este punctul de-a lungul formei de undă. Prin avansarea succesivă a numărului corespunzător fazei este posibil să se deplaseze mai departe de-a lungul ciclului de undă. Numărul digitală care reprezintă faza, are loc în oscilator cu comandă numerică. Numărul care a avut loc aici corespunde cu faza și este crescută la intervale regulate. În acest fel se poate fi trimis la acumulatorul de fază care este de fapt o formă de contor. Atunci când este cronometrat se adaugă un număr prestabilit de cel care deja a avut loc. Când se umple, se resetează și începe numărătoarea de la zero din nou. Cu alte cuvinte, aceasta corespunde pentru a ajunge la un cerc complet pe diagrama de fază și repornirea din nou.
Următoarea etapă a procesului este de a converti numerele digitale provenind din tabelul de căutare sinusoidale într-o tensiune analogică. Acest lucru este realizat cu ajutorul unui convertor digital analog. Acest semnal este filtrat pentru a elimina orice semnale nedorite și amplificate pentru a oferi nivelul necesar în funcție de necesități. Reglare este realizată prin creșterea sau reducerea dimensiunii pașilor de etapă sau fază
între diferite puncte de eșantionare. O creștere mai mare la fiecare modificare a acumulatorul de fază va însemna că faza atinge valoarea ciclu complet mai repede și frecvența este corespunzător de mare. Pași mai mici la valoarea acumulator de fază înseamnă că este nevoie de mai mult timp pentru a crește valoarea ciclu complet și o valoare scăzută corespunzător de frecvență. În acest fel este posibil pentru a controla frecvența. Acesta poate fi de asemenea observat că schimbările de frecvență se poate face instantaneu prin simpla schimbare a valorii incrementare. Nu este nevoie de a seta un timp ca în cazul sintetizatorul cu buclă blocată în fază. Din aceasta se poate observa că există o diferență finită între o frecvență și următorul frecvență, și că diferența de frecvență minimă sau rezoluția de frecvență este determinată de numărul total de puncte disponibile în acumulatorul de fază.
Partea Software (Limbajul de asamblare)
Ce este limbajul de asamblare
Un limbaj de asamblare este un limbaj de programare a calculatoarelor care, în locul codului mașină, folosește o desemnare simbolică a elementelor programului, relativ ușor de citit și interpretat de către om.
Fiecare calculator personal are un microprocesor care gestionează activitățile aritmetice, logice și de control ale computerului. Fiecare familie de procesoare are propriul set de instrucțiuni de manipulare diverse operații, cum ar fi obținerea de intrare de la tastatură, afișarea informațiilor pe ecran și efectuarea de diverse alte locuri de muncă. Aceste set de instrucțiuni sunt denumite "instrucțiuni limbaj mașină". Procesor înțelege doar instrucțiuni limbaj mașină, care sunt șiruri de 1 si 0. Cu toate acestea, limbaj mașină este prea obscură și complexă pentru utilizarea în dezvoltarea de software. Deci, limbajul de asamblare de nivel scăzut este proiectat pentru o anumită familie de procesoare, care reprezintă diverse instrucțiuni în cod simbolic și o formă mai ușor de înțeles.
Caracteristici
Fiecare tip de procesor deține propriul său limbaj numit "codul mașină", care reprezintă modul binar de codificare a instrucțiunilor și datelor în memorie, în forma direct executabilă. Instrucțiunile pot fi în general operații elementare sau/și operații
de comandă și control a procesorului. Codul mașină este, ca orice cod, format mai ales din cifre, fiind greu de reținut pentru un programator.
Pentru a putea fi interpretate de procesor, programul scris de om trebuie mae a calculatoarelor care, în locul codului mașină, folosește o desemnare simbolică a elementelor programului, relativ ușor de citit și interpretat de către om.
Fiecare calculator personal are un microprocesor care gestionează activitățile aritmetice, logice și de control ale computerului. Fiecare familie de procesoare are propriul set de instrucțiuni de manipulare diverse operații, cum ar fi obținerea de intrare de la tastatură, afișarea informațiilor pe ecran și efectuarea de diverse alte locuri de muncă. Aceste set de instrucțiuni sunt denumite "instrucțiuni limbaj mașină". Procesor înțelege doar instrucțiuni limbaj mașină, care sunt șiruri de 1 si 0. Cu toate acestea, limbaj mașină este prea obscură și complexă pentru utilizarea în dezvoltarea de software. Deci, limbajul de asamblare de nivel scăzut este proiectat pentru o anumită familie de procesoare, care reprezintă diverse instrucțiuni în cod simbolic și o formă mai ușor de înțeles.
Caracteristici
Fiecare tip de procesor deține propriul său limbaj numit "codul mașină", care reprezintă modul binar de codificare a instrucțiunilor și datelor în memorie, în forma direct executabilă. Instrucțiunile pot fi în general operații elementare sau/și operații
de comandă și control a procesorului. Codul mașină este, ca orice cod, format mai ales din cifre, fiind greu de reținut pentru un programator.
Pentru a putea fi interpretate de procesor, programul scris de om trebuie mai întâi redus prin compilare la "codul obiect", în acest scop fiind folosite "compilatoarele", "asambloarele" sau "interpretorii".
Programarea în limbaj de asamblare presupune o bună cunoaștere a structurii procesorului și a componentelor sale adiacente. Ea face ca utilizatorul să aibă acces la toate facilitățile unui calculator; dar programul rezultat va putea funcționa numai pe acest tip de calculator. Dacă programul trebuie transpus și pe alte tipuri de calculatoare, atunci se preferă limbajele de programare de nivel mai înalt.
De obicei limbajele de asamblare oferă și posibilitatea alcătuirii de așa numite macrouri, după necesitățile programului. Un macro este o pseudo-instrucțiune creată și definită chiar de către programator, care constă într-o grupare de mai multe instrucțiuni obișnuite și care primește un nume cu care poate apoi fi chemată în programul propriu-zis. Macrourile măresc eficiența programării, deoarece prescurtează programarea și o fac mai facilă. În cursul asamblării macrourile sunt înlocuite cu gruparea de instrucțiuni obișnuite, conform definiției respective, proces care se numește macro substituție. Din cauza facilităților de tip macro limbajul "assembler" este numit uneori și "macro assembler".
Într-un sens macrourile se aseamănă cu subprogramele / subrutinele.
Asamblarea
Asamblarea este procesul prin care codul sursă, scris în limbaj de asamblare, este transformat în cod mașină sau cod obiect. Codul sursă poate fi dispus pe mai multe module. Procesul invers se numește "dezasamblare".
Etapele asamblării:
Mai întâi se generează o tabelă de simboluri, ce conține toate numele simbolice din programul sursă, exceptând numele simbolice externe , instrucțiuni și directive de asamblare.
Asamblorul contorizează instrucțiunile și datele, asociind numelor simbolice un "deplasament" față de începutul
programului, ca și cum programul ar începe de la adresa 0. În realitate, programul nu se încarcă în RAM la adresa 0, ci de la o adresă furnizată de sistemul de operare, în spațiul de memorie disponibil; această adresă chiar poate de fiecare dată să fie alta. Deci programul furnizat de asamblor trebuie de obicei să fie "relocabil".
Se obține programul obiect, traducând fiecare instrucțiune și înlocuind numele simbolice cu valoarea sau adresa din tabela de simboluri.
Programul executabil se obține în urma etapei de editare de legături, care permite legarea mai multor module relocabile într-un singur fișier executabil, rezolvându-se referințele încrucișate dintre ele.
Avantajele limbajului de asamblare
O înțelegere a limbajului de asamblare oferă cunoștințe de:
Interfață de programe cu sistem de operare, procesor și BIOS;
Reprezentarea datelor în memorie și alte dispozitive externe;
Cum accesează și execută procesor instrucțiuni;
Cum accesează instrucțiuni și procesul de date;
Cum accesează un program dispozitive externe.
Este nevoie de mai puțină memorie și timp de execuție;
Este potrivit pentru locuri de muncă cu timp critic;
Este cel mai potrivit pentru a scrie rutine de întrerupere de servicii și alte programe de memorie rezidente.
Partea Microcontrolere
Generalități
La modul general un controler este, actualmente, o structură electronică destinată controlului unui proces sau, mai general, unei interacțiuni caracteristice cu mediul exterior, fără să fie necesară intervenția operatorului uman. Primele
controlere au fost realizate în tehnologii pur analogice, folosind componente electronice discrete și/sau componente electromecanice. Cele care fac apel la tehnica numerică modernă au fost realizate inițial pe baza logicii cablate și a unei electronici analogice uneori complexe, motiv pentru care "străluceau" prin dimensiuni mari, consum energetic pe măsură și, nu de puține ori, o fiabilitate care lăsa de dorit.
Apariția și utilizarea microprocesoarelor de uz general a dus la o reducere consistentă a costurilor, dimensiunilor, consumului și o îmbunătățire a fiabilității. Există și la ora actuală o serie de astfel de controlere de calitate, realizate în jurul unor microprocesoare de uz general cum ar fi Z80 (Zilog), 8086/8088 (Intel), 6809 (Motorola), etc.
O definiție, cu un sens foarte larg de cuprindere, ar fi aceea că un microcontroler este un microcircuit care incorporează o unitate centrală și o memorie împreună cu resurse care-i permit interacțiunea cu mediul exterior.
Utilizarea microcontrolerelor
Toate aplicațiile în care se utilizează microcontrolere fac parte din categoria așa ziselor sisteme încapsulate-integrate (“embedded systems”), la care existența unui sistem de calcul incorporat este transparentă pentru utilizator.
Printre multele domenii unde utilizarea lor este practic un standard industrial se pot menționa: în industria de automobile (controlul aprinderii motorului, climatizare, diagnoză, sisteme de alarmă, etc.), în așa zisă electronică de consum (sisteme audio, televizoare, camere video și videocasetofoane, telefonie mobilă, GPS-uri, jocuri electronice etc.), în aparatura electrocasnică (mașini de spălat, frigidere, cuptoare cu microunde, aspiratoare), în controlul mediului și climatizare (sere, locuințe, hale industriale), în industria aerospațială, în mijloacele moderne de măsurare – instrumentație (aparate de măsură, senzori și traductoare inteligente), la realizarea de periferice pentru calculatoare, în medicină.
Echipamente hardware folosite
AD9835
Descriere generală
AD9835 în general este un oscilator controlat numeric folosind un acumulator de fază, o tabelă cosinus și un convertor Digital / Analog pe 10-bit integrat pe un singur cip CMOS. Capabilitățile de modulație sunt prevăzute de modulație de fază și de frecvență de modulare. Viteza de ceas este acceptate până la 50 MHz. Precizia frecvenței pot fi controlate de unu la 4 miliarde. Modularea este afectat de încărcarea registre prin interfața serială. Un bit de putere-jos permite utilizatorului să reduce puterea AD9835 când nu este utilizat, așadar puterea consumată este redusă până la 1.75mW.
Schema bloc de funcționare
Figura …
Configurarea pinilor
Semnal analogic și de referință:
1 – FS ADJUST – Full-Scale Adjust – Un rezistor (RSET) este conectat între acest pin și AGND. Aceasta determină magnitudinea scară largă la convertorul digital analog actuală. Relația dintre RSET și curentul pe scară largă este:
2 – REFIN – Voltage Reference Input – AD9835 poate fi folosit fie cu referința la bord, care este disponibil din REFOUT pin, sau o referință externă. Este conectat de referință pentru a fi utilizate la pinul REFIN. AD9835 acceptă o referință de 1.21 V nominal.
3 – REFOUT – Voltage Reference Output – AD9835 are o referință la bordul valoare 1.21 V nominală. Referința este pus la dispoziție pe pinul REFOUT. Această referință este utilizată ca referință pentru convertor analog digital prin conectarea REFOUT cu REFIN. REFOUT ar trebui decuplat cu un condensator de 10 nF la AGND.
14 – IOUT – Current Output – Aceasta este o sursă de curent de înaltă impedanță. Un rezistor de sarcină ar trebui să fie conectate între IOUT și AGND.
16 – COMP – Compensation pin – Acesta este un pin de compensare pentru amplificatorul de referință intern. O decuplare 10 nF condensator ceramic trebuie să fie conectate între COMP și AVDD.
Alimentare:
4 – DVDD – Sursă de alimentare pozitiv pentru secțiunea digitală. Un 0,1 mF condensator trebuie conectat între DVDD și DGND. DVDD poate avea o valoare de 5 V ± 5%.
5 – DGND – Masă digitală
13 – AGND – Masă analogică
15 – AVDD – Sursă de alimentare pozitiv pentru secțiunea analogică. Un 0,1 mF condensator trebuie conectat între AVDD și AGND. AVDD poate avea o valoare de 5 V ± 5%.
Interfața digitală și controlul:
6 – MCLK – Digital Clock Input – Frecvențe de ieșire DDS sunt exprimate ca fracție binară a frecvenței MCLK. Precizia ieșire de frecvență și zgomot de fază sunt determinate de acest ceas.
7 – SCLK – Serial Clock, Logic Input – Date este cronometrat în AD9835 pe fiecare muchie SCLK care se încadrează.
8 – SDATA – Serial Data In, Logic Input – Cuvânt de date 16 biți serial este aplicată în această intrare.
9 – FSYNC – Data Synchronization Signal, Logic Input – Atunci când această intrare este luat scăzut, logica internă este informat că un nou cuvânt se încarcă in dispozitiv.
10 – FSELECT – Frequency Select Input – FSELECT controlează care registrul de frecvență, FREQ0 sau FREQ1, este utilizat în acumulator de fază. Registrul de frecvență care urmează să fie utilizate pot fi selectate cu ajutorul pinul FSELECT sau bitul FSELECT. FSELECT sunt prelevate pe marginea creștere MCLK. FSELECT trebuie să fie în starea de echilibru atunci când are loc o creștere margine MCLK. Dacă FSELECT modifică valoarea atunci când apare o margine în creștere, atunci există o incertitudine de un ciclu MCLK cu privire la momentul controlul este transferat la celălalt registru de frecvență. Pentru a evita orice incertitudine, o schimbare pe FSELECT nu trebuie să coincidă cu o creștere margine MCLK. Când bitul este utilizat pentru a selecta registrul de frecvență, pinul FSELECT trebuie legată de DGND.
11, 12 – PSEL0, PSEL1 – Phase Select Input – AD9835 are patru registre de fază. Aceste registre pot fi utilizate pentru a modifica valoarea fiind de intrare
la ROM COS. Conținutul registrului de fază se adaugă la acumulatorul de fază la ieșire, intrările PSEL0 și PSEL1 selectează registrul de fază care să fie utilizate. Alternativ registrul de fază pentru a fi utilizate pot fi selectate cu ajutorul biți PSEL0 și PSEL1. Așa cum a fost la intrarea FSELECT, PSEL0 și PSEL1 se prelevează de pe marginea în creștere MCLK. Prin urmare, aceste intrări trebuie să fie în starea de echilibru, atunci când are loc o creștere margine MCLK sau există o incertitudine de un ciclu MCLK ca la atunci controlul este transferat în registrul faza selectată. Când registrele de fază sunt controlate de biți PSEL0 și PSEL1, pinii ar trebui să fie legat de DGND.
Descrierea circuitului
AD9835 oferă un nou nivel de integrare pentru proiectantul în sistemului radio frecvență sau în comunicație. AD9835 combină oscilator numeric controlat, tabela cosinus, frecvență și modulatoare de fază și convertor digital analogic pe un singur circuit integrat. Circuitul intern al AD9835 este format din trei secțiuni principale. Acestea sunt:
– oscilator numeric controlat + modulator de fază
– COS Look-Up Table
– convertor digital analogic
AD9835 este un cip sinteză directă digitală complet integrat. Cipul necesită un ceas de referință, un rezistor de precizie scăzut și opt condensatori de decuplare pentru a furniza unde sinusoidale digitale până la 25 MHz. Pe lângă generarea din acest semnal RF, cip este pe deplin capabil de o gamă largă de scheme simple și complexe de modulare. Aceste scheme de modulație sunt puse în aplicare integral în domeniul digital, care permite realizarea corectă și simplu de algoritmi de modulare complexe, utilizând tehnici de DSP.
Teoria de operare
Undele cosinus sunt de obicei gândit în termeni de mărime care formează a(t)= cos(ωt). Cu toate acestea, acestea sunt neliniare și nu ușor pentru a genera, decât prin construcție piese înțelept. Pe de altă parte, informațiile unghiulară este liniară în natură. Adică unghiul de fază se rotește cu un unghi fix pentru fiecare
unitate de timp. Rata unghiulară depinde de frecvența semnalului de rata tradiționale de ω = 2*pi*f.
Știind că faza a unui undă cos este liniară și având o referință interval, rotația de fază pentru perioada respectivă poate fi determinată.
Rezolvarea coeficientul :
Rezolvarea pentru F și substituirea frecvența de ceas de referință pentru perioada de referință (1/fMCLK = t)
AD9835 construiește ieșirea bazat pe această ecuație simplă. Un simplu cip de DDS pot pune în aplicare această ecuație cu trei sub circuite majore.
Oscilator numeric controlată și modulator de fază
Aceasta constă din două registre de frecvență un acumulator de fază și patru faza de offset registre. Componenta principală al oscilator numeric control este un acumulator de fază de 32 de biți care asamblează componenta de fază a semnalului de ieșire. Semnale de timp continuu are o serie de fază de la 0 pi până la 2pi. În afara acestui interval de numere, funcțiile sinusoidale se repetă în mod periodic. Implementarea digitală nu este diferită. Acumulatorul pur și simplu scalează gama de numere într-o fază în multiple cuvânt digitale. Acumulatorul de fază în AD9835 este implementat cu 32 de biți. Prin urmare, în AD9835, . De asemenea, termenul ΔPhase este scalată în acest interval de numere 0< ΔPhase<232-1. Efectuarea aceste substituții în ecuația de mai sus
unde 0 < ΔPhase < 232
Intrarea la acumulatorul de fază poate fi selectată fie din registrul FREQ0 sau din registrul FREQ1 și acest lucru este controlat de către pinul FSELECT sau bit FSELECT. Oscilatorul numeric controlat în mod inerent generă semnale
de fază continuă, evitând astfel orice discontinuitate de ieșire atunci când comută între frecvențe. Ca urmare o fază de compensare pot fi adăugate pentru a efectua
modulație de fază, utilizând registrele de fază 12-bit. Conținutul acestui registru se adaugă la cele mai semnificative biți ai oscilatorului. AD9835 are patru registre de fază, soluționarea acestor registre fiind 2pi/4096.
COS Look-Up Table
Pentru a face ieșirea util, semnalul trebuie convertit din faza de informație într-o valoare sinusoidal. Din moment ce informații de fază mapează direct în amplitudine, un ROM LUT convertește informațiile de fază în amplitudine. Pentru a face acest lucru, informația de fază digital este folosit pentru a aborda un ROM LUT COS. Deși oscilatorul conține un acumulator de fază de 32 de biți, ieșirea NCO este trunchiat la 12 biți. Utilizând rezoluția completă a acumulatorul de fază este imposibil și inutil ca acest lucru ar necesita un tabel look-up de 232 de intrări. Este necesar doar să aibă rezoluție suficientă în fază, astfel încât eroarea de curent continuu la ieșire este dominat de eroarea de cuantizare în convertoare digital analog. Acest lucru necesită tabelul de căutare a avea mai multe doi biți de rezoluție fază decât de 10-bit DAC.
Convertor digital analogic
AD9835 include o impedanță mare sursă de curent de 10-bit, capabil de a conduce o gamă largă de sarcini, la viteze diferite. Curent de ieșire pe scară largă poate fi ajustat, pentru o putere optimă și cerințele de sarcină externe, prin utilizarea unui singur rezistor extern. Rezistenței de sarcină poate fi orice valoare necesar, atât timp cât tensiunea scară largă dezvoltat peste ea nu depășește intervalul de conformitate tensiune. Deoarece curent pe scară largă este controlat de RSET, ajustările RSET poate echilibra modificările aduse de către rezistor de sarcină. Cu toate acestea, în cazul în care curentul de ieșire pe scară largă al convertorului este semnificativ mai mic decât 4 mA, liniaritate convertorului poate degrada.
Aplicații
AD9835 conține funcții care face potrivite pentru aplicații de modulație. Partea poate fi utilizat pentru a efectua modulație simplă, cum ar fi FSK. Scheme de modulație mai complexe, cum ar fi GMSK și QPSK pot fi de asemenea implementate folosind AD9835. Într-o aplicație FSK, cele două registre de frecvență ale AD9835 sunt încărcate cu valori diferite; o frecvență va reprezenta frecvența spațiu în timp, celălalt va reprezenta frecvența de semn. Fluxul de date digitale este alimentat la pinul FSELECT, ceea ce va determina AD9835 să moduleze frecvența purtătoare dintre cele două valori.
AD9835 are patru registre de fază; acest lucru permite o parte pentru a efectua PSK. Cu defazaj de manipulare, frecvența purtătoare este defazat, faza fiind modificate printr-o valoare care este legată de fluxul de biți de intrare fiind la modulatorul. Prezența cele patru registre de deplasare ușurează interacțiunea necesară între DSP și AD9835.
AD9835 este de asemenea potrivit pentru aplicații care generează semnal. Cu un consum redus de curent, este potrivit pentru aplicații în care acesta poate fi folosit ca un oscilator local.
Microcontrolerul PIC16F84A
Descriere generală, schema bloc
PIC16F84 aparține unei clase de microcontrolere de 8 biți cu arhitectura RISC. Structura lui generală este arătată în schița următoare reprezentând blocurile de baza.
Memoria program (FLASH) – este pentru memorarea unui program scris, pentru ca memoria ce este făcută în tehnologia FLASH poate fi programata si ștearsă mai mult decât odată, aceasta face microcontrolerul potrivit pentru dezvoltarea de componenta.
EEPROM – memorie de date ce trebuie să fie salvate când nu mai este alimentare. Este în mod uzual folosita pentru memorarea de date importante ce nu trebuie pierdute dacă sursa de alimentare se întrerupe dintr-o dată. De exemplu, o astfel de dată este o temperatură prestabilită în regulatoarele de temperatură. Dacă în timpul întreruperii alimentării aceasta data se pierde, va trebui sa facem ajustarea încă o data la revenirea alimentării. Astfel componenta noastră pierde în privința auto-menținerii.
RAM-memorie de date folosită de un program în timpul executării sale. În RAM sunt memorate toate rezultatele intermediare sau datele temporare ce nu sunt cruciale la întreruperea sursei de alimentare.
PORTUL A si PORTUL B sunt conexiuni fizice între microcontroler și lumea de afară. Portul A are 5 pini, iar portul B are 8 pini.
TIMER-UL LIBER (FREE-RUN) este un registru de 8 biți în interiorul microcontrolerului ce lucrează independent de program. La fiecare al patrulea impuls de ceas al oscilatorului își incrementează valoarea lui până ce atinge maximul (255), și apoi începe să numere tot din nou de la zero. După cum știm timpul exact dintre fiecare două incrementări ale conținutului timer-ului, poate fi folosit pentru măsurarea timpul lui ce este foarte util la unele componente.
UNITATEA DE PROCESARE CENTRALĂ are rolul unui element de conectivitate între celelalte blocuri ale microcontrolerului. Coordonează lucrul altor blocuri și execută programul utilizatorului.
CISC, RISC
S-a spus deja că PIC1684 are o arhitectură RISC. Acest termen este adeseori găsit în literatura despre calculatoare, și are nevoie să fie explicat aici mai în detaliu. Arhitectura Harvard este un concept mai nou decât von-Neumann. S-a născut din nevoia de mărire a vitezei microcontrolerului. În arhitectura Harvard, bus-ul de date și bus-ul de adrese sunt separate. Astfel este posibil un mare debit de date prin unitatea de procesare centrală, și bineînțeles,
o viteza mai mare de lucru. Separarea programului de memoria de date face posibil că mai departe instrucțiunile să nu trebuiască să fie cuvinte de 8 biți. PIC16F84 folosește 14 biți pentru instrucțiuni ceea ce permite ca toate instrucțiunile să fie instrucțiuni dintr-un singur cuvânt. Este de asemenea tipic
pentru arhitectura Harvard să aibă mai puține instrucțiuni decât von-Neumann și să aibă instrucțiuni executate uzual într-un ciclu.
Microcontrolerele cu arhitectura Harvard sunt de asemenea numite "microcontrolere RISC". RISC înseamnă Reduced Instruction Set Computer. Microcontrolerele cu arhitectura von-Neumann sunt numite "microcontrolere CISC". Titlul CISC înseamnă Complex Instruction Set Computer.
Pentru că PIC16F84 este un microcontroler RISC, aceasta înseamnă ca are un set redus de instrucțiuni, mai precis 35 de instrucțiuni. Toate aceste instrucțiuni sunt executate într-un ciclu cu excepția instrucțiunilor jump si branch. Conform cu ceea ce spune constructorul, PIC16F84 ajunge la rezultate de 2:1 în compresia cod și 4:1 în viteza în comparație cu alte microcontrolere de 8 biți din clasa sa.
Aplicații
PIC16F84 se potrivește perfect în multe folosințe, de la industriile auto și aplicațiile de control casnice la instrumentele industriale, senzori la distantă, mânere electrice de uși și dispozitivele de securitate. Este de asemenea ideal pentru cardurile smart ca și pentru aparatele alimentate de baterie din cauza consumului lui mic.
Memoria EEPROM face mai ușoara aplicarea microcontrolerelor la aparate unde se cere memorarea permanentă a diferitor parametri. Costul scăzut, consumul scăzut, mânuirea ușoara și flexibilitatea fac PIC16F84 aplicabil chiar și în domenii unde microcontrolerele nu au fost prevăzute înainte.
Programabilitatea sistemului acestui cip face posibila flexibilitatea produsului, după ce asamblarea și testarea au fost terminate. Aceasta capabilitate poate fi folosită pentru a crea producție pe linie de asamblare, de a înmagazina date de calibrare disponibile doar după testarea finală, sau poate fi folosit pentru a îmbunătăți programele la produsele finite.
Ciclul instrucțiune
Clock-ul sau ceasul este starter-ul principal al microcontrolerului, și este obținut dintr-o componentă de memorie externă numită "oscilator". Dacă ar fi
să comparăm un microcontroler cu un ceas de timp, "clock-ul" nostru ar fi un ticăit pe care l-am auzi de la ceasul de timp. În acest caz, oscilatorul ar putea fi comparat cu arcul ce este răsucit astfel ca ceasul de timp să meargă. De asemenea, forța folosita pentru a întoarce ceasul poate fi comparata cu o sursă electrică.
Clock-ul de la oscilator intră într-un microcontroler prin pinul OSC1 unde circuitul intern al microcontrolerului divide clock-ul în 4 clock-uri egale Q1, Q2, Q3 si Q4 ce nu se suprapun. Aceste 4 clock-uri constituie un ciclu de o singură instrucțiune în timpul căreia instrucțiunea este executată.
Executarea instrucțiunii începe prin apelarea unei instrucțiuni care este următoarea în linie. Instrucțiunea este apelată din memoria program la fiecare Q1 și este scrisă în registrul de instrucțiuni la Q4. Decodarea si executarea instrucțiunii sunt făcute între următoarele cicluri Q1 și Q4.
Pipelining
Ciclul instrucțiune constă din ciclurile Q1, Q2, Q3 și Q4. Ciclurile de instrucțiuni de apelare și executare sunt conectate într-un așa fel încât pentru a face o apelare, este necesar un ciclu cu o instrucțiune, și mai este nevoie de încă unul pentru decodare și executare. Totuși, datorită pipelining-ului (folosirea unei pipeline-conductă, și este aducerea unei instrucțiuni din memorie în timp ce se execută alta), fiecare instrucțiune este executată efectiv într-un singur ciclu. Dacă instrucțiunea cauzează o schimbare în contorul programului, si PC-ul nu direcționează spre următoarea ci spre alte adrese (poate fi cazul cu subprogramele jumps sau calling), 2 cicluri sunt necesare pentru executarea unei instrucțiuni. Aceasta este pentru că instrucțiunea trebuie procesată din nou, dar de data aceasta de la adresa corectă. Ciclul începe cu clock-ul Q1, prin scrierea în registrul instruction register (IR). Decodarea și executarea începe cu clock-urile Q2, Q3 și Q4.
Semnificația pinilor
PIC16F84 are un număr total de 18 pini. Cel mai adesea se găsește într-o capsula de tip DIP18 dar se poate găsi de asemenea si într-o capsula SMD care
este mai mica ca cea DIP. DIP este prescurtarea de la Dual In Package. SMD este prescurtarea de la Surface Mount Devices sugerând ca găurile pentru pini unde să intre aceștia, nu sunt necesare în lipirea acestui tip de componentă.
Pinii microcontrolerului PIC16F84 au următoarea semnificație:
Pin nr.1 RA2 Al doilea pin la portul A. Nu are funcție adițională.
Pin nr.2 RA3 Al treilea pin la portul A. Nu are funcție adițională.
Pin nr.3 RA4 Al patrulea pin la portul A. TOCK1 care funcționează ca timer se găsește de asemenea la acest pin.
Pin nr.4 MCLR Resetează intrarea și tensiunea de programare Vpp a microcontrolerului.
Pin nr.6 RB0 Pin de zero la portul B. Intrarea Întrerupere este o funcție adițională.
Pin nr.7 RB1 Primul pin la portul B. Nu are funcție adițională.
Pin nr.8 RB2 Al doilea pin la portul B. Nu are funcție adițională.
Pin nr.9 RB3 Al treilea pin la portul B. Nu are funcție adițională.
Pin nr.10 RB4 Al patrulea pin la portul B. Nu are funcție adițională.
Pin nr.11 RB5 Al cincilea pin la portul B. Nu are funcție adițională.
Pin nr.12 RB6 Al șaselea pin la portul B. Linia de 'Clock' în mod programare.
Pin nr.13 RB7 Al șaptelea pin la portul B. Linia 'Data' în mod programare.
Pin nr.14 Vdd Polul pozitiv al sursei.
Pin nr.15 OSC2 Pin desemnat pentru conectarea la un oscilator.
Pin nr.16 OSC1 Pin desemnat pentru conectarea la un oscilator.
Pin nr.17 RA2 Al doilea pin la portul A. Nu are funcție adițională.
Pin nr.18 RA1 Primul pin la portul A. Nu are funcție adițională
Encoder-ul optic
Descriere generală
Codificatoarele furnizează informații despre sisteme de control al mișcării pe poziție, numărul, viteza, și de direcție. Așa cum arborele codificatorului se rotește, semnale de ieșire sunt produse, proporțional cu distanța de rotație. Semnalul poate fi sub forma unui semnal dreptunghiular sau o măsură absolută a poziției.
Codificatoare optice incrementale sunt cea mai populara alegere de senzori în aplicații, unde mișcarea mecanică trebuie să fie transformată în informație digitală. Comparativ cu tehnologii alternative, codificatoare optice reprezintă cea mai bună combinație de precizie, rezoluție, fiabilitate, robustețe, ușurința de utilizare, valoare și varietate de soluții din industrie. Din aceste motive, codificatoare optice sunt alegerea cea mai bună în care viteza, accelerația, distanta, poziție, sau de direcție trebuie să fie măsurat cu precizie și economic.
Codificatoare absolute, designul lor simplificat le face soluții ideale, cost-eficiente în multe probleme cu care se confruntă în controlul mișcării și în automatizări industriale. Acestea sunt potrivite în special pentru aplicații în cazul în care un dispozitiv este inactiv pentru perioade îndelungate sau se mișcă într-un ritm lent, cum ar fi controlul poarta de inundații, telescoape, macarale, supape, mașina de scule, imprimare, fabricarea hârtiei și multe alte industrii. Codificatoare absolute generează un unic binar "cuvânt" de ieșire pentru fiecare poziție arbore solubil, astfel încât fiecare poziție a arborelui este determinat complet. Aceste cuvinte de cod pot fi create în cod Gray, în
cod binar natural, sau exces cod Gray. Prin utilizarea poziție absolută, mai degrabă decât de date conta incrementale, poziția arborelui este întotdeauna cunoscut, chiar și după întreruperea curentului. Proiectarea de sistem poate fi, de asemenea simplificată, deoarece nu este nevoie de a efectua un ciclu de referință sau a reveni la funcția acasă pentru a determina poziția mașinii adevărată.
Schema generală
Amplificatorul MAX4012
Descriere generală
Amplificatoarele operaționale sunt amplificatoare electronice de curent continuu, care reprezintă o categorie de circuite integrate analogice amplificatoare cu performanțe deosebite, cu ajutorul cărora se pot realiza o diversitate extrem de mare de aplicații liniare și neliniare.
Denumirea de “operaționale” se datorează faptului că primele tipuri de amplificatoare de acest tip au fost folosite pentru realizarea anumitor operații matematice simple (adunare, scădere, înmulțire și împărțire cu o constantă). Primele tipuri de AO aveau componente discrete și performanțe modeste. Odată cu apariția și dezvoltarea tehnologiei circuitelor integrate performanțele AO au crescut spectaculos.
Schema bloc
Un amplificator operațional conține trei etaje distincte realizate cu componente integrate și este prevăzut cu: două intrări (o intrare inversoare și o intrare ne inversoare), o ieșire, terminale de alimentare cu tensiune, terminale suplimentare utilizate pentru reglajul componentei continue a ieșirii (offset) și/sau pentru compensare.
Elementele schemei bloc:
IN+ intrarea ne inversoare – semnalul aplicat pe această intrare, la ieșire este amplificat și este în fază cu semnalul de intrare (semnalul de ieșire nu este inversat)
IN- intrarea inversoare – semnalul aplicat pe această intrare, la ieșire este amplificat și defazat cu 180° față de semnalul de intrare (semnalul este inversat)
E ieșirea AO
V+ , V- – terminale pentru alimentarea cu tensiune a AO. Alimentarea cu tensiune se poate face de la o sursă de curent continuu diferențială de tensiune (+V, -V)
AD amplificator diferențial – este etajul de intrare a AO și amplifică diferența semnalelor aplicate la intrările AO. Acest bloc, prin structura sa, amplifică și semnalele de curent continuu.
AI amplificator intermediar – este un etaj de adaptare care preia semnalul de la ieșirea etajului de intrare și îl prelucrează pentru a corespunde cerințelor etajului de ieșire
AE amplificator de ieșire – este un etaj de putere care asigură curentul de ieșire necesar
offset – terminale utilizate pentru reglarea componentei continue a semnalului de ieșire si pentru compensare.
Despre MAX4012
Sunt amplificatoare care folosesc tehnici de curent de feedback pentru a realiza rate slew 600V/μs și lățimi de bandă de 200 MHz. Armonice distorsiuni și diferențial performanță excelentă câștig / faza de a face aceste amplificatoare o alegere ideală pentru o mare varietate de video și aplicații de procesare a semnalului RF. Feedback-ul local, în jurul stadiul de ieșire asigură impedanță scăzută de ieșire în buclă deschisă pentru a reduce sensibilitatea câștig pentru a încărca variații. Acest feedback produce, de asemenea, prejudecată curentă bazată pe cerere de tranzistori de ieșire de ±120mA capacitatea de unitate, în timp ce de constrângere curent total de alimentare este mai puțin de 7mA.
Configurarea pinilor
Avem două tipuri de configurație la amplificatorul MAX4012; una miniatură cu 5 pin-uri SOT23-5 și avem SO care folosește 8 pin-uri. În proiect a fost utilizat cel SOT23-5 cu 5 pin-uri.
Descrierea pinilor:
MAX4012 SOT23-5
Amplificator de ieșire
Negativ sursă de alimentare sau masă
Intrarea de neinversoare
Intrarea de inversor
Pozitiv sursă de alimentare
MAX4012 SO
1,5,8- Nu există conexiune. Nu este conectat intern
6- Amplificator de ieșire
4- Negativ sursă de alimentare sau masă
3- Intrarea de neinversoare
2- Intrarea de inversor
7- Pozitiv sursă de alimentare
Display-ul LCD 2×16
Descriere generală
LCD (Liquid Crystal Display) ecranul este un modul de afișaj electronic și de a găsi o gamă largă de aplicații. Un ecran 16×2 LCD este modul foarte de bază și este foarte frecvent utilizat în diverse dispozitive și circuite. Aceste module sunt de preferat peste șapte segmente și alte LED-uri mai multe segmente. Motivele fiind: LCD-urile sunt economice; ușor programabile; nu au nici o limitare a afișa caractere speciale și chiar personalizate (spre deosebire de șapte segmente), animații și așa mai departe.
Un LCD 16×2 înseamnă că pot afișa 16 caractere pe linie și există două astfel de linii. In acest LCD fiecare caracter este afișat în matrice 5×7 pixeli. Acest LCD are două registre: comandă și de date.
Registrul de comandă stochează instrucțiunile de comandă date la LCD. O comandă este o instrucțiune dată de LCD pentru a face o sarcină predefinită ca inițializare, de compensare ecranul său, stabilind poziția cursorului, controlul de afișare. Registrul de date stochează datele care urmează să fie afișate pe ecranul LCD. Datele reprezintă valoarea ASCII a caracterului care urmează să fie afișat pe ecranul LCD.
Schema LCD
Configurarea pinilor
VSS – Tensiunea negativă
VDD – Tensiunea de alimentare 5V
VEE – Contrastul de ajustare; printr-un rezistor variabil
RS – Register Select – Selectează registrul de comandă atunci când este scăzut; și înregistrează date atunci când este ridicat
RW – Read/write – Scăzut pentru a scrie la registru; Ridicat pentru a citi de la registru
E – Enable – Trimite date către pini de date atunci când un puls ridicat către scăzut este dat
D0 – Pin de date
D1 – Pin de date
D2 – Pin de date
D3 – Pin de date
D4 – Pin de date
D5 – Pin de date
D6 – Pin de date
D7 – Pin de date
BL1 – Backlight Power (+5V)
BL2 – Backlight Power (0V)
GND – Masă (0V)
Proiectarea sistemului propus
Proiectarea Hardware-lui propus
Avem următoarele componente U:
U1 – este piesa DDS-ul
U2 – este microcontrolerul PIC16F84A
U3 – este un generator de frecvență 50 MHz
U4 – este amplificatorul MAX4012
U5 – este sursa de alimentare
LCD – Liquid Crystal Display
X1 – pregătește semnalul de ceas pentru procesor
Componentele R (rezistențele)
R1 – rezistență de ridicare de semnal
R2 – rezistență pentru setare contrast LCD
R3 – rezistență pentru DDS (FS_ADJUST)
R4, R5 – rezistență pentru setarea filtrului de impedanță
R6 – rezistență pentru potențial atenuator care transmite mai departe către intrare
R7, R8 – este puncte de operare
R9, R10 – este folosit ca amplificator
R11, R12 – output-ul 50MHz
R13, R14, R15 – rezistență de ridicare de semnal
Componente C (condensatori):
C1, C2 – condensator pentru funcționarea oscilator
C3 – condensator pentru resetarea circuitul de sincronizare
C4, C5, C6, C7 – condensator pentru putere de filtrare
C8 – condensator pentru compensare FRCK
C9, C10, C11, C12 – condensator pentru setarea filtrelor
C13, C14 – condensator tampon
C15 – condensator pentru putere de filtrare
C16 – condensator putere de filtrare pentru amplificator
C17 – condensator ceramică
C18, C19 – condensator pentru input/output
C20 – condensator ceramică
C21, C22, C23, C24 – condensator pentru putere de filtrare
Componentele J:
J1 – Encoder-ul optic
J2 – Input (sursa de alimentare)
J3 – Output
J4 – pentru butoane
J5 – pentru LCD
Componentele L (filtre):
L1 – filtrează semnalele de interferență
L2 ,L3 ,L4 – filtre trece jos
Proiectarea Software-lui propus
Software-ul propus care a fost realizat folosește ca principiul limbajul de asamblare. Programul de control este pentru un generator de semnal prin sinteza directă digitală construit cu un cip AD9850 DDS, un encoder, un comutator buton și un afișaj cu cristale lichide (LED).
Prin întregul program a fost realizat câțiva caracteristici pentru software-ul propus. A fost aplicate următoarele caracteristicile. Prima oară a fost aplicate reglaj de rată variabilă, al doilea caracteristică este memorii de bandă și al treilea este modul de calibrare.
Reglajul de rată variabilă este bazat pe viteza cu care codificatorul este răsucit. Codificatorul are de asemenea construit în el un comutator, care va schimba dimensiunea pas de la 1Hz la 1kHz dacă arborele encoder este apăsat în timp ce pornește.
La memorie de bandă s-a realizat un comutator buton extern, care permite frecvența să fie reciclate în jurul benzile de radioamatori de înaltă frecvență.
Se introduce modul de calibrare dacă butonul extern este apasă în timp ce circuitul este alimentat. Display-ul este setat la 10,000.000 CAL și rămâne fixă, chiar dacă ajustările sunt făcute. În cazul în care butonul este ținut apăsat, apoi rotirea arborele codificatorului rezultă la creșterea sau la descreșterea valoarea "OSC", care este folosit pentru a calcula cuvântul de control sinteza directă digitală. Rata de ajustare de calibrare de bază este foarte scăzut. O viteză de ajustare ceva mai rapid este disponibil prin apăsarea arborele codificatorului jos în timp ce codificatorul este rotit. Un contor de frecvență extern la ieșirea sinteza direct digitală este nevoie pentru observarea acestei ajustare. Pentru a ieși din modul de calibrare, trebuie eliberat butonul extern care a fost apăsat și trebuie rotite arbora codificatorului mai multe ori, așa iese programul din modul de calibrare. După calibrare valoarea calibrată ".osc" este stocate în memoria EEPROM.
În scopul de a înțelege programul mai bine urmează niște secvențele de program mai importante cu care a fost realizat software-ul pentru proiectul prezentat.
Secvența de cod cu care începem prezintă tipul de dispozitiv și opțiuni pe care avem la dispoziție:
processor PIC16F84
radix dec
errorlevel -220
errorlevel -305
După secvența care detectează tipul de dispozitiv și opțiunile pe care le oferă dispozitivul urmează secvența cu informațiile despre configurarea siguranțelor:
_CP_ON EQU H'000F'
_CP_OFF EQU H'3FFF'
_PWRTE_ON EQU H'3FF7'
_PWRTE_OFF EQU H'3FFF'
_WDT_ON EQU H'3FFF'
_WDT_OFF EQU H'3FFB'
_LP_OSC EQU H'3FFC'
_XT_OSC EQU H'3FFD'
_HS_OSC EQU H'3FFE'
_RC_OSC EQU H'3FFF'
_config _CP_OFF & _PWRTE_ON & _WDT_ON & _XT_OSC
În continuare este necesar să introducem ecuație generală pe care folosim în software. Aceste ecuații pot fi modificate pentru a se potrivi frecvența de ceas de referință, adică limita superioară de frecvență dorit și frecvența de pornire obișnuită.
ref_osc reprezintă schimbarea în cuvântul de control de frecvență, care rezultă într-o schimbare de 1 Hz la frecvența de ieșire. Acesta este interpretat ca un punct fix întreg în formatul <ref_osc_3>. <ref_osc_2> <ref_osc_1> <ref_osc_0>.
Valorile pentru frecvențe de oscilator comune sunt următoarele:
Pentru a calcula alte valori:
ref_osc_3 = (232/ frecvențe oscilator în Hertz);
ref_osc_2, ref_osc_1 și ref_osc_0 sunt parte fracționată a (232 / frecvențe
oscilator în Hertz) ori 224;
Notă: 232 = 4294967296 și 224 = 16777216
De exemplu, pentru un ceas 120 MHz:
ref_osc_3 este (232 / 120 x 106) = 35.791394133 rotunjit la 35 are valoarea (0x23)
ref_osc_2 este bitul mai mare (.791394133 x 2^24) = 13277390.32
13277390.32 = 0xCA98CE, deci bitul mare este CA.
ref_osc_1 este următorul bit pentru 0xCA98CE sau 98
ref_osc_0 este ultimul bit pentru 0xCA98CE sau CE
Momentan oscilatorul este setat la 100 de MHz care înseamnă că ref_osc_3 este cel mai semnificativ bit, după care urmează ref_osc_2 următorul bit, după care vine ref_osc_1 care este la fel următorul bit și la sfârșit vine ref_osc_0 care este cel mai puțin semnificativ bit.
ref_osc_3 equ 0x2A
ref_osc_2 equ 0xF3
ref_osc_1 equ 0x1D
ref_osc_0 equ 0xC4
Urmează limita care conține frecvența limită superioară, un întreg pe 32 biți. Aceasta nu ar trebui să fie setat la mai mult de o treime din frecvența oscilatorului de
referință. Filtrul de ieșire a plăcii sinteza direct digitală trebuie să fie proiectate așa cum să trece frecvențele până la maxim.
limit_3 equ 0x01 ; Cel mai semnificativ bit pentru 30 MHz
limit_2 equ 0xC9 ; Bitul următor
limit_1 equ 0xC3 ; Bitul următor
limit_0 equ 0x80 ; Cel mai puțin semnificativ bit
Secvența Default conține frecvența de pornire implicit ca un întreg pe 32 de biți.
default_3 equ 0x00 ; Cel mai semnificativ bit pentru 14.025 MHz
default_2 equ 0xD6 ; Bitul următor
default_1 equ 0x01 ; Bitul următor
default_0 equ 0x28 ; Cel mai puțin semnificativ bit
band_end equ 0x28 ; Diferența față de ultima intrare tabel bandă
După ce am discutat despre ecuațiile generale pe care folosește programul trecem la porturi și la constantele EEPROM. Constantele sunt implementate cu următorul secvență de cod.
PortA equ 0x05
PortB equ 0x06
TRISA equ 0x05
TRISB equ 0x06
EEdata equ 0x08
EEadr equ 0x09
WREN equ 0x02
WR equ 0x01
RD equ 0x00
Ca să știm ce, unde și cum se produce în microcontroler trebuie să denumim pini de intrare și de ieșire. Asta a fost realizat pentru registru A și B cu următorul secvență de cod.
; Biți registru B:
DDS_load equ 0x00 ; Actualizarea PIN-ul pe AD9850
LCD_rs equ 0x01 ; 0=instrucțiune, 1=data
LCD_rw equ 0x02 ; 0=scriere, 1=citire
LCD_e equ 0x03 ; 0=inactivare, 1=activare
DDS_clk equ 0x05 ; AD9850 scrie ceasul
DDS_dat equ 0x07 ; AD9850 introducere datelor de serie
; Biți registru A:
pb_switch equ 0x03 ; Calibrarea Push Button-lui
După care alocă variabilele în scop general, în spațiu de registru; la care la sfârșit microcontrolerul este resetat la 0, adică la 0x00 și vectorul de întrerupere este setat la 0x04.
Programul folosește așa numit masă de bandă la care fiecare intrare este alcătuit din patru instrucțiuni lungi; fiecare grup de patru literali reprezintă frecvența ca un întreg pe 32 de biți. Noile mențiuni pot fi adăugate la sfârșitul tabelului sau între intrările existente. Constantă band_end trebuie incrementată cu 4 pentru fiecare intrare adăugat. Acest tabel este plasat în partea de sus a programului, pentru a permite o masă cât mai mare posibil pentru a fi indexat cu valoarea opt biți în W.
După resetarea microcontrolerului secvența următoare Sare în jurul mesei de bandă la programul principal.
ORG 0x0000
reset_entry
goto start
După care vine masa de bandă cu 4 instrucțiuni.
band_table
addwf PCL,f ;
retlw 0x00 ; 0 Hz
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ; 160 meters
retlw 0x1B ;
retlw 0x77 ;
retlw 0x40 ;
retlw 0x00 ; 80 meters
retlw 0x35 ;
retlw 0x67 ;
retlw 0xE0 ;
retlw 0x00 ; 40 meters
retlw 0x6A ;
retlw 0xCF ;
retlw 0xC0 ;
retlw 0x00 ; 30 meters
retlw 0x9A ;
retlw 0x1D ;
retlw 0x20 ;
retlw 0x00 ; 20 meters
retlw 0xD5 ;
retlw 0x9F ;
retlw 0x80 ;
retlw 0x01 ; 17 meters
retlw 0x13 ;
retlw 0xB2 ;
retlw 0x20 ;
retlw 0x01 ; 15 meters
retlw 0x40 ;
retlw 0x6F ;
retlw 0x40 ;
retlw 0x01 ; 12 meters
retlw 0x7B ;
retlw 0xCA ;
retlw 0x90 ;
retlw 0x01 ; 10 meters
retlw 0xAB ;
retlw 0x3F ;
retlw 0x00 ;
retlw 0x01 ; 30 MHz
retlw 0xC9 ;
retlw 0xC3 ;
retlw 0x80 ;
Până acum a fost vorba despre tipul de dispozitiv pe care folosim, configurarea siguranței, ecuații pe care folosește programul, porturi, constanta EEPROM și așa mai departe. Acuma urmează codul principal, adică putem să spunem că aicea începe programul. Are ca scop să inițializează displayul LCD și detectează dacă să intre în modul de calibrare. Dacă detectează intră în rutina de calibrare. În caz contrar, se stabilește frecvența de pornire și intră în bucla de sondaj a codificatorului. Din asta rezultă ca intrarea, adică inputul este frecvența de pornire care este definit în default 3, definițiile de mai sus, se bazează pe oscilatorul de referință și constanta este definită în ref_osc_3, ref_osc_2, ref_osc_1, ref_osc_0. Ca rezultat la ieșire, adică la output primim funcționarea normală a generatorului de semnal.
start
clrf INTCON ; Nu sunt întreruperi de acum
bsf STATUS,B_RP0 ; Comută la banca 1
bsf 0x01,7 ; Dezactivarea tracțiuni slabe
movlw 0xFF ; Port tri state A
movwf TRISA ;
clrf TRISB ; Setează portul B la toate ieșirile
bcf STATUS,B_RP0 ; Comută înapoi la bancă 0
call init_LCD ; Inițializează LCD
Întră în modul de calibrare în cazul în care buton este apăsat în timp ce porniți alimentarea.
btfsc PortA,pb_switch ; Este apăsat comutatorul?
goto read_EEocs ; Nu, obține ceas de frecvențe de la EEPROM
call calibrate ; Da, calibră
Ia constanta oscilator de referință de la EEPROM.
read_EEocs
clrf EEadr ; Resetă adresa de citire EEPROM
call read_EEPROM ; Citește EEPROM
movf EEdata,w ; Ia primul bit OSC
movwf osc_0 ; Salvează frecvență OSC
call read_EEPROM ; Ia următorul bit
movf EEdata,w ;
movwf osc_1 ; Salvează
call read_EEPROM ; Ia al treilea bit
movf EEdata,w ;
movwf osc_2 ; Salvează
call read_EEPROM ; Ia al patrulea bit
movf EEdata,w ;
movwf osc_3 ; Salvează
Setează puterea de la frecvență la valoarea definită.
movlw default_0 ; Ia cel mai puțin semnificativ bit
movwf freq_0 ; Salvează
movlw default_1 ; Ia următorul bit
movwf freq_1 ; Salvează
movlw default_2 ; Și următorul
movwf freq_2 ; Salvează
movlw default_3 ; Obține cel mai semnificativ bit
movwf freq_3 ; Salvează
Afișarea puterea pe frecvență.
call bin2BCD ; Îl transformă în BCD
call show_freq ; Afișă
Trimite puterea de frecvență la cip DDS.
call calc_dds_word ; Conversia în valoare delta
call send_dds_word ; Trimite frecvența de pornire a
; AD9850 în modul de serie
Ia puterea de la valoarea codificatorului.
movf PortA,w ; Citește portul A
movwf ren_read ; Salvează în ren_read
movlw 0x03 ; Ia masca encoder
andwf ren_read,w ; Ia biți encoder
movwf ren_old ; Salvează în ren_old
Inițializa variabile.
clrf ren_timer_1 ; Inițializa cronometrul viteză encoder
movlw 0x40 ; la
movwf ren_timer_0 ; 0x0040
clrf last_dir ; Șterge indicatorul de direcție
clrf band ; Șterge indicatorul de bandă
După inițializarea LCD-ul și detectarea să intră în modul de calibrare sau nu, se încadrează mai departe spre buclă principală a codului. Asta are ca scopul să apeleze la poll_encoder. Când arbora codificatorului se schimbă direcția în care se mută este determinată și stocată în last_dir. Subrutina apoi revine la programul principal.
În cazul în care comutatorul de buton nu a fost apăsată, atunci fstep variabilă este calculată pe baza de întârziere între modificarea arborele codificatorului. ren_timer conține valoarea de întârziere determinată de subrutina poll_encoder. Se adaugă fstep variabil sau scade de la frecvența VFO curent stocate în frecvențe. Conținutul de frecvențe sunt apoi convertite la un număr BCD în subrutina bin2BCD. Subrutină show_freq este apoi apelat pentru a afișa rezultatul pe Display-ul LED. Apoi, calc_dds_word subrutina este folosit pentru a calcula DDS cuvântul de control al frecvenței de la valorile de frecvențe și OSC. Rezultatul este stocat în AD9850. Aceste date sunt transferate la cipul AD9850 DDS prin subrutina apel send_dds_word.
Dacă butonul este apăsat în timp ce pornește codificatorul atunci frecvența este încărcat cu o constantă stocate în band_table. Banda variabilă este folosit ca index în tabela. Banda este incrementat sau decrementat în funcție de direcția codificatorului.
main
call poll_encoder ; Verificarea pentru mișcarea butonului
btfss ren_read,3 ; Schimbă banda?
goto change_band ; Da, schimbă banda
Determină pasul dimensiunii pentru a folosi (1 Hz sau 1 kHz).
clrf fstep_3 ; Dorește 1Hz pentru stabilirea fstep la ; unu.
clrf fstep_2 ;
clrf fstep_1 ;
movlw 0x01 ;
movwf fstep_0 ;
btfsc ren_read,2 ; Este apăsat butonul codificatorului?
goto go_step ; Nu, utilizează pasul 1 Hz
movlw 0xE8 ; Da, setați valoarea pasului de 1 kHz
movwf fstep_0 ; prin stabilirea fstep_0 la 0xE8 și
movlw 0x03 ; fstep_1 la 0x03
movwf fstep_1 ;
goto go_step ; Utilizează pasul 1 kHz
Reglați pas de tuning bazat pe ren_timer. ren_timer este incrementat cu 8 de la valoarea inițială de 0x0040 de fiecare dată când poll_encoder găsește nici o schimbare la intrarea codificatorului până când bitul ridicat de ren_timer_1 devine unu. Implicit
fstep de 1 Hz este înmulțit cu doi pentru fiecare zero la ren_timer, până la un maxim 9 ori. Cu cât mai repede butonul este rotit, cu atât scade numărul la ren_timer și va fi valoare de pas mai mare.
bump_step
bcf STATUS,B_C ;
rlf fstep_0,f ; Multiplicarea pasul cu 2 prin rotirea ; la stânga
rlf fstep_1,f ;
rlf fstep_2,f ;
rlf fstep_3,f ;
go_step
rlf ren_timer_0,f ; Multiplică cronometrul codificatorului
; cu 2
rlf ren_timer_1,f ;
btfss STATUS,B_C ;
goto bump_step ;
În funcție de direcția butonului, fie adunarea sau scăderea incrementului, actualizează LCD-ul și DDS-ul.
btfsc last_dir,1 ; Crește?
goto up ; Da, atunci se adaugă incrementul
down
call sub_step ; Scade fstep de la frecvența
goto write ; Actualizarea LCD și DDS
up
call add_step ; Adaugă fstep la frecvența
call check_add ; Asigurarea că nu este depăși valoarea ; maximă
goto write ; Actualizarea LCD și DDS
Următorul segment de incrementare prin masă de bandă, fiecare dată când butonului se mută o crestătură, actualizează LCD-ul și DDS-ul, până când butonul de bandă nu mai este apăsat.
change_band
btfsc last_dir,1 ; Merge sus în lista de bandă?
goto band_up ; Da, adresa bandă creștere
movlw 0x04 ; Nu, primește 4 biți pentru scădere
subwf band,f ; Deplasarea jos în lista de bandă
movlw 0xFF-band_end ; Verificați pentru a vedea dacă am căzut
addwf band,w ; de pe partea de jos a tabelului.
btfss STATUS,B_C ; Pe partea de jos?
goto valid ; Nu, continua
movlw band_end ; Da, du-te la cel mai înalt intrare
movwf band ;
valid
call get_band ; Ia noua banda de frecvență
goto write ; Setează frecvența și continuă
band_up
movlw 0x04 ; Intrări de tabel sunt 4 biți distanță
addwf band,f ; Incrementarea indicatorul de bandă
movlw 0xFF-band_end ; Verificarea pentru a vedea dacă am
addwf band,w ; trecut peste partea de sus a tabelului.
btfsc STATUS,B_C ; Am trecut peste partea de sus a ; tabelului?
clrf band ; Da, du-te la intrarea de jos
call get_band ; Ia noua banda de frecvență
write
call bin2BCD ; Convertă frecvența la BCD
call show_freq ; Afișarea frecvența pe ecranul LCD
call calc_dds_word ; Găsește cuvântul de control pentru cip ; DDS
call send_dds_word ; Trimite cuvântul de control pentru ; cip DDS
goto main ; Continua interogarea codificatorului
Următorul rutină citește valoarea de frecvență de la o intrare de tabel de bandă indicat cu bandă și returnează aceasta în freq_3 … freq_0. După care trece la inițializarea ecranul LCD. Ecranul LCD trebuie să fie echivalent cu un Hitachi 44780, se presupune că ecran LCD este dimensiunea de 16 X 2. Toate inițializare se produce in subrutina init_LCD.
Rutina următoare se adaugă la valoarea de 32 biți al fstep la valoarea de 32 biți la frecvențe. Când incrementează, valoarea fstep este un număr întreg pozitiv. Când este decrementat, fstep este valoarea scăzute al complementului.
add_step
movf fstep_0,w ; Ia bitul scăzută a incrementului
addwf freq_0,f ; Adaugă-l la bitul scăzut de frecvențe
btfss STATUS,B_C ; Orice transfer?
goto add1 ; Nu, se adaugă la bitul următor
incfsz freq_1,f ; Pulsația transportă până la următorul ; bit
goto add1 ; Nu transportă nou, se adaugă următorul ; bit
incfsz freq_2,f ; Pulsația transportă până la următorul ; bit
goto add1 ; Nu transporta nou, se adaugă următorul ; bit
incf freq_3,f ; Pulsația transportă până la cel mai ; înalt bit
add1
movf fstep_1,w ; Ia următorul bit de incrementare
addwf freq_1,f ; Adauga-l la următoarea bit superior
btfss STATUS,B_C ; Orice transport?
goto add2 ; Nu, se adaugă la bitul următor
incfsz freq_2,f ; Pulsația transporta până la următorul ; bit
goto add2 ; Nu transporta nou, se adaugă următorul ; bit
incf freq_3,f ; Pulsația transporta până la cel mai ; înalt octet
add2
movf fstep_2,w ; Ia următorul cea mai semnificativă ; increment
addwf freq_2,f ; Adaugă-l la bitul de frecvențe
btfss STATUS,B_C ; Orice transport?
goto add3 ; Nu, se adaugă ultimul bit
incf freq_3,f ; Pulsația transportă până la cel mai ; înalt bit
add3
movf fstep_3,w ; Obține cel mai semnificativ bit de ; incrementare
addwf freq_3,f ; Adaugă-l la cea mai semnificativă ; frecvențe
return ; Revenim la apelant
Următorul pas ar fi verificarea dacă frecvențe depășește limita superioară. În care verifică cel mai semnificativ bit, după aia verifică al doilea cel mai semnificativa bit, al treilea cel mai semnificativ bit și verifică în ultimul rând cel mai puțin semnificativ bit, după care revine la apelant.
Se scade pasul de incrementare de frecvențe, și verifică să nu trece sub zero.
sub_step
comf fstep_0,f ; Scăderea fstep de la
comf fstep_1,f ; frecvențe se face prin adaugarea
comf fstep_2,f ; compliment câte două de la fstep
comf fstep_3,f ; frecvențe.
incfsz fstep_0,f ; Incrementare ultimul bit
goto comp_done ; Diferită de zero, continuă
incfsz fstep_1,f ; Incrementare următorul bit
goto comp_done ; Diferită de zero, continuă
incfsz fstep_2,f ; Incrementare următorul bit
goto comp_done ; Diferită de zero, continuă
incf fstep_3,f ; Incrementare bitul înaltă
comp_done
call add_step ; Adaugă compliment pentru a face ; scăderea
În cazul în care frecvența a plecat negativ, se șterge la zero.
btfss freq_3,7 ; Este frecvența înaltă bit "negativ"?
goto exit2 ; Nu, merge mai departe
set_min
clrf freq_0 ; Da, setează frecvența la zero
clrf freq_1 ;
clrf freq_2 ;
clrf freq_3 ;
exit2
return ; Revenim la apelant
Secvența care urmează face următoarele înregistrează cât de mult le-a luat pentru butonul să se mute o crestătură în ren_timer. Șterge timer-ul watchdog. Și citește biții codificatorului până când este detectată o schimbare. Când este detectată o schimbare, atunci determină direcția la care a fost mutat butonul.
După secvența anterior programul avansează la rutina când programul a intrat în mod de calibrare. Cum a fost menținut aceasta rutina intră în mod de calibrare numai dacă este apăsat butonul la pornirea sistemului. "10,000.00 CAL" este afișat pe ecranul LCD, iar cipul DDS este programat pentru a produce 10 MHz, în funcție de valoarea OSC stocate în EEPROM. Atâta timp cât este apăsat butonul, valoarea OSC este modificată lent pentru a permite ieșirea să fie tăiată la exact 10 MHz. Odată codificatorul este rotit după ce butonul este eliberat, noua valoare OSC este stocată în EEPROM și începe funcționarea normală.
calibrate
movlw 0x80 ; Setează frecvența de 10MHz de
movwf freq_0 ; setarea de frecvențe la echivalentul ; binar
movlw 0x96 ; de 10.000.000.
movwf freq_1 ; .
movlw 0x98 ; .
movwf freq_2 ; .
movlw 0x00 ; .
movwf freq_3 ; .
După care citește valorarea de referință a oscilatorului de la EEPROM.
Urmează rutina, unde trimite cuvântul de control AD9850 la cip DDS folosind un transfer de date seriale. Asta se întâmplă la rutina send_dds_word.
send_dds_word
movlw AD9850_0 ; Punct FSR la AD9850
movwf FSR ;
next_byte
movf INDF,w ;
movwf byte2send ;
movlw 0x08 ; Setează contorul la 8
movwf bit_count ;
next_bit
rrf byte2send,f ; Testarea în cazul în care următorul bit ; este 1 sau 0
btfss STATUS,B_C ; A fost zero?
goto send0 ; Da, trimite la zero
bsf PortB,7 ; Nu, trimite unu
bsf PortB,5 ; Ceas de scriere comutare
bcf PortB,5 ;
goto break ;
send0
bcf PortB,7 ; Trimite la zero
bsf PortB,5 ; Ceas de scriere comutare
bcf PortB,5 ;
break
decfsz bit_count,f ; A fost trimis toate biți?
goto next_bit ; Nu, merge mai departe.
incf FSR,f ; Începe următorul bit dacă nu e terminat
movlw AD9850_4+1 ; Următorul bit
subwf FSR,w ;
btfss STATUS,B_C ;
goto next_byte ;
bsf PortB,0 ; Trimite semnal de sarcină la AD9850
bcf PortB,0 ;
return ;
Subrutina următoare convertește un număr de 32 de biți în binar la un număr de BCD 10 cifre. Valoarea de intrare luată de la freq(0 la 3) este păstrată. Ieșirea este în BCD (0 la 4), și păstrează fiecare bit (hi_digit,lo_digit) cele mai semnificative cifre se afle în BCD_4.
bin2BCD
movlw 0x20 ; Setează contorul de buclă
movwf BCD_count ; la 32
clrf BCD_0 ; Șterge ieșirea
clrf BCD_1 ; " "
clrf BCD_2 ; " "
clrf BCD_3 ; " "
clrf BCD_4 ; " "
bin_loop
bcf STATUS,B_C ; Șterge bitul de transport în STATUS
Se rotească biți în biți de frecvențe. Mută de la bitul LS (freq_0) la bitul următoare (freq_1). De asemenea, trecerea de la freq_1 la freq_2 și de la freq_2 la freq_3.
rlf freq_0,f ; Rotire la stânga, 0->LS bit, MS bit-> ; -> Carry
rlf freq_1,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
rlf freq_2,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
rlf freq_3,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
btfsc STATUS,B_C ; Transportul este clar?
; Dacă da, sare instrucțiunea următoare
bsf freq_0,0 ; Transportul este setat la bitul 0 în
; freq_0
Construiește biți BCD. Mute în LS bit în BCD bit (LS de BCD_0) de la MS bit de freq_3 prin bit Carry.
rlf BCD_0,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
rlf BCD_1,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
rlf BCD_2,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
rlf BCD_3,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
rlf BCD_4,f ; Rotire la stânga, Carry->LS bit, MS ; bit->Carry
decf BCD_count,f ; Decrementează numărul de buclă
btfss STATUS,B_Z ; Este, acuma contorul de buclă zero?
goto adjust ; Nu, merge să face reglare
return ; Da, iese
Subrutina adjust este o subrutină intern, la care bin2BCD apelează numai la buclă principală. Așa cum biți BCD sunt construite, asigură că nu este mai mare decât 9. În cazul în care devine mai mare decât 9, incrementează următorul.
adjust
movlw BCD_0 ; Ia pointerul de la BCD_0
movwf FSR ; Pune pointerul în FSR pentru abordarea ; indirectă
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă ; la BCD_1
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă ; la BCD_2
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă ; la BCD_3
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă ; la BCD_4
call adj_BCD ;
goto bin_loop ; Trece înapoi la bucla principală
Subrutină intern, apelează numai adjust
adj_BCD
movlw 3 ; Adaugă 3
addwf INDF,w ; la cel mai puțin semnificativ bit
movwf BCD_temp ; Salvează în temp
btfsc BCD_temp,3 ; Este cel mai puțin semnificativ bit + 3 ; > 7
movwf INDF ; Da, salvează valoare incrementat ca cel ; mai puțin semnificat bit
movlw 0x30 ; Adaugă 3
addwf INDF,w ; la cel mai semnificatic bit
movwf BCD_temp ; Salvează în temp
btfsc BCD_temp,7 ; Este cel mia semnificativ bit +3 > 7
movwf INDF ; Da, salvați valoare incrementat ca cel ; mai semnificativ bit
return ; Revine la subrutina adjust
Verifică dacă LCD s-a efectuat ultima operație. Subrutina următoare este pentru a determina dacă LCD-ul a realizat ultima operație.
busy_check
clrf PortB ; Șterge toate ieșirile pe PortB
bsf STATUS,B_RP0 ; Comută cu bancă 1 pentru operarea ; Tristate
movlw b'11110000' ; Setează RB7, RB6, RB5, RB4 ca intrări ; și RB3, RB2, RB1, RB0 ca ieșiri
movwf TRISB ; prin Tristate
bcf STATUS,B_RP0 ; Comuta înapoi la bancă 0
bcf PortB,LCD_rs ; Configură LCD pentru Read Busy Flag bsf PortB,LCD_rw ; Configură LCD pentru Read
movlw 0xFF ; Configură constanta 255
movwf timer1 ; pentru cronometru buclă contor
LCD_is_busy
bsf PortB,LCD_e ; Set E înalt
movf PortB,w ; Citește PortB în W
movwf LCD_read ; Salvează W pentru testarea mai târziu
bcf PortB,LCD_e ; Aruncă din nou E
nop ; Așteaptă
nop ; puțin timp
bsf PortB,LCD_e ; Puls E înalt
nop ; așteaptă,
bcf PortB,LCD_e ; și aruncă E iarăși
decf timer1,f ; Decrementează bucla de contor
btfsc STATUS,B_Z ; Este bucla de contor la zero?
goto not_busy ; Dacă da, întoarce indiferent btfsc LCD_read,7 ; Este bitul Busy Flag (RB7) salvat?
goto LCD_is_busy ; Dacă nu, este ocupat și sare înapoi
not_busy
return
Secvența de cod care urmează se referă la EEPROM. Scrie bitul de date la EEdata la EEPROM la adresa EEadr.
write_EEPROM
bsf STATUS,B_RP0 ; Comută la bancă 1
bsf EEdata,WREN ; Setează EEPROM la bit write enable
movlw 0x55 ; Scrie 0x55 și 0xAA la EEPROM
movwf EEadr ; registru de control, după cum este ; necesar
movlw 0xAA ; pentru scriere
movwf EEadr ;
bsf EEdata,WR ; Setează WR să inițieze scriere
bit_check
btfsc EEdata,WR ; A finalizat scrierea?
goto bit_check ; Nu, păstreze verificarea
bcf EEdata,WREN ; Golește la EEPROM bitul write enable
bcf STATUS,B_RP0 ; Comuta la bancă 0
incf EEadr,f ; Incrementează adresa de scriere EE
return ; Revine la apelant
Citește un bit de date EEPROM la adresa EEADR în EEDATA.
read_EEPROM
bsf STATUS,B_RP0 ; Comuta la bancă 1
bsf EEdata,RD ; Cerere de citire
bcf STATUS,B_RP0 ; Comuta la bancă 0
incf EEadr,f ; Incrementează adresa de citire
return ; Revine la apelant
După citirea din EEPROM, ultimul secvență este pentru așteptarea pentru un anumit număr de milisecunde. În care avem
Punct de intrare wait_128ms: Așteaptă 128 ms
Punct de intrare wait_64ms: Așteaptă 64 ms
Punct de intrare wait_32ms: Așteaptă 32 ms
Punct de intrare wait_16ms: Așteaptă 16 ms
Punct de intrare wait_8ms: Așteaptă 8 ms
wait_128ms
movlw 0xFF ; Configurarea buclei exterioară
movwf timer1 ; contorul la 255
goto outer_loop ; Merge la bucle de așteptare
wait_64ms
movlw 0x80 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 128
goto outer_loop ; Merge la bucle de așteptare
wait_32ms
movlw 0x40 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 64
goto outer_loop ; Merge la bucle de așteptare
wait_16ms
movlw 0x20 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 32
goto outer_loop ; Merge la bucle de așteptare
wait_8ms
movlw 0x10 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 16
outer_loop
movlw 0xFF ; Configurarea contorul buclă interioară movwf timer2 ; la 255
inner_loop
decfsz timer2,f ; Decrementează contorul de buclă ; interioară
goto inner_loop ; Dacă contor buclă interior nu este la ; zero, apoi merge înapoi la bucla ; interioară din nou
decfsz timer1,f ; Da, Decrementează contorul buclă ; exterioară
goto outer_loop ; Dacă contor buclă exterioară nu este la ; zero, apoi merge înapoi la bucla ; exterioară din nou
return ; Da, revine la apelant
După asta iese din buclă și termină programul.
Rezultate experimentale
––
Concluzi
––
Bibliografie
[1] Ian Poole, DDS basics, http://www.radio-electronics.com/info/rf-technology-design/pll-synthesizers/direct-digital-synthesizer-dds-tutorial.php
[2] Paul Kern (July 2007). "Direct digital synthesis enables digital PLLs".
[3] Nebojsa Matic (May 2000) PIC microcontrollers for beginners, too!
[4] Tutorialspoint, Assembly – Introduction, http://www.tutorialspoint.com/assembly_programming/assembly_introduction.htm
[5] Analog Devices, Inc., All About Direct Digital Synthesis, http://www.analog.com/library/analogdialogue/archives/38-08/dds.html
Anexa
Anexa 1 Schema DDS
Anexa 2 Cod sursă
; ****************************************************************************
; * Tip de dispozitiv și opțiuni *
; ****************************************************************************
processor PIC16F84
radix dec
errorlevel -220
errorlevel -305
; ****************************************************************************
; * Informațiile de configurare al siguranței *
; ****************************************************************************
_CP_ON EQU H'000F'
_CP_OFF EQU H'3FFF'
_PWRTE_ON EQU H'3FF7'
_PWRTE_OFF EQU H'3FFF'
_WDT_ON EQU H'3FFF'
_WDT_OFF EQU H'3FFB'
_LP_OSC EQU H'3FFC'
_XT_OSC EQU H'3FFD'
_HS_OSC EQU H'3FFE'
_RC_OSC EQU H'3FFF'
__config _CP_OFF & _PWRTE_ON & _WDT_ON & _XT_OSC
;Stabilit pentru 100 MHz.
ref_osc_3 equ 0x2A ; Cel mai semnificativ bit la oscilator
ref_osc_2 equ 0xF3 ; Bitul următoare
ref_osc_1 equ 0x1D ; Bitul următoare
ref_osc_0 equ 0xC4 ; Cel mai puțin semnificativ bit
; Limita conține frecvența limită superioară precum un număr întreg de 32 de biț.
limit_3 equ 0x01 ; Cel mai semnificativ bit pentru 30 MHz
limit_2 equ 0xC9 ; Bitul următoare
limit_1 equ 0xC3 ; Bitul următoare
limit_0 equ 0x80 ; Cel mai puțin semnificativ bit
; Implicit conține frecvența de pornire implicit ca un întreg pe 32 de biț.
default_3 equ 0x00 ; Cel mai semnificativ bit pentru 14.025 MHz
default_2 equ 0xD6 ; Bitul următoare
default_1 equ 0x01 ; Bitul următoare
default_0 equ 0x28 ; Cel mai puțin semnificativ bit
band_end equ 0x28 ; Diferența față de ultima intrare tabel bandă
; ****************************************************************************
; * Port și EEPROM Constantă *
; ****************************************************************************
PortA equ 0x05
PortB equ 0x06
TRISA equ 0x05
TRISB equ 0x06
EEdata equ 0x08
EEadr equ 0x09
WREN equ 0x02
WR equ 0x01
RD equ 0x00
; ****************************************************************************
; * Informații despre locație ID *
; ****************************************************************************
ORG 0x2000
DATA 0x007F
DATA 0x007F
DATA 0x007F
DATA 0x007F
; ****************************************************************************
; * Configurare constanta inițială, în funcție de frecvența oscilatorului *
; * de referință. Acest lucru poate fi optimizat cu funcția de calibrare. *
; ****************************************************************************
ORG 0x2100
DATA ref_osc_0
DATA ref_osc_1
DATA ref_osc_2
DATA ref_osc_3
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; ****************************************************************************
; * Pagina RAM registre de fișiere independente: *
; ****************************************************************************
INDF EQU 0x00
PCL EQU 0x02
STATUS EQU 0x03
FSR EQU 0x04
PCLATH EQU 0x0A
INTCON EQU 0x0B
; *****************************************************************************
; * Numere de biți pentru registrul STATUS: *
; *****************************************************************************
B_RP0 EQU 5
B_NTO EQU 4
B_NPD EQU 3
B_Z EQU 2
B_DC EQU 1
B_C EQU 0
; ****************************************************************************
; * Atribuirea numele de pini IO. *
; ****************************************************************************
; Biți registru B:
DDS_load equ 0x00 ; Actualizarea PIN-ul pe AD9850
LCD_rs equ 0x01 ; 0=instrucțiune, 1=data
LCD_rw equ 0x02 ; 0=scriere, 1=citire
LCD_e equ 0x03 ; 0=inactivare, 1=activare
DDS_clk equ 0x05 ; AD9850 scrie ceasul
DDS_dat equ 0x07 ; AD9850 introducere datelor de serie
; Biți registru A:
pb_switch equ 0x03 ; Calibrarea Push Button-lui, (activ scăzut)
; ****************************************************************************
; * Alocă variabile în scop general, spațiu registru *
; ****************************************************************************
CBLOCK 0x0c ; Start date Block
freq_0 ; Frecvență de afișare (hex)
freq_1 ; (4 biți)
freq_2
freq_3
BCD_0 ; Frecvență de afișare (BCD)
BCD_1 ; (5 biți)
BCD_2
BCD_3
BCD_4
AD9850_0 ; AD9850 cuvânt de control
AD9850_1 ; (5 biți)
AD9850_2
AD9850_3
AD9850_4
fstep_0 ; Frecvență inc/dec
fstep_1 ; (4 biți)
fstep_2
fstep_3
BCD_count ; Folosit în rutina bin2BCD
BCD_temp ; "
mult_count ; Folosit în calc_dds_word
bit_count ; "
byte2send ;
osc_0 ; Oscilator actuală
osc_1 ; (4 biți)
osc_2
osc_3
osc_temp_0 ; Frecvență de oscilație
osc_temp_1 ; (4 biți)
osc_temp_2
osc_temp_3
LCD_char ; Caracter fiind trimis la LCD
LCD_read ; Caracter citit de pe ecranul LCD
timer1 ; Utilizat în rutine de întârziere
timer2 ; "
ren_timer_0 ; Pentru acordare rată variabilă
ren_timer_1 ; (2 biți)
ren_new ; Nou valoare a encoderului pini A și B
ren_old ; Vechea valoare a encoderului pini A și B
ren_read ; Pini encoder A și B și comutator pini
last_dir ; Indică ultima direcție de encoder
next_dir ; Indică direcția așteptată
count ; contor buclă
band ; Utilizat pentru a indexa un tabel de frecvențe
rs_value ; Valoarea LCD rs
ENDC ; Sfârșitul blocul de date
; ****************************************************************************
; * 16F84 resetează la 0x00. *
; * Vectorul de întrerupere este la 0x04. (Nefolosit) *
; ****************************************************************************
ORG 0x0000
reset_entry
goto start ; Sare în jurul tabela de bandă
; la programul principal
band_table
addwf PCL,f ;
retlw 0x00 ; 0 Hz
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ; 160 metri
retlw 0x1B ;
retlw 0x77 ;
retlw 0x40 ;
retlw 0x00 ; 80 metri
retlw 0x35 ;
retlw 0x67 ;
retlw 0xE0 ;
retlw 0x00 ; 40 metri
retlw 0x6A ;
retlw 0xCF ;
retlw 0xC0 ;
retlw 0x00 ; 30 metri
retlw 0x9A ;
retlw 0x1D ;
retlw 0x20 ;
retlw 0x00 ; 20 metri
retlw 0xD5 ;
retlw 0x9F ;
retlw 0x80 ;
retlw 0x01 ; 17 metri
retlw 0x13 ;
retlw 0xB2 ;
retlw 0x20 ;
retlw 0x01 ; 15 metri
retlw 0x40 ;
retlw 0x6F ;
retlw 0x40 ;
retlw 0x01 ; 12 metri
retlw 0x7B ;
retlw 0xCA ;
retlw 0x90 ;
retlw 0x01 ; 10 metri
retlw 0xAB ;
retlw 0x3F ;
retlw 0x00 ;
retlw 0x01 ; 30 MHz
retlw 0xC9 ;
retlw 0xC3 ;
retlw 0x80 ;
; *****************************************************************************
; * Acesta este începutul programului. *
; *****************************************************************************
start
clrf INTCON ; Nu sunt întreruperi de acum
bsf STATUS,B_RP0 ; Comută la banca 1
bsf 0x01,7 ; Dezactivarea tracțiuni slabe
movlw 0xFF ; Port tri state A
movwf TRISA ;
clrf TRISB ; Setează portul B la toate ieșirile
bcf STATUS,B_RP0 ; Comuta înapoi la bancă 0
call init_LCD ; Inițializă LCD
; Întră în modul de calibrare în cazul în care buton este apăsat în timp ce porniți
; alimentarea.
btfsc PortA,pb_switch ; Este apăsat comutatorul?
goto read_EEocs ; Nu, obține ceas de frecvențe de la EEPROM
call calibrate ; Da, calibră
; Ia constanta oscilator de referință de la EEPROM.
read_EEocs
clrf EEadr ; Resetă adresa de citire EEPROM
call read_EEPROM ; Citește EEPROM
movf EEdata,w ; Ia primul bit OSC
movwf osc_0 ; Salvează frecvență OSC
call read_EEPROM ; Ia următorul bit
movf EEdata,w ;
movwf osc_1 ; Salvați-l
call read_EEPROM ; Ia al treilea bit
movf EEdata,w ;
movwf osc_2 ; Salvați-l
call read_EEPROM ; Ia al patrulea bit
movf EEdata,w ;
movwf osc_3 ; Salvați-l
; Setează puterea de la frecvență la valoarea definită.
movlw default_0 ; Ia cel mai puțin semnificativ bit
movwf freq_0 ; Salvați-l
movlw default_1 ; Ia următorul bit
movwf freq_1 ; Salvați-l
movlw default_2 ; Și următorul
movwf freq_2 ; Salvați-l
movlw default_3 ; Obține cel mai semnificativ bit
movwf freq_3 ; Salvați-l
; Afișarea puterea pe frecvență.
call bin2BCD ; Îl transformă în BCD
call show_freq ; Afișă
; Trimite puterea de frecvență la cip DDS.
call calc_dds_word ; Conversia în valoare delta
call send_dds_word ; Trimite frecvența de pornire a
; AD9850 în modul de serie
; Ia puterea de la valoarea encoder.
movf PortA,w ; Citesc portul A
movwf ren_read ; Salvați-l în ren_read
movlw 0x03 ; Ia masca encoder
andwf ren_read,w ; Ia biți encoder
movwf ren_old ; Salvați în ren_old
; Inițializa variabile.
clrf ren_timer_1 ; Inițializa cronometrul viteză encoder
movlw 0x40 ; la
movwf ren_timer_0 ; 0x0040
clrf last_dir ; Șterge indicatorul de direcție
clrf band ; Șterge indicatorul de bandă
; Se încadrează în programul principal de buclă
main
call poll_encoder ; Verificați mișcarea butonului
btfss ren_read,3 ; Schimba banda?
goto change_band ; Da, schimba banda
; Determina dimensiunea pas de a utiliza (1 Hz sau 1 kHz).
clrf fstep_3 ; Ne dorim 1 Hz prin stabilirea fstep la 1.
clrf fstep_2 ;
clrf fstep_1 ;
movlw 0x01 ;
movwf fstep_0 ;
btfsc ren_read,2 ; Este apăsat butonul encoder?
goto go_step ; Nu, utilizează pasul 1 Hz
movlw 0xE8 ; Da, setați valoarea pasului de 1 kHz
movwf fstep_0 ; prin stabilirea fstep_0 la 0xE8 și
movlw 0x03 ; fstep_1 la 0x03
movwf fstep_1 ;
goto go_step ; Utilizați pasul 1 kHz
bump_step
bcf STATUS,B_C ; Șterge carry flag-ul
rlf fstep_0,f ; Multiplică pasul cu 2 pentru rotirea la stânga
rlf fstep_1,f ;
rlf fstep_2,f ;
rlf fstep_3,f ;
go_step
rlf ren_timer_0,f ; Multiplică cronometrul encoder cu 2
rlf ren_timer_1,f ;
btfss STATUS,B_C ;
goto bump_step ;
; În funcție de direcția butonul, fie pentru a adăuga sau scade increment,
; apoi actualizează LCD și DDS.
btfsc last_dir,1 ; Butonul merge în sus?
goto up ; Da, apoi se adaugă increment
down
call sub_step ; Scade fstep de frecvențe
goto write ; Actualizare LCD și DDS
up
call add_step ; Adaugă fstep la frecvențe
call check_add ; Asigură că nu am depăși valoarea maximă
goto write ; Actualizarea LCD și DDS
change_band
btfsc last_dir,1 ; Mergem sus în lista de bandă?
goto band_up ; Da, incrementează adresa de bandă
movlw 0x04 ; Nu, primește 4 biți pentru a scădea
subwf band,f ; Mutare în jos în lista de bandă
movlw 0xFF-band_end ; Verificarea pentru a vedea dacă am
addwf band,w ; căzut de pe partea de jos a tabelului.
btfss STATUS,B_C ; Căzut de pe tabel?
goto valid ; Nu, continuă
movlw band_end ; Da, merge la cel mai înalt intrare
movwf band ;
valid
call get_band ; Ia noua banda de frecvență
goto write ; Setează frecvența și continua
band_up
movlw 0x04 ; Intrări de tabel sunt 4 biți de distanță
addwf band,f ; Incrementarea indicatorul benzii
movlw 0xFF-band_end ; Verificarea pentru a vedea dacă am trecut de-a lungul
addwf band,w ; partea de sus a tabelului.
btfsc STATUS,B_C ; Am trece peste partea de sus a tabelului?
clrf band ; Da, du-te la intrarea de jos
call get_band ; Ia noua banda de frecvență
write
call bin2BCD ; Convertesc frecvența la BCD
call show_freq ; Afișarea frecvenței pe ecranul LCD
call calc_dds_word ; Găsește cuvântul de control pentru cip DDS
call send_dds_word ; Trimite cuvântul de control pentru cipul DDS
goto main ; Continua interogarea codificatorului
get_band
movf band,w ; Ia indicele octetul
call band_table ; Ia valoarea în W
movwf freq_3 ; Salvează în freq_3
incf band,f ; Incrementarea indicelui pentru următorul octet
movf band,w ; Ia indicele din următorul octet
call band_table ; Ia valoarea în W
movwf freq_2 ; Salvează în freq_2
incf band,f ; Incrementarea indicele pentru următorul octet
movf band,w ; Ia indicele pentru următorul octet
call band_table ; Ia valoarea în W
movwf freq_1 ; Salvează în freq_1
incf band,f ; Incrementarea indicele de octet scăzut
movf band,w ; Ia indicele de octet scăzut
call band_table ; Ia valoarea în W
movwf freq_0 ; Salvează în freq_0
movlw 0x03 ; Obține o constantă trei
subwf band,f ; Restabili valoarea inițială din benzii
return ; Revine la apelant
init_LCD
call wait_64ms ; Așteaptă LCD-ul pentru a porni
movlw 0x30 ; Inițializarea instrucțiunile LCD
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Setați E linia de LCD ridicat,
call wait_64ms ; aștepte un timp "lung",
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x30 ; Inițializarea instrucțiunile LCD
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Set E ridicat,
call wait_32ms ; așteptați puțin,
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x30 ; Inițializarea instrucțiunile LCD
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Set E ridicat,
call wait_32ms ; așteptați puțin,
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x20 ; Instrucțiuni modului 4 bit
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Set E ridicat,
call wait_16ms ; așteptați puțin,
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x28 ; 1/16 ciclu, matrice 5×8
call cmnd2LCD ; Trimite comanda în w la LCD
movlw 0x08 ; Afișarea oprit, cursorul oprit
call cmnd2LCD ; Trimite comanda la LCD
movlw 0x01 ; Ștergerea și resetarea cursorlui
call cmnd2LCD ; Trimite comanda în w la LCD
movlw 0x06 ; Setează cursorul pentru a muta dreapta
call cmnd2LCD ; Trimite comanda în w la LCD
movlw 0x0C ; Afișare pornit, cursorul oprit
call cmnd2LCD ; Trimite comanda în w la LCD
return ;
add_step
movf fstep_0,w ; Ia octetul scăzut a incrementului
addwf freq_0,f ; Adauga-l la octet scăzut din frecvența
btfss STATUS,B_C ; Orice purtătoare?
goto add1 ; Nu, se adaugă următorul octet
incfsz freq_1,f ; Pulsația transportă până la următorul octet
goto add1 ; Nu transportă nou, se adaugă următorul octet
incfsz freq_2,f ; Pulsația transportă până la următorul octet
goto add1 ; Nu transportă nou, se adaugă următorul octet
incf freq_3,f ; Pulsația transportă până la cel mai mare octet
add1
movf fstep_1,w ; Ia următorul octet incrementat
addwf freq_1,f ; Adaugă-l la următoarea octet superior
btfss STATUS,B_C ; Orice purtătoare?
goto add2 ; Nu, se adaugă următorul octet
incfsz freq_2,f ; Pulsația transportă până la următorul octet
goto add2 ; Nu transportă nou, se adaugă următorul octet
incf freq_3,f ; Pulsația transportă până la cel mai înalt octet
add2
movf fstep_2,w ; Ia cea mai semnificativă octet incrementat
addwf freq_2,f ; Adaugă-l la octetul de frecventă
btfss STATUS,B_C ; Orice purtătoare?
goto add3 ; Nu, se adaugă ultimul octet
incf freq_3,f ; Pulsația transportă până la cel mai mare octet
add3
movf fstep_3,w ; Obține cel mai semnificativ increment octet
addwf freq_3,f ; Adaugă-l la cea mai semnificativă frecvență
return ; Revine la apelant
check_add
;
; Verifică cel mai semnificativ octet.
;
movlw 0xFF-limit_3 ; Get
addwf freq_3,w ; Adauga-l la octetul de curent mare
btfsc STATUS,B_C ; A fost ridicat octetul prea mare?
goto set_max ; Da, se aplică limita
movlw limit_3 ; Ia valoare limită ridicată
subwf freq_3,w ; Se scade valoarea limitată
btfss STATUS,B_C ; Suntem la limita octetului?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
;
; Verificați al doilea cel mai important octet.
;
movlw 0xFF-limit_2 ; Get
addwf freq_2,w ; Adauga-l la octetul de curent mare
btfsc STATUS,B_C ; A fost ridicat octetul prea mare?
goto set_max ; Da, se aplică limita
movlw limit_2 ; Al doilea octetul de limită
subwf freq_2,w ; Se scade valoarea limitată
btfss STATUS,B_C ; Suntem la limita octetului?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
;
; Check the third most significant byte.
;
movlw 0xFF-limit_1 ; Get
addwf freq_1,w ; Adauga-l la octetul de curent mare
btfsc STATUS,B_C ; A fost ridicat octetul prea mare?
goto set_max ; Da, se aplică limita
movlw limit_1 ; Al treilea octetul de limită
subwf freq_1,w ; Se scade valoarea limitată
btfss STATUS,B_C ; Suntem la limita octetului?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
;
; Verificarea cel mai puțin semnificativ octet.
;
movlw limit_0 ; Al patrulea octetul de limită
subwf freq_0,w ; Valoarea limită de scădere
btfss STATUS,B_C ; Suntem la limita de octet?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
set_max
movlw limit_0 ; Ia limita cel mai puțin semnificativ
movwf freq_0 ; Pune în frecvențe
movlw limit_1 ; Ia următorul octet de limită
movwf freq_1 ; Pune în freq_1
movlw limit_2 ; Ia următorul octet de limită
movwf freq_2 ; Pune în freq_2
movlw limit_3 ; Ia limita cea mai semnificativă
movwf freq_3 ; Pune în freq_3
exit1
return ; Revine la apelant
sub_step
comf fstep_0,f ; Scăderea fstep de la
comf fstep_1,f ; freq se face prin adaugarea
comf fstep_2,f ; câte două compliment de la fstep
comf fstep_3,f ; la frecvență.
incfsz fstep_0,f ; Incrementare ultimul octet
goto comp_done ; Diferită de zero, continua
incfsz fstep_1,f ; Incrementarea următorul octet
goto comp_done ; Diferită de zero, continua
incfsz fstep_2,f ; Incrementarea următorul octet
goto comp_done ; Diferită de zero, continua
incf fstep_3,f ; Incrementarea octetul cel mai semnificativ
comp_done
call add_step ; Adaugă compliment pentru a face scăderea
;
; În cazul în care frecvența a plecat negativ, se șterge la zero.
;
btfss freq_3,7 ; Frecventa cel mai semnificatic bit este "negativ"?
goto exit2 ; Nu, mergi mai departe
set_min
clrf freq_0 ; Da, setează frecvența la zero
clrf freq_1 ;
clrf freq_2 ;
clrf freq_3 ;
exit2
return ; Revine la apelant
poll_encoder
clrf ren_timer_1 ; Pune valorile de pornire în ren_timer
movlw 0x40 ; Începe cu bitul cel mai semnificativ stabilit în ren_timer
movwf ren_timer_0 ;
read_encoder
clrwdt ; Resetarea cronometrul watchdog
btfsc ren_timer_1,7 ; Are bitul plutit până jos în ren_timer?
goto no_inc ; Da, nu-l muta mai departe
movlw 0x08 ;
addwf ren_timer_0,f ;
btfsc STATUS,B_C ;
incf ren_timer_1,f ;
no_inc ;
movf PortA,w ; Ia valoarea codificatorul curent
movwf ren_read ; Salvează
movlw 0x03 ; Ia masca codificator
andwf ren_read,w ; Izolă octetul codificator
movwf ren_new ; Salvează noua valoare
xorwf ren_old,w ; Le-a schimbat?
btfsc STATUS,B_Z ;
goto read_encoder ; Nu, sa mai caut până când se modifică
;
; Determină în ce direcție este rotit codificatorul.
;
bcf STATUS,B_C ; Șterge bitul de transport
rlf ren_old,f ;
movf ren_new,w ;
xorwf ren_old,f ;
movf ren_old,w ;
andlw 0x02 ;
movwf next_dir ;
xorwf last_dir,w ;
;
; Împiedica alunecarea codificatorului de la a da o schimbare fals în direcție.
;
btfsc STATUS,B_Z ; Zero?
goto pe_continue ; Nici o alunecare; continuă
movf next_dir,w ; Da, actualizarea direcției
movwf last_dir ;
movf ren_new,w ; Salvează bitul actual pentru data viitoare
movwf ren_old ;
goto read_encoder ; Încercarea din nou
pe_continue
btfsc ren_old,1 ; Vom merge jos?
goto up2 ; Nu, indica ca mergem sus
clrf last_dir ; Da, curăță last_dir
goto exit3 ; Terminarea și returnarea
up2
movlw 0x02 ; Configurarea valoare în last_dir
movwf last_dir ;
exit3
movf ren_new,w ; Ia biți codificatorului actuale
movwf ren_old ; Salvează în ren_old pentru data viitoare
return ; Revine la apelant
calibrate
movlw 0x80 ; Setarea frecvența pe 10MHz de
movwf freq_0 ; setarea de frecvențe la echivalentul binar
movlw 0x96 ; de 10.000.000.
movwf freq_1 ; .
movlw 0x98 ; .
movwf freq_2 ; .
movlw 0x00 ; .
movwf freq_3 ; .
;
; Citește valorarea de referință a oscilatorului de la EEPROM
;
clrf EEadr ; Resetează adresa de citire EEPROM
call read_EEPROM ; Citește EEPROM
movf EEdata,w ; Ia primul octet OSC
movwf osc_0 ; Salvează frecvență OSC
call read_EEPROM ; Ia următorul octet
movf EEdata,w ;
movwf osc_1 ; Salvează
call read_EEPROM ; Ia al trelea octet
movf EEdata,w ;
movwf osc_2 ; Salvează
call read_EEPROM ; Ia al patrulea octet
movf EEdata,w ;
movwf osc_3 ; Salvează
call bin2BCD ; Se calculează versiune BCD de 10.000,00
call show_freq ; Afișarea frecvența pe ecranul LCD
movlw 0xC4 ; Punct LCD la 14 cifre
movwf LCD_char ;
call cmnd2LCD ;
movlw 'C' ; Trimite un C
movwf LCD_char ;
call data2LCD ;
movlw 'A' ; Trimite un A
movwf LCD_char ;
call data2LCD ;
movlw 'L' ; Trimite un L
movwf LCD_char ;
call data2LCD ;
cal_loop
call calc_dds_word ; Calcularea valorii DDS bazat pe OSC curent
call send_dds_word ; Actualiza cip DDS
call poll_encoder ; Așteptarea până când codificatorul este mutat.
clrf fstep_3 ; Șterge cele mai importante trei
clrf fstep_2 ; biți de fstep
clrf fstep_1 ;
movlw 0x10 ; Să presupunem că suntem de adaptare lent
movwf fstep_0 ; Utilizează increment mică
btfsc ren_read,2 ; Codificatorul schimbă încet?
goto update_osc ; Da, atunci continuă cu increment mic
movlw 0x80 ; Nu, atunci utilizează increment mare
movwf fstep_0 ;
update_osc
nop ; Așteaptă un ciclu
btfsc last_dir,1 ; Ne mutăm jos?
goto faster ; Nu, crește valoarea OSC
;
; slower
;
comf fstep_0,f ; Scăderea fstep se face prin
comf fstep_1,f ; adăugând complimentul câte doi de fset
comf fstep_2,f ; la osc
comf fstep_3,f ;
incfsz fstep_0,f ; Incrementarea ultimul octet
goto faster ; Diferită de zero, continua
incfsz fstep_1,f ; Incrementarea următorul octet
goto faster ; Diferită de zero, continua
incfsz fstep_2,f ; Incrementarea următorul octet
goto faster ; Diferită de zero, continua
incf fstep_3,f ; Incrementarea cel mai semnificativ octet
faster
movf fstep_0,w ; Ia incrementul octet scăzut
addwf osc_0,f ; Adaugă-l la octetul OSC scăzut
btfss STATUS,B_C ; A existat un transport?
goto add4 ; Nu, se adaugă următoarele octeți
incfsz osc_1,f ; Pulsația transportă până la următorul octet
goto add4 ; Nu transportă nou, se adaugă următoarele octeți
incfsz osc_2,f ; Pulsația transportă până la următorul octet
goto add4 ; Nu transportă nou, se adaugă următoarele octeți
incf osc_3,f ; Pulsația transportă până la cel mai semnificativ octet
add4
movf fstep_1,w ; Ia de-al doilea octet incrementat
addwf osc_1,f ; Adaugă la al doilea octet OSC
btfss STATUS,B_C ; A existat un transport?
goto add5 ; Nu, se adaugă al treilea octet
incfsz osc_2,f ; Pulsația transportă până la următorul octet
goto add5 ; Nu transportă nou, se adaugă al treilea octet
incf osc_3,f ; Pulsația transportă până la cel mai semnificativ octet
add5
movf fstep_2,w ; Ia de-al treilea octet incrementat
addwf osc_2,f ; Adaugă la al treilea octet OSC
btfss STATUS,B_C ; A existat un transport?
goto add6 ; Nu, se adaugă al patrulea octet
incf osc_3,f ; Pulsația transportă până la cel mai semnificativ octet
add6
movf fstep_3,w ; Ia de-al patrulea octetul incrementat
addwf osc_3,f ; Adăugă la al patrulea octet
btfss ren_read,3 ; Este butonul apăsat încă?
goto cal_loop ; Da, rămâne în mod calibrare
clrf EEadr ; Scrie valoarea finală în EEPROM
movf osc_0,w ; Înregistrează primul
movwf EEdata ; osc
call write_EEPROM ; octet
movf osc_1,w ; Înregistrează al doilea
movwf EEdata ; osc
call write_EEPROM ; octet
movf osc_2,w ; Înregistreazăe al treilea
movwf EEdata ; osc
call write_EEPROM ; octet
movf osc_3,w ; Înregistrează al patrulea
movwf EEdata ; osc
call write_EEPROM ; octet
return ; Revine la apelant
calc_dds_word
clrf AD9850_0 ; Șterge octetul cuvântul de control al AD9850
clrf AD9850_1 ;
clrf AD9850_2 ;
clrf AD9850_3 ;
clrf AD9850_4 ;
movlw 0x20 ; Setarea numărătorului la 32
movwf mult_count ; Continua să numără
movf osc_0,w ; Mută patru octet de OSC
movwf osc_temp_0 ; pentru depozitare temporară pentru acest multiplicări
movf osc_1,w ;
movwf osc_temp_1 ;
movf osc_2,w ;
movwf osc_temp_2 ;
movf osc_3,w ;
movwf osc_temp_3 ;
mult_loop
bcf STATUS,B_C ; Începe cu golirea Carry
btfss osc_temp_0,0 ; Octetul este 0?
goto noAdd ; Nu, nu trebuie să adăugăm termen de frecvențe totală
movf freq_0,w ; Da, obține termenul freq_0
addwf AD9850_1,f ; si adaugă total
btfss STATUS,B_C ; Are ca rezultat acest plus într-o purtătoare
goto add7 ; Nu, continuă cu următorul termen de frecvență
incfsz AD9850_2,f ; Da, se adaugă unu și verifică pentru un alt carry
goto add7 ; Nu, continuă cu următorul termen de frecvență
incfsz AD9850_3,f ; Da, se adaugă unu și verifică pentru un alt carry
goto add7 ; Nu, continuă cu următorul termen de frecvență
incf AD9850_4,f ; Da, adaugă unu și continuă
add7
movf freq_1,w ; Folosește termenul freq_1
addwf AD9850_2,f ; Adaugă termen de frecvențe totalul în poziție corectă
btfss STATUS,B_C ; Are ca rezultat acest plus într-o purtare?
goto add8 ; Nu, continuă cu următorul termen de frecvență
incfsz AD9850_3,f ; Da, se adaugă unu și verifică pentru un alt carry
goto add8 ; Nu, continuă cu următorul termen de frecvență
incf AD9850_4,f ; Da, adaugă unu și continuă
add8
movf freq_2,w ; Folosește termenul freq_2
addwf AD9850_3,f ; Adaugă termen de frecvențe totalul în poziție corectă
btfss STATUS,B_C ; Are ca rezultat acest plus într-o purtare?
goto add9 ; Nu, continuă cu următorul termen de frecvență
incf AD9850_4,f ; Da, adaugă unu și continuă
add9
movf freq_3,w ; Folosește termenul freq_3
addwf AD9850_4,f ; Adaugă termen de frecvențe totalul în poziție corectă
noAdd
rrf AD9850_4,f ; Trecerea următoare multiplicare bit pe poziția
rrf AD9850_3,f ; Rotirea biții la dreapta de la octet la octet
rrf AD9850_2,f ;
rrf AD9850_1,f ;
rrf AD9850_0,f ;
rrf osc_temp_3,f ; Trecerea următoare multiplicare bit pe poziția
rrf osc_temp_2,f ; Rotirea biții la dreapta de la octet la octet
rrf osc_temp_1,f ;
rrf osc_temp_0,f ;
decfsz mult_count,f ; Încă un bit a fost făcut. Am terminat?
goto mult_loop ; Nu, du-te înapoi pentru a utiliza acest bit
clrf AD9850_4 ; Da, clear _4. Rezultatul este în bytes _3 .. _0
return ;
send_dds_word
movlw AD9850_0 ; Punct FSR la AD9850
movwf FSR ;
next_byte
movf INDF,w ;
movwf byte2send ;
movlw 0x08 ; Setează contorul la 8
movwf bit_count ;
next_bit
rrf byte2send,f ; Testarea bitul următor dacă este 1 sau 0
btfss STATUS,B_C ; A fost zero?
goto send0 ; Da, trimite la zero
bsf PortB,7 ; Nu, trimite unu
bsf PortB,5 ; Ceas de scriere comutare
bcf PortB,5 ;
goto break ;
send0
bcf PortB,7 ; Trimite la zero
bsf PortB,5 ; Ceas de scriere comutare
bcf PortB,5 ;
break
decfsz bit_count,f ; A fost trimis toate biți?
goto next_bit ; Nu, merge mai departe.
incf FSR,f ; Începe următorul bit dacă nu e terminat
movlw AD9850_4+1 ; Următorul bit
subwf FSR,w ;
btfss STATUS,B_C ;
goto next_byte ;
bsf PortB,0 ; Trimite semnal de sarcină la AD9850
bcf PortB,0 ;
return ;
bin2BCD
movlw 0x20 ; Setează contorul de buclă
movwf BCD_count ; la 32
clrf BCD_0 ; Șterge ieșirea
clrf BCD_1 ; " "
clrf BCD_2 ; " "
clrf BCD_3 ; " "
clrf BCD_4 ; " "
bin_loop
bcf STATUS,B_C ; Șterge bitul de transport în STATUS
rlf freq_0,f ; Rotire la stânga, 0 -> LS bit, MS bit -> Carry
rlf freq_1,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf freq_2,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf freq_3,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
btfsc STATUS,B_C ; Transportul este clar? Dacă da, sare instrucțiunea următoare
bsf freq_0,0 ; Transportul este setat la bitul 0 în freq_0
rlf BCD_0,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_1,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_2,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_3,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_4,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
decf BCD_count,f ; Decrementează numărul de buclă
btfss STATUS,B_Z ; Este, acuma contorul de buclă zero?
goto adjust ; Nu, merge să face reglare
return ; Da, iese
adjust
movlw BCD_0 ; Ia pointerul de la BCD_0
movwf FSR ; Pune pointerul în FSR pentru abordarea indirectă
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_1
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_2
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_3
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_4
call adj_BCD ;
goto bin_loop ; Trece înapoi la bucla principală
adj_BCD
movlw 3 ; Adaugă 3
addwf INDF,w ; la cel mai puțin semnificativ bit
movwf BCD_temp ; Salvează în temp
btfsc BCD_temp,3 ; Este cel mai puțin semnificativ bit + 3 > 7
movwf INDF ; Da, salvează valoare incrementat ca cel mai puțin semnificat bit
movlw 0x30 ; Adaugă 3
addwf INDF,w ; la cel mai semnificatic bit
movwf BCD_temp ; Salvează în temp
btfsc BCD_temp,7 ; Este cel mia semnificativ bit +3 > 7
movwf INDF ; Da, salvați valoare incrementat ca cel mai semnificativ bit
return ; Revine la subrutina adjust
show_freq
movlw 0x81 ; Punctul LCD pentru prima cifră
call cmnd2LCD ; Trimite punctul de plecare
swapf BCD_3,w ; Schimbă 10MHz în BCD cifre pentru W
andlw 0x0F ;
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movf BCD_3,w ; Schimbă 1MHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movlw ',' ; Ia-o virgulă
call data2LCD ; Trimite octetul în W pentru LCD
swapf BCD_2,w ; Schimbă 10MHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movf BCD_2,w ; Schimbă 10KHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
swapf BCD_1,w ; Schimbă 1KHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movlw '.' ; Configurarea W cu perioada ASCII
call data2LCD ; Trimite octet de date în W pentru LCD
movlw 0xC0 ; Numărul de cifre 9
call cmnd2LCD ; Trimite octet de comandă în W pentru LCD
movf BCD_1,w ; Schimbă 100Hz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
swapf BCD_0,w ; Schimbă 10Hz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movf BCD_0,w ; Schimbă 1Hz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movlw ' ' ; Trimite un spațiu
call data2LCD ; pentru LCD
movlw 'k' ; Trimite un 'k'
call data2LCD ; pentru LCD
movlw 'H' ; Trimite un "H"
call data2LCD ; pentru LCD
movlw 'z' ; Trimite un 'z'
call data2LCD ; pentru LCD
return ;
busy_check
clrf PortB ; Șterge toate ieșirile pe PortB
bsf STATUS,B_RP0 ; Comută cu bancă 1 pentru operarea Tristate
movlw b'11110000' ; Setează RB7, RB6, RB5, RB4 ca intrări
; și RB3, RB2, RB1, RB0 ca ieșiri
movwf TRISB ; prin Tristate
bcf STATUS,B_RP0 ; Comuta înapoi la bancă 0
bcf PortB,LCD_rs ; Configură LCD pentru Read Busy Flag
bsf PortB,LCD_rw ; Configură LCD pentru Read
movlw 0xFF ; Configură constanta 255
movwf timer1 ; pentru cronometru buclă contor
LCD_is_busy
bsf PortB,LCD_e ; Set E înalt
movf PortB,w ; Citește PortB în W
movwf LCD_read ; Salvează W pentru testarea mai târziu
bcf PortB,LCD_e ; Aruncă din nou E
nop ; Așteaptă
nop ; puțin timp
bsf PortB,LCD_e ; Puls E înalt
nop ; așteaptă,
bcf PortB,LCD_e ; și aruncă E iarăși
decf timer1,f ; Decrementează bucla de contor
btfsc STATUS,B_Z ; Este bucla de contor la zero?
goto not_busy ; Dacă da, întoarce indiferent
btfsc LCD_read,7 ; Este bitul Busy Flag (RB7) salvat?
goto LCD_is_busy ; Dacă nu, este ocupat și sare înapoi
not_busy
return ;
cmnd2LCD
movwf LCD_char ; Salvează octetul pentru a scrie la LCD
clrf rs_value ; Amintește pentru a seta RS
bcf PortB,LCD_rs ; Setarea RS de comandă pentru LCD
goto write2LCD ; Du-te la cod comun
data2LCD
movwf LCD_char ; Salvează octetul pentru a scrie la LCD
bsf rs_value,0 ; Amintește pentru a seta RS
bsf PortB,LCD_rs ; Setarea RS de comandă pentru LCD
write2LCD
call busy_check ; Verificați pentru a vedea dacă LCD este gata pentru noi date
clrf PortB ; Șterge toate Port B
bsf STATUS,B_RP0 ; Comutare la bancă 1 pentru operarea Tristate
movlw 0x00 ; Configurarea pentru a permite pini de date PORTB
movwf TRISB ; Toate pini (RB7.. RB0) sunt ieșiri
bcf STATUS,B_RP0 ; Comuta la bancă 0
bcf PortB,LCD_rw ; Setează LCD înapoi la modul de a scrie
bcf PortB,LCD_rs ; RS ar trebui să fie gol
btfsc rs_value,0 ; Rs trubie să fie gol?
bsf PortB,LCD_rs ; Nu, setează RS
movlw 0x0F ; Configurarea masca
andwf PortB,f ; Șterge vechea RB7..RB4
movf LCD_char,w ; Pune octetul de date în W
andlw 0xF0 ; Masca pentru XXXX0000 în W
iorwf PortB,f ; Trimite RB7..RB4 fără să schimbe RB3..RB0
bsf PortB,LCD_e ; Puls linia E mare,
nop ; așteptă,
bcf PortB,LCD_e ; și aruncă din nou
movlw 0x0F ; Configurarea masca
andwf PortB,f ; Șterge vechea RB7..RB4
swapf LCD_char,w ; Pune octetul de date în W
andlw 0xF0 ; Masca pentru XXXX0000 în WW
iorwf PortB ; Trimite RB7..RB4 fără să schimbe RB3..RB0
bsf PortB,LCD_e ; Puls linia E mare,
nop ; așteptă,
bcf PortB,LCD_e ; și aruncă din nou
return
write_EEPROM
bsf STATUS,B_RP0 ; Comută la bancă 1
bsf EEdata,WREN ; Setează EEPROM la bit write enable
movlw 0x55 ; Scrie 0x55 și 0xAA la EEPROM
movwf EEadr ; registru de control, după cum este
movlw 0xAA ; necesar pentru scriere
movwf EEadr ;
bsf EEdata,WR ; Setează WR să inițieze scriere
bit_check
btfsc EEdata,WR ; A finalizat scrierea?
goto bit_check ; Nu, păstreze verificarea
bcf EEdata,WREN ; Golește la EEPROM bitul write enable
bcf STATUS,B_RP0 ; Comuta la bancă 0
incf EEadr,f ; Incrementează adresa de scriere EE
return ; Revine la apelant
read_EEPROM
bsf STATUS,B_RP0 ; Comuta la bancă 1
bsf EEdata,RD ; Cerere de citire
bcf STATUS,B_RP0 ; Comuta la bancă 0
incf EEadr,f ; Incrementează adresa de citire
return ; Revine la apelant
wait_128ms ; ****** Entry point ******
movlw 0xFF ; Configurarea buclei exterioară
movwf timer1 ; contorul la 255
goto outer_loop ; Merge la bucle de așteptares
wait_64ms ; ****** Entry point ******
movlw 0x80 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 128
goto outer_loop ; Merge la bucle de așteptare
wait_32ms ; ****** Entry point ******
movlw 0x40 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 64
goto outer_loop ; Merge la bucle de așteptare
wait_16ms ; ****** Entry point ******
movlw 0x20 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 32
goto outer_loop ; Merge la bucle de așteptare
wait_8ms ; ****** Entry point ******
movlw 0x10 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 16
outer_loop
movlw 0xFF ; Configurarea contorul buclă interioară
movwf timer2 ; la 255
inner_loop
decfsz timer2,f ; Decrementează contorul de buclă interioară
goto inner_loop ; Dacă contor buclă interior nu este la zero,
; apoi merge înapoi la bucla interioară din nou
decfsz timer1,f ; Da, Decrementează contorul buclă exterioară
goto outer_loop ; Dacă contor buclă exterioară nu este la
; zero, apoi merge înapoi la bucla exterioară din nou
return ; Da, revine la apelantr
END
Bibliografie
[1] Ian Poole, DDS basics, http://www.radio-electronics.com/info/rf-technology-design/pll-synthesizers/direct-digital-synthesizer-dds-tutorial.php
[2] Paul Kern (July 2007). "Direct digital synthesis enables digital PLLs".
[3] Nebojsa Matic (May 2000) PIC microcontrollers for beginners, too!
[4] Tutorialspoint, Assembly – Introduction, http://www.tutorialspoint.com/assembly_programming/assembly_introduction.htm
[5] Analog Devices, Inc., All About Direct Digital Synthesis, http://www.analog.com/library/analogdialogue/archives/38-08/dds.html
Anexa
Anexa 1 Schema DDS
Anexa 2 Cod sursă
; ****************************************************************************
; * Tip de dispozitiv și opțiuni *
; ****************************************************************************
processor PIC16F84
radix dec
errorlevel -220
errorlevel -305
; ****************************************************************************
; * Informațiile de configurare al siguranței *
; ****************************************************************************
_CP_ON EQU H'000F'
_CP_OFF EQU H'3FFF'
_PWRTE_ON EQU H'3FF7'
_PWRTE_OFF EQU H'3FFF'
_WDT_ON EQU H'3FFF'
_WDT_OFF EQU H'3FFB'
_LP_OSC EQU H'3FFC'
_XT_OSC EQU H'3FFD'
_HS_OSC EQU H'3FFE'
_RC_OSC EQU H'3FFF'
__config _CP_OFF & _PWRTE_ON & _WDT_ON & _XT_OSC
;Stabilit pentru 100 MHz.
ref_osc_3 equ 0x2A ; Cel mai semnificativ bit la oscilator
ref_osc_2 equ 0xF3 ; Bitul următoare
ref_osc_1 equ 0x1D ; Bitul următoare
ref_osc_0 equ 0xC4 ; Cel mai puțin semnificativ bit
; Limita conține frecvența limită superioară precum un număr întreg de 32 de biț.
limit_3 equ 0x01 ; Cel mai semnificativ bit pentru 30 MHz
limit_2 equ 0xC9 ; Bitul următoare
limit_1 equ 0xC3 ; Bitul următoare
limit_0 equ 0x80 ; Cel mai puțin semnificativ bit
; Implicit conține frecvența de pornire implicit ca un întreg pe 32 de biț.
default_3 equ 0x00 ; Cel mai semnificativ bit pentru 14.025 MHz
default_2 equ 0xD6 ; Bitul următoare
default_1 equ 0x01 ; Bitul următoare
default_0 equ 0x28 ; Cel mai puțin semnificativ bit
band_end equ 0x28 ; Diferența față de ultima intrare tabel bandă
; ****************************************************************************
; * Port și EEPROM Constantă *
; ****************************************************************************
PortA equ 0x05
PortB equ 0x06
TRISA equ 0x05
TRISB equ 0x06
EEdata equ 0x08
EEadr equ 0x09
WREN equ 0x02
WR equ 0x01
RD equ 0x00
; ****************************************************************************
; * Informații despre locație ID *
; ****************************************************************************
ORG 0x2000
DATA 0x007F
DATA 0x007F
DATA 0x007F
DATA 0x007F
; ****************************************************************************
; * Configurare constanta inițială, în funcție de frecvența oscilatorului *
; * de referință. Acest lucru poate fi optimizat cu funcția de calibrare. *
; ****************************************************************************
ORG 0x2100
DATA ref_osc_0
DATA ref_osc_1
DATA ref_osc_2
DATA ref_osc_3
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; ****************************************************************************
; * Pagina RAM registre de fișiere independente: *
; ****************************************************************************
INDF EQU 0x00
PCL EQU 0x02
STATUS EQU 0x03
FSR EQU 0x04
PCLATH EQU 0x0A
INTCON EQU 0x0B
; *****************************************************************************
; * Numere de biți pentru registrul STATUS: *
; *****************************************************************************
B_RP0 EQU 5
B_NTO EQU 4
B_NPD EQU 3
B_Z EQU 2
B_DC EQU 1
B_C EQU 0
; ****************************************************************************
; * Atribuirea numele de pini IO. *
; ****************************************************************************
; Biți registru B:
DDS_load equ 0x00 ; Actualizarea PIN-ul pe AD9850
LCD_rs equ 0x01 ; 0=instrucțiune, 1=data
LCD_rw equ 0x02 ; 0=scriere, 1=citire
LCD_e equ 0x03 ; 0=inactivare, 1=activare
DDS_clk equ 0x05 ; AD9850 scrie ceasul
DDS_dat equ 0x07 ; AD9850 introducere datelor de serie
; Biți registru A:
pb_switch equ 0x03 ; Calibrarea Push Button-lui, (activ scăzut)
; ****************************************************************************
; * Alocă variabile în scop general, spațiu registru *
; ****************************************************************************
CBLOCK 0x0c ; Start date Block
freq_0 ; Frecvență de afișare (hex)
freq_1 ; (4 biți)
freq_2
freq_3
BCD_0 ; Frecvență de afișare (BCD)
BCD_1 ; (5 biți)
BCD_2
BCD_3
BCD_4
AD9850_0 ; AD9850 cuvânt de control
AD9850_1 ; (5 biți)
AD9850_2
AD9850_3
AD9850_4
fstep_0 ; Frecvență inc/dec
fstep_1 ; (4 biți)
fstep_2
fstep_3
BCD_count ; Folosit în rutina bin2BCD
BCD_temp ; "
mult_count ; Folosit în calc_dds_word
bit_count ; "
byte2send ;
osc_0 ; Oscilator actuală
osc_1 ; (4 biți)
osc_2
osc_3
osc_temp_0 ; Frecvență de oscilație
osc_temp_1 ; (4 biți)
osc_temp_2
osc_temp_3
LCD_char ; Caracter fiind trimis la LCD
LCD_read ; Caracter citit de pe ecranul LCD
timer1 ; Utilizat în rutine de întârziere
timer2 ; "
ren_timer_0 ; Pentru acordare rată variabilă
ren_timer_1 ; (2 biți)
ren_new ; Nou valoare a encoderului pini A și B
ren_old ; Vechea valoare a encoderului pini A și B
ren_read ; Pini encoder A și B și comutator pini
last_dir ; Indică ultima direcție de encoder
next_dir ; Indică direcția așteptată
count ; contor buclă
band ; Utilizat pentru a indexa un tabel de frecvențe
rs_value ; Valoarea LCD rs
ENDC ; Sfârșitul blocul de date
; ****************************************************************************
; * 16F84 resetează la 0x00. *
; * Vectorul de întrerupere este la 0x04. (Nefolosit) *
; ****************************************************************************
ORG 0x0000
reset_entry
goto start ; Sare în jurul tabela de bandă
; la programul principal
band_table
addwf PCL,f ;
retlw 0x00 ; 0 Hz
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ; 160 metri
retlw 0x1B ;
retlw 0x77 ;
retlw 0x40 ;
retlw 0x00 ; 80 metri
retlw 0x35 ;
retlw 0x67 ;
retlw 0xE0 ;
retlw 0x00 ; 40 metri
retlw 0x6A ;
retlw 0xCF ;
retlw 0xC0 ;
retlw 0x00 ; 30 metri
retlw 0x9A ;
retlw 0x1D ;
retlw 0x20 ;
retlw 0x00 ; 20 metri
retlw 0xD5 ;
retlw 0x9F ;
retlw 0x80 ;
retlw 0x01 ; 17 metri
retlw 0x13 ;
retlw 0xB2 ;
retlw 0x20 ;
retlw 0x01 ; 15 metri
retlw 0x40 ;
retlw 0x6F ;
retlw 0x40 ;
retlw 0x01 ; 12 metri
retlw 0x7B ;
retlw 0xCA ;
retlw 0x90 ;
retlw 0x01 ; 10 metri
retlw 0xAB ;
retlw 0x3F ;
retlw 0x00 ;
retlw 0x01 ; 30 MHz
retlw 0xC9 ;
retlw 0xC3 ;
retlw 0x80 ;
; *****************************************************************************
; * Acesta este începutul programului. *
; *****************************************************************************
start
clrf INTCON ; Nu sunt întreruperi de acum
bsf STATUS,B_RP0 ; Comută la banca 1
bsf 0x01,7 ; Dezactivarea tracțiuni slabe
movlw 0xFF ; Port tri state A
movwf TRISA ;
clrf TRISB ; Setează portul B la toate ieșirile
bcf STATUS,B_RP0 ; Comuta înapoi la bancă 0
call init_LCD ; Inițializă LCD
; Întră în modul de calibrare în cazul în care buton este apăsat în timp ce porniți
; alimentarea.
btfsc PortA,pb_switch ; Este apăsat comutatorul?
goto read_EEocs ; Nu, obține ceas de frecvențe de la EEPROM
call calibrate ; Da, calibră
; Ia constanta oscilator de referință de la EEPROM.
read_EEocs
clrf EEadr ; Resetă adresa de citire EEPROM
call read_EEPROM ; Citește EEPROM
movf EEdata,w ; Ia primul bit OSC
movwf osc_0 ; Salvează frecvență OSC
call read_EEPROM ; Ia următorul bit
movf EEdata,w ;
movwf osc_1 ; Salvați-l
call read_EEPROM ; Ia al treilea bit
movf EEdata,w ;
movwf osc_2 ; Salvați-l
call read_EEPROM ; Ia al patrulea bit
movf EEdata,w ;
movwf osc_3 ; Salvați-l
; Setează puterea de la frecvență la valoarea definită.
movlw default_0 ; Ia cel mai puțin semnificativ bit
movwf freq_0 ; Salvați-l
movlw default_1 ; Ia următorul bit
movwf freq_1 ; Salvați-l
movlw default_2 ; Și următorul
movwf freq_2 ; Salvați-l
movlw default_3 ; Obține cel mai semnificativ bit
movwf freq_3 ; Salvați-l
; Afișarea puterea pe frecvență.
call bin2BCD ; Îl transformă în BCD
call show_freq ; Afișă
; Trimite puterea de frecvență la cip DDS.
call calc_dds_word ; Conversia în valoare delta
call send_dds_word ; Trimite frecvența de pornire a
; AD9850 în modul de serie
; Ia puterea de la valoarea encoder.
movf PortA,w ; Citesc portul A
movwf ren_read ; Salvați-l în ren_read
movlw 0x03 ; Ia masca encoder
andwf ren_read,w ; Ia biți encoder
movwf ren_old ; Salvați în ren_old
; Inițializa variabile.
clrf ren_timer_1 ; Inițializa cronometrul viteză encoder
movlw 0x40 ; la
movwf ren_timer_0 ; 0x0040
clrf last_dir ; Șterge indicatorul de direcție
clrf band ; Șterge indicatorul de bandă
; Se încadrează în programul principal de buclă
main
call poll_encoder ; Verificați mișcarea butonului
btfss ren_read,3 ; Schimba banda?
goto change_band ; Da, schimba banda
; Determina dimensiunea pas de a utiliza (1 Hz sau 1 kHz).
clrf fstep_3 ; Ne dorim 1 Hz prin stabilirea fstep la 1.
clrf fstep_2 ;
clrf fstep_1 ;
movlw 0x01 ;
movwf fstep_0 ;
btfsc ren_read,2 ; Este apăsat butonul encoder?
goto go_step ; Nu, utilizează pasul 1 Hz
movlw 0xE8 ; Da, setați valoarea pasului de 1 kHz
movwf fstep_0 ; prin stabilirea fstep_0 la 0xE8 și
movlw 0x03 ; fstep_1 la 0x03
movwf fstep_1 ;
goto go_step ; Utilizați pasul 1 kHz
bump_step
bcf STATUS,B_C ; Șterge carry flag-ul
rlf fstep_0,f ; Multiplică pasul cu 2 pentru rotirea la stânga
rlf fstep_1,f ;
rlf fstep_2,f ;
rlf fstep_3,f ;
go_step
rlf ren_timer_0,f ; Multiplică cronometrul encoder cu 2
rlf ren_timer_1,f ;
btfss STATUS,B_C ;
goto bump_step ;
; În funcție de direcția butonul, fie pentru a adăuga sau scade increment,
; apoi actualizează LCD și DDS.
btfsc last_dir,1 ; Butonul merge în sus?
goto up ; Da, apoi se adaugă increment
down
call sub_step ; Scade fstep de frecvențe
goto write ; Actualizare LCD și DDS
up
call add_step ; Adaugă fstep la frecvențe
call check_add ; Asigură că nu am depăși valoarea maximă
goto write ; Actualizarea LCD și DDS
change_band
btfsc last_dir,1 ; Mergem sus în lista de bandă?
goto band_up ; Da, incrementează adresa de bandă
movlw 0x04 ; Nu, primește 4 biți pentru a scădea
subwf band,f ; Mutare în jos în lista de bandă
movlw 0xFF-band_end ; Verificarea pentru a vedea dacă am
addwf band,w ; căzut de pe partea de jos a tabelului.
btfss STATUS,B_C ; Căzut de pe tabel?
goto valid ; Nu, continuă
movlw band_end ; Da, merge la cel mai înalt intrare
movwf band ;
valid
call get_band ; Ia noua banda de frecvență
goto write ; Setează frecvența și continua
band_up
movlw 0x04 ; Intrări de tabel sunt 4 biți de distanță
addwf band,f ; Incrementarea indicatorul benzii
movlw 0xFF-band_end ; Verificarea pentru a vedea dacă am trecut de-a lungul
addwf band,w ; partea de sus a tabelului.
btfsc STATUS,B_C ; Am trece peste partea de sus a tabelului?
clrf band ; Da, du-te la intrarea de jos
call get_band ; Ia noua banda de frecvență
write
call bin2BCD ; Convertesc frecvența la BCD
call show_freq ; Afișarea frecvenței pe ecranul LCD
call calc_dds_word ; Găsește cuvântul de control pentru cip DDS
call send_dds_word ; Trimite cuvântul de control pentru cipul DDS
goto main ; Continua interogarea codificatorului
get_band
movf band,w ; Ia indicele octetul
call band_table ; Ia valoarea în W
movwf freq_3 ; Salvează în freq_3
incf band,f ; Incrementarea indicelui pentru următorul octet
movf band,w ; Ia indicele din următorul octet
call band_table ; Ia valoarea în W
movwf freq_2 ; Salvează în freq_2
incf band,f ; Incrementarea indicele pentru următorul octet
movf band,w ; Ia indicele pentru următorul octet
call band_table ; Ia valoarea în W
movwf freq_1 ; Salvează în freq_1
incf band,f ; Incrementarea indicele de octet scăzut
movf band,w ; Ia indicele de octet scăzut
call band_table ; Ia valoarea în W
movwf freq_0 ; Salvează în freq_0
movlw 0x03 ; Obține o constantă trei
subwf band,f ; Restabili valoarea inițială din benzii
return ; Revine la apelant
init_LCD
call wait_64ms ; Așteaptă LCD-ul pentru a porni
movlw 0x30 ; Inițializarea instrucțiunile LCD
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Setați E linia de LCD ridicat,
call wait_64ms ; aștepte un timp "lung",
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x30 ; Inițializarea instrucțiunile LCD
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Set E ridicat,
call wait_32ms ; așteptați puțin,
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x30 ; Inițializarea instrucțiunile LCD
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Set E ridicat,
call wait_32ms ; așteptați puțin,
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x20 ; Instrucțiuni modului 4 bit
movwf PortB ; Trimite la LCD prin RB7 .. RB0
bsf PortB,LCD_e ; Set E ridicat,
call wait_16ms ; așteptați puțin,
bcf PortB,LCD_e ; și apoi Clear E
movlw 0x28 ; 1/16 ciclu, matrice 5×8
call cmnd2LCD ; Trimite comanda în w la LCD
movlw 0x08 ; Afișarea oprit, cursorul oprit
call cmnd2LCD ; Trimite comanda la LCD
movlw 0x01 ; Ștergerea și resetarea cursorlui
call cmnd2LCD ; Trimite comanda în w la LCD
movlw 0x06 ; Setează cursorul pentru a muta dreapta
call cmnd2LCD ; Trimite comanda în w la LCD
movlw 0x0C ; Afișare pornit, cursorul oprit
call cmnd2LCD ; Trimite comanda în w la LCD
return ;
add_step
movf fstep_0,w ; Ia octetul scăzut a incrementului
addwf freq_0,f ; Adauga-l la octet scăzut din frecvența
btfss STATUS,B_C ; Orice purtătoare?
goto add1 ; Nu, se adaugă următorul octet
incfsz freq_1,f ; Pulsația transportă până la următorul octet
goto add1 ; Nu transportă nou, se adaugă următorul octet
incfsz freq_2,f ; Pulsația transportă până la următorul octet
goto add1 ; Nu transportă nou, se adaugă următorul octet
incf freq_3,f ; Pulsația transportă până la cel mai mare octet
add1
movf fstep_1,w ; Ia următorul octet incrementat
addwf freq_1,f ; Adaugă-l la următoarea octet superior
btfss STATUS,B_C ; Orice purtătoare?
goto add2 ; Nu, se adaugă următorul octet
incfsz freq_2,f ; Pulsația transportă până la următorul octet
goto add2 ; Nu transportă nou, se adaugă următorul octet
incf freq_3,f ; Pulsația transportă până la cel mai înalt octet
add2
movf fstep_2,w ; Ia cea mai semnificativă octet incrementat
addwf freq_2,f ; Adaugă-l la octetul de frecventă
btfss STATUS,B_C ; Orice purtătoare?
goto add3 ; Nu, se adaugă ultimul octet
incf freq_3,f ; Pulsația transportă până la cel mai mare octet
add3
movf fstep_3,w ; Obține cel mai semnificativ increment octet
addwf freq_3,f ; Adaugă-l la cea mai semnificativă frecvență
return ; Revine la apelant
check_add
;
; Verifică cel mai semnificativ octet.
;
movlw 0xFF-limit_3 ; Get
addwf freq_3,w ; Adauga-l la octetul de curent mare
btfsc STATUS,B_C ; A fost ridicat octetul prea mare?
goto set_max ; Da, se aplică limita
movlw limit_3 ; Ia valoare limită ridicată
subwf freq_3,w ; Se scade valoarea limitată
btfss STATUS,B_C ; Suntem la limita octetului?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
;
; Verificați al doilea cel mai important octet.
;
movlw 0xFF-limit_2 ; Get
addwf freq_2,w ; Adauga-l la octetul de curent mare
btfsc STATUS,B_C ; A fost ridicat octetul prea mare?
goto set_max ; Da, se aplică limita
movlw limit_2 ; Al doilea octetul de limită
subwf freq_2,w ; Se scade valoarea limitată
btfss STATUS,B_C ; Suntem la limita octetului?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
;
; Check the third most significant byte.
;
movlw 0xFF-limit_1 ; Get
addwf freq_1,w ; Adauga-l la octetul de curent mare
btfsc STATUS,B_C ; A fost ridicat octetul prea mare?
goto set_max ; Da, se aplică limita
movlw limit_1 ; Al treilea octetul de limită
subwf freq_1,w ; Se scade valoarea limitată
btfss STATUS,B_C ; Suntem la limita octetului?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
;
; Verificarea cel mai puțin semnificativ octet.
;
movlw limit_0 ; Al patrulea octetul de limită
subwf freq_0,w ; Valoarea limită de scădere
btfss STATUS,B_C ; Suntem la limita de octet?
goto exit1 ; Nu, mai jos. Verificările sunt efectuate.
set_max
movlw limit_0 ; Ia limita cel mai puțin semnificativ
movwf freq_0 ; Pune în frecvențe
movlw limit_1 ; Ia următorul octet de limită
movwf freq_1 ; Pune în freq_1
movlw limit_2 ; Ia următorul octet de limită
movwf freq_2 ; Pune în freq_2
movlw limit_3 ; Ia limita cea mai semnificativă
movwf freq_3 ; Pune în freq_3
exit1
return ; Revine la apelant
sub_step
comf fstep_0,f ; Scăderea fstep de la
comf fstep_1,f ; freq se face prin adaugarea
comf fstep_2,f ; câte două compliment de la fstep
comf fstep_3,f ; la frecvență.
incfsz fstep_0,f ; Incrementare ultimul octet
goto comp_done ; Diferită de zero, continua
incfsz fstep_1,f ; Incrementarea următorul octet
goto comp_done ; Diferită de zero, continua
incfsz fstep_2,f ; Incrementarea următorul octet
goto comp_done ; Diferită de zero, continua
incf fstep_3,f ; Incrementarea octetul cel mai semnificativ
comp_done
call add_step ; Adaugă compliment pentru a face scăderea
;
; În cazul în care frecvența a plecat negativ, se șterge la zero.
;
btfss freq_3,7 ; Frecventa cel mai semnificatic bit este "negativ"?
goto exit2 ; Nu, mergi mai departe
set_min
clrf freq_0 ; Da, setează frecvența la zero
clrf freq_1 ;
clrf freq_2 ;
clrf freq_3 ;
exit2
return ; Revine la apelant
poll_encoder
clrf ren_timer_1 ; Pune valorile de pornire în ren_timer
movlw 0x40 ; Începe cu bitul cel mai semnificativ stabilit în ren_timer
movwf ren_timer_0 ;
read_encoder
clrwdt ; Resetarea cronometrul watchdog
btfsc ren_timer_1,7 ; Are bitul plutit până jos în ren_timer?
goto no_inc ; Da, nu-l muta mai departe
movlw 0x08 ;
addwf ren_timer_0,f ;
btfsc STATUS,B_C ;
incf ren_timer_1,f ;
no_inc ;
movf PortA,w ; Ia valoarea codificatorul curent
movwf ren_read ; Salvează
movlw 0x03 ; Ia masca codificator
andwf ren_read,w ; Izolă octetul codificator
movwf ren_new ; Salvează noua valoare
xorwf ren_old,w ; Le-a schimbat?
btfsc STATUS,B_Z ;
goto read_encoder ; Nu, sa mai caut până când se modifică
;
; Determină în ce direcție este rotit codificatorul.
;
bcf STATUS,B_C ; Șterge bitul de transport
rlf ren_old,f ;
movf ren_new,w ;
xorwf ren_old,f ;
movf ren_old,w ;
andlw 0x02 ;
movwf next_dir ;
xorwf last_dir,w ;
;
; Împiedica alunecarea codificatorului de la a da o schimbare fals în direcție.
;
btfsc STATUS,B_Z ; Zero?
goto pe_continue ; Nici o alunecare; continuă
movf next_dir,w ; Da, actualizarea direcției
movwf last_dir ;
movf ren_new,w ; Salvează bitul actual pentru data viitoare
movwf ren_old ;
goto read_encoder ; Încercarea din nou
pe_continue
btfsc ren_old,1 ; Vom merge jos?
goto up2 ; Nu, indica ca mergem sus
clrf last_dir ; Da, curăță last_dir
goto exit3 ; Terminarea și returnarea
up2
movlw 0x02 ; Configurarea valoare în last_dir
movwf last_dir ;
exit3
movf ren_new,w ; Ia biți codificatorului actuale
movwf ren_old ; Salvează în ren_old pentru data viitoare
return ; Revine la apelant
calibrate
movlw 0x80 ; Setarea frecvența pe 10MHz de
movwf freq_0 ; setarea de frecvențe la echivalentul binar
movlw 0x96 ; de 10.000.000.
movwf freq_1 ; .
movlw 0x98 ; .
movwf freq_2 ; .
movlw 0x00 ; .
movwf freq_3 ; .
;
; Citește valorarea de referință a oscilatorului de la EEPROM
;
clrf EEadr ; Resetează adresa de citire EEPROM
call read_EEPROM ; Citește EEPROM
movf EEdata,w ; Ia primul octet OSC
movwf osc_0 ; Salvează frecvență OSC
call read_EEPROM ; Ia următorul octet
movf EEdata,w ;
movwf osc_1 ; Salvează
call read_EEPROM ; Ia al trelea octet
movf EEdata,w ;
movwf osc_2 ; Salvează
call read_EEPROM ; Ia al patrulea octet
movf EEdata,w ;
movwf osc_3 ; Salvează
call bin2BCD ; Se calculează versiune BCD de 10.000,00
call show_freq ; Afișarea frecvența pe ecranul LCD
movlw 0xC4 ; Punct LCD la 14 cifre
movwf LCD_char ;
call cmnd2LCD ;
movlw 'C' ; Trimite un C
movwf LCD_char ;
call data2LCD ;
movlw 'A' ; Trimite un A
movwf LCD_char ;
call data2LCD ;
movlw 'L' ; Trimite un L
movwf LCD_char ;
call data2LCD ;
cal_loop
call calc_dds_word ; Calcularea valorii DDS bazat pe OSC curent
call send_dds_word ; Actualiza cip DDS
call poll_encoder ; Așteptarea până când codificatorul este mutat.
clrf fstep_3 ; Șterge cele mai importante trei
clrf fstep_2 ; biți de fstep
clrf fstep_1 ;
movlw 0x10 ; Să presupunem că suntem de adaptare lent
movwf fstep_0 ; Utilizează increment mică
btfsc ren_read,2 ; Codificatorul schimbă încet?
goto update_osc ; Da, atunci continuă cu increment mic
movlw 0x80 ; Nu, atunci utilizează increment mare
movwf fstep_0 ;
update_osc
nop ; Așteaptă un ciclu
btfsc last_dir,1 ; Ne mutăm jos?
goto faster ; Nu, crește valoarea OSC
;
; slower
;
comf fstep_0,f ; Scăderea fstep se face prin
comf fstep_1,f ; adăugând complimentul câte doi de fset
comf fstep_2,f ; la osc
comf fstep_3,f ;
incfsz fstep_0,f ; Incrementarea ultimul octet
goto faster ; Diferită de zero, continua
incfsz fstep_1,f ; Incrementarea următorul octet
goto faster ; Diferită de zero, continua
incfsz fstep_2,f ; Incrementarea următorul octet
goto faster ; Diferită de zero, continua
incf fstep_3,f ; Incrementarea cel mai semnificativ octet
faster
movf fstep_0,w ; Ia incrementul octet scăzut
addwf osc_0,f ; Adaugă-l la octetul OSC scăzut
btfss STATUS,B_C ; A existat un transport?
goto add4 ; Nu, se adaugă următoarele octeți
incfsz osc_1,f ; Pulsația transportă până la următorul octet
goto add4 ; Nu transportă nou, se adaugă următoarele octeți
incfsz osc_2,f ; Pulsația transportă până la următorul octet
goto add4 ; Nu transportă nou, se adaugă următoarele octeți
incf osc_3,f ; Pulsația transportă până la cel mai semnificativ octet
add4
movf fstep_1,w ; Ia de-al doilea octet incrementat
addwf osc_1,f ; Adaugă la al doilea octet OSC
btfss STATUS,B_C ; A existat un transport?
goto add5 ; Nu, se adaugă al treilea octet
incfsz osc_2,f ; Pulsația transportă până la următorul octet
goto add5 ; Nu transportă nou, se adaugă al treilea octet
incf osc_3,f ; Pulsația transportă până la cel mai semnificativ octet
add5
movf fstep_2,w ; Ia de-al treilea octet incrementat
addwf osc_2,f ; Adaugă la al treilea octet OSC
btfss STATUS,B_C ; A existat un transport?
goto add6 ; Nu, se adaugă al patrulea octet
incf osc_3,f ; Pulsația transportă până la cel mai semnificativ octet
add6
movf fstep_3,w ; Ia de-al patrulea octetul incrementat
addwf osc_3,f ; Adăugă la al patrulea octet
btfss ren_read,3 ; Este butonul apăsat încă?
goto cal_loop ; Da, rămâne în mod calibrare
clrf EEadr ; Scrie valoarea finală în EEPROM
movf osc_0,w ; Înregistrează primul
movwf EEdata ; osc
call write_EEPROM ; octet
movf osc_1,w ; Înregistrează al doilea
movwf EEdata ; osc
call write_EEPROM ; octet
movf osc_2,w ; Înregistreazăe al treilea
movwf EEdata ; osc
call write_EEPROM ; octet
movf osc_3,w ; Înregistrează al patrulea
movwf EEdata ; osc
call write_EEPROM ; octet
return ; Revine la apelant
calc_dds_word
clrf AD9850_0 ; Șterge octetul cuvântul de control al AD9850
clrf AD9850_1 ;
clrf AD9850_2 ;
clrf AD9850_3 ;
clrf AD9850_4 ;
movlw 0x20 ; Setarea numărătorului la 32
movwf mult_count ; Continua să numără
movf osc_0,w ; Mută patru octet de OSC
movwf osc_temp_0 ; pentru depozitare temporară pentru acest multiplicări
movf osc_1,w ;
movwf osc_temp_1 ;
movf osc_2,w ;
movwf osc_temp_2 ;
movf osc_3,w ;
movwf osc_temp_3 ;
mult_loop
bcf STATUS,B_C ; Începe cu golirea Carry
btfss osc_temp_0,0 ; Octetul este 0?
goto noAdd ; Nu, nu trebuie să adăugăm termen de frecvențe totală
movf freq_0,w ; Da, obține termenul freq_0
addwf AD9850_1,f ; si adaugă total
btfss STATUS,B_C ; Are ca rezultat acest plus într-o purtătoare
goto add7 ; Nu, continuă cu următorul termen de frecvență
incfsz AD9850_2,f ; Da, se adaugă unu și verifică pentru un alt carry
goto add7 ; Nu, continuă cu următorul termen de frecvență
incfsz AD9850_3,f ; Da, se adaugă unu și verifică pentru un alt carry
goto add7 ; Nu, continuă cu următorul termen de frecvență
incf AD9850_4,f ; Da, adaugă unu și continuă
add7
movf freq_1,w ; Folosește termenul freq_1
addwf AD9850_2,f ; Adaugă termen de frecvențe totalul în poziție corectă
btfss STATUS,B_C ; Are ca rezultat acest plus într-o purtare?
goto add8 ; Nu, continuă cu următorul termen de frecvență
incfsz AD9850_3,f ; Da, se adaugă unu și verifică pentru un alt carry
goto add8 ; Nu, continuă cu următorul termen de frecvență
incf AD9850_4,f ; Da, adaugă unu și continuă
add8
movf freq_2,w ; Folosește termenul freq_2
addwf AD9850_3,f ; Adaugă termen de frecvențe totalul în poziție corectă
btfss STATUS,B_C ; Are ca rezultat acest plus într-o purtare?
goto add9 ; Nu, continuă cu următorul termen de frecvență
incf AD9850_4,f ; Da, adaugă unu și continuă
add9
movf freq_3,w ; Folosește termenul freq_3
addwf AD9850_4,f ; Adaugă termen de frecvențe totalul în poziție corectă
noAdd
rrf AD9850_4,f ; Trecerea următoare multiplicare bit pe poziția
rrf AD9850_3,f ; Rotirea biții la dreapta de la octet la octet
rrf AD9850_2,f ;
rrf AD9850_1,f ;
rrf AD9850_0,f ;
rrf osc_temp_3,f ; Trecerea următoare multiplicare bit pe poziția
rrf osc_temp_2,f ; Rotirea biții la dreapta de la octet la octet
rrf osc_temp_1,f ;
rrf osc_temp_0,f ;
decfsz mult_count,f ; Încă un bit a fost făcut. Am terminat?
goto mult_loop ; Nu, du-te înapoi pentru a utiliza acest bit
clrf AD9850_4 ; Da, clear _4. Rezultatul este în bytes _3 .. _0
return ;
send_dds_word
movlw AD9850_0 ; Punct FSR la AD9850
movwf FSR ;
next_byte
movf INDF,w ;
movwf byte2send ;
movlw 0x08 ; Setează contorul la 8
movwf bit_count ;
next_bit
rrf byte2send,f ; Testarea bitul următor dacă este 1 sau 0
btfss STATUS,B_C ; A fost zero?
goto send0 ; Da, trimite la zero
bsf PortB,7 ; Nu, trimite unu
bsf PortB,5 ; Ceas de scriere comutare
bcf PortB,5 ;
goto break ;
send0
bcf PortB,7 ; Trimite la zero
bsf PortB,5 ; Ceas de scriere comutare
bcf PortB,5 ;
break
decfsz bit_count,f ; A fost trimis toate biți?
goto next_bit ; Nu, merge mai departe.
incf FSR,f ; Începe următorul bit dacă nu e terminat
movlw AD9850_4+1 ; Următorul bit
subwf FSR,w ;
btfss STATUS,B_C ;
goto next_byte ;
bsf PortB,0 ; Trimite semnal de sarcină la AD9850
bcf PortB,0 ;
return ;
bin2BCD
movlw 0x20 ; Setează contorul de buclă
movwf BCD_count ; la 32
clrf BCD_0 ; Șterge ieșirea
clrf BCD_1 ; " "
clrf BCD_2 ; " "
clrf BCD_3 ; " "
clrf BCD_4 ; " "
bin_loop
bcf STATUS,B_C ; Șterge bitul de transport în STATUS
rlf freq_0,f ; Rotire la stânga, 0 -> LS bit, MS bit -> Carry
rlf freq_1,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf freq_2,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf freq_3,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
btfsc STATUS,B_C ; Transportul este clar? Dacă da, sare instrucțiunea următoare
bsf freq_0,0 ; Transportul este setat la bitul 0 în freq_0
rlf BCD_0,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_1,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_2,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_3,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
rlf BCD_4,f ; Rotire la stânga, Carry->LS bit, MS bit->Carry
decf BCD_count,f ; Decrementează numărul de buclă
btfss STATUS,B_Z ; Este, acuma contorul de buclă zero?
goto adjust ; Nu, merge să face reglare
return ; Da, iese
adjust
movlw BCD_0 ; Ia pointerul de la BCD_0
movwf FSR ; Pune pointerul în FSR pentru abordarea indirectă
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_1
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_2
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_3
call adj_BCD ;
incf FSR,f ; Mută indicatorul de adresare indirectă la BCD_4
call adj_BCD ;
goto bin_loop ; Trece înapoi la bucla principală
adj_BCD
movlw 3 ; Adaugă 3
addwf INDF,w ; la cel mai puțin semnificativ bit
movwf BCD_temp ; Salvează în temp
btfsc BCD_temp,3 ; Este cel mai puțin semnificativ bit + 3 > 7
movwf INDF ; Da, salvează valoare incrementat ca cel mai puțin semnificat bit
movlw 0x30 ; Adaugă 3
addwf INDF,w ; la cel mai semnificatic bit
movwf BCD_temp ; Salvează în temp
btfsc BCD_temp,7 ; Este cel mia semnificativ bit +3 > 7
movwf INDF ; Da, salvați valoare incrementat ca cel mai semnificativ bit
return ; Revine la subrutina adjust
show_freq
movlw 0x81 ; Punctul LCD pentru prima cifră
call cmnd2LCD ; Trimite punctul de plecare
swapf BCD_3,w ; Schimbă 10MHz în BCD cifre pentru W
andlw 0x0F ;
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movf BCD_3,w ; Schimbă 1MHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movlw ',' ; Ia-o virgulă
call data2LCD ; Trimite octetul în W pentru LCD
swapf BCD_2,w ; Schimbă 10MHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movf BCD_2,w ; Schimbă 10KHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
swapf BCD_1,w ; Schimbă 1KHz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movlw '.' ; Configurarea W cu perioada ASCII
call data2LCD ; Trimite octet de date în W pentru LCD
movlw 0xC0 ; Numărul de cifre 9
call cmnd2LCD ; Trimite octet de comandă în W pentru LCD
movf BCD_1,w ; Schimbă 100Hz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
swapf BCD_0,w ; Schimbă 10Hz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movf BCD_0,w ; Schimbă 1Hz în BCD cifre pentru W
andlw 0x0F ; Masca
addlw 0x30 ; Adauga compensa pentru setul ASCII caracter
call data2LCD ; Trimite octetul în W pentru LCD
movlw ' ' ; Trimite un spațiu
call data2LCD ; pentru LCD
movlw 'k' ; Trimite un 'k'
call data2LCD ; pentru LCD
movlw 'H' ; Trimite un "H"
call data2LCD ; pentru LCD
movlw 'z' ; Trimite un 'z'
call data2LCD ; pentru LCD
return ;
busy_check
clrf PortB ; Șterge toate ieșirile pe PortB
bsf STATUS,B_RP0 ; Comută cu bancă 1 pentru operarea Tristate
movlw b'11110000' ; Setează RB7, RB6, RB5, RB4 ca intrări
; și RB3, RB2, RB1, RB0 ca ieșiri
movwf TRISB ; prin Tristate
bcf STATUS,B_RP0 ; Comuta înapoi la bancă 0
bcf PortB,LCD_rs ; Configură LCD pentru Read Busy Flag
bsf PortB,LCD_rw ; Configură LCD pentru Read
movlw 0xFF ; Configură constanta 255
movwf timer1 ; pentru cronometru buclă contor
LCD_is_busy
bsf PortB,LCD_e ; Set E înalt
movf PortB,w ; Citește PortB în W
movwf LCD_read ; Salvează W pentru testarea mai târziu
bcf PortB,LCD_e ; Aruncă din nou E
nop ; Așteaptă
nop ; puțin timp
bsf PortB,LCD_e ; Puls E înalt
nop ; așteaptă,
bcf PortB,LCD_e ; și aruncă E iarăși
decf timer1,f ; Decrementează bucla de contor
btfsc STATUS,B_Z ; Este bucla de contor la zero?
goto not_busy ; Dacă da, întoarce indiferent
btfsc LCD_read,7 ; Este bitul Busy Flag (RB7) salvat?
goto LCD_is_busy ; Dacă nu, este ocupat și sare înapoi
not_busy
return ;
cmnd2LCD
movwf LCD_char ; Salvează octetul pentru a scrie la LCD
clrf rs_value ; Amintește pentru a seta RS
bcf PortB,LCD_rs ; Setarea RS de comandă pentru LCD
goto write2LCD ; Du-te la cod comun
data2LCD
movwf LCD_char ; Salvează octetul pentru a scrie la LCD
bsf rs_value,0 ; Amintește pentru a seta RS
bsf PortB,LCD_rs ; Setarea RS de comandă pentru LCD
write2LCD
call busy_check ; Verificați pentru a vedea dacă LCD este gata pentru noi date
clrf PortB ; Șterge toate Port B
bsf STATUS,B_RP0 ; Comutare la bancă 1 pentru operarea Tristate
movlw 0x00 ; Configurarea pentru a permite pini de date PORTB
movwf TRISB ; Toate pini (RB7.. RB0) sunt ieșiri
bcf STATUS,B_RP0 ; Comuta la bancă 0
bcf PortB,LCD_rw ; Setează LCD înapoi la modul de a scrie
bcf PortB,LCD_rs ; RS ar trebui să fie gol
btfsc rs_value,0 ; Rs trubie să fie gol?
bsf PortB,LCD_rs ; Nu, setează RS
movlw 0x0F ; Configurarea masca
andwf PortB,f ; Șterge vechea RB7..RB4
movf LCD_char,w ; Pune octetul de date în W
andlw 0xF0 ; Masca pentru XXXX0000 în W
iorwf PortB,f ; Trimite RB7..RB4 fără să schimbe RB3..RB0
bsf PortB,LCD_e ; Puls linia E mare,
nop ; așteptă,
bcf PortB,LCD_e ; și aruncă din nou
movlw 0x0F ; Configurarea masca
andwf PortB,f ; Șterge vechea RB7..RB4
swapf LCD_char,w ; Pune octetul de date în W
andlw 0xF0 ; Masca pentru XXXX0000 în WW
iorwf PortB ; Trimite RB7..RB4 fără să schimbe RB3..RB0
bsf PortB,LCD_e ; Puls linia E mare,
nop ; așteptă,
bcf PortB,LCD_e ; și aruncă din nou
return
write_EEPROM
bsf STATUS,B_RP0 ; Comută la bancă 1
bsf EEdata,WREN ; Setează EEPROM la bit write enable
movlw 0x55 ; Scrie 0x55 și 0xAA la EEPROM
movwf EEadr ; registru de control, după cum este
movlw 0xAA ; necesar pentru scriere
movwf EEadr ;
bsf EEdata,WR ; Setează WR să inițieze scriere
bit_check
btfsc EEdata,WR ; A finalizat scrierea?
goto bit_check ; Nu, păstreze verificarea
bcf EEdata,WREN ; Golește la EEPROM bitul write enable
bcf STATUS,B_RP0 ; Comuta la bancă 0
incf EEadr,f ; Incrementează adresa de scriere EE
return ; Revine la apelant
read_EEPROM
bsf STATUS,B_RP0 ; Comuta la bancă 1
bsf EEdata,RD ; Cerere de citire
bcf STATUS,B_RP0 ; Comuta la bancă 0
incf EEadr,f ; Incrementează adresa de citire
return ; Revine la apelant
wait_128ms ; ****** Entry point ******
movlw 0xFF ; Configurarea buclei exterioară
movwf timer1 ; contorul la 255
goto outer_loop ; Merge la bucle de așteptares
wait_64ms ; ****** Entry point ******
movlw 0x80 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 128
goto outer_loop ; Merge la bucle de așteptare
wait_32ms ; ****** Entry point ******
movlw 0x40 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 64
goto outer_loop ; Merge la bucle de așteptare
wait_16ms ; ****** Entry point ******
movlw 0x20 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 32
goto outer_loop ; Merge la bucle de așteptare
wait_8ms ; ****** Entry point ******
movlw 0x10 ; Configurarea buclei exterioară
movwf timer1 ; contorul la 16
outer_loop
movlw 0xFF ; Configurarea contorul buclă interioară
movwf timer2 ; la 255
inner_loop
decfsz timer2,f ; Decrementează contorul de buclă interioară
goto inner_loop ; Dacă contor buclă interior nu este la zero,
; apoi merge înapoi la bucla interioară din nou
decfsz timer1,f ; Da, Decrementează contorul buclă exterioară
goto outer_loop ; Dacă contor buclă exterioară nu este la
; zero, apoi merge înapoi la bucla exterioară din nou
return ; Da, revine la apelantr
END
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Sinteza Directa Digitala (ID: 123887)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
