Há algumas semanas comecei a idealizar um gerador de sinais usando um modulo DDS AD9850 comprado a anos atrás, o qual não sabia se estava funcionado.
Com base em uma placa Arduino Uno R3, liguei o modulo DDS, fiz um Sketch básico seguindo o exemplo, e conectei uma das saídas no Osciloscópio. Feito o upload, uma forma de onda apareceu na tela do Osciloscópio, e mostrando a frequência programada.
Em seguida conectei um LCD 16x2 via o modulo LCD-I2C, e testei com o Sketch exemplo.
Inclui o LCD no código do gerador DDS.
Precisava de uma forma mais prática de entrar com a frequência do que via monitor serial, adicionei um teclado 3x4 de telefone. Código testado a parte e integrado ao do DDS.
Assim, construí um gerador de sinais rudimentar.
Para dar continuidade ao projeto, resolvi que usar a placa Arduino não seria muito prático, então comprei alguns Atmega328p, e programei o bootloader. Montando o mínimo necessário para o seu funcionamento.
Atualmente tenho tudo montando em um breadboard/protoboard, a intenção e passar para uma PCI.
Também foi adicionado rotinas para usar a eeprom para armazenar a frequência de calibração e a última frequência usada. Essa parte do eeprom me deixou confuso, já que, deveria armazenar 124998500, mas estava obtendo 124998496. Esse número estava declarado como double. Ficou correto após declarar como long.
E o código do Sketch atual e esse:
/*
* Sketch de um protopito de gerador de sinais usando o modulo AD9850
*
* Autor: Paulino Kenji Sato <pksato+arduino@gmail.com>
* Data: 22/07/2020
*
* Modulos usados:
* Chip Atmega328P com bootloader (Arduino Uno R3), comprado pelo mercado livre
* Modulo DDS AD9850 (comprado em site chines)
* Modulo LCD 16x2, reaproveitado.
* Modulo I2C para LCD, comprado no site Baú da Eletronica.
* Teclado 3x4, reaproveitado de um telefone sem fio antigo.
*
* Objetivos:
* Programar o DDS AD9850 para gerar uma frequencia qualquer.
* Ler a frequencia desejada digitado no teclado.
* Apresentar a frequencia no display LCD.
* Gravar e Ler os parametros na eeprom.
* Ler o pino A0/23 e conforme o estado, usar ou não a eeprom.
*
*/
#include <Wire.h>
#include <EEPROM.h>
#include <AD9850.h> // Instalado manualmente http://github.com/F4GOJ/AD9850
#include <LiquidCrystal_I2C.h> // Biblioteca do Arduino https://github.com/johnrickman/LiquidCrystal_I2C
#include <Keypad.h> // Biblioteca do Arduino https://playground.arduino.cc/Code/Keypad/
// IO Geral
const int GPIN_EEP_RW = A0; // Usa ou não os dados a eeprom, leitura e escrita, HIGH=usa, LOW=não usa.
// Eeprom OBS.: Uma struc simplicaria o endereçamento
const int EEP_SIGADDR = 0; // Endereço da assinatura para verificar se a eeprom contem a assinatura ZDDS
const int EEP_DDS_CALXTAL = 4; // Endereço do parametro DDS_CALXTAL
const int EEP_DDS_STARTFRQ = 8; // Endereço do parametro DDS_STARTFRQ
const long EEP_SIGNATURE = 0x5A444453; // Assinatura para validar a eeprom (ZDDS)
// Definições do DDS AD9850
const int DDS_WCLK = 10; // Pino de Clock
const int DDS_FQUD = 11; // Pino de Frequency update
const int DDS_DATA = 12; // Pino de Data
const int DDS_REST = 13; // Pino de Reset
const long DDS_NOCALXTAL = 125000000; // Frequencia nominal do cristal.
const long DDS_MAXFRQ = 40000000; // Frequencia máxima do AD9850
const int DDS_PHASE = 0; // Fase do DDS. Sempre Zero
long DDS_CALXTAL = 124998500; // Frequencia calibrada do cristal do DDS, armazenar na eeprom
long DDS_STARTFRQ = 10000000; // Frequencia inicial, armazenar na eeprom
// Definições do Teclado
const byte TLinhas = 4; // Quatro linhas
const byte TColunas = 3; // Trez Colunas
char teclas[TLinhas][TColunas] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte PinosLinhas[TLinhas] = {6, 5, 4, 3};
byte PinosColunas[TColunas] = {9, 8, 7};
Keypad teclado = Keypad( makeKeymap(teclas), PinosLinhas, PinosColunas, TLinhas, TColunas );
// Definições do LCD 16 Colunas e 2 Linhas
LiquidCrystal_I2C lcd(0x27,16,2);
// String da frequencia atual e da anterior.
String sFrequencia = "";
String aFrequencia = String(DDS_STARTFRQ);
// Função para escrever na segunda linha do LCD a frequencia, alinhada a direita e terminado em Hz.
void lcdfrq(String frequencia) {
lcd.setCursor(0,1);
lcd.print(" Hz"); // Apaga (escreve espaços) a linha e termina em Hz
lcd.setCursor(14-frequencia.length(),1);
lcd.print(frequencia);
}
void setup() {
pinMode(GPIN_EEP_RW, INPUT_PULLUP);
long eep_tmp = 0; // variavel temporaria para ler a eeprom;
lcd.init();
lcd.setCursor(0,0);
lcd.print("DDS AD9850 Teste");
// Se GPIN_EEP_RW estiver aberto ou em +5V, usa os dados da eeprom.
if (digitalRead(GPIN_EEP_RW) == HIGH ) {
// Possui uma assinature válida?
EEPROM.get(EEP_SIGADDR, eep_tmp);
if (eep_tmp == EEP_SIGNATURE ) { // E valida
// le a frequencia de calibração
eep_tmp=0;
EEPROM.get(EEP_DDS_CALXTAL, eep_tmp);
// Verifica se a frequencia não esta muito diferenete da DDS_NOCALXTAL
int eep_diff = DDS_NOCALXTAL - eep_tmp;
if (abs(eep_diff) <= 5000 ) {
DDS_CALXTAL=eep_tmp;
}
// le a frequencia inicial
eep_tmp=0;
EEPROM.get(EEP_DDS_STARTFRQ, eep_tmp);
// Verifica se a frequencia esta dentro da capacidade do AD9850 de 1 a DDS_MAXFRQ
if (eep_tmp > 0 && eep_tmp <= DDS_MAXFRQ) {
DDS_STARTFRQ=eep_tmp;
aFrequencia = String(DDS_STARTFRQ);
}
} else {
// grava os parametros iniciais na eeprom.
EEPROM.put(EEP_SIGADDR, EEP_SIGNATURE);
EEPROM.put(EEP_DDS_CALXTAL, DDS_CALXTAL);
EEPROM.put(EEP_DDS_STARTFRQ, DDS_STARTFRQ);
} // fim EEP_SIGNATURE
} // fim GPIN_EEP_RW
DDS.begin(DDS_WCLK, DDS_FQUD, DDS_DATA, DDS_REST);
DDS.calibrate((double)DDS_CALXTAL); // A lib DDS pede um double, então e feito um cast por garantia.
DDS.setfreq((double)DDS_STARTFRQ, DDS_PHASE);
lcd.setCursor(0,1);
lcdfrq(aFrequencia);
}
void loop() {
char Tecla = teclado.getKey();
if (Tecla) {
if (isDigit(Tecla)) {
sFrequencia += Tecla;
lcdfrq('#'+sFrequencia);
} else {
if (Tecla == '#' && sFrequencia.toDouble() > 0) {
DDS.setfreq(sFrequencia.toDouble(), DDS_PHASE);
if (digitalRead(GPIN_EEP_RW) == HIGH ) { // Se GPIN_EEP_RW estiver aberto/alto grava na EEPROM
EEPROM.put(EEP_DDS_STARTFRQ, sFrequencia.toInt());
}
lcdfrq(sFrequencia);
aFrequencia=sFrequencia;
sFrequencia = "";
} else {
lcdfrq(aFrequencia);
sFrequencia = "";
}
}
}
}
[code]

