Проблема с DDS AD9850
- Войдите на сайт для отправки комментариев
Пнд, 11/11/2013 - 06:34
Добрый день!
Проблема с DDS на AD9850 (синяя плата HC-RS08, только что приехала с Китая).
Не могу добиться работы DDS. На выходе ZOUT1 (да и на других) ничего нет. Проверял включением осциллографа между ZOUT1 и GND.
Брак в плате, в руках или программе?
01 | #include <LiquidCrystal.h> |
02 |
03 | #define DDS_CLOCK 125000000 |
04 | #define CLOCK 3 //pin connections for DDS |
05 | #define LOAD 2 |
06 | #define DATA 1 |
07 | #define RESET 0 |
08 |
09 | LiquidCrystal lcd(8, 9, 4, 5, 6, 7); |
10 |
11 | void AD9850_init() |
12 | { |
13 | digitalWrite(RESET, LOW); |
14 | digitalWrite(CLOCK, LOW); |
15 | digitalWrite(LOAD, LOW); |
16 | digitalWrite(DATA, LOW); |
17 | } |
18 |
19 |
20 |
21 | void AD9850_reset() |
22 | { |
23 | //reset sequence is: |
24 | // CLOCK & LOAD = LOW |
25 | // Pulse RESET high for a few uS (use 5 uS here) |
26 | // Pulse CLOCK high for a few uS (use 5 uS here) |
27 | // Set DATA to ZERO and pulse LOAD for a few uS (use 5 uS here) |
28 | |
29 | // data sheet diagrams show only RESET and CLOCK being used to reset the device, but I see no output unless I also |
30 | // toggle the LOAD line here. |
31 | |
32 | digitalWrite(CLOCK, LOW); |
33 | digitalWrite(LOAD, LOW); |
34 | |
35 | digitalWrite(RESET, LOW); |
36 | delay(5); |
37 | digitalWrite(RESET, HIGH); //pulse RESET |
38 | delay(5); |
39 | digitalWrite(RESET, LOW); |
40 | delay(5); |
41 | |
42 | digitalWrite(CLOCK, LOW); |
43 | delay(5); |
44 | digitalWrite(CLOCK, HIGH); //pulse CLOCK |
45 | delay(5); |
46 | digitalWrite(CLOCK, LOW); |
47 | delay(5); |
48 | digitalWrite(DATA, LOW); //make sure DATA pin is LOW |
49 | |
50 | digitalWrite(LOAD, LOW); |
51 | delay(5); |
52 | digitalWrite(LOAD, HIGH); //pulse LOAD |
53 | delay(5); |
54 | digitalWrite(LOAD, LOW); |
55 | // Chip is RESET now |
56 | } |
57 |
58 | void SetFrequency(unsigned long frequency) |
59 | { |
60 | unsigned long tuning_word = (frequency * 4294967296LL) / DDS_CLOCK; |
61 | digitalWrite (LOAD, LOW); |
62 |
63 | shiftOut(DATA, CLOCK, LSBFIRST, tuning_word); |
64 | shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 8); |
65 | shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 16); |
66 | shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 24); |
67 | shiftOut(DATA, CLOCK, LSBFIRST, 0x0); |
68 | |
69 | digitalWrite (LOAD, HIGH); |
70 | } |
71 |
72 |
73 | void setup () |
74 | { |
75 | lcd.begin(16, 2); // start the library |
76 | lcd.setCursor(1,0); |
77 | lcd.print( "**DDS AD9850**" ); |
78 | } |
79 |
80 | void loop () |
81 | { |
82 | AD9850_init; |
83 | AD9850_reset; |
84 | SetFrequency(1000); |
85 | lcd.setCursor(0,1); |
86 | lcd.print( "Freq=1kHz" ); |
87 | while (1); |
88 | } |
01
void
setup
()
02
{
03
pinMode(RESET, OUTPUT);
04
pinMode(DATA, OUTPUT);
05
pinMode(CLOCK, OUTPUT);
06
pinMode(LOAD, OUTPUT);
07
lcd.begin(16, 2);
// start the library
08
lcd.setCursor(1,0);
09
lcd.print(
"**DDS AD9850**"
);
10
AD9850_init;
11
AD9850_reset;
12
}
13
14
void
loop
()
15
{
16
delay(500);
17
SetFrequency(10000);
18
while
(1);
19
}
Разобрался. Тему можно закрыть.
А поделиться информацией? Возможно кому то это тоже может помочь.
kisoft +1, мне любопытно. Хочу на нём собрать гетеродинный приёмник для пассивного считавания EM4100 RFId меток.
Ошибка в том, что я снимал сигнал с выхода QOUT1, а не ZOUT1
QOUT1 всегда 0, QOUT2 всегда 1. Потенциометр не крутил. По идее это выходы не для синуса, а для меандра.
У этой платы обнаружил особенность - чем выше частота (заметнее на частотах > 5Мгц), тем меньше амплитуда сигнала.
Причем, Vmax сигнала остаётся в районе 1В (1.04в, если быть точным), а Vmin с увеличением частоты тоже увеличивается.
Вечером накидаю график зависимости, может будет кому-то полезным.
Записал видео, как меняется амплитуда сигнала в зависимости от генерируемой частоты.
На видео видна форма сигнала, максимальное и минимальное напряжение.
Диапазон частот - 20КГц÷20Мгц с шагом 20КГц
Трафик! 2 мин - 130 Мбайт.
https://dl.dropboxusercontent.com/u/72215607/VID_20131113_191651.3gp
01
#include <LiquidCrystal.h>
02
03
#include <EF_AD9850.h>
04
05
EF_AD9850 AD9850(3,2,0,1);
06
07
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
08
09
unsigned
long
freq = 10000, delta = 20000;
10
11
void
setup
() {
12
AD9850.init();
13
AD9850.reset();
14
lcd.begin(16, 2);
15
16
}
17
18
void
loop
() {
19
lcd.home();
20
delay(10000);
21
lcd.print(
"** DDS AD9850**"
);
22
for
(freq=delta; freq<=20000000; freq+=delta){
23
AD9850.wr_serial(0,freq);
24
lcd.setCursor(0,1);
25
lcd.print(
"Freq="
);
26
lcd.print(freq);
27
lcd.print(
"Hz "
);
28
delay(100);
29
}
30
31
}
Кому будет интересно, составил график зависимости амплитуды от генерируемой частоты
http://s019.radikal.ru/i637/1311/bc/d4b0a5262872.png
А можно фото проекта?
Здравствуйте!
Делаю синтезатор на ардуино и платке с AD9850. Нашел код запустил работает, теперь мне нужно изменить код для введения одной функции. А именно, сейчас синтезатор выдает частоту от 1мгц до 30 мгц а нужно разбить на небольшие отрезки, переключаемые кнопкой, подключенной ну например к выводу A1
Например разбить на 9 кусочков
1. от 1мгц до 2мгц
2. от 2мгц до 3мгц
.....
9 от 9мгц до 10 мгц
И что бы диапазоны переключались цикличиски. Вот что имею. Помогите с кодом пожалуйста
001
/*
002
Main code by Richard Visokey AD7C - <a href="http://www.ad7c.com" title="www.ad7c.com" rel="nofollow">www.ad7c.com</a>
003
Revision 2.0 - November 6th, 2013
004
*/
005
//Если необходима функция выбора шага энкодера на щелчек, Смотрим строки 57, 89 и 110
006
//Резерв для описания
007
//Резерв для описания
008
//Резерв для описания
009
//Резерв для описания
010
//Резерв для описания
011
//Резерв для описания
012
//Резерв для описания
013
//Резерв для описания
014
//Резерв для описания
015
//Резерв для описания
016
//Резерв для описания
017
//Резерв для описания
018
//Резерв для описания
019
//Резерв для описания
020
//Резерв для описания
021
//Резерв для описания
022
// Include the library code
023
//Инициализация библиотек
024
#include <LiquidCrystal.h> //библиотека 1602
025
#include <rotary.h> //библиотека энкодера
026
#include <EEPROM.h> //библиотека EEPROM
027
028
//Setup some items
029
//Настройка некоторых элементов
030
//Подключаем модуль синтезатора
031
#define W_CLK 10 // Pin 10 - connect to AD9850 module word load clock pin (CLK)
032
// Выыод 10 - подкоючаем к выводу W_CLK модуля синтезатора (таймер)
033
#define FQ_UD 11 // Pin 11 - connect to freq update pin (FQ)
034
// Выыод 11 - подкоючаем к выводу FQ_UD модуля синтезатора (обновление частоты)
035
#define DATA 12 // Pin 12 - connect to serial data load pin (DATA)
036
// Выыод 12 - подкоючаем к выводу DATA модуля синтезатора (загрузка данных)
037
#define RESET 13 // Pin 13 - connect to reset pin (RST)
038
// Выыод 13 - подкоючаем к выводу RESET модуля синтезатора (сброс)
039
040
041
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
042
Rotary r = Rotary(2,3);
// sets the pins the rotary encoder uses. Must be interrupt pins.
043
//Подключаем энкодер к 2 и 3 ножкам
044
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
// I used an odd pin combination because I need pin 2 and 3 for the interrupts.
045
//Подключаем 1602 дисплей к соответствующим пинам, указываем номера портовв порядке RS, E, DB4, DB5, DB6, DB7
046
int_fast32_t rx=10000000;
// Base (starting) frequency of VFO. This only loads once. To force load again see ForceFreq variable below.
047
//Запуск синтезатора с этой частоты, единожды, для дальнейшего обращения используем переменную ForceFreq ниже
048
int_fast32_t rx2=1;
// variable to hold the updated frequency
049
// Переменная для хранения новой частоты
050
int_fast32_t increment = 100;
// starting VFO update increment in HZ.
051
// Установка шага на один щелчек энкодера при запуске.
052
int_fast32_t iffreq = 1000000;
// Intermedite Frequency - Amount to subtract (-) from base frequency. ********************************************
053
// Здесь необходимо выставить частоту ПЧ в герцах
054
int
buttonstate = 0;
055
int
buttonstate2 = 0;
056
int
GoIF = 1;
057
//String hertz = "100 Hz"; //Нужно для установки шага энкодера, при необходимости раскомментировать.
058
int
hertzPosition = 5;
059
byte
ones,tens,hundreds,thousands,tenthousands,hundredthousands,millions ;
//Placeholders
060
//Заполнители?
061
String freq;
// string to hold the frequency
062
//Строка для хранения частоты
063
int_fast32_t timepassed = millis();
// int to hold the arduino miilis since startup
064
// Провести инициализацию ардуино в милисекундах после запуска
065
int
memstatus = 1;
// value to notify if memory is current or old. 0=old, 1=current.
066
// Смотрим, в памяти значение старое или новое. 0 - Старое 1 -Новое
067
068
069
int
ForceFreq = 0;
// Change this to 0 after you upload and run a working sketch to activate the EEPROM memory. YOU MUST PUT THIS BACK TO 0 AND UPLOAD THE SKETCH AGAIN AFTER STARTING FREQUENCY IS SET!
070
// Если установить 0 то при включении программа возьмет из памяти EEPROM последнее значение частоты, если 1 то стартует с частоты указанной 30 строке.
071
// Внимание, при первой прошивке и запуске значение в EEPROM нет, поэтому нужно выствить 1 прошить ардуино. Затем, если нужна память на последнюю частоту, выставить 0 в скетче и прошить ардуино снова.
072
073
void
setup
() {
074
pinMode(A5,INPUT);
// Подключаем к кнопку которая при нажатии замыкает вывод А5 на общий провод
075
digitalWrite(A5,HIGH);
//Подтягиваем вывод A5 к плюсу питания
076
lcd.begin(16, 2);
//Указываем сколько у нас символов и строк на дисплее.
077
PCICR |= (1 << PCIE2);
078
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
079
sei();
080
pinMode(FQ_UD, OUTPUT);
//Выставляем вывод как цифровой выход
081
pinMode(W_CLK, OUTPUT);
//Выставляем вывод как цифровой выход
082
pinMode(DATA, OUTPUT);
//Выставляем вывод как цифровой выход
083
pinMode(RESET, OUTPUT);
//Выставляем вывод как цифровой выход
084
pulseHigh(RESET);
085
pulseHigh(W_CLK);
086
pulseHigh(FQ_UD);
// this pulse enables serial mode on the AD9850 - Datasheet page 12.
087
// Этот импульс необходим для последовательной шины, Datasheet страница 12.
088
lcd.setCursor(hertzPosition,1);
089
//lcd.print(hertz); //Начало настроек для выбора кнопки переключения шага энкодера----------------
090
//pinMode(A0,INPUT); // Connect to a button that goes to GND on push |
091
// Подключаем к кнопку которая при нажатии замыкает вывод А0 на общий провод |
092
//digitalWrite(A0,HIGH); //Подтягиваем вывод A0 к плюсу питания |
093
//-------------------Окончание настроек для выбора кнопки переключения шага энкодера-----------------
094
// Load the stored frequency
095
//Загружаем сохраненную частоту
096
if
(ForceFreq == 0) {
097
freq = String(EEPROM.read(0))+String(EEPROM.read(1))+String(EEPROM.read(2))+String(EEPROM.read(3))+String(EEPROM.read(4))+String(EEPROM.read(5))+String(EEPROM.read(6));
098
rx = freq.toInt();
099
}
100
}
101
102
103
void
loop
() {
104
// Обновляем частоту на дисплее и частоту синтезатора если она (частота) изменилась
105
if
(rx != rx2){
106
showFreq();
107
sendFrequency(rx);
108
rx2 = rx;
109
}
110
//---------------------------------------------Начало участка кода для управления шагом щелчка энкодером.
111
112
// Циклически меняем шаг перестройки при нажатии и удержании кнопки, при необходимости раскомментировать
113
//buttonstate = digitalRead(A0);
114
//if(buttonstate == LOW) {
115
//setincrement();
116
//};
117
118
//void setincrement(){ //Здесь закомментированы шаги переключения энкодера, необходимое раскомментировать
119
//if(increment == 10){increment = 50; hertz = "50 Hz"; hertzPosition=5;}
120
//else if (increment == 50){increment = 100; hertz = "100 Hz"; hertzPosition=4;}
121
//else if (increment == 100){increment = 500; hertz="500 Hz"; hertzPosition=4;}
122
//else if (increment == 500){increment = 1000; hertz="1 Khz"; hertzPosition=6;}
123
//else if (increment == 1000){increment = 2500; hertz="2.5 Khz"; hertzPosition=4;}
124
//else if (increment == 2500){increment = 5000; hertz="5 Khz"; hertzPosition=6;}
125
//else if (increment == 5000){increment = 10000; hertz="10 Khz"; hertzPosition=5;}
126
//else if (increment == 10000){increment = 100000; hertz="100 Khz"; hertzPosition=4;}
127
//else if (increment == 100000){increment = 1000000; hertz="1 Mhz"; hertzPosition=6;}
128
//else{increment = 10; hertz = "10 Hz"; hertzPosition=5;};
129
//lcd.setCursor(0,1);
130
//lcd.print(" ");
131
//lcd.setCursor(hertzPosition,1);
132
//lcd.print(hertz);
133
//delay(250); // С помощью этой задержки можно менять скорость изменения шага при нажатой кнопке
134
//};
135
//---------------------------------------------Окончание участка кода для управления шагом щелчка энкодером.
136
137
138
139
// Проверяем уровень на выводе А5, если низкий - включаем отступ на ПЧ
140
// на дисплее остается частота приема, синтезатор получает "Частота приема - Частота ПЧ"
141
// (тут напутано вроде или я глючу ? вроде как наоборот низкий уровень - нет вычета ПЧ)
142
buttonstate = digitalRead(A5);
143
if
(buttonstate != buttonstate2){
144
if
(buttonstate == LOW) {
145
lcd.setCursor(15,1);
146
lcd.print(
"."
);
147
GoIF = 0;
148
buttonstate2 = buttonstate;
149
sendFrequency(rx);
150
}
151
else
{
152
lcd.setCursor(15,1);
153
lcd.print(
" "
);
154
GoIF = 1;
155
buttonstate2 = buttonstate;
156
sendFrequency(rx);
157
};
158
};
159
160
// Записываем частоту в постоянную память если она не изменнялась поседние 2 секунды
161
if
(memstatus == 0){
162
if
(timepassed+2000 < millis()){
163
storeMEM();
164
}
165
}
166
167
}
168
169
170
// Процедура прерывания по событию изменение состояния энкодера
171
ISR(PCINT2_vect) {
172
unsigned
char
result = r.process();
173
if
(result) {
174
if
(result == DIR_CW){rx=rx+increment;}
175
else
{rx=rx-increment;};
176
if
(rx >=30000000){rx=rx2;};
// Верхний предел частоты
177
if
(rx <=1000000){rx=rx2;};
// Нижний предел частоты
178
}
179
}
180
181
// вычисление частоты из даташита, стр. 8 = <sys clock> * <frequency tuning word>/2^32
182
void
sendFrequency(
double
frequency) {
183
if
(GoIF == 1){frequency=frequency-iffreq;};
// Если на выводе А5 низкий уровень - вычитаем ПЧ
184
int32_t freq = frequency * 4294967295/125000000;
// Для тактовой 125 МГц на AD9850. Можно слегка поиграться значением для более точной настройки.
185
for
(
int
b=0; b<4; b++, freq>>=8) {
186
tfr_byte(freq & 0xFF);
187
}
188
tfr_byte(0x000);
// Завершающий байт последовательности, 0 для AD9850 (1 для AD9851 если не путаю)
189
pulseHigh(FQ_UD);
// Готово! Дергаем ножкой мк
190
}
191
192
// Передача байта по биту за раз в режиме "сначала младший" (LSB) на AD9850 через последовательую шину (DATA)
193
void
tfr_byte(
byte
data)
194
{
195
for
(
int
i=0; i<8; i++, data>>=1) {
196
digitalWrite(DATA, data & 0x01);
197
pulseHigh(W_CLK);
// после отправки каждого бита отправляем одиночный импульс высокого уровня на CLK
198
}
199
}
200
201
void
showFreq(){
//Вывод частоты в верхнюю строку
202
millions =
int
(rx/1000000);
//Показать колличество мегагерц на верхнюю строку
203
hundredthousands = ((rx/100000)%10);
204
tenthousands = ((rx/10000)%10);
205
thousands = ((rx/1000)%10);
206
hundreds = ((rx/100)%10);
207
tens = ((rx/10)%10);
208
ones = ((rx/1)%10);
209
lcd.setCursor(0,0);
210
lcd.print(
" "
);
//Пустой символ перед частотой для выравнивания надписи в верхней строке
211
if
(millions > 9){lcd.setCursor(1,0);}
212
else
{lcd.setCursor(2,0);}
213
lcd.print(millions);
214
lcd.print(
"."
);
215
lcd.print(hundredthousands);
216
lcd.print(tenthousands);
217
lcd.print(thousands);
218
lcd.print(
"."
);
219
lcd.print(hundreds);
220
lcd.print(tens);
221
lcd.print(ones);
222
lcd.print(
" Mhz "
);
//Вывод на дисплей Mhz после частоты в первой строке
223
timepassed = millis();
224
memstatus = 0;
// Сигнализируем об изменении частоты и потенциальной необходимости ее записи в постоянную память
225
};
226
227
void
storeMEM(){
228
//Записываем частоту в постоянную память (EEPROM) поразрядно (это коряво, но работает)
229
EEPROM.write(0,millions);
230
EEPROM.write(1,hundredthousands);
231
EEPROM.write(2,tenthousands);
232
EEPROM.write(3,thousands);
233
EEPROM.write(4,hundreds);
234
EEPROM.write(5,tens);
235
EEPROM.write(6,ones);
236
memstatus = 1;
// Сигнализируем программе, что последние изменения частоты записаны в постоянную память (EEPROM)
237
};
Кто-нибудь вообще в курсе, как правильно подключить и закодить зелёную плату с AD 9850?
Я гуглил, нашёл три скетча, ни один из них ни хрена не работает.
Что надо: скетч, в котором задал частоту и осциллок, подключённый к выводу SinA показывает синусоиду указанной частоты.
Помогите, пожалуйста, может, кто-то уже кодил сей генератор?
Может кому пригодится.
DDS генератор синусоидальных и прямоугольных сигналов в диапазононе частот 0 - 40МГц на базе
Arduino Uno + AD9850 DDS
Для сборки надо:
Arduino Uno R3
шилд DFRobot LCD Keypad Shield
модуль HC-RS08 AD9850 DDS
8 проводов для соединения модулей
Сборка:
1.Подключаем к компьютеру плату Arduino Uno и загружаем в нее Sketch:
#include <LiquidCrystal.h> // Подключение библиотек
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// Инициализация LCD с указанием пинов
float
freq = 10000;
// Оглашение переменных -- Частота
float
bigStep = 1000;
// Шаг изменения частоты при нажатии вверх/вниз
float
littleStep = 10;
// Шаг изменения частоты при нажатии вправо/влево
int
lcd_key = 0;
int
adc_key_in = 0;
#define btnRIGHT 0 // Создание директив для кнопок
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
#define W_CLK 15 // Пин A1 Arduino - подключен к CLK
#define FQ_UD 16 // Пин A2 Arduino - подключен к FQ (FU)
#define DATA 17 // Пин A3 Arduino - подключен к DATA
#define RESET 18 // Пин A4 Arduino - подключен к RST
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
//------------------------------------------------------
int
read_LCD_buttons(){
// Функция считывания нажатия кнопок
adc_key_in = analogRead(0);
if
(adc_key_in > 1000)
return
btnNONE;
if
(adc_key_in < 50)
return
btnRIGHT;
if
(adc_key_in < 150)
return
btnUP;
if
(adc_key_in < 315)
return
btnDOWN;
if
(adc_key_in < 600)
return
btnLEFT;
if
(adc_key_in < 850)
return
btnSELECT;
return
btnNONE;}
//-------------------------------------------------------
void
tfr_byte(
byte
data){
// Функция побитной отправки байта
for
(
int
i=0; i<8; i++, data>>=1) {
// данных в модуль генератора
digitalWrite(DATA, data & 0x01);
pulseHigh(W_CLK);}}
// Подача импульса на CLK после каждого бита
//-------------------------------------------------------
void
sendFrequency(
double
frequency) {
// Преобразование и отправка
int32_t freq = frequency * 4294967295/125000000;
// значения частоты
for
(
int
b=0; b<4; b++, freq>>=8) {tfr_byte(freq & 0xFF);}
tfr_byte(0x000);
// Отправка завершательного контрольного байта
pulseHigh(FQ_UD);}
// Обновление частоты генератора
//----------------------------------------------------
void
setup
()
{
lcd.begin(16, 2);
// Старт библиотеки. Указанием количества символов и строк
pinMode(FQ_UD, OUTPUT);
pinMode(W_CLK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(RESET, OUTPUT);
pulseHigh(RESET);
// Отправка импульсов для запуска модуля генератора
pulseHigh(W_CLK);
pulseHigh(FQ_UD);
}
//----------------------------------------------------
void
loop
()
{
lcd.setCursor(0,0);
// Далее вывод текущего значения частоты
lcd.print(
"Freq: "
);
lcd.setCursor(6,0);
lcd.print(
" "
);
lcd.setCursor(6,0);
if
(freq<1000){lcd.print(freq);
lcd.print(
"Hz"
);}
if
((freq>=1000)&&(freq<1000000)){lcd.print(freq / 1000);
lcd.print(
"kHz"
);}
if
((freq>=1000000)&&(freq<50000000)){lcd.print(freq / 1000000);
lcd.print(
"MHz"
);}
lcd.setCursor(0,1);
lcd.print(
" Genie v1.0"
);
if
(freq<100){bigStep = 10;
// Определение шага грубой и точной
littleStep = 1;}
// настройки в зависимости от частоты
if
((freq>=100)&&(freq<1000)){bigStep = 100;
littleStep = 1;}
if
((freq>=1000)&&(freq<10000)){bigStep = 1000;
littleStep = 10;}
if
((freq>=10000)&&(freq<100000)){bigStep = 10000;
littleStep = 100;}
if
((freq>=100000)&&(freq<1000000)){bigStep = 100000;
littleStep = 1000;}
if
((freq>=1000000)&&(freq<10000000)){bigStep = 1000000;
littleStep = 10000;}
if
((freq>=10000000)&&(freq<40000000)){bigStep = 10000000;
littleStep = 100000;}
lcd_key = read_LCD_buttons();
// Считывание клавиш
switch
(lcd_key)
// Далее обработка нажатий клавиш
{
case
btnRIGHT:
{freq += littleStep;
break
;}
case
btnLEFT:
{freq -= littleStep;
break
;}
case
btnUP:
{freq += bigStep;
break
;}
case
btnDOWN:
{
if
(freq == bigStep){freq -= (bigStep/10);}
else
{freq -= bigStep;}
break
;}
case
btnSELECT:
{
break
;}
case
btnNONE:
{
break
;}
}
if
(freq<1) freq=1;
// Ограничение значений частоты
if
(freq>40000000) freq=40000000;
sendFrequency(freq);
// Вызов функции отправки частоты
delay (200);
// Пауза 200 мс
}
2.Получаем сообщение "Done uploading." = значит все сделано правильно и приступаем к соединению модулей.
На ножки Arduino Uno втыкаем в DFRobot LCD Keypad Shield.
Затем HC-RS08 AD9850 DDS подключить с помощью проводников по следующей схеме:
Выводы Arduino Uno соединяем с штырьками HC-RS08 AD9850 DDS
+5V → VCC
GND → GND
A1 → W_CLK
A2 → FU_UD
A3 → DATA
A4 → RESET
Выходной сигнал снимаем с pin модуля HC-RS08 AD9850 DDS:
QOUT1, QOUT2 =прямоугольный сигнал
ZOUT1 и ZOUT2 =синусоидальный
2. Подаем питание. Через несколько секунд появляется значение частоты по умолчанию- 10 кГц. Его можно изменить нажатиями кнопок вверх/вниз и вправо/влево.
Все пользуем.
Добрый вечер всем. Может кому пригодится. Частота задается через COM порт.
01
float
freq = 0;
02
long
com=0;
// Оглашение переменных -- Частота
03
#define W_CLK 15 // Пин A1 Arduino - подключен к CLK
04
#define FQ_UD 16 // Пин A2 Arduino - подключен к FQ (FU)
05
#define DATA 17 // Пин A3 Arduino - подключен к DATA
06
#define RESET 18 // Пин A4 Arduino - подключен к RST
07
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
08
//-------------------------------------------------------
09
void
tfr_byte(
byte
data){
// Функция побитной отправки байта
10
for
(
int
i=0; i<8; i++, data>>=1) {
// данных в модуль генератора
11
digitalWrite(DATA, data & 0x01);
12
pulseHigh(W_CLK);}}
// Подача импульса на CLK после каждого бита
13
//-------------------------------------------------------
14
void
sendFrequency(
double
frequency) {
// Преобразование и отправка
15
int32_t freq = frequency * 4294967295/125000000;
// значения частоты
16
for
(
int
b=0; b<4; b++, freq>>=8) {tfr_byte(freq & 0xFF);}
17
tfr_byte(0x000);
// Отправка завершательного контрольного байта
18
pulseHigh(FQ_UD);}
// Обновление частоты генератора
19
//----------------------------------------------------
20
void
setup
()
21
{
22
Serial
.begin(9600);
23
pinMode(FQ_UD, OUTPUT);
24
pinMode(W_CLK, OUTPUT);
25
pinMode(DATA, OUTPUT);
26
pinMode(RESET, OUTPUT);
27
}
28
//----------------------------------------------------
29
void
loop
()
30
{
31
if
(
Serial
.available()>0) {
//если данные пришли
32
com=
Serial
.parseInt();
33
freq=com;
34
if
(freq<0) freq=0;
// Ограничение значений частоты
35
if
(freq>40000000) freq=40000000;
36
pulseHigh(RESET);
// Отправка импульсов для запуска модуля генератора
37
pulseHigh(W_CLK);
38
pulseHigh(FQ_UD);
39
sendFrequency(freq);
// Вызов функции отправки частоты
40
Serial
.println(freq);
41
}
42
}
Для получения квадратных импульсов с выводов QOUT1 и 2 плату нужно настроить !!! На плате есть переменный резистор R13 (большая синяя фигня на плате с пазами под крестовую отвертку). Подключаем плату к Ардуино, выставляем любую частоту, подключаем QOUT1 и GRN к осцилографу и крутим резистор до появления сигнала. Пришло из Китая 10 плат, ни одна не настоена ! С начала думал брак...
Для получения квадратных импульсов с выводов QOUT1 и 2 плату нужно настроить !!! На плате есть переменный резистор R13 (большая синяя фигня на плате с пазами под крестовую отвертку). Подключаем плату к Ардуино, выставляем любую частоту, подключаем QOUT1 и GRN к осцилографу и крутим резистор до появления сигнала. Пришло из Китая 10 плат, ни одна не настоена ! С начала думал брак...
Фиг его знает, я его уже во все стороны как только не крутил... меандра так и не добился.
Синус нормальный.
Может кто помочь ?
встроил в код генератора вольтметр.
делаю измерения пока постоянного напряжения по входа А1 от 0-5в
почему то показания вольтметра скачат, при том. если я выбираю диапазон от 0-100кгц они пляшут , если от 100кгц до 10мгц они стоят ровно.
такое ощущение что работу ацп кто то сбивает, и оно не успевает считать.
как победить эту проблему не могу.
001
#include <Rotary.h>
002
003
004
/*
005
Main code by Igor Krepsky - <a href="http://www.frompinskto.wordpress.com" title="www.frompinskto.wordpress.com" rel="nofollow">www.frompinskto.wordpress.com</a>
006
based on fragments of code by Richard Visokey AD7C - <a href="http://www.ad7c.com" title="www.ad7c.com" rel="nofollow">www.ad7c.com</a>
007
Rev. 2.2 - Spt., 2016 for AD9851 chip.
008
*/
009
// Подключение библиотек
010
#include <LiquidCrystal.h>
011
#include <rotary.h>
012
013
014
//Определения
015
#define W_CLK A2 // A2 - connect to AD9851 module word load clock pin (CLK)
016
#define FQ_UD A3 // A3 - connect to freq update pin (FQ)
017
#define DATA A4 // A4 - connect to serial data load pin (DATA)
018
#define RESET A5 // A5 - connect to reset pin (RST)
019
#define ENC_A 2 // Pin 2 - 1 канал валкодера
020
#define ENC_B 3 // Pin 3 - 2 канал валкодера
021
#define ENC_KEY 4 // Pin 4 - кнопка валкодера
022
#define MODE_1 0 // Pin 0 - переключатель mode vfo
023
#define MODE_2 1 // Pin 1 - переключатель mode sweep
024
#define KEY_1 5 // Pin 5 - доп. кнопка
025
const
int
analogInPin = A1;
// Analog input pin
026
027
float
outputValue = A1;
028
029
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
030
031
Rotary r = Rotary(2,3);
// Устанавливает пины для каналов энкодера. Должны поддерживать прерывания.
032
033
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
// ПРИСВОЕНИЕ ДЛЯ LCD (RS_E_4_5_6_7)R/W=gnd
034
035
// Переменные
036
int_fast32_t rx=0000000;
// Стартовая частота VFO
037
int_fast32_t rif=0;
// Значение IF
038
int_fast32_t wif=450000;
// рабочее значение IF
039
int_fast32_t rx2=1;
// переменная для сохранения обновлённой частоты
040
int_fast32_t increment = 1;
// начальный VFO инкремент в HZ.
041
int_fast32_t delta=1000;
// Стартовая величина ширины качания sweep в Hz
042
int_fast32_t sstep=1;
// Стартовая величина шага качания sweep в Hz
043
int
buttonstate = 0;
// Переменная для чтения состояния кнопки
044
String hertz =
"1 Hz"
;
045
int
hertzPosition = 0;
046
byte
ones,tens,hundreds,thousands,tenthousands,hundredthousands,millions ;
//Разряды для частоты
047
byte
a_1, a_2;
// разряды для отображения IF
048
String freq;
// string для получения частоты
049
boolean mod_1;
// текущее значение переключателя mode vfo
050
boolean mod_1_old;
// сохранённое значение переключателя mode vfo
051
boolean mod_2;
// текущее значение переключателя mode sweep
052
boolean mod_2_old;
// сохранённое значение переключателя mode sweep
053
054
void
setup
() {
055
// put your setup code here, to run once:
056
pinMode(ENC_KEY,INPUT);
// кнопка валкодера, 0 при нажатии
057
digitalWrite(ENC_KEY,HIGH);
058
lcd.begin(16, 2);
059
pinMode(ENC_A, INPUT);
060
pinMode(ENC_B, INPUT);
061
pinMode(MODE_1, INPUT);
062
pinMode(MODE_2, INPUT);
063
PCICR |= (1 << PCIE2);
064
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
065
sei();
066
pinMode(FQ_UD, OUTPUT);
067
pinMode(W_CLK, OUTPUT);
068
pinMode(DATA, OUTPUT);
069
pinMode(RESET, OUTPUT);
070
pulseHigh(RESET);
071
pulseHigh(W_CLK);
072
pulseHigh(FQ_UD);
// this pulse enables serial mode on the AD9851 - see datasheet
073
lcd.setCursor(hertzPosition,1);
074
lcd.print(hertz);
075
}
// END SETUP
076
077
void
loop
() {
078
079
outputValue =
float
(analogRead(analogInPin)) / 204.6;
//вольтметр
080
lcd.setCursor(6, 1);
081
lcd.print(
" Vout= "
);
082
lcd.setCursor(6, 1);
083
lcd.print(
" Vout="
);
084
int
mv = outputValue * 1000;
085
if
(mv<1000)
086
{
087
lcd.print(mv);
088
}
089
else
090
{
091
lcd.print(outputValue);
092
lcd.print(
" "
);
093
}
094
095
delay(100);
096
097
// ИЗМЕНЕНИЕ ИНКРЕМЕНТА (кнопка валкодера)
098
buttonstate = digitalRead(ENC_KEY);
// если нажатие кнопки валкодера - изменить инкремент
099
if
(buttonstate == LOW) {
100
setincrement();
101
}
102
// ВОЗВРАТ ШАГА ИЗМЕНЕНИЯ ЧАСТОТЫ к 1КГЦ в РЕЖИМЕ ГЕНЕРАТОРА
103
if
((mod_1 == 1)&&(mod_2 == 1)){
104
buttonstate = digitalRead(KEY_1);
105
if
(buttonstate == LOW){increment = 1; hertz=
"1Hz"
; hertzPosition=0;
106
lcd.setCursor(hertzPosition,1);
107
lcd.print(
" "
);
108
lcd.setCursor(hertzPosition,1);
109
lcd.print(hertz);
110
delay(250);
// Adjust this delay to speed up/slow down the button menu scroll speed.
111
}
112
}
113
// ПЕРЕКЛЮЧАТЕЛЬ MODE
114
mod_1 = digitalRead (MODE_1);
// чтение значения переключателя mode vfo.
115
mod_2 = digitalRead (MODE_2);
// чтение значения переключателя mode sweep.
116
117
// ДЕЙСТВИЯ ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE
118
if
((mod_1 != mod_1_old)||(mod_2 != mod_2_old)){
// если произошло переключение mode
119
// и вывод на дисплей
120
121
// 1.очистка
122
123
lcd.setCursor(0,1);
124
lcd.print(
" "
);
125
126
// 2.вывод значения
127
128
if
((mod_1 == 1)&&(mod_2 == 0)){
// если режим генератора
129
rif=0;
130
lcd.setCursor(hertzPosition,1);
131
lcd.print(hertz);
132
}
133
134
135
if
((mod_1 == 0)&&(mod_2 == 1)){
// если режим SWEEP
136
rif=0;
137
lcd.setCursor(hertzPosition,1);
138
lcd.print(hertz);
139
if
(delta < 10000){
140
lcd.setCursor(5,1);
141
lcd.print(
" SWP:"
);
142
lcd.print(delta/1000);
143
lcd.print(
"KHz "
);
144
}
145
else
if
(delta >= 100000){
146
lcd.setCursor(5,1);
147
lcd.print(
"SWP:"
);
148
lcd.print(delta/1000);
149
lcd.print(
"KHz "
);
150
}
151
else
152
{
153
lcd.setCursor(5,1);
154
lcd.print(
" SWP:"
);
155
lcd.print(delta/1000);
156
lcd.print(
"KHz "
);
157
}
158
}
159
160
// ВЫВОД НА ДИСПЛЕЙ ЧАСТОТЫ И ПЕРЕДАЧА ЕЁ В DDS ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE
161
showFreq();
162
sendFrequency(rx+rif);
163
rx2 = rx;
164
mod_1_old = mod_1;
165
mod_2_old = mod_2;
166
}
167
// ОКОНЧАНИЕ ДЕЙСТВИЯ ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE
168
169
// ВЫЧИСЛЕНИЕ ЧАСТОТЫ ДЛЯ РЕЖИМА SWEEP
170
if
((mod_1 == 0)&&(mod_2 == 1)){
171
rif = rif + sstep;
172
if
(rif > delta) {rif = 0;}
173
sendFrequency(rx+rif);
// отправить частоту в синтезатор
174
// переключение delta
175
buttonstate = digitalRead(KEY_1);
176
if
(buttonstate == LOW) {
177
if
(delta == 1000){delta = 5000;}
178
else
if
(delta == 5000){delta = 10000; sstep = 2;}
179
else
if
(delta == 10000){delta = 50000; sstep = 5;}
180
else
if
(delta == 50000){delta = 100000; sstep = 10;}
181
else
{delta = 1000; sstep = 1;}
182
if
(delta < 10000){
183
lcd.setCursor(5,1);
184
lcd.print(
" SWP:"
);
185
lcd.print(delta/1000);
186
lcd.print(
"kHz "
);
187
}
188
else
if
(delta == 100000){
189
lcd.setCursor(5,1);
190
lcd.print(
"SWP:"
);
191
lcd.print(delta/1000);
192
lcd.print(
"kHz "
);
193
}
194
else
195
{
196
lcd.setCursor(5,1);
197
lcd.print(
" SWP:"
);
198
lcd.print(delta/1000);
199
lcd.print(
"kHz "
);
200
}
201
// delay(500);
202
}
203
}
204
// ВЫЧИСЛЕНИЕ ЧАСТОТЫ ДЛЯ РЕЖИМА УЧЁТА ПРОМЕЖУТОЧНОЙ ЧАСТОТЫ
205
if
((mod_1 == 1)&&(mod_2 == 0)){
206
rif = wif;
207
208
209
buttonstate = digitalRead(KEY_1);
210
if
(buttonstate == LOW);
// read the analog in value:
211
212
213
}
214
215
// ВЫВОД НА ДИСПЛЕЙ ЧАСТОТЫ И ПЕРЕДАЧА ЕЁ В DDS В ОБЩЕМ СЛУЧАЕ
216
217
if
(rx != rx2)
218
{
219
showFreq();
// при изменении частоты вывести на дисплей
220
sendFrequency(rx+rif);
// отправить частоту в синтезатор
221
rx2 = rx;
222
}
223
224
}
// END LOOP
225
226
// ПОДПРОГРАММЫ
227
// Обработка прерывания
228
ISR(PCINT2_vect) {
229
230
// обработка энкодера
231
unsigned
char
result = r.process();
232
if
(result) {
233
if
(result == DIR_CW){rx=rx+increment;}
234
else
{rx=rx-increment;};
235
// конец обработки валкодера
236
if
((rx+rif) >40000000){rx=(40000000-rif);};
// ВЕРХНИЙ VFO LIMIT
237
if
(rx <1){rx=0;};
// НИЖНИЙ VFO LIMIT
238
}
239
}
240
241
242
// расчёт частоты на основе докумментации на микросхему = <sys clock> * <frequency tuning word>/2^32
243
void
sendFrequency(
double
frequency) {
244
int32_t freq = frequency * 4294967296./125000997;
// note 180 MHz clock on 9851. если генератор на 125мгц, то вписать . тут же можно и подогнать частоту генератора
245
for
(
int
b=0; b<4; b++, freq>>=8)
246
{
247
tfr_byte(freq & 0xFF);
248
}
249
tfr_byte(0x000);
// Final control byte, LSB 1 to enable 6 x xtal multiplier on 9851 set to 0x000 for 9850
250
pulseHigh(FQ_UD);
// Сделано! Должен увидеть выход.
251
}
252
253
// передаёт байт, по биту за раз, начиная с LSB на 9851 через serial DATA line
254
void
tfr_byte(
byte
data)
255
{
256
for
(
int
i=0; i<8; i++, data>>=1) {
257
digitalWrite(DATA, data & 0x01);
258
pulseHigh(W_CLK);
//после передачи каждого бита, CLK is pulsed high
259
}
260
}
261
262
void
setincrement(){
// установка значения инкремента частоты
263
if
(increment == 1){increment = 10; hertz =
"10Hz"
; hertzPosition=0;}
264
else
if
(increment == 10){increment = 100; hertz =
"100Hz"
; hertzPosition=0;}
265
else
if
(increment == 100){increment = 1000; hertz=
"1Khz"
; hertzPosition=0;}
266
else
if
(increment == 1000){increment = 10000; hertz=
"10Khz"
; hertzPosition=0;}
267
else
if
(increment == 10000){increment = 100000; hertz=
"100Khz"
; hertzPosition=0;}
268
else
if
(increment == 100000){increment = 1000000; hertz=
"1Mhz"
; hertzPosition=0;}
269
else
if
(increment == 1000000){increment = 10000000; hertz=
"10Mhz"
; hertzPosition=0;}
270
else
{increment = 1; hertz =
"1Hz"
; hertzPosition=0;};
271
lcd.setCursor(hertzPosition,1);
272
lcd.print(
" "
);
273
lcd.setCursor(hertzPosition,1);
274
lcd.print(hertz);
275
delay(100);
// Adjust this delay to speed up/slow down the button menu scroll speed.
276
};
277
278
void
showFreq(){
// вывод значения частоты на дисплей
279
millions =
int
(rx/1000000);
280
hundredthousands = ((rx/100000)%10);
281
tenthousands = ((rx/10000)%10);
282
thousands = ((rx/1000)%10);
283
hundreds = ((rx/100)%10);
284
tens = ((rx/10)%10);
285
ones = ((rx/1)%10);
286
lcd.setCursor(0,0);
287
lcd.print(
" "
);
288
if
(millions > 9){lcd.setCursor(2,0);}
289
else
{lcd.setCursor(2,0);}
290
lcd.print(millions);
291
lcd.print(
"."
);
292
lcd.print(hundredthousands);
293
lcd.print(tenthousands);
294
lcd.print(thousands);
295
lcd.print(
"."
);
296
lcd.print(hundreds);
297
lcd.print(tens);
298
lcd.print(ones);
299
lcd.print(
" Hz "
);
300
301
};