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

Similar Posts