Que tal compañeros, me encuentro en un problema tratando de diseñar SW que me permita controlar un pic para que me genera una señal PWM el cual me varie la frecuencia con un potenciometro en AN0 desde 1hz hasta 1Khz, con un ciclo de servicio constante que sea siempre el equivalente a un septimo del periodo, algo como esto:
Programando en asm me ha quedado esto, pero descubri que es muy dificil reslizar divisiones en este lenguaje (que no sean entre 2, 4 y
, asi que con ayuda de una calculadora hice unos experimentos y descubri que restandole 1/8 a 1/4 de algun numero, se obtiene aproximadamente 1/7
p,ej, 74/4= 18.5 74/8=9.25 18.5-9.25=9.25
74/7= 10.57
Pero no es exacto como podran darse cuenta, y el lo que no se como resolver aparte de que la frecuencia no logro ajustarla, les dejo aqui el codigo.
###########################################################
List p=16F877A ;Tipo de procesador
include "P16F877A.INC" ;Definiciones de registros internos
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
Periodo equ 0x20 ;Variable para el periodo
Duty_H equ 0x21
Duty_L equ 0x22 ;Variable para la anchura de pulso
resta equ 0x0c
org 0x00 ;Vector de Reset
goto Inicio
org 0x05 ;Salva el vector de interrupción
;Programa principal
Inicio clrf PORTA
clrf PORTB
clrf PORTC
bsf STATUS,RP0 ;Selecciona banco 1
clrf ADCON1 ;Puerta A analógica, justificación izda.
clrf TRISB ;Puerta B se configura como salida
movlw b'00000001'
movwf TRISA ;RA0 entrada
movlw b'11111011'
movwf TRISC ;RC2/CCP1 salida
movlw b'11001101'
movwf OPTION_REG ;Preescaler de 128 asociado al WDT
bcf STATUS,RP0 ;Selecciona banco 0
;Se activa el ADC y se selecciona el canal RA0/AN0. Frecuencia de trabajo Fosc/32
Loop clrwdt
movlw b'10000001'
movwf ADCON0 ;ADC en On, seleciona canal AN0
bcf PIR1,ADIF ;Restaura el flag del conversor AD
nop
bsf ADCON0,GO ;Inicia la conversión
ADC_0 btfss PIR1,ADIF ;Fin de conversión ?
goto ADC_0 ;Todavía no
movf ADRESH,w
movwf Periodo ;Registra valor actual para el periodo
movwf resta
movwf Duty_H ;Salva parte alta de la conversión
bsf STATUS,RP0 ;Selecciona página 1
bcf STATUS,C
rrf ADRESL,F
rrf ADRESL,F
bcf STATUS,C
rrf ADRESL,W
bcf STATUS,RP0 ;Selecciona página 0
andlw b'00110000'
movwf Duty_L ;Salva parte baja de la conversión
;El módulo CCP1 se configura en modo PWM con salida por RC2/CCP1. Los bits LSB se obtienen
;de la variable Duty_L
movlw b'00001100'
iorwf Duty_L,W
movwf CCP1CON ;Modo PWM para el módulo CCP1
;El periodo se determina según el valor de la variable "Periodo". Este se carga sobre el
;registro PR2.
movf Periodo,W
bsf STATUS,RP0 ;Selecciona página 1
movwf PR2
bcf STATUS,RP0 ;Selecciona página 0
;La anchura del pulso o "Duty" se determina según el valor con que se cargue el registro
;CCPR1L concatenado con los bits 4 y 5 de CCP1CON. Dichos valores se obtiene de las varia-
;bles Duty_H y Duty_L respectivamente.
clrw
bcf STATUS,C
rrf Duty_H,F
bcf STATUS,C
rrf Duty_H,F
bcf STATUS,C ; Ciclo de servicio dividido entre 4
rrf resta,F
bcf STATUS,C
rrf resta,F
bcf STATUS,C
rrf resta,F ; Ciclo de servicio dividido entre 8
bcf STATUS,C
movf resta,W
subwf Duty_H,F ; Resta del resultado entre 4 menos resultado de /8
bcf STATUS,C
rrf Duty_H,W
movwf CCPR1L
;Trabajando con un preescaler 1:1 y a una frecuancia de 4MHz, el TMR2 evoluciona cada 1 uS.
movlw b'00000100'
movwf T2CON ;TMR2 en On
goto Loop
end ;Fin del programa fuente
############################################################
Ese es todo el programa, se que se tienen que incrustar algunos retardos o cambiar el valor del timer2 pero no se muy bien cual es la manera, apenas hace dos meses comence de lleno con esto de la programacion en asm.
Me aconsejan que programe en C pero me es dificil comenzar otra vez a aprender un lenguaje, sin embargo, he hecho dos diferentes programas (con ayuda claro) que tampoco me van. estos son mucho mas cortos y sencillos.
///////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <16f877A.h>
#device ADC=8
#fuses NOPROTECT,NOCPD,NOLVP,NOWDT,XT
#use fast_io (A)
#use fast_io (B)
#byte resultado=0x20
#byte PORTB=0x06
#use delay(clock=4000000)
main()
{
set_tris_a(0x01);
set_tris_b(0x00);
setup_adc(adc_clock_div_32);
setup_adc_ports(AN0);
while(1)
{
set_adc_channel(0);
resultado = read_adc();
bit_set(PORTB,0);
delay_ms(resultado);
bit_clear(PORTB,0);
delay_ms(resultado);
delay_ms(resultado);
delay_ms(resultado);
delay_ms(resultado);
delay_ms(resultado);
delay_ms(resultado);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
Aqui solo muestrea la entrada AN0 y el resultado se envia a la salida con retardos equivalentes a la conversion. Aun asi es el que mas se ha acercado, lo malo fue la frecuencia a la que trabaja, ademas de que la salida no se puede leer bien,
////////////////////////////////////////////////////////////////////////////////////////////////
#include <16f877a.h>
#device ADC=8
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use standard_io(b)
#use standard_io(c)
int duty;
void toma_adc_y_transmite(void){
// Lectura del canal 0
set_adc_channel(0);
duty=read_adc();
}
void main() {
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(RA0_ANALOG);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1,255,1);
do {
toma_adc_y_transmite();
set_pwm1_duty(duty);
}while(true);
}
//////////////////////////////////////////////////////////////////////////////////////////////
Este ultimo es un ejemplo tipico sobre el modulo ccpx trabajando como PWM, en este no se como hacerle para que tambien varie el periodo, obtener un septimo del ciclo basta con dividir duty/7, y aun asi, no da exactamente un septimo.
He estado haciendo modificaciones a estos si ningun resultado, la verdad ya no se que hacer, he visto manuales, cursos y demas cosas que encontramos en san google y otros foros, pero no encuentro la manera, cualquier comentario o sugerencia sera bien recibido, gracias por su tiempo.