DDS AD9850
- Войдите на сайт для отправки комментариев
Пт, 10/02/2017 - 22:11
Может кто помочь ?
встроил в код генератора вольтметр.
делаю измерения пока постоянного напряжения по входа А1 от 0-5в
почему то показания вольтметра скачат, при том. если я выбираю диапазон от 0-100кгц они пляшут , если от 100кгц до 10мгц они стоят ровно.
такое ощущение что работу ацп кто то сбивает, и оно не успевает считать.
как победить эту проблему не могу.
#include <Rotary.h> /* Main code by Igor Krepsky - <a href="http://www.frompinskto.wordpress.com" title="www.frompinskto.wordpress.com" rel="nofollow">www.frompinskto.wordpress.com</a> 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> Rev. 2.2 - Spt., 2016 for AD9851 chip. */ // Подключение библиотек #include <LiquidCrystal.h> #include <rotary.h> //Определения #define W_CLK A2 // A2 - connect to AD9851 module word load clock pin (CLK) #define FQ_UD A3 // A3 - connect to freq update pin (FQ) #define DATA A4 // A4 - connect to serial data load pin (DATA) #define RESET A5 // A5 - connect to reset pin (RST) #define ENC_A 2 // Pin 2 - 1 канал валкодера #define ENC_B 3 // Pin 3 - 2 канал валкодера #define ENC_KEY 4 // Pin 4 - кнопка валкодера #define MODE_1 0 // Pin 0 - переключатель mode vfo #define MODE_2 1 // Pin 1 - переключатель mode sweep #define KEY_1 5 // Pin 5 - доп. кнопка const int analogInPin = A1; // Analog input pin float outputValue = A1; #define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); } Rotary r = Rotary(2,3); // Устанавливает пины для каналов энкодера. Должны поддерживать прерывания. LiquidCrystal lcd(8, 9, 10, 11, 12, 13); // ПРИСВОЕНИЕ ДЛЯ LCD (RS_E_4_5_6_7)R/W=gnd // Переменные int_fast32_t rx=0000000; // Стартовая частота VFO int_fast32_t rif=0; // Значение IF int_fast32_t wif=450000; // рабочее значение IF int_fast32_t rx2=1; // переменная для сохранения обновлённой частоты int_fast32_t increment = 1; // начальный VFO инкремент в HZ. int_fast32_t delta=1000; // Стартовая величина ширины качания sweep в Hz int_fast32_t sstep=1; // Стартовая величина шага качания sweep в Hz int buttonstate = 0; // Переменная для чтения состояния кнопки String hertz = "1 Hz"; int hertzPosition = 0; byte ones,tens,hundreds,thousands,tenthousands,hundredthousands,millions ; //Разряды для частоты byte a_1, a_2; // разряды для отображения IF String freq; // string для получения частоты boolean mod_1; // текущее значение переключателя mode vfo boolean mod_1_old; // сохранённое значение переключателя mode vfo boolean mod_2; // текущее значение переключателя mode sweep boolean mod_2_old; // сохранённое значение переключателя mode sweep void setup() { // put your setup code here, to run once: pinMode(ENC_KEY,INPUT); // кнопка валкодера, 0 при нажатии digitalWrite(ENC_KEY,HIGH); lcd.begin(16, 2); pinMode(ENC_A, INPUT); pinMode(ENC_B, INPUT); pinMode(MODE_1, INPUT); pinMode(MODE_2, INPUT); PCICR |= (1 << PCIE2); PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); sei(); pinMode(FQ_UD, OUTPUT); pinMode(W_CLK, OUTPUT); pinMode(DATA, OUTPUT); pinMode(RESET, OUTPUT); pulseHigh(RESET); pulseHigh(W_CLK); pulseHigh(FQ_UD); // this pulse enables serial mode on the AD9851 - see datasheet lcd.setCursor(hertzPosition,1); lcd.print(hertz); }// END SETUP void loop() { outputValue = float(analogRead(analogInPin)) / 204.6; //вольтметр lcd.setCursor(6, 1); lcd.print(" Vout= "); lcd.setCursor(6, 1); lcd.print(" Vout="); int mv = outputValue * 1000; if(mv<1000) { lcd.print(mv); } else { lcd.print(outputValue); lcd.print(" "); } delay(100); // ИЗМЕНЕНИЕ ИНКРЕМЕНТА (кнопка валкодера) buttonstate = digitalRead(ENC_KEY); // если нажатие кнопки валкодера - изменить инкремент if(buttonstate == LOW) { setincrement(); } // ВОЗВРАТ ШАГА ИЗМЕНЕНИЯ ЧАСТОТЫ к 1КГЦ в РЕЖИМЕ ГЕНЕРАТОРА if ((mod_1 == 1)&&(mod_2 == 1)){ buttonstate = digitalRead(KEY_1); if (buttonstate == LOW){increment = 1; hertz="1Hz"; hertzPosition=0; lcd.setCursor(hertzPosition,1); lcd.print(" "); lcd.setCursor(hertzPosition,1); lcd.print(hertz); delay(250); // Adjust this delay to speed up/slow down the button menu scroll speed. } } // ПЕРЕКЛЮЧАТЕЛЬ MODE mod_1 = digitalRead (MODE_1); // чтение значения переключателя mode vfo. mod_2 = digitalRead (MODE_2); // чтение значения переключателя mode sweep. // ДЕЙСТВИЯ ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE if ((mod_1 != mod_1_old)||(mod_2 != mod_2_old)){// если произошло переключение mode // и вывод на дисплей // 1.очистка lcd.setCursor(0,1); lcd.print(" "); // 2.вывод значения if ((mod_1 == 1)&&(mod_2 == 0)){// если режим генератора rif=0; lcd.setCursor(hertzPosition,1); lcd.print(hertz); } if ((mod_1 == 0)&&(mod_2 == 1)){// если режим SWEEP rif=0; lcd.setCursor(hertzPosition,1); lcd.print(hertz); if (delta < 10000){ lcd.setCursor(5,1); lcd.print(" SWP:"); lcd.print(delta/1000); lcd.print("KHz "); } else if (delta >= 100000){ lcd.setCursor(5,1); lcd.print("SWP:"); lcd.print(delta/1000); lcd.print("KHz "); } else { lcd.setCursor(5,1); lcd.print(" SWP:"); lcd.print(delta/1000); lcd.print("KHz "); } } // ВЫВОД НА ДИСПЛЕЙ ЧАСТОТЫ И ПЕРЕДАЧА ЕЁ В DDS ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE showFreq(); sendFrequency(rx+rif); rx2 = rx; mod_1_old = mod_1; mod_2_old = mod_2; } // ОКОНЧАНИЕ ДЕЙСТВИЯ ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE // ВЫЧИСЛЕНИЕ ЧАСТОТЫ ДЛЯ РЕЖИМА SWEEP if ((mod_1 == 0)&&(mod_2 == 1)){ rif = rif + sstep; if (rif > delta) {rif = 0;} sendFrequency(rx+rif);// отправить частоту в синтезатор // переключение delta buttonstate = digitalRead(KEY_1); if (buttonstate == LOW) { if (delta == 1000){delta = 5000;} else if (delta == 5000){delta = 10000; sstep = 2;} else if (delta == 10000){delta = 50000; sstep = 5;} else if (delta == 50000){delta = 100000; sstep = 10;} else {delta = 1000; sstep = 1;} if (delta < 10000){ lcd.setCursor(5,1); lcd.print(" SWP:"); lcd.print(delta/1000); lcd.print("kHz "); } else if (delta == 100000){ lcd.setCursor(5,1); lcd.print("SWP:"); lcd.print(delta/1000); lcd.print("kHz "); } else { lcd.setCursor(5,1); lcd.print(" SWP:"); lcd.print(delta/1000); lcd.print("kHz "); } // delay(500); } } // ВЫЧИСЛЕНИЕ ЧАСТОТЫ ДЛЯ РЕЖИМА УЧЁТА ПРОМЕЖУТОЧНОЙ ЧАСТОТЫ if ((mod_1 == 1)&&(mod_2 == 0)){ rif = wif; buttonstate = digitalRead(KEY_1); if (buttonstate == LOW); // read the analog in value: } // ВЫВОД НА ДИСПЛЕЙ ЧАСТОТЫ И ПЕРЕДАЧА ЕЁ В DDS В ОБЩЕМ СЛУЧАЕ if (rx != rx2) { showFreq();// при изменении частоты вывести на дисплей sendFrequency(rx+rif);// отправить частоту в синтезатор rx2 = rx; } }// END LOOP // ПОДПРОГРАММЫ // Обработка прерывания ISR(PCINT2_vect) { // обработка энкодера unsigned char result = r.process(); if (result) { if (result == DIR_CW){rx=rx+increment;} else {rx=rx-increment;}; // конец обработки валкодера if ((rx+rif) >40000000){rx=(40000000-rif);}; // ВЕРХНИЙ VFO LIMIT if (rx <1){rx=0;}; // НИЖНИЙ VFO LIMIT } } // расчёт частоты на основе докумментации на микросхему = <sys clock> * <frequency tuning word>/2^32 void sendFrequency(double frequency) { int32_t freq = frequency * 4294967296./125000997; // note 180 MHz clock on 9851. если генератор на 125мгц, то вписать . тут же можно и подогнать частоту генератора for (int b=0; b<4; b++, freq>>=8) { tfr_byte(freq & 0xFF); } tfr_byte(0x000); // Final control byte, LSB 1 to enable 6 x xtal multiplier on 9851 set to 0x000 for 9850 pulseHigh(FQ_UD); // Сделано! Должен увидеть выход. } // передаёт байт, по биту за раз, начиная с LSB на 9851 через serial DATA line void tfr_byte(byte data) { for (int i=0; i<8; i++, data>>=1) { digitalWrite(DATA, data & 0x01); pulseHigh(W_CLK); //после передачи каждого бита, CLK is pulsed high } } void setincrement(){// установка значения инкремента частоты if(increment == 1){increment = 10; hertz = "10Hz"; hertzPosition=0;} else if(increment == 10){increment = 100; hertz = "100Hz"; hertzPosition=0;} else if (increment == 100){increment = 1000; hertz="1Khz"; hertzPosition=0;} else if (increment == 1000){increment = 10000; hertz="10Khz"; hertzPosition=0;} else if (increment == 10000){increment = 100000; hertz="100Khz"; hertzPosition=0;} else if (increment == 100000){increment = 1000000; hertz="1Mhz"; hertzPosition=0;} else if (increment == 1000000){increment = 10000000; hertz="10Mhz"; hertzPosition=0;} else{increment = 1; hertz = "1Hz"; hertzPosition=0;}; lcd.setCursor(hertzPosition,1); lcd.print(" "); lcd.setCursor(hertzPosition,1); lcd.print(hertz); delay(100); // Adjust this delay to speed up/slow down the button menu scroll speed. }; void showFreq(){// вывод значения частоты на дисплей millions = int(rx/1000000); hundredthousands = ((rx/100000)%10); tenthousands = ((rx/10000)%10); thousands = ((rx/1000)%10); hundreds = ((rx/100)%10); tens = ((rx/10)%10); ones = ((rx/1)%10); lcd.setCursor(0,0); lcd.print(" "); if (millions > 9){lcd.setCursor(2,0);} else{lcd.setCursor(2,0);} lcd.print(millions); lcd.print("."); lcd.print(hundredthousands); lcd.print(tenthousands); lcd.print(thousands); lcd.print("."); lcd.print(hundreds); lcd.print(tens); lcd.print(ones); lcd.print(" Hz "); };
http://i.imgur.com/W6eKF8J.jpg как идет считывание это 64гц частота
http://i.imgur.com/eJ5nTYG.jpg более стабильно , и полностью стабильно будет если выбрать частоту более или равно 100кгц.
измеряю постоянное напряжение ацп А1 в районе от 0-5в
в данном случае должно быть 498мВ
но как видно по первому скрину, то ацп не до считывает.
777Andrej, для измерения переменного тока существуют специальные алгоритмы, на форуме на эту тему неоднократно вели обсуждения, пользуйтесь поиском.
тут нет измерения переменного!
измеряется постоянное напряжение в пределах от 0 до 5в
для теста выбран предел просто 498мВ
просто пределы переключения частоты а их там
1гц
10гц
100гц
и тд
каким то образом влияют на счет ацп.
777Andrej, по скетчу не видно что вы измеряете, как это всё включено, итп. Очевидно наводки на вход идут -> аппаратный косяк.
хорошо , если я на вход А1 подам 5в
почему напряжение обрывается и считает
0,24в
0,59в
1,23
2,57
3,05
и снова
0,24в
0,59в
1,23
2,57
3,05
но до 5в никогда не дойдет!?
возможно обрыв счета ацп идет из за отправки частоты в синтезатор?
и вопрос, почему выше 100кгц если включен этот диапазон , то вольтметру хватает время на счет!?
Подробно ваш скетч не разбирал, но возможно все банально просто. Время измерения напряжения командой analogRead составляет 1/10000 секунды. А что произойдет если во время выполнения этого измерения будет вызвано прерывание? Которое в данной программе обрабатывается не с использованием стандартных библиотек типа TimerOne, а напрямую. Думаю из за этого процесс измерения может прерваться в любой момент и analogRead() выдаст некорректный результат.
Решение - или исправлять обработку прерывания так, чтобы она не мешала функции analogRead(). Или отказаться от использования analogRead() и делать измерения напрямую через регистры управления АЦП. Или заменить свой обработчик прерываний на стандарную библиотеку TimerOne или что-то аналогичное. Думаю что разработчики библиотеки позаботились о корректной работе её с analogRead().
Полностью с вами согласен! и тоже уверен в этом , что именно не хватает времени на измерение.
но вся проблема , я не очень так разбираюсь в этом пока, и сделать такие изменения я не смогу сам .