Duda programa 16f88 para entrada analogica y PWM

Hola amigos,

Estoy aprendiendo poco a poco en esto de programar PIC (basicamente en C), y temas de entradas y salidas digitales, mas o menos lo controlo :) (al menos lo básico). Pero ahora tenia en mente complicarme un poco mas y creo que me he pasado de complicación. :unsure:.

Me gustaria en un 16f88, tener una entrada analogica con un potenciometro entre 0 y 5v, y una salida PWM con un led que parpadee y varie su velocidad de parpadeo segun el valor del potenciometro.

Me podeis orientar un poco sobre como "diseñar" el programa.

Gracias!!!!
 
eso que quieres hacer es bastante sencillo, y mas sencillo todavía si utilizas ccs. yo tengo el programa hecho en c18 para un 18f4550. si quieres subo el programa pero lo que hago es lo siguiente. primero leo la entrada analógica que me da un valor entre 0 y 1024, y tu ciclo de trabajo puede variar entre 0 y 100 (o entre 0 y 1, si es así luego divides entre 100). para no calentarme mucho la cabeza hice la siguiente aproximación 1024=1000. . . .se te va a ir muy poquito, asi que para meterle el ciclo de trabajo tan solo tienes que dividir la solución de tu conversión ad entre 10 para meterle el ciclo de trabajo entre 0 y 100 o entre 1000 para tenerlo entre 0 y 1. dime que programa estas utilizando para hacer el código y te podre ayudar de una forma mas especifica.
un saludo
 
Hola,

Gracias meta por el enlace, viene bastante bien explicado, al menos la teoria, lo malo es que el ensamblador me parece muy complicado, y ya que se puede mas sencillo en C....:D

Lo que si Pablet, me vendria de lujo si puedes poner tu codigo de ccs, al menos para tener una base y luego ya ir probando y cambiando cosillas.

Gracias a los dos.
 
mi codigo no esta en ccs, sino en c18, de todas formas si lo estas haciendo en ccs es mucho mas sencillo. ahi va mi codigo.
Código:
//En el programa se hace una pequeña aproximación (0.976=1) en la forma de pasar 
//el resultado de la conversion 0->1024 a 0->1000, de esta forma al dividir por el
//100 que nos sale d ela operacion del DC podemos trabajar directamente con el  
//valor  de ADRESH
#pragma config WDT=OFF
#pragma config FOSC=HS
#pragma config DEBUG=OFF
#pragma config LVP=OFF
#pragma config MCLRE=OFF
#pragma config ICPRT=OFF


double duty; //Variable del ciclo de trabajo (Duty Cicle)

void main (void){

TRISC=0xFD;
TRISA=0xFF;

ADCON0=0x01;// b00000001: AN0
ADCON1=0x0E;// b00001110: VSS, VDD como referencias, todos los canales digitales excepto AN0
ADCON2=0x11;// b00010001: justificacion izquierdas, 0Tad, ADCclk=Fosc/8 1us
//se justifica a izquierdas para manejar solo 8 bits

CCP2CON=0x0F;// b00001111: Modo PWM
T2CON=0x04;// b00000100: Post-Escalar desactivado, Pre-Escalar 1:1, T2 en Marcha
PR2=249;

while(1){
ADCON0bits.GO=1;
while(ADCON0bits.DONE==1);
//ahora introducimos el ciclo de trabajo

CCPR2L=(ADRESH);
CCP2CONbits.DC2B1=(ADRESH*4)&0X02;
CCP2CONbits.DC2B0=(ADRESH*4)&0X01;

}

}

En ccs no tengo ningun codigo pero es mucho mas facil.

Un saludo
 
ese es el código completo del programa, no hay mas, el programa solo hace eso, coge la señal de un potenciometro y la convierte en un ciclo de trabajo para la salida.

Un saludo
 
el esquema es muy sencillo, tan solo hay un potenciometro con el cursor a AN0, y en la salida del modulo CCP2 el led con una resistencia. repito que este codigo es para c18 y solo funciona con pics 18f, el programa a pesar d estar hecho en c esta a bastante bajo nivel, sin utilizar librerias, sino modificando registros, si haces eso mismo en asm para un pic 16 deberia funcionar. . . modificando el nombre del registro por su dirección.

Un saludo
 
Buenas,

Gracias Pablet por el codigo, aunq tal y como dices esta a bastante bajo nivel y me cuesta enterderlo.

Voy a hacer mas pruebas con "C" del que es "mas programacion", a ver si consigo algo.

Animo Meta y a ver si lo conseguimos (y).

Saludos.
 
hola de nuevo, he hecho este codigo, pero la verdad es que e sla primera vez que lo hago en ccs y no funciona y no se porque, de todas formas lo pongo para que te hagas una idea de lo que tienes que hacer.

Código:
#include <16f88.h>
#device adc=10

#use delay(clock=8000000)
#fuses HS, NOWDT, NOLVP, NOMCLR


int duty;

void main(void){

//CONFIGURACIÓN CONVERSOR AD
SETUP_ADC(ADC_CLOCK_INTERNAL); //TIEMPO DE CONVERSION Fosc/8
SETUP_ADC_PORTS(sAN0);      // CONFIGURACION DE AN0 COMO CANAL ANALÓGICO
SET_ADC_CHANNEL(0);         //SELECCIONAMOS EL CANAL 0 PARA LA CONVERSION

//CONFIGURACION MÓDULO CCP
  setup_timer_2(T2_DIV_BY_16,124,1); //configuramos el timer 2 para una frecuencia de 1000hz
//setup_timer_2(modo, pr2, postescalar)

SETUP_CCP1(CCP_PWM); //CONFIGURAMOS MODULO CCP PARA PWM
SET_PWM1_DUTY(50);    //DAMOS UN CICLO DE TRABAJO INICIAL DE 50%



while(1){

duty=read_adc();  //leemos canal analogico que nos devuelve un numero entre 0 y 1024
duty=duty/1000; //dividimos el numero entre 10 para tener un numero entre 0 y 102,4

if(duty>100)  //si el numero es mayor que 100 le asiugnamos el valor 100
   duty=100;
SET_PWM1_DUTY(duty); //establecemos el nuevo ciclo d etrabajo

delay_ms(200);


}
}
espero que te sirva de ayuda.
Un saludo
 
HOla Pablet,

He realizado la simulacion y me hace cosas muy raras :cry:.

De todas formas puede que esta linea este mal:

Código:
duty=duty/1000; //dividimos el numero entre 10 para tener un numero entre 0 y 102,4

Continuo probando.

Saludos.
 
vaya eso es que lo he ido cambiando para probar y al final lo he dejado divbidido entre 1000. . mi idea era dividirlo entre 10 para tener un numero al final entre 0 y 100, ya te digo que el programa basicamente es ese pero no se porque no funciona. yo no controlo mucho ccs quiza pueda ayudarte alguien que lo conozca mas o buscando por internet.
un saludo
 
Buenas,

Adjunto el esquema en Proteus, el codigo en C del programa y el HEX compilado. Pues tampoco consigo que funcione, ni olvidandome de la parte PWM.

He intentado que segun el voltaje de entrada, encienda tres leds, pero no hay manera.

No se que sera pero agradeceria un poco de ayuda de algún experto :cool:.

Saludos.
 

Adjuntos

  • Programa PIC Analogico.rar
    17.6 KB · Visitas: 113
Hola; esto es lo que logre en ASM donde lee un canal ADC y el resultado lo pone directamente para generar el PWM. Está a un valor max. de 255 para no complicar haciendo a 10bit:
Código:
	PROCESSOR	16F88
#include <P16F88.inc>	
	errorlevel -302
	__CONFIG	_CONFIG1, _DEBUG_OFF & _CCP1_RB3 & _LVP_OFF & _MCLR_OFF & _WDT_OFF & _INTRC_IO
	__CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_ON
	
	cblock	0x20
	DL1, DL2
	DATH, DATL
	endc
	
	org	0x00
	banksel	OSCCON
	movlw	b'01100100'
	movwf	OSCCON			; a 4Mhz
	bsf		TRISA,0			; Un canal ADC
	bsf		ANSEL,0
	movlw	0xFF			; Para el PWM
	movwf	PR2
	clrf	TRISB
	banksel ADCON0
	movlw	b'11000001'
	movwf	ADCON0
	clrf 	CCPR1L			; Inicia a 0% el duty del PWM
	bcf 	CCP1CON,CCP1X
	bcf 	CCP1CON,CCP1Y
	bsf 	CCP1CON,CCP1M3	; Modo PWM
	bsf 	CCP1CON,CCP1M2
	movlw	b'01111111'
	movwf	T2CON			; Inicia el PWM por el pin RB3
	clrf	PORTB
	
Loop:
	movlw	.0
	iorlw	.193
	movwf	ADCON0			; Canal 0
	call	Del				; Delay
	bsf		ADCON0,GO_DONE
	btfsc	ADCON0,GO_DONE	; Inicia ADC
	goto	$ - 1
	movfw	ADRESH			; Obtiene el valor
	movwf	DATH
	movwf	CCPR1L			; El resultado se pone para el PWM
	goto	Loop
	
Del:						; Delay
	movlw	.20
	movwf	DL1
	decfsz	DL1, F
	goto	$ - 1
	return	
	end

Sobre el CCS, tiene varios bugs por lo que seria recomendable revisar el código ASM que genera al compilar.

Saludos
 
Hola; esto es lo que logre en ASM donde lee un canal ADC y el resultado lo pone directamente para generar el PWM. Está a un valor max. de 255 para no complicar haciendo a 10bit:
Código:
    PROCESSOR    16F88
#include <P16F88.inc>    
    errorlevel -302
    __CONFIG    _CONFIG1, _DEBUG_OFF & _CCP1_RB3 & _LVP_OFF & _MCLR_OFF & _WDT_OFF & _INTRC_IO
    __CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_ON
    
    cblock    0x20
    DL1, DL2
    DATH, DATL
    endc
    
    org    0x00
    banksel    OSCCON
    movlw    b'01100100'
    movwf    OSCCON            ; a 4Mhz
    bsf        TRISA,0            ; Un canal ADC
    bsf        ANSEL,0
    movlw    0xFF            ; Para el PWM
    movwf    PR2
    clrf    TRISB
    banksel ADCON0
    movlw    b'11000001'
    movwf    ADCON0
    clrf     CCPR1L            ; Inicia a 0% el duty del PWM
    bcf     CCP1CON,CCP1X
    bcf     CCP1CON,CCP1Y
    bsf     CCP1CON,CCP1M3    ; Modo PWM
    bsf     CCP1CON,CCP1M2
    movlw    b'01111111'
    movwf    T2CON            ; Inicia el PWM por el pin RB3
    clrf    PORTB
    
Loop:
    movlw    .0
    iorlw    .193
    movwf    ADCON0            ; Canal 0
    call    Del                ; Delay
    bsf        ADCON0,GO_DONE
    btfsc    ADCON0,GO_DONE    ; Inicia ADC
    goto    $ - 1
    movfw    ADRESH            ; Obtiene el valor
    movwf    DATH
    movwf    CCPR1L            ; El resultado se pone para el PWM
    goto    Loop
    
Del:                        ; Delay
    movlw    .20
    movwf    DL1
    decfsz    DL1, F
    goto    $ - 1
    return    
    end
Sobre el CCS, tiene varios bugs por lo que seria recomendable revisar el código ASM que genera al compilar.

Saludos

Muchísimas gracias, voy a comprobar.
 
Gracias por el codigo, lo q pasa q yo de ASM ni papa....:cry:

De momento los programas realizados en CCS me has funcionado bien, pero igual este no se genera bien por alguna razon.

En fin continuare investigando y probando.

Saludos.
 
Buenas:
Esto es lo que logré con el CCS V4.104:
Código:
#include "P16F88_Ad_pwm.h"

#device *=16
#device adc=10
#FUSES NOWDT, INTRC_IO, PUT, NOMCLR, NOBROWNOUT, NOLVP, NOCPD        
#FUSES NOWRT, NODEBUG, NOPROTECT, FCMEN, NOIESO 

#use delay(internal=4Mhz)
#byte OSCCON = getenv("SFR:OSCCON")
#use Fast_io(a)
#use Fast_io(b)

int16 dato;

void main()
{
   OSCCON = 100;
   setup_adc_ports(sAN0|VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_2(T2_DIV_BY_4,249,1);
   setup_ccp1(CCP_PWM);
   set_pwm1_duty(0);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   set_tris_b(0);
   set_tris_a(1);
   
   while(TRUE){
      set_adc_channel(0);
      delay_us(10);      
      dato = read_adc();
      set_pwm1_duty(dato);
   }
}

Según leí, aparte de algunos bugs las nuevas versiones reducen el código compilado lo que provoca algunos desastres... Otros prefieren la V4.084, según dicen es más estable.
También tengo una duda con respecto a los fuses; en otros compiladores puedo seleccionar el pin RB0 o RB3 para ser usado con el módulo CCP pero en el CCS no encontré esa opción en los fuses, ¿Saben como ponerla?

El esquema lo use tanto para el código en ASM y C del CCS.

Saludos
 

Adjuntos

  • adpwm.gif
    adpwm.gif
    54.1 KB · Visitas: 115
Muchas gracias ByAxel,

Tu codigo funciona perfectamente y es muy simple de entender !!! :aplauso::aplauso::aplauso::aplauso:

Por fin tengo el programa funcionando como queria, lo unico que modifique xq sino me daba problemas era la primera linea:

#include "P16F88_Ad_pwm.h" => Por => #include "16F88.h"

En el proteus va genial, luego el tema "fuses" del PIC ya los ajusto a mano en el Winpic.

El tema de seleccionar el pin RB0 o RB3 lamento decirte que tampoco lo se.

Gracias. ;)
 
Última edición:
Atrás
Arriba