I2C NavKey + AD9850

дааа, когда код не встает это проблема….
а версия esp >3 чистое зло!

в ЧЧ?

Дык и дипломы ж красные не у всех :frowning:

Разве?! :roll_eyes: Ведь очень полезная тема, и скейтч,и стаканчики. Правда за библиотекой надо к производителю, а в библиотеке уже есть пример для проверки, но кто мы такие, что-бы судить. А лишний круг никому не помешал. Всё для здоровья.

я просто предложил
Я вообще без понятия, почему вдруг ТС-у пришло в голову загрузить сюда этот код, который, к тому же, не его.

Жалко их, конечно, но это был их выбор
:frowning:

обманули все таки вы… этот код не от этой библиотеки, не подходит!
https://github.com/DuPPadotnet/I2CNavKey
на форуме мошенник! дает кода не от той библиотеки..

нет, я изголодался по свежим кодам, скачиваю библиотеку по ссылке, а там я даже не вижу файлы .h .cpp ладно допустим я могу их там в какой то папке найти и перенести, но а дальше то что ? код не соберется…
или кто то подправил ваше сообщение, или вы что то не то опубликовали))))

и главное что бы в ардуино идэ работало)))

может вот так надо было #include <i2cEncoderMiniLib.h> а может еще как… что то не сходится)))

сюда щёлкнуть не пробовал?


ну ктож знал что на странице надо еще читать, а не методом тыка искать….
поторопился чуть чуть))) извините)))
а для версии ядра 2.0.17 esp32 что делать ?! вопрос наверное риторический)))

Бесплатно не буду. Хотите, чтобы отрицал, давайте договариваться о стоимости этой услуги.

#include <Wire.h>
#include <i2cNavKey.h>
#include <Ticker.h>
#include "AD985X.h"

#ifndef ESP32
#error ESP32 only example, please select appropriate board
#endif

// ========== Настройка AD9850 ==========
uint8_t AD_RST = 9;
uint8_t AD_FQUDP = 10;
uint8_t AD_DATA = 11;
uint8_t AD_CLK = 13;
AD9850 freqGen(AD_RST, AD_FQUDP, AD_DATA, AD_CLK);

uint32_t rife_freq = 1100000;
uint32_t rife_prev = 0;
uint32_t rife_maxFreq;

// ========== Таймер для NavKey ==========
Ticker tNavkey;

// ========== ШИМ для модулятора (меандр) ==========
const int pwmPin = 15;
const int pwmChannel = 0;      // Канал LEDC (0-15)
volatile int freq = 1000;      // Частота 1 кГц
const int resolution = 10;     // Разрешение 10 бит (0-1023)
volatile int fcounter = 0;
volatile int fcounter_old = 0;
volatile bool fflag = true;    // true - модуляция, false - несущая
volatile bool fmflag = false;

// ========== Настройка пинов I2C ==========
const int SDA_PIN = 1;
const int SCL_PIN = 3;
const int INT_PIN = 4;

// ========== НАСТРОЙКА PDM (старое ядро 2.x) ==========
#include <driver/i2s.h>

#define I2S_BCLK_PIN 17    // PDM CLK
#define I2S_DOUT_PIN 18    // PDM DATA
#define SAMPLE_RATE 48000
#define BUFFER_SIZE 1024

int16_t pcm_buffer[BUFFER_SIZE];

// ========== Объект NavKey ==========
i2cNavKey navkey(0x10);
volatile bool eventFlag = false;

// ========== Прототипы функций ==========
void fill_sine_buffer(int16_t* buffer, int samples, float freq_hz, int sample_rate);
void initPDM();
void tnav();
void IRAM_ATTR navkeyISR();
void help();

// ========== Callbacks NavKey ==========
void UP_Button_Pressed(i2cNavKey* p) {
Serial.println("ВВЕРХ нажата");
}

void DOWN_Button_Pressed(i2cNavKey* p) {
Serial.println("ВНИЗ нажата");
}

void LEFT_Button_Pressed(i2cNavKey* p) {
Serial.println("ВЛЕВО нажата - переключено на модуляцию");
fflag = true;
}

void RIGHT_Button_Pressed(i2cNavKey* p) {
Serial.println("ВПРАВО нажата - переключено на несущую");
fflag = false;
}

void CENTRAL_Button_Pressed(i2cNavKey* p) {
Serial.println("ЦЕНТР нажата");
}

void CENTRAL_Button_Double(i2cNavKey* p) {
Serial.println("Двойное нажатие ЦЕНТР!");
}

void Encoder_Rotate(i2cNavKey* p) {
Serial.printf("Значение энкодера: %d\n", p->readCounterInt());

if (fflag) {
// Меняем частоту модуляции (шаг 10 Гц)
fcounter = p->readCounterInt();
if (fcounter > fcounter_old) {
freq += 10;
if (freq > 20000) freq = 20000;
fcounter_old = fcounter;
fmflag = true;
// В старом ядре меняем частоту через перенастройку канала
ledcSetup(pwmChannel, freq, resolution);
ledcWrite(pwmChannel, 512);
}
if (fcounter < fcounter_old) {
freq -= 10;
if (freq < 10) freq = 10;
fcounter_old = fcounter;
fmflag = true;
ledcSetup(pwmChannel, freq, resolution);
ledcWrite(pwmChannel, 512);
}
} else {
// Меняем несущую частоту AD9850 (шаг 1000 Гц)
fcounter = p->readCounterInt();
if (fcounter > fcounter_old) {
rife_freq += 1000;
if (rife_freq > rife_maxFreq && rife_maxFreq > 0) rife_freq = rife_maxFreq;
rife_prev = rife_freq;
fcounter_old = fcounter;
freqGen.setFrequency(rife_freq);
Serial.printf("Несущая частота: %lu Гц\n", rife_freq);
}
if (fcounter < fcounter_old) {
if (rife_freq >= 1000) rife_freq -= 1000;
rife_prev = rife_freq;
fcounter_old = fcounter;
freqGen.setFrequency(rife_freq);
Serial.printf("Несущая частота: %lu Гц\n", rife_freq);
}
}
}

// ========== Заполнение буфера синусом ==========
void fill_sine_buffer(int16_t* buffer, int samples, float freq_hz, int sample_rate) {
for (int i = 0; i < samples; i++) {
float phase = 2.0f * 3.14159265f * freq_hz * i / sample_rate;
buffer[i] = (int16_t)(32767.0f * sin(phase));
}
}

// ========== Инициализация PDM для старого ядра ==========
void initPDM() {
// Конфигурация I2S в режиме PDM
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_PDM),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 256,
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = 0
};

// Конфигурация пинов I2S
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_PIN_NO_CHANGE,
.ws_io_num = I2S_BCLK_PIN,
.data_out_num = I2S_DOUT_PIN,
.data_in_num = I2S_PIN_NO_CHANGE
};

// Установка конфигурации
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &pin_config);
i2s_set_clk(I2S_NUM_0, SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);

Serial.println("PDM инициализирован (старое ядро)");
}

// ========== Обработчик прерывания NavKey ==========
void IRAM_ATTR navkeyISR() {
eventFlag = true;
}

void tnav() {
if (eventFlag) {
eventFlag = false;
navkey.updateStatus();
}
}

// ========== Справка ==========
void help() {
Serial.println();
Serial.println("===== УПРАВЛЕНИЕ =====");
Serial.println("+ :  увеличить несущую на 1 Гц");
Serial.println("- :  уменьшить несущую на 1 Гц");
Serial.println("* :  умножить несущую на 10");
Serial.println("/ :  разделить несущую на 10");
Serial.println("? :  показать справку");
Serial.println("R :  AD9850 reset");
Serial.println("P :  AD9850 power down");
Serial.println("U :  AD9850 power up");
Serial.println("=========================");
Serial.println("Кнопки NavKey:");
Serial.println("  ВЛЕВО  - энкодер управляет частотой МОДУЛЯЦИИ");
Serial.println("  ВПРАВО - энкодер управляет НЕСУЩЕЙ частотой");
Serial.println("=========================");
}

// ========== SETUP ==========
void setup(void) {
Serial.begin(115200);
delay(1000);
Serial.println("\n\n=== ЗАПУСК СИСТЕМЫ ===\n");

// ========== Инициализация I2C для NavKey ==========
Wire.begin(SDA_PIN, SCL_PIN);
pinMode(INT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(INT_PIN), navkeyISR, FALLING);

Serial.println("Инициализация I2C NavKey...");

navkey.reset();
navkey.begin(i2cNavKey::INT_DATA | i2cNavKey::WRAP_ENABLE | i2cNavKey::DIRE_RIGHT | i2cNavKey::IPUP_ENABLE);
navkey.writeCounter((int32_t)0);
navkey.writeMax((int32_t)256);
navkey.writeMin((int32_t)-256);
navkey.writeStep((int32_t)1);
navkey.writeDoublePushPeriod(50);

navkey.onUpPush = UP_Button_Pressed;
navkey.onDownPush = DOWN_Button_Pressed;
navkey.onRightPush = RIGHT_Button_Pressed;
navkey.onLeftPush = LEFT_Button_Pressed;
navkey.onCentralPush = CENTRAL_Button_Pressed;
navkey.onCentralDoublePush = CENTRAL_Button_Double;
navkey.onChange = Encoder_Rotate;

navkey.autoconfigInterrupt();

Serial.print("ID CODE: 0x");
Serial.println(navkey.readIDCode(), HEX);

tNavkey.attach(0.005, tnav);

// ========== Инициализация ШИМ (меандр) для старого ядра ==========
ledcSetup(pwmChannel, freq, resolution);
ledcAttachPin(pwmPin, pwmChannel);
ledcWrite(pwmChannel, 512);
Serial.println("PWM (меандр) на пине 15 включен");

// ========== Инициализация AD9850 ==========
Serial.println("Инициализация AD9850...");
freqGen.begin();
freqGen.powerUp();
rife_maxFreq = freqGen.getMaxFrequency();
Serial.printf("Максимальная частота AD9850: %lu Гц\n", rife_maxFreq);
freqGen.setFrequency(rife_freq);
Serial.printf("Несущая частота: %lu Гц\n", rife_freq);

help();

// ========== Инициализация PDM ==========
initPDM();

// Заполняем буфер синусом 1000 Гц
fill_sine_buffer(pcm_buffer, BUFFER_SIZE, (float)freq, SAMPLE_RATE);
Serial.println("PDM генерация синуса запущена");

Serial.println("\n=== СИСТЕМА ГОТОВА ===\n");
}

// ========== LOOP ==========
void loop() {
// ========== Обработка команд из Serial ==========
if (Serial.available() > 0) {
int c = Serial.read();
switch (c) {
case '?':
help();
break;
case 'R':
freqGen.reset();
rife_freq = 1100000;
freqGen.setFrequency(rife_freq);
Serial.println("AD9850 сброшен");
break;
case 'P':
freqGen.powerDown();
Serial.println("AD9850 выключен (power down)");
break;
case 'U':
freqGen.powerUp();
freqGen.setFrequency(rife_freq);
Serial.println("AD9850 включен (power up)");
break;
case '+':
rife_freq += 1;
break;
case '-':
if (rife_freq > 0) rife_freq -= 1;
break;
case '*':
rife_freq *= 10;
break;
case '/':
rife_freq /= 10;
break;
}
if (rife_freq > rife_maxFreq && rife_maxFreq > 0) rife_freq = rife_maxFreq;
if (rife_freq < 0) rife_freq = 0;
}
// ========== Обновление частоты AD9850 ==========
if (rife_prev != rife_freq) {
rife_prev = rife_freq;
freqGen.setFrequency(rife_freq);
Serial.printf("Несущая частота: %lu Гц\n", rife_freq);
}
// ========== Отправка данных через PDM ==========
size_t bytes_written;
i2s_write(I2S_NUM_0, pcm_buffer, BUFFER_SIZE * sizeof(int16_t), &bytes_written, portMAX_DELAY);
// ========== Обновление буфера при изменении частоты модуляции ==========
if (fmflag) {
fmflag = false;
fill_sine_buffer(pcm_buffer, BUFFER_SIZE, (float)freq, SAMPLE_RATE);
Serial.printf("Частота модуляции изменена: %d Гц\n", freq);
}
}

не знаю будет ли работать))) если не лень проверьте

ты с кем только не знаком… мы наслышаны…

какая интересная тема получилась, нужная))
а главное удалось “срочно проверить”, что с нашим визави все в порядке, а то я начал беспокоится из за его долгово отсутствия на форуме, и он в своем репертуаре.

deepseek всё знает

IDE 1.8.19, ядро 2.0.14

Работает!
Синусоида - идеальная, размах при изменении частоты от 40 герц до 11 килогерц уменьшается с 2 вольт до 1

PS выжать из ядра 3.x.x сигнал аналогичный формируемому под ядром 2.0.14 (то-есть идеальную синусоиду), невозможно,
это был баг, разработчики его исправили

ну тогда наверное точно тему можно перенести в проекты))) я даже вроде видел кому то нужен был генератор частот на этом форуме….

BABOS, ты такой продвинутый. Вот бы ещё под спойлер научился свою писанину размещать - цены б тебе не было бы.
О форматировании я молчу - это клиника.

Не просто в проекты, а анаалы, ведь микросхема созданная для генерации синуса может выдавать синус!

А у меня все его сообщения под спойлером - очень удобно. Когда хочу - открываю, все остальное время место не занимают, глаза не мозолят…