Disculpame la demora en responder.
Lo que hice fue realizar una tabla de valores para la ecuación en diferencias:
..............
Hace de cuenta que partí de esta ecuación, asumiendo una f=10Hz y un Ts=10ms. Como el ángulo es w.Ts=2pi*10*0.01=0.628, por eso, al reemplazar y operar esa k que tienes, se obtiene 1.61, que es el valor inicial que tome. Básicamente lo que observé en la tabla de valores que armé, es que el seno que se forma, tiene una amplitud aproximada a 2, por eso hice la escalización a 2.
Si ok, el inconveniente eran los valores iniciales y1,y2 que parecían puestos al azar y son muy importantes porque te definen la amplitud de la oscilación.
Si querés usar el valor del ADC para variar la amplitud lo tenés que hacer en el escalado: xpwm = q*y/2+512 ;
Por qué pones y/2?
Porque q llega hasta 1023, y si le sumás 512 te pasás de los 10 bits del PWM.
De todas formas, como vi que estás usando el 16F877 a 4MHz , para un duty 100% el máximo es 800.
Sin embargo, hay dos cosas que aun no te entiendo del codigo que me sugeriste a seguir:
Por qué un if (tic), y declararlo al principio como tic=0, luego como 1, y así?
Como las operaciones en punto flotante son consumidoras de tiempo, es preferible que no estén dentro de interrupciones que deben ocurrir a intervalos precisos. En muchos casos puede no ser necesario, yo lo hice por default

.
Lo que hago con el tic es ponerlo en 1 cuando ocurre la interrupcion, de esa manera se entera el bucle en main() y ejecuta los cálculos con todo el tiempo del mundo disponible y sin problemas ante otras interrupciones que podrían ocurrir.
Luego de el if(tic) se pone en 0 para que no se vuelva ejecutar hasta que lo active la interrupción.
Por qué me dices que hay que multiplicar por el 512 al xpwm?
xpwm debe ser un numero entre 0 y 1023 a 20MHz y entre 0 y 800 a 4MHz
- Si tenés un float entre +/-1 tenés multiplicarlo por la nueva amplitud y sumarle un offset:
xpwm = y*512 + 512 = (y+1)*512 (para 20MHz)
xpwm = y*400 + 400 = (y+1)*400 (para 4MHz)
- Si querés variar es amplitud con la lectura del ADC (0-1023) tenés que escalarla también:
xpwm = (q/1024) *y*512 + 512 = y*q/2 + 512 (para 20MHz)
xpwm = (q/1024) *y*400 + 400 = y*q/2.56 + 400 (para 4MHz)
--------------------------------------------------------------------------
Te pongo un ejemplo sin la parte de ADC.
- Genero un seno de 4Hz que luce mejor que de 10Hz.
#include <16f877a.h>
#device adc=10
#fuses hs,nowdt,noprotect,noput
#use delay (clock=4M)
int1 tic = 0 ;
int16 xpwm ;
#define PERIODO 65536-625
#INT_TIMER1
void tic_10ms()
{
tic = 1 ;
set_timer1(PERIODO);
set_pwm1_duty(xpwm);
}
void main(){
set_tris_c(0b000);
setup_timer_1(t1_internal|t1_div_by_8);
set_timer1(PERIODO);
setup_timer_2(T2_DIV_BY_1, 199, 1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(0);
enable_interrupts(int_timer1);
enable_interrupts(global);
float32 k = 1.937 ; // 2*cos(2*PI*f*T)
float32 y1 = .2363 ; // Amp*seno(2*PI*f*T)
float32 y2 = 0 ; // Amp = .95 f = 4 Hz T = .01s
float32 y ;
xpwm = (y1+1)*400 ;
while(TRUE)
{
if(tic)
{
tic = 0 ;
y = k*y1-y2 ;
xpwm = (y+1)*400 ;
y2 = y1 ; y1 = y ;
}
}
}
- Cambié las constantes del filtro RC. Aún así, le falta un poco.
- Al osciloscopio le dejé dos trazos para marcar 0 y 5V
- Los glitches no estoy seguro si es el simulador que hace mal la parte analógica al no ser en tiempo real o algún problemita raro con el intervalo entre interrupciones.
