pic12F683 no se comporta como se espera

0

Tengo este problema extraño. Cuando una parte del código está habilitada, mi pin GP4 puede usarse como salida para controlar un relé. Se cambia a 0 y 1 según una variable que se cambia de 0 a 1.

Golpeé un chip DS18b20 para obtener lecturas de temperatura. Funciona. Puedo verificar usando un analizador analógico o mi osciloscopio que los datos están llegando.

El problema que tengo es que ambas partes del código funcionan de forma independiente. La temperatura se lee en GP5 y el relé se controla a través de GP4. GP4 siempre es una salida.

El problema surge cuando intento leer la temperatura y controlar el relé al mismo tiempo. Cuando hago eso, GP4 solo se eleva a 1 por 1us o menos. Y al mismo tiempo, parece que la temperatura de lectura deja de funcionar. Pero podría haber resuelto esto ya.

simular este circuito : esquema creado usando CircuitLab

Me preguntaba si había alguna limitación en el chip que hace que no pueda mantener el pin GP4 como salida y alto. No uso ninguna interrupción y cada parte del código toca los bits TRIS que necesitan sin anular todo el registro.

Aquí hay un fragmento del código principal.

#define _XTAL_FREQ 8000000L

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>
#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
#include "onewire.h"

void main(void)
{
    ConfigureOscillator();

    TRISIObits.TRISIO5 = 0;
    TRISIObits.TRISIO4 = 0;

    struct OneWire ow;

    ow_reset(&ow);
    ow_search(&ow);

    __delay_ms(1);

    float real_temp = 0;
    bool ok = true;
    uint8_t res;
    GP4 = 1;

    while(1)
    {
        __delay_ms(1);

        ow_start_conversion(&ow);

        __delay_ms(1000);

        real_temp = ow_read_temperature(&ow) / 16.f;

        if (ok) {
            GP4 = 1;
        } else {
            GP4 = 0;
        }
        ok = ok ^ true;
    }
}

Si elimino todas las líneas relacionadas con OneWire, se puede controlar el relé. Pensé que el par de un cable no está cambiando GP4 o TRISbits para GP4. La biblioteca OW está escrita por mí según el Arduino.

Leí en alguna parte que había un límite de llamada de función y cierto límite en la pila. Me pregunto si no es algún tipo de problema que el compilador simplemente no selecciona y cuando uso ambas partes del código, me excedo de los límites.

Con ese código actual, el compilador me dice que estoy usando alrededor del 80% -90% del espacio de código y el espacio de ram.

También las bibliotecas se movieron a bibliotecas individuales y, lamentablemente, mplabx no parece poder depurar el "proyecto de bibliotecas". También podría ser un problema.

Estoy un poco confundido en cuanto a por qué ambas "características" funcionan de forma independiente pero juntas fallan.

Esto funciona:

#define _XTAL_FREQ 8000000L

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>
#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
#include "onewire.h"


void main(void)
{
    ConfigureOscillator();

    TRISIObits.TRISIO5 = 0;
    TRISIObits.TRISIO4 = 0;

    float real_temp = 0;
    bool ok = true;
    uint8_t res;
    GP4 = 1;

    while(1)
    {
        __delay_ms(1000);

        if (ok) {
            GP4 = 1;
        } else {
            GP4 = 0;
        }
        ok = ok ^ true;
    }
}

Y esto funciona:

#define _XTAL_FREQ 8000000L

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>
#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
#include "onewire.h"

void main(void)
{
    ConfigureOscillator();

    TRISIObits.TRISIO5 = 0;
    TRISIObits.TRISIO4 = 0;

    struct OneWire ow;

    ow_reset(&ow);
    ow_search(&ow);

    __delay_ms(1);

    float real_temp = 0;
    bool ok = true;
    uint8_t res;
    GP4 = 1;

    while(1)
    {
        __delay_ms(1);

        ow_start_conversion(&ow);

        __delay_ms(1000);

        real_temp = ow_read_temperature(&ow) / 16.f;
    }
}

Podré mostrar alguna pantalla desde el osciloscopio más adelante o desde el analizador lógico.

Editar:

Ajustes de configuración:

// CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Detect (BOR disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

Y la configuración del oscilador:

IRCF0 = 1;
IRCF1 = 1;
IRCF2 = 1;

Después de cambiar el primer __delay_ms en el bucle a 2sec, puedo ver que mi relé se enciende durante 2sec y antes sería alto durante 1ms como se configuró el delay_us. La captura de temperatura funciona, pero el relé baja (GP4) tan pronto como el pin GP5 se gira como entrada o cambia su salida.

uint8_t ow_read_bit(struct OneWire* self) {
    uint8_t r;
    GP5 = 0;
    TRISIO5 = 0;
    __delay_us(3); // 3
    TRISIO5 = 1;
    __delay_us(10); // 10
    r = GP5;
    __delay_us(53); //53
    return r;
}

void ow_write_bit(struct OneWire* self, uint8_t value) {
  if (value & 1) {
      GP5 = 0;
      TRISIO5 = 0;
      __delay_us(6); // 6
      GP5 = 1;
      __delay_us(64); // 64
  } else {
      GP5 = 0;
      TRISIO5 = 0;
      __delay_us(60); // 60
      GP5 = 1;
      __delay_us(5); // 10
  }
}

uint8_t ow_reset(struct OneWire* self) {
    uint8_t res = 0;
    uint8_t retries = 255;
    TRISIO5 = 1;

    do {
        if (--retries == 0) return 0;
        __delay_us(1);
    } while(!GP5);

    GP5 = 0;
    TRISIO5 = 0;
    __delay_us(480); // 480
    TRISIO5 = 1;
    __delay_us(125); //25
    res = GP5;
    __delay_us(410); // 410
    return res;
}

Esos son los tres métodos en juego que leen / escriben en el DS18B20, ninguna otra función toca los bits TRIS o GP5.

EDIT2:

Una solución, agregué un cheque después de la ow_start_conversion que restableció GP4 cualquiera que sea el valor de ok y agregué un límite entre la base / vdd del transistor. Solo es suficiente para evitar que el transitor se apague y que el relé esté activo continuamente. Realmente no soluciona el problema, ya que el GP4 no funciona pero el relé se puede controlar como se espera. En mi configuración más compleja, el pin está controlado por un PID y funciona. Entonces veo que el chip no se reinicia desde allí.

También GP4 se apaga cada vez que se cambian GP5 y TRISIO5.

    

2 respuestas

1

Finalmente encontré el problema ... Esto es extraño, ya que la Hoja de datos dice que cualquier conjunto de pines como analógico seguirá funcionando como salida digital (que es lo que es GP4).

Finalmente, mientras probaba en el simulador, encontré que mi pin GP4 estaba configurado como un AnalogOUT. Configuré el bit ANSEL.ANS3 a 0 para convertirlo en un pin digital y ahora el GP4 está funcionando como se esperaba. No es necesario que el hack de "reinicio" y la GP4 siempre se mantenga en 1 sin importar lo que pase en los otros pines.

    
respondido por el Loïc Faure-Lacroix
0

Dos cosas sobre tu esquema se destacan a mí:

  1. Estás flotando el pin MCLR. Ya que tiene "#pragma config MCLRE = ON", el pin MCLR (GP3) debe colocarse alto para evitar que el PIC se reinicie. Un pin MCLR flotante puede actuar de forma impredecible o estar influenciado por campos eléctricos locales en su proximidad.

  2. No tiene un condensador de derivación en los pines VDD y VSS. Los condensadores de derivación son necesarios en cualquier IC, incluidos los microcontroladores.

Es posible que ocurra algún efecto localizado dentro del PIC cuando se está ejecutando esa parte del código que está causando que el pin MCLR se lea de repente, lo que restablece el programa. Una prueba simple sería colocar una resistencia de 10kOhm entre el pin MCLR y el VDD y ver si eso lo corrige.

Editar:
Otro comentario. Usted está obteniendo aproximadamente 22mA de GP4 para manejar el transistor: $$ \ frac {V_ {DD} -V_ {BE}} {R_b} = \ frac {5V-0.6V} {200 \ Omega} = 0.022A $ $ La corriente de fuente máximo absoluto de cualquier pin IO es 25mA. Eso no es mucha sobrecarga. Además, apuesto a que el PIC no es capaz de mantener GP4 a 5V cuando se está suministrando 22mA. La salida de GP4 probablemente esté disminuyendo un poco, lo que está subestimando el transistor y, por lo tanto, está privando a la bobina del relé de corriente. Es posible que desee considerar la posibilidad de rediseñar el circuito de la unidad.

    
respondido por el Dan Laks

Lea otras preguntas en las etiquetas