Cómo usar un puerto entrada analógica y entrada digital en CCS (lenguaje C)

#1
Estoy usando el PIC16F873A
Quiero usar el puerto A como entrada analógica y digital a la misma vez, debido a que quiero leer el voltaje proveniente de un LM35 (pin RA0) y dos entradas donde se leerán los pulsadores RA4 y RA5.
Por favor si me pueden ayudar en la programación

Código:
//termostato 
#include <16F873A.h>
#device adc=10
#FUSES NOWDT                    
#FUSES HS                       
#FUSES NOPUT                    
#FUSES NOPROTECT                
#FUSES NODEBUG                 
#FUSES NOBROWNOUT              
#FUSES NOLVP                   
#FUSES NOCPD                    
#use delay(clock=20000000)
#define time 200
#define use_portb_lcd true    
#include <lcd.c>    

#BYTE TRISA = 0x85 
#BYTE PORTA = 0x05
#BYTE PC=0x07

unsigned int16 adc;
float tamb;
int w=0;
int i=0;
int tdes[41]=
               {0,1,2,3,4,5,6,7,8,9,10,11,12,
                13,14,15,16,17,18,19,20,21,
                22,23,24,25,26,27,28,29,30,
                31,32,33,34,35,36,37,38,39,40};

int tb[41]=
               {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
                0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
                0x28};

void main(){

bit_set (TRISA , 4);          // A4 como entrada digital, para el pulsador
bit_set (TRISA , 5);          // A5 como entrada digital, para el pulsador
set_tris_c(0b00000000);    
pc=0b00000000;             
   
setup_adc_ports(AN0);         //A0 como entrada analogica, para lm35     
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
delay_us(20);

lcd_init();         
lcd_putc("\\f");     
lcd_gotoxy(1,1);               
printf(lcd_putc,"   Bienvenido");  
delay_ms(500);

while (true)
{

adc=read_adc();                
delay_ms(1);                    
tamb=adc*(0.48875);

lcd_putc(\'\\f\');
lcd_gotoxy(1,1);             
printf(lcd_putc,"Temp-des:%d C",tdes[w]);  
lcd_gotoxy(1,2);
printf(lcd_putc,"Temp-amb:%f C",tamb);
output_c(tb[i]);
delay_ms(10);

 if(input(pin_a4)==1){
delay_ms(time);
w++;
i++;
 if((w>41)&&(i>0x29))
 {
 w=0;
 i=0;
 }

lcd_putc(\'\\f\');
lcd_gotoxy(1,1);            
printf(lcd_putc,"Temp-des:%u C",tdes[w]);  
lcd_gotoxy(1,2);
printf(lcd_putc,"Temp-amb:%f C",tamb);
output_c(tb[i]);
delay_ms(100);

}
 if (input(pin_a5)==1){
delay_ms(time);
w--;
i--;
 if((w==255)&&(i==255))
{
 w=41;
 i=0x29;
}
lcd_putc(\'\\f\');
lcd_gotoxy(1,1);            
printf(lcd_putc,"Temp-des:%u C",tdes[w]); 
lcd_gotoxy(1,2);
printf(lcd_putc,"Temp-amb:%f C",tamb);
output_c(tb[i]);
delay_ms(100);
}
}
} ...
 
#2
Parece que esta bien, ¿que es lo que te falla?

El código es que no corre en mi compilador.
 
Última edición:
#4
Intenta declarando la función set_adc_channel() dentro del bucle...

PHP:
#include <16F84A.h> 
#device adc=8 
 
#FUSES NOWDT                    
#FUSES HS                       
#FUSES NOPUT                    
#FUSES NOPROTECT                
#FUSES NODEBUG                 
#FUSES NOBROWNOUT              
#FUSES NOLVP                   
#FUSES NOCPD
 
#use delay(clock=4000000) 
 
#include <LCD420.C> 
 
float sensor, temper;
 
void main(){ 
   setup_adc_ports(ALL_ANALOG); 
   setup_adc(adc_clock_internal); 
 
   lcd_init(); 
   for(;;){ 
     set_adc_channel(0); 
         delay_ms(10); 
         sensor = read_adc(); 
         temper = (1.97 * sensor);
     lcd_gotoxy(1,1); 
     printf(lcd_putc "    %.1f%CC      ",temper,0xDF); 
}
 
#5
Este código a mi me funciona perfecto:

Código:
//Placa entrenadora PicEBasic (PIC16F876)
#include <16F876.h>
#device adc=10
#use delay (clock = 20000000) //Reloj a 20Mhz
#FUSES HS         //Fast clock
#FUSES PUT        //Power-up Timer
#FUSES BROWNOUT   //Brown-out reset 
#FUSES NOWDT      //No, Watchdog Timer 
#FUSES NOCPD      //No, Data EEPROM Memory Code Protection
#FUSES NOPROTECT  //No, (CP) Flash Program Memory Code Protection
#FUSES NOLVP      //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

//#use standard_io (a) //Por defecto
//#use standard_io (b) //Por defecto
//#use standard_io (c) //Por defecto
//#use fast_io (a)
//#use fast_io (b)
//#use fast_io (c)

#include "Flex_Lcd.c"
#use rs232 (UART1, BAUD = 4800, PARITY=N, BITS=8, TIMEOUT=1)

#BYTE PORTA = 0x05
#BYTE PORTB = 0x06
#BYTE PORTC = 0x07
#BYTE TRISA = 0x85 
#BYTE TRISC = 0x86
#BYTE TRISC = 0x87

void main()
{
   //Configuración general Pic EBasic
   setup_adc_ports(NO_ANALOGS); //Puerto como I/O
   setup_adc(ADC_OFF); //Módulo ADC a Off
   setup_ccp1(CCP_OFF); //Módulo CCP a Off
   set_tris_a(0b11111111); 
   set_tris_b(0b11011110);
   set_tris_c(0b11111111);

   //Constantes (codigos de control ASCII del hyperterminal)
   Const int FF = 0x0c;  //FF, Avance de pagina
   Const int BELL = 0x07;  //BELL, Señal sonora
   Const int SP = 0x20; //SP, Espacio
   Const int BKSP = 0x08;  //BKSP, Retroceso
   Const int CR = 0x0d; //CR, retorno de carro
   Const int LF = 0x0a; //LF, Salto de linea
   Const int CTRLZ = 0x1a; //Ctrl-z
   Const int ESC = 0x1b;   //Escape

   //setup_adc_ports(NO_ANALOGS); //Puerto como I/O
   lcd_init();
   _lcdclear();
   
   //setup_adc_ports(ALL_ANALOG);     //AN4 como entrada analogica, para lm35
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(4);
   delay_us(20); 

 while(TRUE){
   Int16 _adc;
   //setup_adc_ports(ALL_ANALOG); //Puerto como Analogico
   _adc = read_adc();
   //setup_adc_ports(NO_ANALOGS); //Puerto como I/O
   _lcdline1home();
   printf(lcd_putc, "ADC:%Lu   ", _adc);
   //lcd_putc("hello");
   printf("ADC:%Lu", _adc);
   putc(cr);
   putc(lf);
   
   if (bit_test(portb, 2) == 0) Bit_clear(PORTB, 0);
   Bit_set(PORTB, 5);
   delay_ms(100);
   if (bit_test(portb, 2) == 0) Bit_set(PORTB, 0);
   Bit_clear(PORTB, 5);
   Delay_ms(100);
 }
}
El display está en el puerto A también, por lo que este trabaja como analógico e I/O.
 
Última edición:
#7
//#use standard_io (a) //Por defecto
//#use standard_io (b) //Por defecto
//#use standard_io (c) //Por defecto

Cuando no se indica nada el ccs incorpora la #use standard_io (letra del port), esto implica que se le deja al compilador la misión de configurar los pin como analógicos o I/O que son utilizados en sus funciones.
Entonces, llamamos una sola vez a "setup_adc_ports(NO_ANALOGS); //Puerto como I/O", esto indica que se elije por defecto los "NO_ANALOGS", por lo tanto al llamar a una función del sistema el compilador almacena "NO_ANALOGS" y luego reconfigura los pin que utiliza la función según la necesidad de esta, posteriormente al terminar la función vuelve a configurar los puertos por defecto "NO_ANALOGS", sin embargo, si la ultima llamada que hicimos fue "ALL_ANALOG", esta quedará por defecto y el programa no funcionará ya que este cambio automático no se aplica al manejo directo de puertos, al parecer solo se aplica a las funciones.



Yo solo uso la #use fast_io y no tengo un circuito donde pueda probar exactamente tu configuración.
La "#use fast_io" obliga al programador a definir en todo momento como trabajan los puertos, el compilador por su cuenta no cambia la configuración de los pin. Puedes probar a incorporarla en tu código, lo mismo te soluciona el problema, pero ten en cuenta que prevalece la ultima configuración de puertos que hagas. Así que la ultima configuración tiene que ser la que tu deseas. Seguramente con esta ultima opción el uso de NO_ANALOGS o ALL_ANALOG, puede generar problemas dependiendo de donde los coloques o todo lo contrario.

Nota: el programa funciona perfectamente en hardware.
 
Última edición:
#8
:unsure: Lo digo es por el "//" al comienzo de la línea, al colocar eso, la línea de código se convierte en comentario y pierde efecto...
 
#9
Esto es lo que predomina, lo demás han sido pruebas para ver lo que pasa.

PHP:
void main()
{
   //Configuración general Pic EBasic
   setup_adc_ports(NO_ANALOGS); //Puerto como I/O

------------------------------------------------------------------------

//Placa entrenadora PicEBasic (PIC16F876)
#include <16F876.h>
#device adc=10
#use delay (clock = 20000000) //Reloj a 20Mhz
#FUSES HS         //Fast clock
#FUSES PUT        //Power-up Timer
#FUSES BROWNOUT   //Brown-out reset 
#FUSES NOWDT      //No, Watchdog Timer 
#FUSES NOCPD      //No, Data EEPROM Memory Code Protection
#FUSES NOPROTECT  //No, (CP) Flash Program Memory Code Protection
#FUSES NOLVP      //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#include "Flex_Lcd.c"
#use rs232 (UART1, BAUD = 4800, PARITY=N, BITS=8, TIMEOUT=1)

#BYTE PORTA = 0x05
#BYTE PORTB = 0x06
#BYTE PORTC = 0x07
#BYTE TRISA = 0x85 
#BYTE TRISB = 0x86 //Corregido: antes decía TRISC.
#BYTE TRISC = 0x87

void main()
{
   //Configuración general Pic EBasic
   setup_adc_ports(NO_ANALOGS); //Puerto como I/O
   setup_adc(ADC_OFF); //Módulo ADC a Off
   setup_ccp1(CCP_OFF); //Módulo CCP a Off
   set_tris_a(0b11111111); 
   set_tris_b(0b11011110);
   set_tris_c(0b11111111);

   //Constantes (codigos de control ASCII del hyperterminal)
   Const int FF = 0x0c;  //FF, Avance de pagina
   Const int BELL = 0x07;  //BELL, Señal sonora
   Const int SP = 0x20; //SP, Espacio
   Const int BKSP = 0x08;  //BKSP, Retroceso
   Const int CR = 0x0d; //CR, retorno de carro
   Const int LF = 0x0a; //LF, Salto de linea
   Const int CTRLZ = 0x1a; //Ctrl-z
   Const int ESC = 0x1b;   //Escape

   lcd_init();
   _lcdclear();
   
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(4);
   delay_us(20); 

 while(TRUE){
   Int16 _adc;
   _adc = read_adc();
   _lcdline1home();
   printf(lcd_putc, "ADC:%Lu   ", _adc);
   //lcd_putc("hello");
   printf("ADC:%Lu", _adc);
   putc(cr);
   putc(lf);
   
   if (bit_test(portb, 2) == 0) Bit_clear(PORTB, 0);
   Bit_set(PORTB, 5);
   delay_ms(100);
   if (bit_test(portb, 2) == 0) Bit_set(PORTB, 0);
   Bit_clear(PORTB, 5);
   Delay_ms(100);
 }
}
 
Última edición por un moderador:
#10
:unsure: Pero mientras sigas diciendo:

PHP:
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
El puerto analógico no se va activar, no se, digo yo...
 
#11
Lo he vuelto a probar en mi hardware porque no había definido el "TRISB", y sigue funcionado correctamente.

Código:
#BYTE TRISC = 0x86 (mal) ----> #BYTE TRISB= 0x86 (Ok)
Este que parece más lógico también me funciona, hace lo mismo que el anterior.

PHP:
//Placa entrenadora PicEBasic (PIC16F876)
//Test puerto RS232
#include <16F876.h>
#device adc=10
#use delay (clock = 20000000) //Reloj a 20Mhz
#FUSES HS         //Fast clock
#FUSES PUT        //Power-up Timer
#FUSES BROWNOUT   //Brown-out reset 
#FUSES NOWDT      //No, Watchdog Timer 
#FUSES NOCPD      //No, Data EEPROM Memory Code Protection
#FUSES NOPROTECT  //No, (CP) Flash Program Memory Code Protection
#FUSES NOLVP      //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#include "Flex_Lcd.c"
#use rs232 (UART1, BAUD = 4800, PARITY=N, BITS=8, TIMEOUT=1)

#BYTE PORTA = 0x05
#BYTE PORTB = 0x06
#BYTE PORTC = 0x07
#BYTE TRISA = 0x85 
#BYTE TRISB = 0x86
#BYTE TRISC = 0x87

void main()
{
   //Configuración general Pic EBasic
   setup_adc_ports(NO_ANALOGS); //Puerto como I/O
   setup_adc(ADC_OFF); //Módulo ADC a Off
   setup_ccp1(CCP_OFF); //Módulo CCP a Off
   set_tris_a(0b11111111); 
   set_tris_b(0b11011110);
   set_tris_c(0b11111111);

   //Constantes (codigos de control ASCII del hyperterminal)
   Const int FF = 0x0c;  //FF, Avance de pagina
   Const int BELL = 0x07;  //BELL, Señal sonora
   Const int SP = 0x20; //SP, Espacio
   Const int BKSP = 0x08;  //BKSP, Retroceso
   Const int CR = 0x0d; //CR, retorno de carro
   Const int LF = 0x0a; //LF, Salto de linea
   Const int CTRLZ = 0x1a; //Ctrl-z
   Const int ESC = 0x1b;   //Escape

   setup_adc_ports(NO_ANALOGS); //Puerto como I/O
   lcd_init(); //Líneas de datos LCD a 4Bit (PORTA).
   _lcdclear();
   
   setup_adc_ports(ALL_ANALOG);   //AN4 como entrada analogica, para lm35
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(4);
   delay_us(20); 

 while(TRUE){
   Int16 _adc;
   setup_adc_ports(ALL_ANALOG); //Puerto como analogico
   _adc = read_adc();
   setup_adc_ports(NO_ANALOGS); //Puerto como I/O, a partir de aquí solo digital.
   _lcdline1home();
   printf(lcd_putc, "ADC:%Lu   ", _adc);
   //lcd_putc("hello");
   printf("ADC:%Lu", _adc);
   putc(cr);
   putc(lf);
   
   if (bit_test(portb, 2) == 0) Bit_clear(PORTB, 0);
   Bit_set(PORTB, 5);
   delay_ms(100);
   if (bit_test(portb, 2) == 0) Bit_set(PORTB, 0);
   Bit_clear(PORTB, 5);
   Delay_ms(100);
 }
}
 
Última edición por un moderador:
Arriba