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