DDS.c


1
//includes
2
//////////
3
#include "avr/io.h"
4
#include <util/delay.h>
5
6
7
//defines
8
/////////
9
#define DDS_MCLK     24000000    /* DDS Clock */
10
#define DDS_CONSTANT   0x10000000   /* 2^28 */
11
#define DDS_DDR      DDRD    /* data direction reg*/
12
#define DDS_PORT    PORTD
13
#define DDS_SDATA    PIN0
14
#define DDS_SCLCK    PIN1
15
#define DDS_FSYNC    PIN2
16
17
18
#define A       PINA1 // Schalter A im Drehgeber 
19
#define B       PINA0 // Schalter B im Drehgeber
20
#define Geber   PINA  // Drehgeber Port
21
22
23
//predeclarations
24
void DDS_WriteWord(int16_t wValue);
25
void ToggleDDSPIN(int nBit);
26
void RotaryBlink(void);
27
void DebounceKey(int nPort, int nPin);
28
void SetFrequency(int32_t dwFreq);
29
30
31
//calculate codeword:
32
//CW = (Freq / DDS_MCLK) * DDS_CONSTANT
33
//for 5 mhz with 25 MHz clock:  0x33333333
34
35
36
37
int main(void)
38
{
39
  //variables
40
  ///////////
41
  int32_t dwFreq     = 1000000;
42
43
  int    richtung    = 0;
44
  char   alter_status = 0;
45
  char  step = 0;
46
    char    neuer_status;
47
    
48
49
  //port init
50
  DDS_PORT = 0x0;
51
  DDS_DDR  = 0xFF;  //all output
52
  
53
54
  DDRA   = 0x0;    //all input
55
  PORTA   = 0xFF;  //pull up
56
57
  DDRC   = 0xFF;  //all output
58
  PORTC   = 0x00;  //no pull up
59
60
  //wait before we init 
61
  //the ad9833
62
  _delay_ms(1000);
63
64
65
  SetFrequency(dwFreq);
66
67
68
  RotaryBlink();
69
  RotaryBlink();
70
71
72
73
  while(1)
74
  {
75
      neuer_status = Geber & (_BV(A) | _BV(B));     // Änderung einlesen
76
      if ((neuer_status ^ step)==(_BV(A) | _BV(B)))
77
       {
78
        if ((neuer_status ^ alter_status) ==_BV(A))
79
      {
80
            richtung +=1; // Es war nach rechts
81
        RotaryBlink();
82
83
        dwFreq += 1000;
84
        SetFrequency(dwFreq);
85
      }
86
         else
87
      {
88
            richtung -=1; // Es war nach links
89
        RotaryBlink();
90
        
91
        dwFreq -= 1000;
92
        SetFrequency(dwFreq);
93
      }
94
        
95
      step = neuer_status;
96
      }
97
  
98
      alter_status = neuer_status;
99
100
101
102
  /*
103
    if((PINA & 0x2) == 0x0)
104
    {
105
      RotaryBlink();
106
107
      dwFreq += 10000;
108
      SetFrequency(dwFreq);
109
      DebounceKey(PINA, 0x2);
110
    };
111
112
    if((PINA & 0x4) == 0x0)
113
    {
114
      RotaryBlink();
115
      RotaryBlink();
116
117
      dwFreq -= 10000;
118
      SetFrequency(dwFreq);
119
      DebounceKey(PINA, 0x4);
120
    };
121
  */
122
  }
123
124
  return 0;
125
}
126
127
128
129
void SetFrequency(int32_t dwFreq)
130
{
131
  //variables
132
  ///////////
133
  float     fVal    = ((float)dwFreq / (float)DDS_MCLK);
134
  int32_t   dwCodeWord   = fVal * DDS_CONSTANT;
135
  int16_t   wWord       = 0x0;
136
137
  //send the control byte
138
  wWord = 0x2000;                //0010 0000 0000 0000
139
  DDS_WriteWord(wWord);
140
141
  _delay_ms(1);
142
143
144
145
  //send lsb
146
  wWord  = (dwCodeWord & 0x00003FFF);        //lsb
147
  wWord |= 0x4000;
148
  DDS_WriteWord(wWord);
149
150
  _delay_ms(1);
151
152
153
154
  //send msb
155
  wWord  = (dwCodeWord & 0x0FFFC000) >> 14;   //msb  
156
  wWord |= 0x4000;                //set bit 15
157
  DDS_WriteWord(wWord);    
158
}
159
160
161
162
/*
163
AD9833 to 80C51/80L51 Interface
164
Figure 12 shows the serial interface between the AD9833 and the
165
80C51/80L51 microcontroller. The microcontroller is operated
166
in mode “0” so that TXD of the 80C51/80L51 drives SCLK of
167
the AD9833, while RXD drives the serial data line SDATA. The
168
FSYNC signal is again derived from a bit programmable pin on
169
the port (P3.3 being used in the diagram). When data is to be
170
transmitted to the AD9833, P3.3 is taken low. The 80C51/80L51
171
transmits data in 8-bit bytes, thus only eight falling SCLK edges
172
occur in each cycle. To load the remaining 8 bits to the AD9833,
173
P3.3 is held low after the first 8 bits have been transmitted, and
174
a second write operation is initiated to transmit the second byte of
175
data. P3.3 is taken high following the completion of the second
176
write operation. SCLK should idle high between the two write
177
operations. The 80C51/80L51 outputs the serial data in a format
178
that has the LSB first. The AD9833 accepts the MSB first
179
(the 4 MSBs being the control information, the next 4 bits being
180
the address, while the 8 LSBs contain the data when writing to a
181
destination register). Therefore, the transmit routine of the
182
80C51/80L51 must take this into account and rearrange the bits
183
so that the MSB is output first.
184
185
186
187
188
6 SDATA Serial Data Input. The 16-bit serial data-word is applied to this input.
189
7 SCLK Serial Clock Input. Data is clocked into the AD9833 on each falling SCLK edge.
190
8 FSYNC Active Low Control Input. This is the frame synchronization signal for the
191
input data. When FSYNC is taken low, the
192
new word is being loaded into the device.
193
194
195
http://www.roboternetz.de/wissen/index.php/Portexpander_am_AVR#Ohne_SPI-Hardware
196
*/
197
void DDS_WriteWord(int16_t wValue)
198
{
199
  //variables
200
  ///////////
201
  int     nBit = 0;
202
  int     n   = 0;  
203
  uint16_t   wVal = wValue;
204
205
  //init
206
  DDS_PORT = DDS_PORT & ~(1 << DDS_SDATA);
207
  DDS_PORT = DDS_PORT | (1 << DDS_SCLCK);        //set
208
  DDS_PORT = DDS_PORT | (1 << DDS_FSYNC);        //set
209
  
210
  _delay_ms(1);
211
212
213
214
  DDS_PORT &= ~(1 << DDS_FSYNC);        //remove
215
216
  _delay_ms(1);
217
218
219
220
221
  for(n = 0; n < 16; ++n)
222
  {
223
    nBit = (wVal & 0x8000) >> 15;
224
    wVal = wVal << 1;    //shift
225
226
    ToggleDDSPIN(nBit);
227
  };  
228
229
230
  DDS_PORT = DDS_PORT | (1 << DDS_FSYNC);        //set
231
232
  _delay_ms(1);
233
}
234
235
236
237
238
void ToggleDDSPIN(int nBit)
239
{
240
  if(nBit == 1)
241
  {
242
    DDS_PORT = DDS_PORT | (1 << DDS_SDATA);    //set      
243
  }
244
245
  _delay_ms(1);
246
247
248
  
249
250
  DDS_PORT = DDS_PORT & ~(1 << DDS_SCLCK);     //remove
251
252
  _delay_ms(1);
253
254
255
256
  DDS_PORT  = DDS_PORT | (1 << DDS_SCLCK);    //set
257
258
  _delay_ms(1);
259
260
261
262
  DDS_PORT = DDS_PORT & ~(1 << DDS_SDATA);     //remove
263
}
264
265
266
void RotaryBlink(void)
267
{
268
  PORTC = (1 << PIN0);
269
270
  _delay_ms(10);
271
272
  PORTC &= ~(1 << PIN0);
273
274
  _delay_ms(10);
275
}
276
277
278
void DebounceKey(int nPort, int nPin)
279
{
280
  while((nPort & nPin) == 0)
281
  {
282
    //do nothing
283
    _delay_ms(1);
284
  }
285
}