Here is a little code I did for a PIC16F877A to generate a sine wave.
It outputs parallel 8-bit samples to a MC1408 DAC from an interrupt routine.
The main() function does the setup from USB data.
I abandoned it because of its limited frequency range. About 10KHz max with the 20MHz PIC clock.
These are just pieces of code. See if you can follow it.
And you are right. You need to send out a lot of samples at a fixed rate.
You are probably better off with the DDS and adding an output driver.
#ifdef WAVEGEN
typedef union {
uint8_t b[2];
uint16_t i;
} bits_t;
uint8_t S_Count;
uint8_t S_Phase;
uint8_t S_PhaseRate;
uint8_t S_TimeRate;
uint8_t S_Triangle;
bits_t S_Time;
bits_t S_Time1;
bits_t S_Time2;
const uint8_t cosine[256] =
{
254, 254, 254, 254, 254, 254, 253, 253, 252, 251, 251, 250, 249, 248, 247, 246,
245, 244, 242, 241, 239, 238, 236, 235, 233, 231, 229, 228, 226, 224, 221, 219,
217, 215, 213, 210, 208, 205, 203, 200, 198, 195, 193, 190, 187, 184, 182, 179,
176, 173, 170, 167, 164, 161, 158, 155, 152, 149, 146, 143, 139, 136, 133, 130,
127, 124, 121, 118, 115, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81,
78, 75, 72, 70, 67, 64, 61, 59, 56, 54, 51, 49, 46, 44, 41, 39,
37, 35, 33, 30, 28, 26, 25, 23, 21, 19, 18, 16, 15, 13, 12, 10,
9, 8, 7, 6, 5, 4, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 8,
9, 10, 12, 13, 15, 16, 18, 19, 21, 23, 25, 26, 28, 30, 33, 35,
37, 39, 41, 44, 46, 49, 51, 54, 56, 59, 61, 64, 67, 70, 72, 75,
78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 115, 118, 121, 124,
127, 130, 133, 136, 139, 143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173,
176, 179, 182, 184, 187, 190, 193, 195, 198, 200, 203, 205, 208, 210, 213, 215,
217, 219, 221, 224, 226, 228, 229, 231, 233, 235, 236, 238, 239, 241, 242, 244,
245, 246, 247, 248, 249, 250, 251, 251, 252, 253, 253, 254, 254, 254, 254, 254,
};
#endif
//================================================================================
void main(void)
{
while (1) {
receivePacket();
switch () {
#ifdef WAVEGEN
// Sine wave generation token...
// MC1408 8-Bit Multiplying Digital-to-Analog Converter
// buffer[2] == Time1 MSB
// buffer[3] == Time1 LSB
// buffer[4] == Time2 MSB
// buffer[5] == Time2 LSB
// buffer[6] == Time rate
// buffer[7] == Phase rate
// buffer[8] == Triangle flag
// buffer[9] == Voltage reference
case FT_WAVEGEN:
S_Time1.b[1]=buffer[2];
S_Time1.b[0]=buffer[3];
S_Time2.b[1]=buffer[4];
S_Time2.b[0]=buffer[5];
S_TimeRate=buffer[6];
S_Time.i=S_Time1.i;
S_PhaseRate=buffer[7];
S_Triangle=buffer[8];
S_Phase=0;
S_Count=0;
TRISC=0x00; // set port C as output
// Setup voltage ref configuration
TRISAbits.TRISA2=1;
CVRCON=buffer[9];
// Setup CCP1 configuration
CCPR1H=S_Time.b[1];
CCPR1L=S_Time.b[0];
CCP1CON=0x0B; // Compare mode, trigger special event
// Setup Timer1 configuration
TMR1H=0;
TMR1L=0;
T1CON=0x05; // 1:1 Prescale | TMR1CS | TMR1ON bits
// Enable CCP1 interrupt
PIR1bits.CCP1IF=0; // CCP1 Interrupt Flag bit
PIE1bits.CCP1IE=1; // CCP1 Interrupt Enable bit
INTCON=0xC0; // GIE and PEIE interrupts
break;
#endif
}
}
}
//================================================================================
#ifdef WAVEGEN
void __interrupt() isr(void)
{
if (PIE1bits.CCP1IE && PIR1bits.CCP1IF) {
PIR1bits.CCP1IF=0; // clear CCP1 Interrupt Flag
IOCKpin=0; // set CLOCK- pin low
if (S_Triangle) {
if (S_Phase < 128)
PORTC=S_Phase*2;
else
PORTC=(255-S_Phase)*2;
} else {
PORTC=cosine[S_Phase];
}
S_Phase+=S_PhaseRate;
if (S_TimeRate > 0) {
if (S_Count == 0) {
if (S_Time2.i > S_Time1.i) {
S_Time.i+=S_TimeRate;
if (S_Time.i > S_Time2.i) S_Time.i=S_Time1.i;
}
if (S_Time2.i < S_Time1.i) {
S_Time.i-=S_TimeRate;
if (S_Time.i < S_Time2.i) S_Time.i=S_Time1.i;
}
CCPR1L=S_Time.b[0];
CCPR1H=S_Time.b[1];
}
S_Count++;
}
IOCKpin=1; // set CLOCK- pin high
}
}
#endif