A continuación presento el programa completo que es ejecutado en el PIC y la rutina de calculo de los datos a enviar al DDS.
Programa para PIC 16F870
El siguiente código escrito en lenguaje C corresponde al programa que ejecuta el PIC 16F870 para controlar el DDS AD9835 y comunicarse con la PC.
El AD9835 posee ademas registros de control de fase pero su uso esta fuera del alcance de estos ejemplos.
El programa basicamente en un bucle sin fin que esta permanentemente leyendo el puerto serie en busca de comando enviados por la PC.
Los comandos son:
I -> Inicializa el DDS.
R -> Resetea el DDS.
S -> Aun no implementado.
T -> Recibe 4 bytes desde la PC que definen la frecuencia de la señal a generar.
G -> Inicia generacion de señal
=================================================================================================
#include <16F870.h>
#include <stdlib.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000) // Proc speed 20Mhz.
#use rs232(baud=9600, xmit=PIN_B0, rcv=PIN_B1)
// PIC definicion de pines en uso
#define Fsync PIN_B3
#define Sdata PIN_B4
#define SClk PIN_B5
#define SoundPin PIN_B2
// Comandos DDS
#define DdsReset 0xD800
#define DdsSelSrc 0xB000
#define DdsRegSel 0x6000
#define DdsGo 0xC000
#define DdsWrHMSB 0x3300
#define DdsWrLMSB 0x2200
#define DdsWrHLSB 0x3100
#define DdsWrLLSB 0x2000
// Variables Globales
int8 HMSB;
int8 LMSB;
int8 HLSB;
int8 LLSB;
// Funciones
void Beep(int8 t){ // Genera un tono para confirmar recepcion de datos. t = cantidad de beeps.
int8 i,x=0;
for (x=t ; x > 0 ; x--){
for (i=0; i < 25 ; i++){
output_high (SoundPin);
delay_us(500);
output_low (SoundPin);
delay_us(500);
}
Delay_ms(100);
}
}
void SendDataToDds(int16 Data){ // Envía datos al DDS a través de la interface SPI.
int i;
output_low (FSync);
for(i=0 ; i<16 ; ++i){
output_bit(Sdata,shift_left(&Data,2,0));
output_low (Sclk);
delay_us(1);
output_high (Sclk);}
delay_us(1);
output_high (FSync);
}
void InitializeDds() { // Envía al DDS los comandos de inicialización
SendDataToDds(DdsReset);
SendDataToDds(DdsSelSrc);
SendDataToDds(DdsRegSel);
}
void DdsSelReg(int Data) { // Envía Comando Reset al DDS
SendDataToDds(DdsReset);
}
void AckToPC(){ // Envía Ack (OK) a la PC.
printf("OK\n");
}
void SendFwordToDds(){
SendDataToDds(DdsWrHMSB + HMSB); // Envia Comando + HMSB de la frecuencia.
delay_ms(1);
SendDataToDds(DdsWrLMSB + LMSB); // Envia Comando + LMSB de la frecuencia.
delay_ms(1);
SendDataToDds(DdsWrHLSB + HLSB); // Envia Comando + HLSB de la frecuencia.
delay_ms(1);
SendDataToDds(DdsWrLLSB + LLSB); // Envia Comando + LLSB de la frecuencia.
delay_ms(1);
}
// Programa
main() {
char cmd; //Cmd: Comando recibido desde la PC.
char DataFromPC[5];
output_high (FSync); // Inicializa pines usados en la interfase SPI.
output_high (Sdata);
output_high (Sclk);
InitializeDds();
HMSB=00; // Frecuencia de inicio = 0x00015D86 =1KHz.
LMSB=01;
HLSB=0x5D;
LLSB=0x86;
SendFwordToDds(); // Envía frecuencia al DDS.
SendDataToDds(DdsGo);
Beep(2);
do{
do{
cmd=getch();
} while(cmd != 'I' && cmd != 'R' && cmd != 'S' && cmd != 'T' && cmd != 'G');
if (cmd == 'I'){ // I --> Inicializa DDS.
InitializeDds();
AckToPC();
Beep(1);}
else if (cmd == 'R'){ // R --> Reset DDS.
SendDataToDds(DdsReset);
AckToPC();
Beep(1);}
else if (cmd == 'S'){ // S --> Selecciona registro de Frecuencia o Fase.
SendDataToDds(DdsReset);
AckToPC();
Beep(1);}
else if (cmd == 'T'){ // Recibe 4 bytes que definen la frecuencia de la señal.
AckToPC();
gets(DataFromPC); //
HMSB=atoi(DataFromPC);
AckToPC();
gets(DataFromPC); //
LMSB=atoi(DataFromPC);
AckToPC();
gets(DataFromPC); //
HLSB=atoi(DataFromPC);
AckToPC();
gets(DataFromPC); //
LLSB=atoi(DataFromPC);
AckToPC();
SendFwordToDds();}
else if (cmd == 'G'){ // G --> Inicia generación de señal.
SendDataToDds(DdsGo);
Beep(1);
AckToPC();}
} while(true);
}
================================================================================================
Código Visual Basic 6.0 para PC
En esta sección están la principales rutinas del programa que se ejecuta en la PC y sirve como consola para el control del DDS.
- Calculo de los 4 bytes que definen la frecuencia de la señal a generar.
El calculo se realiza a partir de la frecuencia (Fn) que es la suma de 3 valores recibidos en trea variables (Mhz, Khz y Hz).
Luego, Fn es dividido por la resolución (Res) para obtener así el valor que define la frecuencia en función de la frecuencia del clock principal (MClk = 50MHz).
Res = MClk / 2^32
Fn = Fw * (2^32) / MClk
Fw = Fn / Res
Private Sub CmdCalc_Click()
Fn = (Mhz * 1000000) + (Khz * 1000) + Hz
Fw = Fn / Res
Hword = Int(Fw / 65536)
Lword = Fw - (Hword * 65536)
HMSB = Int(Hword / 256)
LMSB = Hword - (HMSB * 256)
HLSB = Int(Lword / 256)
LLSB = Lword - (HLSB * 256)
TxtFword.Text = Hex(HMSB) + " " + Hex(LMSB) + " " + Hex(HLSB) + " " + Hex(LLSB)
FwFlg = True
End Sub
- Rutina de envío de datos al DDS.
Private Sub CmdSend_Click()
CmdSend.Enabled = False
If (FwFlg) Then
TxtStatus.Text = "Sending Control Words to AD9835."
MSComm1.Output = "T"
WaitForAckFromPIC
MSComm1.Output = "0x" & Hex(HMSB) & Chr(13)
WaitForAckFromPIC
MSComm1.Output = "0x" & Hex(LMSB) & Chr(13)
WaitForAckFromPIC
MSComm1.Output = "0x" & Hex(HLSB) & Chr(13)
WaitForAckFromPIC
MSComm1.Output = "0x" & Hex(LLSB) & Chr(13)
WaitForAckFromPIC
Else
Beep
TxtStatus.Text = "Frequency word not calculated."
End If
CmdSend.Enabled = True
CmdSend.SetFocus
End Sub
Referencias
AD9832/AD9835 Programming Examples http://www.analog.com/static/imported-files/application_notes/AN-1108.pdf
Programming the AD9832/AD9835 http://www.sparkfun.com/datasheets/BreakoutBoards/AD9835_app_note.pdf