# Duda programa 16f88 para entrada analogica y PWM



## sokoloko (Sep 2, 2010)

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. .

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!!!!


----------



## Meta (Sep 3, 2010)

Quiero hacer lo mismo con el PCI16F88 pero en ensamblador.

http://www.alos.5u.com/indexpic877.htm

Saludo.


----------



## Pablet (Sep 3, 2010)

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


----------



## sokoloko (Sep 3, 2010)

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....

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.


----------



## Pablet (Sep 3, 2010)

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.

```
//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


----------



## Meta (Sep 3, 2010)

Hola:

¿Puedes meter el código completo en C?

Saludo.


----------



## Pablet (Sep 3, 2010)

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


----------



## Meta (Sep 3, 2010)

¿Puedes poner esquemas?

Pr un lado lo voy hacer con le 16F88 para aprender tanto en C como en ensamblador.


----------



## Pablet (Sep 3, 2010)

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


----------



## sokoloko (Sep 3, 2010)

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 .

Saludos.


----------



## Pablet (Sep 3, 2010)

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.


```
#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


----------



## sokoloko (Sep 3, 2010)

HOla Pablet,

He realizado la simulacion y me hace cosas muy raras .

De todas formas puede que esta linea este mal:


```
duty=duty/1000; //dividimos el numero entre 10 para tener un numero entre 0 y 102,4
```

Continuo probando.

Saludos.


----------



## Pablet (Sep 3, 2010)

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


----------



## Meta (Sep 4, 2010)

¿Hay códigos de ejemplo en asm para el 16F88?


----------



## sokoloko (Sep 5, 2010)

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 .

Saludos.


----------



## ByAxel (Sep 5, 2010)

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:

```
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


----------



## Meta (Sep 5, 2010)

ByAxel dijo:


> 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:
> 
> ```
> PROCESSOR    16F88
> ...



Muchísimas gracias, voy a comprobar.


----------



## sokoloko (Sep 6, 2010)

Gracias por el codigo, lo q pasa q yo de ASM ni papa....

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.


----------



## ByAxel (Sep 6, 2010)

Buenas:
Esto es lo que logré con el CCS V4.104:

```
#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


----------



## sokoloko (Sep 6, 2010)

Muchas gracias ByAxel,

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

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.


----------



## electronica001 (Ago 16, 2013)

hola puedo el pic 16f88 tiene 2 puertos para PWM  quiero controlar 2 motores  ya que ese pic tiene 2 puertos pero los 2 dicen CCP1  o hay algun otro pic de 18 pines que tenga 2 puertos pwm gracias.  si hay como con el 16f88 me pueden ayudar como debo declarar  en CCS gracias.


----------



## ByAxel (Ago 17, 2013)

electronica001 dijo:


> hola puedo el pic 16f88 tiene 2 puertos para PWM  quiero controlar 2 motores  ya que ese pic tiene 2 puertos pero los 2 dicen CCP1  o hay algun otro pic de 18 pines que tenga 2 puertos pwm gracias.  si hay como con el 16f88 me pueden ayudar como debo declarar  en CCS gracias.



El PIC16F88 solo tiene usa salida PWM pero está multiplexado entre dos pines, no es accesible desde código y solo se puede establecer el pin desde los fuses (ver datasheet).

Busca en http://www.microchip.com/ParamChartSearch/Chart.aspx?branchID=1012 el PIC que requieras que esté disponible en tu zona.

Saludos.


----------

