# Pic 16f887 entradas analogas



## kummell (Abr 5, 2010)

Buenas Tardes soy nuevo en el foro y quiciera pedir ayuda con lo siguiente.

Quiero hacer la conversion A/D de 4 señales y mandarlas por rs232, hasta ahora lo he logrado con 1 (cosa sencilla), pero a la hora de hacerlo con más no he podido ya que el Byte ADCON0 solo me permite usar una entrada a la vez.

Tengo que usar alguna clase de interrupción?
Cómo funcionaría?
Gracias

Olvidaba decir que lo estoy haciendo en assembly


----------



## DOA (Abr 5, 2010)

Solo se puede hacer una canal a la vez, al hacer por interrupcion del timer por cada interrupcion se convierte la señal de un solo canal y se utiliza un contador para saber que canal va a ser convertido.
Tambien se puede hacer sin interrupciones pero es mejor utilizar las interrupciones


----------



## ByAxel (Abr 5, 2010)

Hola:
Todos los PIC de la serie 16 y 18 solo pueden leer una canal análogo a la vez,
y para que puedas leer varios debes de:
>> Configurar como entradas a todos los pines que quieres que sean análogos.
>> El ADCON0 se puede escribir tantas veces quieras (como la mayoría de los registros), entonces un ejemplo seria que dentro de un bucle que se repita 4 veces la lectura del ADC.

*Repite:
{Para la 1ra lectura escribes 0000 = AN0, envias por rs232,}
{para la 2da lectura escribes 0001 = AN1, envias por rs232,}
{para la 3ra lectura escribes 0010 = AN2, envias por rs232,}
{para la 4ta lectura escribes 0011 = AN3, envias por rs232}
goto Repite*


----------



## kummell (Abr 5, 2010)

Hello
Con respecto a lo q dice DOA, ya lo había intentado queriendo leer un puerto cada 100ms, el problema es q no sé como sería la secuencia de interrupción a llevar a cabo para que me lea el siguiente puerto. Lo estaba intentando cambiando la config del reg ADCON0. Me gustaría q  me diera un ejemplo siquiera con 2 puertos para tener la idea.

Y con respecto a Carlos Alexis, lo q entiendo es q por ejemplo en dicho bucle (q me imagino iría en la parte principal del prog) habilito AN0 e inmediatamente despues habilito AN1, no necesitaría alguna clase de retraso?
O simplemente leo el primer dato, hago la rutina de conversión y luego cambio el puerto?

Muchas gracias y disculpen si entendí mal sus ideas


----------



## DOA (Abr 5, 2010)

Se necesita una variable que sirve de contador al llegar al ultimo valor debe ser reiniciada a cero, y tambien se puede utilizar este contador para que extraiga de una tabla el valor que va a ser cargado al ADCON


----------



## ByAxel (Abr 5, 2010)

Hola:
Tomando la idea de DOA de usar una tabla para adquirir el número de canal a leer y un ejemplo que trae el datasheet del PIC.
En un ejemplo seria:


```
BANKSEL	ADCON1
	movlw	b'10000000'
	movwf	ADCON1		; Para el ADCON1
	BANKSEL TRISA
	movlw	0x0F
	movwf	TRISA		; Se va usar 4 entradas análogas
	BANKSEL ANSEL
	movlw	0x0F
	movwf	ANSEL		; Las entradas <AN3:AN0> son para el ADC
	BANKSEL ADCON0
	
Init:
	clrf	CNT			; Inicia a 0
Bucle:
	movfw	CNT
	call	Canal		; Obtiene el canal a leer
	xorlw	b'11000001'
	movwf	ADCON0		; Activa el canal a leer
	call	T_Adq		; Tiempo (Ver la hoja de datos)
	bsf		ADCON0,GO	; Inicia adquisición
	btfsc	ADCON0,GO	; Espera hasta que termine
	goto	$ - 1 
	BANKSEl ADRESL
	movfw	ADRESL		; Recoge el valor obtenido
	BANKSEL DATL		; en 2 bytes porque se usa
	movwf	DATL		; la resolución a 10bit
	movfw	ADRESH
	movwf	DATH
	call 	EnviaRS232	; Tu código que envia por RS232
	incf	CNT,F		; Aumenta en 1, se usa como un puntero para
						; obtener el siquiente canal a leer.
	movlw	.4			; Pero solo se usa 4 entradas ADC
	xorwf	CNT,W		
	btfss	STATUS,Z
	goto	Bucle		
	goto	Init		; Al terminar con las 4, reinicia el conteo desde el 1ro = AN0.
	
Canal:					; Obtiene el canal a leer
	addwf	PCL,F
	retlw	b'00000000'
	retlw	b'00000100'
	retlw	b'00001000'
	retlw	b'00001100'
```

Es tan solo un ejemplo.
Lo pruebas.


----------



## kummell (Abr 6, 2010)

Pues les cuento que me pudo, aqui les pongo el cÓdigo para ver si me pueden colaborar en algo.
Como les comentÉ, cuando uso un solo dato funciona, pero al intentar aplicar la multiplexaciÓn...

Aprecio su ayuda


----------



## ByAxel (Abr 6, 2010)

Te devuelvo tu código, le agregue algunas cosas que hacían falta y también todo lo he comentado esta en  ;####

En la simulación funciona.


----------



## kummell (Abr 6, 2010)

Carlos Alexis, Thanks a lot
Lo mirare y probare.


----------



## kummell (Abr 7, 2010)

PUES APARENTEMENTE AHORA SI HACE EL ADC EN LOS PUERTOS, PERO LA Tx POR RS 232 NO LA HACE.
DEBRÍA FUNCIONAR, YA QUE LO HACE CUANDO TRABAJO CON 1 SOLO CANAL.
HABER QUE SUCEDE AHORA.
LA TRANSFERENCIA ES DE 2400 BAUDIOS, 8 BITS DE DATOS, 1 DE PARADA, NO PARIDAD, CONTROL POR HARDWARE. POR EL HYPERTERMINAL


----------



## ByAxel (Abr 7, 2010)

Pues en tu código original al parecer lo hace de pura coincidencia ya que nunca sale de la subrutina "AD" por estas instrucciones que están al final de la misma:
*BTFSS   STATUS,Z 
    GOTO    AD         
    GOTO    VARCONT
    RETURN*

A mi también se me paso ese detalle ya que para la simulación elimine todo lo referido a la transmisión RS232, bueno para que funcione pon esto al final de la sub "AD":

*BTFSS   STATUS,Z      
    RETURN
    CLRF	CNT           ; Ya no es necesario saltar a VARCONT
    RETURN*

De todas formas revisa, pero en la simulación ya envía valores como 1,00; 2,99; etc..
supongo que es lo que querías... además hay un par de cosas que me han llamado la atención pero ese es tu trabajo jeje...

Chao


----------



## kummell (Abr 7, 2010)

Si, tenÍa la duda con esas instrucciones, ya que con un solo canal si funciona, preciso estava mirando eso ya que lo tomÉ del ejemplo que me pasaste.
La verdad que creÍ que era mÁs sencillo.
Por lo que veo el problema estÁ en saber tratar con esa multplexaciÓn.
Sigo esperando su ayuda.

Éste es el código con un solo canal que si funciona, haber qué es lo que sucede que al querer usar más canales no funciona. ADC3

Subo otro código en el cual leo los puertos en forma secuencial, sin embargo solo me manda los datos del último puerto. ADC5
Ya siento que estoy cerca de lograrlo.


----------



## ByAxel (Abr 7, 2010)

Un par de ajustes...
Una observación: Sucede que creo que debes de revisar el code de conversión a numero ya que paso que envía un carácter y no un número en una de las secuencias; el resto está bien.
Revisa el código.


----------



## kummell (Abr 7, 2010)

Pues con algunos detalles mÍnimos, lo he logrado

muy bien carlos alexis, se le agradece bastante

aqui subo el cÓdigo.


----------



## Meta (May 21, 2010)

Por cierto. Con el  16F887 quiero configurar:

PORTA, B, C, D, E que no sean alanógicas. ¿Cómo lo hago?

La primera vez que paso del 16F84A al 16F887.


----------



## DOA (May 21, 2010)

Creo que ese pic utiliza los registro ansel y anselh para configurar como analogico o digital los puertos a, b y e
Los puertos C y D son unicamente digitales


----------



## Meta (May 22, 2010)

Uso el ANSEL para ponerlo a digital así:

movlw     b'00000000'
movwf     ANSEL         ; Digitales.

¿En qué se diferencia ansel y anselh excatamente?


----------



## DOA (May 22, 2010)

Fijate en el datasheet, ansel se utiliza para AN0 a AN7 y anselh para AN8 a AN13

Segun el datasheet:
BANKSEL ANSEL ;
CLRF ANSEL ;digital I/O


----------



## Meta (May 22, 2010)

Gracias, está en la página 41.

BANKSEL PORTA ;
CLRF PORTA ;Init PORTA
BANKSEL ANSEL ;
CLRF ANSEL ;digital I/O
BANKSEL TRISA ;
MOVLW 0Ch ;Set RA<3:2> as inputs
MOVWF TRISA ;and set RA<5:4,1:0>
;as outputs



kummell dijo:


> Pues con algunos detalles mÍnimos, lo he logrado
> 
> muy bien carlos alexis, se le agradece bastante
> 
> aqui subo el cÓdigo.



Hay que acostumbrarse a cuidar las tablas por si acaso.




```
IF (FinTablaCANAL > 0xFF)
        ERROR    "¡CUIDADO!: La tabla ha superado el tamaño de la página  de los"
        MESSG    "primeros 256 bytes de memoria ROM. NO funcionará  correctamente."
    ENDIF
```

Así tienes el código asm más controlado.


```
PROCESSOR 16F887
    INCLUDE <P16F887.INC>
    errorlevel -302
    __CONFIG _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOR_OFF & _IESO_ON & _FCMEN_ON & _LVP_OFF


    CBLOCK 0X20
        LOOP,LOOP2,NIB1,NIB2,NIB3,TEMP,R0,R1,R2,ACAL,ACAH
        ACBL,ACBH,ACCL,ACCH,ACDL,ACDH,COUNT
        CHANN
    ENDC

    ORG     0x00
    GOTO     INI
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CANAL    
    addwf    PCL,F
    retlw    b'10010001'    ; AN4
    retlw    b'10010101' ; AN5
    retlw    b'10011001' ; AN6
    retlw    b'10011101' ; AN7
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FinTablaCANAL

IF (FinTablaCANAL > 0xFF)
        ERROR    "¡CUIDADO!: La tabla ha superado el tamaño de la página de los"
        MESSG    "primeros 256 bytes de memoria ROM. NO funcionará correctamente."
    ENDIF

RETARDO
    MOVWF    LOOP
TOP2
    MOVLW     D'110'
    MOVWF    LOOP2
TOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    DECFSZ    LOOP2        ;,F
    GOTO    TOP
    DECFSZ    LOOP        ;,F
    GOTO    TOP2
    RETURN
    
MULT
    MOVLW    .16
    MOVWF    TEMP
    CLRF    ACCH
    CLRF    ACCL
    CLRF    ACBH
    CLRF    ACBL
    
MPLOOP
    RRF        ACDH,F
    RRF        ACDL,F
    BTFSC    STATUS,C
    CALL    SUM
    RRF        ACBH,F
    RRF        ACBL,F
    RRF        ACCH,F
    RRF        ACCL,F
    DECFSZ    TEMP,F
    GOTO    MPLOOP
    RETLW    0
    
SUM
    MOVF    ACAL,W
    ADDWF    ACBL,F
    BTFSC    STATUS,C
    INCF    ACBH,F
    MOVF    ACAH,W
    ADDWF    ACBH,F
    RETLW    0

B2BCD
    BANKSEL    FSR
    MOVLW    .24
    MOVWF    COUNT
    CLRF    R0
    CLRF    R1
    CLRF    R2

LOOP16
    RLF        ACCL    ;,F
    RLF        ACCH    ;,F    
    RLF        ACBL    ;,F
    RLF        R2,F
    RLF        R1,F
    RLF        R0,F
    DECFSZ    COUNT,F
    GOTO    ADJDEC
    RETLW    0

ADJDEC
    MOVLW    R2
    MOVWF    FSR
    CALL    ADJBCD
    MOVLW    R1
    MOVWF    FSR
    CALL    ADJBCD
    MOVLW    R0
    MOVWF    FSR
    CALL    ADJBCD
    GOTO    LOOP16

ADJBCD
    MOVLW    03
    ADDWF    INDF,W
    MOVWF    TEMP
    BTFSC    TEMP,3
    MOVWF    00
    MOVLW    30
    ADDWF    00,W
    MOVWF    TEMP
    BTFSC    TEMP,7
    MOVWF    00
    RETLW    00

AD
    ;BANKSEL    ADCON1
    ;MOVLW    B'10010010'
    ;MOVWF    ADCON1
    BANKSEL    ADCON0
    movf    CHANN,W
    call    CANAL
    movwf    ADCON0
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ; Esperamos 1 a 2ms aprox.
    movlw     .8
    movwf    LOOP
    movlw    .200
    movwf    LOOP2
    decfsz    LOOP2,F
    goto    $ - 1
    decfsz    LOOP,F
    goto    $ - 5
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    BSF        ADCON0,GO
    NOP
    NOP
    BTFSC    ADCON0,GO
    GOTO    $-1
    MOVF    ADRESH,W
    MOVWF    ACDH
    BANKSEL    ADRESL
    MOVF    ADRESL,W
    BANKSEL    ADRESH
    MOVWF    ACDL
    MOVLW    .232
    MOVWF    ACAL
    MOVLW    .1
    MOVWF    ACAH
    CALL    MULT
    CALL    B2BCD
    SWAPF    R0,W
    ANDLW    0FH
    MOVWF    NIB1
    MOVLW    30H
    ADDWF    NIB1    ;,F
    MOVF    R0,W
    ANDLW    0FH
    MOVWF    NIB2
    MOVLW    30H
    ADDWF    NIB2    ;,F
    SWAPF    R1,W
    ANDLW    0FH
    MOVWF    NIB3
    MOVLW    30H
    ADDWF    NIB3,F
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    incf    CHANN,F        ; <<< ### Apunta a cada canal por vez
    movlw    .4
    xorwf    CHANN,W
    btfsc    STATUS,Z
    clrf    CHANN
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    RETURN

TX
    BANKSEL    PIR1
    MOVF    NIB1,0

ESP1
    BTFSS    PIR1,TXIF
    GOTO    ESP1
    MOVWF    TXREG
    MOVLW    D'44'

ESP3
    BTFSS    PIR1,TXIF
    GOTO    ESP3
    MOVWF    TXREG
    MOVF    NIB2,0

ESP
    BTFSS    PIR1,TXIF
    GOTO    ESP
    MOVWF    TXREG
    MOVF    NIB3,0

ESP2
    BTFSS    PIR1,TXIF
    GOTO    ESP2
    MOVWF    TXREG
    RETURN

INI
    CLRF    OSCTUNE
    MOVLW    B'01100110'
    MOVWF    OSCCON
    BANKSEL    TRISA            
    MOVLW    B'11111111'        ; <<< ### OK, el que sirve solo es RA5/AN4
    MOVWF    TRISA
    MOVWF    TRISB
    MOVLW    B'10111111'
    MOVWF    TRISC
    MOVLW    B'00100110'        ;VEL TX
    MOVWF    TXSTA
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    movlw    b'11111111'        ; <<< ### El AN5, 6, 7 estan en el TRISE
    movwf    TRISE
    BANKSEL    ANSEL            ; <<< ### banco 3
    movlw    b'11111111'        ; <<< ### Entradas para el ADC
    movwf    ANSEL
    BANKSEL SPBRG            ; <<< ### banco 1
    movlw    b'00100100'        ; <<< ### Al ser envio, se configura TXSTA
    movwf    TXSTA            ; <<< ### con 8bit.
                            ; de esperar para poder enviar un nuevo dato.
    movlw    b'10010010'
    movwf    ADCON1
    clrf    CHANN
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    MOVLW    D'103'
    MOVWF    SPBRG            ;GENERADOR BAUD
    BANKSEL    PIR1            
    BSF        PIR1,TXIF        
    MOVLW    B'10000000'        ;HAB COM BIT7 EN 1    
    MOVWF    RCSTA
    MOVLW    B'10010001'        ;AN4
    MOVWF    ADCON0            ;FOSC/32
    
CICLO
    CALL    AD
    CALL    TX
    MOVLW    D'13'
    
ESP4
    BTFSS    PIR1,TXIF
    GOTO    ESP4
    MOVWF    TXREG
    MOVLW    D'10'
    
ESP5
    BTFSS    PIR1,TXIF
    GOTO    ESP5
    MOVWF    TXREG
    NOP
    NOP

ESP6
    BTFSS    PIR1,TXIF
    GOTO    ESP6
    MOVLW    D'250'
    CALL    RETARDO
    GOTO    CICLO

    END
```


----------



## kummell (May 22, 2010)

Con el ADCON0 escoges los canales que quieras volver analogos, mira el registro en el datasheet.


----------



## jerrydevil555 (Ene 21, 2012)

soy nuevo en el foro necesito un favor estoy utilizando el pic 16f877A no se mucho apenas retome y no puedo encender unos leds con un simple boton, mi programa es el siguiente.
La entrada se supone que es en puerto a 0,1 y la salida es el puerto b no me funciona en proteus


__CONFIG _WDT_OFF&_PWRTE_ON&_XT_OSC&_LVP_OFF&_CP_OFF ; Configuración para el programador

LIST P=16F877A
INCLUDE <P16F877A.inc>

PORTA EQU 0x05
PORTB EQU 0x06

ORG 0X00
GOTO inicio
ORG 0X05

inicio
	BCF STATUS,RP1 ; BANCO 1
	BSF STATUS,RP0; Cambia al banco 0
	CLRF PORTA ; inicicaliza el puerto a
	CLRF PORTB ; inicializa el puerto b
    MOVLW B'00001100';
	MOVWF ADCON1;
	MOVLW B'11111111' ;
	MOVWF TRISA;
	MOVLW B'00000000';
	MOVWF TRISB
	BCF STATUS,RP0; BANCO 0

PRINCIPAL
	CLRF PORTB
	CLRF PORTA
	BTFSS PORTA,0;
	GOTO COMP2B2; 
	GOTO COMPB2;	

COMPB2 ; 
	BTFSC PORTA,1;
	GOTO TRES;  
	GOTO DOS; 

COMP2B2 ; 
	BTFSC PORTA,1;
	GOTO CUATRO; 
	GOTO UNO;

UNO
	MOVLW B'00000001'
	MOVWF PORTB
	GOTO PRINCIPAL

DOS
	MOVLW B'00000010';
	MOVWF PORTB
	GOTO PRINCIPAL

TRES
	MOVLW B'00000100'
	MOVWF PORTB
	GOTO PRINCIPAL

CUATRO
	MOVLW B'11110000'
	MOVWF PORTB
	GOTO PRINCIPAL


END ; FIN DEL PROGRAMA


----------



## D@rkbytes (Ene 21, 2012)

jerrydevil555 dijo:


> soy nuevo en el foro necesito un favor estoy utilizando el pic 16f877A no se mucho apenas retome y no puedo encender unos leds con un simple boton, mi programa es el siguiente.
> La entrada se supone que es en puerto a 0,1 y la salida es el puerto b no me funciona en proteus


Saludos.
Le hice algunos cambios a tu programa y ya funciona.
Al menos los LED's ya se prenden 
Datos cambiados:
TRISA
CLRF PORTA
ADCON1  y FUSES


----------

