TODOPIC

Microcontroladores PIC => Primeros pasos - Iniciación a los microcontroladores => Mensaje iniciado por: Mecátronica2012 en 24 de Enero de 2019, 02:42:16

Título: Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 24 de Enero de 2019, 02:42:16
Buenas tardes, estoy construyendo un sencillo proyecto para leer la temperatura de un sensor probablemente un lm35 y desplegarla  en dos displays de 7 segmentos usando multiplexacion.  El programa lo estoy planteando en C en el ide del Pic c compiler, debido a que es algo didáctico, mi intención es prescindir de las funciones del ADC que trae el compilador que a mi gusto abstraen demasiado y alejan al programador de los "fierros".
En este momento estoy atorado, ya que no se como leer el resultado obtenido de la conversion, de los registros adresl y adresh, en el modo de 10 bits que es el que quiero usar, se usaría el resultado del adresl, y los dos bits menos significativos del adresl dependiendo de la justificación usada.
Una idea que rondaba en mi cabeza era hacer una especie de concatenacion, convirtiendo el valor de cada registro a char, concatenarlos y luego castear nuevamente a int16, quizás esté diciendo alguna burrada, alguien me podría orientar?
Muchas gracias a todos.
Título: Re:Concatenar contenido de dos registros
Publicado por: AleSergi en 24 de Enero de 2019, 03:42:49
un desplazamiento de bits y listo....  (está en el return;)

https://circuitdigest.com/microcontroller-projects/pic-microcontroller-pic16f877a-adc-tutorial
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 24 de Enero de 2019, 06:47:37
Considero que si te planteas representarlo como entero, lo justifiques a la derecha.

Y luego en un entero de 16 bits podes desplazar las 2 cantidades:

tu_var = ADRESH << 8;
tu_var |= ADRESL;


Sino la otra, busca lo que es una union, y hace la union de 2 variables  de 8bits con una de 16 bits... De esa forma podes acceder indivualmente sin hacer Shifts.
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 02 de Febrero de 2019, 17:59:07
Buenas tardes, muchas gracias por la ayuda.
En referencia al comentario de killerjc, aun no comprendo del todo los corrimientos, si hicieramos un corrimiento a la derecha 10 veces
algo asi :
 tu_var = ADRESH << 10;

Para acomodar en el segundo byte de tu_var,  los dos bits que llevamos arrastrando del  ADRESH, y dejar reservados los primeros 8 bits de la variable  tu_var , para guardar lo que tengamos en el ADRESL, realizamos la operacion or :
tu_var = tu_var | adresl;
Es correcto este planteamiento? gracias por la ayuda
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 02 de Febrero de 2019, 18:26:18
Si no me equivoco en XC8 podes acceder a los 16bits directamente del ADC... En caso de que unicamente puedas acceder a los 8 bits podes usar:

- Una union
- Desplazamientos.


Respecto al desplazamiento, tenes que recordar que estas desplazando bits. Supongamos que tenes el valor 10 1101 0110 en el ADC ( 10 bits ), es decir:
ADRESH = 0000 0010
ADRESL = 1101 0110

Desplazar es simplemente mover todo 1 espacio a la izquierda o derecha... Por ejemplo si ADRESH lo desplazo 2 veces a la izquierda me quedaria 0000 1000
Si tuviera una variable de 16 bits y le guardo con el valor de ADRESH  desplazado 8 lugares a la izquierda quedaria asi:

ADRESH desplazado 8 veces a la izquierda:  0000 0010 0000 0000

Si luego le hago una OR con ADRESL quedaria:

my_var  0000 0010 0000 0000
ADRESL  0000 0000 1101 0110
---------------------------------------
OR ->    0000 0010  1101 0110


Quedando tu valor de 16 bits completo.
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 05 de Febrero de 2019, 00:36:00
Más claro imposible, muchas gracias por la ayuda, cuando termine el proyecto pondré el código por aquí
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 30 de Marzo de 2019, 00:52:55
Aqui pongo el programa terminado y funcionando, por si a alguien le sirve de algo, saludos :


#include <16f877a.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#fuses XT,NOWDT
#use delay (clock=4M)
#BYTE TRISA=0x85
#BYTE TRISB=0x86
#BYTE PORTA=0x05
#BYTE PORTB=0x06
#BYTE TRISD=0x88
#BYTE OPTION_REG=0x81
#BYTE ADCON0=0x1F    //REGISTROS del ADC
#BYTE ADCON1=0x9F
#BYTE ADRESH=0x1E
#BYTE ADRESL=0x9E
#BYTE ANSEL=0x9B
#define lcd_rs_pin pin_d0
#define lcd_rw_pin pin_d1
#define lcd_enable_pin pin_d2
#define lcd_data4 pin_d4
#define lcd_data5 pin_d5
#define lcd_data6 pin_d6
#define lcd_data7 pin_d7
#include <lcd.c>
#define resolucion 0.004882
#define resCelcius 0.4882
// 1 paso del analogico es igual a 0.4882 grados
void proceso();
int16 LectorADC();

void main()
{
    TRISD = 0x00;
    TRISA = 0x0000001;
    disable_interrupts(GLOBAL);                        //TODAS las interrupciones desactivadas
    ADCON0 = 0x81;
    ADCON1 = 0xCE;
    lcd_init();
    lcd_gotoxy(1,1);
    printf(lcd_putc, "temp = ");
   
    while(true)
    {
        proceso();           
         
    }
   
}

void proceso()
{
     float temp = 0.0;
     int16 retAnalogico = 0;
     retAnalogico = LectorADC();
     temp = resCelcius * retAnalogico;
     lcd_gotoxy(8,1);
     printf(lcd_putc, "%3.1f",temp);
     delay_ms(200);                     //tomara muestras cada 200ms
}

int16 LectorADC()
{
     int16 analogico = 0;
      delay_ms(1);                      //tiempo de establecimiento
     bit_set(ADCON0,2);                //inicia conversion
     while(bit_test(ADCON0,2));        //se espera a que termine la conversion
     analogico =  ADRESH <<8;          //desplazmos 8 veces a la izquierda
     analogico = analogico | ADRESL;   //se realiza operacion or
     return analogico;
}
Título: Re:Concatenar contenido de dos registros
Publicado por: Eduardo2 en 30 de Marzo de 2019, 11:13:41
Como te dijeron,  otra manera de hacerlo es mediante union.

Definís la union:     union HL {int16 hl ; struct {int8 l, h ;};};

Y en la rutina de lectura:

int16 LectorADC()
{
     union HL analog ;

     bit_set(ADCON0,2);                //inicia conversion
     while(bit_test(ADCON0,2));        //se espera a que termine la conversion

     analog.h = ADRESH ;
     analog.l = ADRESL ;
     return analog.hl;
}
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 12 de Abril de 2019, 15:30:43
Buenos dias, estoy empezando a hacer mis primeros programas utilizando timers e interrupciones, este tiene el objetivo de capturar la tecla pulsada utilizando la interrupcion por cambio de estado del RB4-RB7, esa parte funciona bien, sin embargo le agregue el uso del timer 0, para cada segundo mardarlo a leer una temperatura y desplegarla en la parte baja del lcd, esto ultimo no lo realiza y no logro dar con el error o quizas estoy planteando mal el programa, alguien podria echarme un cable? saludos gracias.



#include <16f877a.h>
#fuses XT,NOWDT
#use delay (clock=4M)
#define lcd_data_port getenv("sfr:portd")
#define lcd_enable_pin pin_d0
#define lcd_rs_pin pin_d1
#define lcd_rw_pin pin_d2
#define use_portb_kbd true
#include <lcd.c>
#include <KBD4x4.c>
#BYTE INTCON=getenv("sfr:INTCON")
#BYTE TRISA=getenv("sfr:INTCON")
#BYTE TRISB=getenv("sfr:TRISB")
#BYTE TRISD = getenv("sfr:trisd")
#BYTE OPTION_REG=getenv("sfr:OPTION_REG")
#BYTE ADCON0=getenv("sfr:ADCON0")    //REGISTROS del ADC
#BYTE ADCON1=getenv("sfr:ADCON1")
#BYTE ADRESH=getenv("sfr:ADRESH")
#BYTE ADRESL=getenv("sfr:ADRESL")
#BYTE TMR0=getenv("sfr:TMR0")
#define resolucion 0.004882
#define resCelcius 0.4882

char k;
int contador = 0;                   //Contador usado para el timer
void muestraBoton();                //prototipos de funciones
int16 LectorADC();
void procesoLeeTemp();

#INT_RB
void servicioIntRB()                      //rutina de interrupcion
{
    k = kbd_getc();
    bit_clear(INTCON,0);;            //bandera de la interrupcion a 0 nuevamente
    muestraBoton();
}

#INT_TIMER0
void servicioInttmr0()                     //rutina de interrupcion
{
    contador++;
    TMR0=22;                      //Se recarga el timer
    bit_clear(INTCON,2);          //Se vuelve a poner a 0 el bit de bandera de desbordamiento
    if (contador == 17)           //si ha transcurrido un segundo
    {
        contador = 0;
        procesoLeeTemp();
    }

}

void main()
{
     TRISA = 0x1;           //Pin RA0 como entrada para analogico
     TRISB = 0xff;         //puerto b como entrada
     TRISD = 0x00;         //puerto d como salida
     port_b_pullups(true);
     lcd_init();
     kbd_init();
     lcd_gotoxy(1,1);
     printf(lcd_putc,"iniciando");
     delay_ms(1000);
     lcd_putc("\f");              //se borra la pantalla
     lcd_gotoxy(1,1);
     printf(lcd_putc,"Teclado con");
     lcd_gotoxy(1,2);
     printf(lcd_putc,"interrupciones");
     delay_ms(2000);
     lcd_putc("\f");
     lcd_gotoxy(1,2);
     printf(lcd_putc,"Temp = ");
     OPTION_REG=0b00000111;   //preescaler 1:256
     ADCON0 = 0x81;
     ADCON1 = 0xCE;
     INTCON = 0xA8;  ////habilitacion global de interrupcion, habilitacion de int por cambio de estado RB4-RB7,flag RBIE a 0,habilitacion int timer0
     TMR0=22;                 //se carga con un valor de 256 - 22, para contar 60ms

    while(true)
    {
             
    }

}

void muestraBoton()
{
    if (k!=0)
         {
            lcd_gotoxy(1,1);
            printf(lcd_putc,"tecla pulsada: %c",k);
         }
}

void procesoLeeTemp()
{
     float temp = 0.0;
     int16 retAnalogico = 0;
     retAnalogico = LectorADC();
     temp = resCelcius * retAnalogico;
     lcd_gotoxy(7,2);
     printf(lcd_putc, "%3.1f",temp);     
}

int16 LectorADC()
{
     int16 analogico = 0;
     delay_ms(1);                      //tiempo de establecimiento
     bit_set(ADCON0,2);                //inicia conversion
     while(bit_test(ADCON0,2));        //se espera a que termine la conversion
     analogico =  ADRESH <<8;          //desplazmos 8 veces a la izquierda
     analogico = analogico | ADRESL;   //se realiza operacion or
     return analogico;
}
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 13 de Mayo de 2019, 16:12:11
Alguien sabe si en proteus está simulada la interrupción por termino de conversión ADC?
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 13 de Mayo de 2019, 18:13:33
en CSS tenes funcion para todo, asi no tocas los registros y todo se vuelve mas facil, seguramente habras visto codigos por ahi que usan read_adc()

Busca como leer el ADC.
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 14 de Mayo de 2019, 18:02:56
Gracias por contestar, entiendo eso que comentas, pero mi duda actual es si en proteus está simulada la interrupción por ADC
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 15 de Mayo de 2019, 06:39:25
Gracias por contestar, entiendo eso que comentas, pero mi duda actual es si en proteus está simulada la interrupción por ADC

Tengo entendido que si... En realidad no es que esta habilitada la interrupcion por ADC, en realidad esta habilitada la interrupcion, ya que salta al mismo lugar y luego es el programa quien determina que tipo de interrupcion fue. Asi que si funciona una, deberia funcionar la otra :P
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 15 de Junio de 2019, 01:29:57
Les agradezco a todos la ayuda brindada.
En este momento traigo una inquietud respecto a la comunicación ethernet tcp-ip. El proyecto hace necesario enviar una serie de strings, desde una aplicación de escritorio escrita en c#, hacia un microcontrolador situado remotamente, he pensado en usar sockets, tengo nociones de como hacerlo del lado de la aplicación de c#, pero del lado del microcontrolador estoy muy perdido en lo que respecta a recibir los paquetes y almacenarlos en la ram del micro. Sé que debo usar un modulo ethernet, tengo uno de hecho (un
ENC28J60), sería una comunicación de punto a punto, pero no he encontrado demasiada documentación al respecto unido a mí falta de conocimientos en lo que respecta a redes, alguien como podría abordar esto o algún ejemplo de código?
Muchas gracias a todos
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 15 de Junio de 2019, 07:47:12
Ejemplo no .... deberias encontrar ejemplos en la Microchip Libraries for Applicattion de Microchip o resumido (MLA)

En si ese modulo de ethernet es un modulo que no hace completamente todo, sino que hace una parte... La otra parte la debe hacer el microcontrolador, por lo tanto vas a tener que poner un stack TCP/IP sobre el PIC.

Si posees un modulo ethernet con otro intergado, por ejemplo hace poco se trato del W5500 va a ser un poco mas simple, ya que tiene el stack TCP/IP incorporado, aunque vas a tener que buscar algun codigo y tal ves portarlo al PIC.

En fin... Si vas por el primer caso, lo mas simple es que selecciones un IP en el rango del PC (IP fijo), por ejemplo si tu PC es 192.168.0.2 podrias ponerle 192.168.0.10. A esa direccion vas a abrir un socket y enviar tus cosas desde la PC. Luego en el micro preguntaras si es que llego algo por la red, como para leerlo y mostrarlo o enviarlo.
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 29 de Junio de 2019, 18:01:07
Muchas gracias, investigando en los foros de microchip encontre algunos ejemplos para uso de sockets, creen que habra que ir sobre la serie PIC18 para implementar el stack TCP/IP de microchip, o bastara por ejemplo con los 7kb de memoria de programa y 368bytes de ram de un PIC16f88? , estoy poco familiarizado con los PIC18, preferira un PIC16 si fuera posible
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 29 de Junio de 2019, 21:02:23
Si lo haces en C, va a haber poca diferencia entre un PIC16 y un PIC18.

Y siempre tenes algun tutorial:

https://www.studentcompanion.co.za/interfacing-enc28j60-ethernet-controller-with-pic-microcontroller-xc8/
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 02 de Septiembre de 2019, 01:15:21
Buenas tardes a todos, he estado tratando de implementar en un programa que estoy realizando las interrupciones por cambio de estado en los pines RB4-RB7, sin embargo habra manera de que solo lance esta interrupcion en determinado flanco, ya sea el de subida o de bajada? he buscado informacion pero no encuentro nada al respecto.
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 02 de Septiembre de 2019, 12:49:36
Buenas tardes a todos, he estado tratando de implementar en un programa que estoy realizando las interrupciones por cambio de estado en los pines RB4-RB7, sin embargo habra manera de que solo lance esta interrupción en determinado flanco, ya sea el de subida o de bajada? he buscado información pero no encuentro nada al respecto.

La interrupción se dispara por cambio de nivel (los dos flancos podríamos pensar)..
Si buscas un flanco ascendente, no vas a evitar que entre en un flanco descendente a tu interrupción. Pero lo que si podes evitar es realizar algo.
Entonces necesito determinar cuando es ascendente. Lo que voy a hacer es guardar el valor de la entrada que me interesa. Por ejemplo imagínate quiero saber el flanco ascendente de RB6.

Tengo las siguientes situaciones donde entrarías a tu interrupción:

- Que cambie cualquier otra entrada
- Que cambie la entrada RB6 de 1 a 0
- Que cambie la entrada RB6 de 0 a 1

En la unica que voy a querer hacer algo es en la tercera.
Por lo que cada vez que entre a la interrupción voy a fijarme el valor de RB6 con el valor de la misma entrada que tenia guardado de la ultima ves que entro a la interrupción.
Si lo que tenia guardado es en 0, y paso a 1, entonces hubo un flanco ascendente y actúo en consecuencia. En todos los casos debo actualizar los valores que tengo guardado de las entrada asi determinar que flanco es.
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 03 de Septiembre de 2019, 01:42:53
Gracias me funciono a la perfeccion, pongo el codigo de la funcion de interrupcion :


int volatile CurrentState;
int volatile PreviusState;
void Isr_ToggleBit();

void interrupt Isr_ChangeState()
{
    if (INTCONbits.RBIF == 1)
    {
        //Se guarda el estado actual
        if (PORTBbits.RB7 == 1)
        {
            CurrentState = 1;
        }
        else
        {
            CurrentState = 0;
        }
       
        //se valida si es flanco ascendente
        if ((PreviusState == 0) && (CurrentState == 1))
        {
            Isr_ToggleBit();
        }
    }
   
    PreviusState = CurrentState;
    INTCONbits.RBIF = 0;
}
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 03 de Septiembre de 2019, 06:46:23
El if no tiene sentido...
Código: C
  1. void interrupt Isr_ChangeState()
  2. {
  3.     if (INTCONbits.RBIF == 1)
  4.     {
  5.         CurrentState = PORTBbits.RB7;
  6.        
  7.         //se valida si es flanco ascendente
  8.         if ((PreviusState == 0) && (CurrentState == 1))
  9.         {
  10.             Isr_ToggleBit();
  11.         }
  12.  
  13.     PreviusState = CurrentState;
  14.     INTCONbits.RBIF = 0;
  15.  
  16.     }
  17. }

Y tambien estaba pensando si es posible hacerlo asi, ya que solo me interesa cuando sea menor es decir Previous en 0 y Current en 1.
Código: C
  1. void interrupt Isr_ChangeState()
  2. {
  3.     if (INTCONbits.RBIF == 1)
  4.     {
  5.         CurrentState = PORTBbits.RB7;
  6.        
  7.         //se valida si es flanco ascendente
  8.         if (PreviusState < CurrentState)
  9.         {
  10.             Isr_ToggleBit();
  11.         }
  12.  
  13.     PreviusState = CurrentState;
  14.     INTCONbits.RBIF = 0;
  15.  
  16.     }
  17. }
Título: Re:Concatenar contenido de dos registros
Publicado por: Mecátronica2012 en 11 de Septiembre de 2019, 18:41:54
Muchas gracias por la ayuda, ahora estoy empezando a introducirme a la gama PIC18, en concreto con el 18F4550, pero el manejo de los bits de configuracion es un poco mas lioso y no me aclaro muy bien con la parte que tiene que ver con la configuracion del oscilador, quiero manejar una frecuencia de 4mhz, usando un oscilador externo de cristal, sin preescaler ni postacaler de ningun tipo :

// CONFIG1L
#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = XT_XT     // Oscillator Selection bits (XT oscillator (XT))
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

esta correcto ?
Una duda mas , este bit : #pragma config PBADEN = OFF, segun la descripcion, los bits, RB4-rb0 son configurados como analogicos en el reset, pero haciendo pruebas no he encontrado ninguna diferencia entre dejarlo en 1 o en 0, alguien sabe que utilidad tiene este bit?
Un saludo a todos
Título: Re:Concatenar contenido de dos registros
Publicado por: KILLERJC en 11 de Septiembre de 2019, 19:57:58
El USB necesita si o si 6Mhz o 48Mhz para funcionar.
Por lo tanto si usas el USB vas a necesitar una de esas dos frecuencias. La primera es con un cristal directo, y la segunda usando el PLL.

La mejor forma de entender el oscilador es viendo el diagrama del mismo. El diagrama lo tenes en la parte de "oscilador" en el datasheet. Y necesitas seguir la "linea" desde la entrada del oscilador hacia donde quieras ir.

El PLL necesita si o si una frecuencia de 4Mhz. Si pones un cristal mas grande entones tenes que dividirlo para eso esta el PLLDIV

Citar
quiero manejar una frecuencia de 4mhz, usando un oscilador externo de cristal, sin preescaler ni postacaler de ningun tipo :

Suponiendo que tenes un cristal de 4Mhz y necesitas 4Mhz, entonces no vas a poder usar el USB:

Código: C
  1. #pragma config FOSC = XT_XT     // Oscillator Selection bits (XT oscillator (XT))
  2. #pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])

Y lo demas no importa, Estamos seleccionado XT sin el PLL, y sin preescaler (1:1)

Si necesitas si o si USB, Entonces no vas a lograr tener tus 4Mhz, solo vas a lograr un minimo de 16Mhz (maximo 48Mhz) y quedaria así para el minimo:
Código: C
  1. // CONFIG1L
  2. #pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
  3. #pragma config CPUDIV = OSC4_PLL6// System Clock Postscaler Selection bits ([Primary Oscillator Src: /4][96 MHz PLL Src: /6])
  4. #pragma config USBDIV = 2       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes from the 96 MHz PLL divided by 2)
  5.  
  6. // CONFIG1H
  7. #pragma config FOSC = XTPLL_XT  // Oscillator Selection bits (XT oscillator, PLL enabled (XTPLL))


Citar
Una duda mas , este bit : #pragma config PBADEN = OFF, segun la descripcion, los bits, RB4-rb0 son configurados como analogicos en el reset, pero haciendo pruebas no he encontrado ninguna diferencia entre dejarlo en 1 o en 0, alguien sabe que utilidad tiene este bit?
Un saludo a todos

Usualmente siempre pero siempre modificas el TRIS, el ADCON1 para ponerlos en digital... si es que lo necesitas como digital.
Y SI, apenas ocurre el reset estan como analogicos, si vos desactivas este bit, inician como digitales. Esto te ahorraría el modificar el registro ADCON1 para pasarlos a digitales.
O basicamente esto es lo que ocurre...
Si PBADEN es OFF (entradas en digital) el ADCON1 tiene los bits asi PCFG<3:0> = 0111. (todos los RB como digitales) , si lo tenes en ON el ADCON1 tiene los bits asi PCFG<3:0> = 0000; (Todos analogicos), pensalo como un pre-set del registro ADCON1.

Por si no queda claro:
Todo esta en el datasheet :3