ejemplos de administración de memoria pic en C

1

¿Alguien puede recomendar un buen recurso / sitio web para EJEMPLOS de uso de memoria pic en C? Estoy teniendo dificultades para seguir todas las cosas de TBLPTR / TBLRD sin ver que se usan en muchas aplicaciones diferentes y simples. Me sorprende lo difícil que es encontrar ejemplos claros y BÁSICOS de cómo manejar la memoria en los PIC.

Algo parecido a lo que haría un programa con los resultados de ADC, almacenar en una tabla, elegir ubicaciones de memoria, etc.

    
pregunta Mark

1 respuesta

2

Estás haciendo una pregunta muy amplia; hay una gran variedad de PIC, y probablemente no usaría la administración de memoria "formal" para ninguno de ellos. No hay necesidad.

Los resultados de la conversión A / D, el filtrado, los buffers UART, etc. normalmente se almacenarán en matrices antiguas en la memoria. Puede aumentarlos con punteros de cabeza y cola para buffers de anillo o variables de índice u otros medios, pero sus técnicas típicas de manipulación de datos no son diferentes para un PIC que las que tendría en una PC una vez que tenga la dirección para el buffer. Con los pequeños microcontroladores integrados, simplemente declara la matriz y la utiliza.

Alternativamente, puede trabajar con el enlazador para disminuir artificialmente la cantidad de memoria disponible que verá el sistema y luego usar las instrucciones de lectura / escritura de la tabla y / o los accesos de punteros estándar para acceder a esta memoria "oculta". Reduce la memoria que el compilador puede usar para que la pila (que normalmente crece desde la parte superior de la memoria hacia abajo) no colisione con su área de almacenamiento, o BSS y el montón (que normalmente se encuentran al comienzo de la memoria de datos) no lo hacen Interfiere con tu área de memoria. Los medios exactos para lograr esta magia de vinculador dependen del conjunto de compiladores, por supuesto.

Si pudiera proporcionar más detalles, quizás una aplicación más específica también podría proporcionar respuestas más específicas. Creo que quizás estás sobre-analizando el problema. C es C; puede declarar memoria arbitraria y usarla en una PC también, siempre y cuando no esté en conflicto con la MMU.

edite para agregar un ejemplo de código de lectura y promedio de ADC:

Tiendo a escribir mi código de manera simple y clara; Uso pequeñas funciones de un solo propósito y tiendo a escribir código como máquinas de estado. También tiendo a dejar la optimización al compilador a menos que tenga una necesidad específica de optimizar a mano. Esto viene de años (casi dos décadas) de diseño integrado y de aprender cosas por las malas.

El código configura una interrupción de temporizador de 1 ms, dos canales ADC y luego los muestrea continuamente; Las lecturas se filtran utilizando un simple filtro deslizante promedio. En este ejemplo, las muestras de datos de cada canal ADC no se almacenan individualmente. Cada canal tiene su propia suma corriente; los últimos 8 valores (la constante FILTER_POINTS) se promedian y este valor de conteo filtrado se almacena. Se debe tener cuidado para asegurarse de que la variable de suma sea lo suficientemente grande como para almacenar el número que se puede crear si 8 muestras de ADC están a escala completa.

Finalmente, una temperatura en 1/10 de grado F, usando una función de conversión. La función de conversión, por supuesto, es específica de los sensores que estoy muestreando. Sus propias funciones de conversión deberían escribirse para adaptarse a sus sensores.

Esto está escrito para su uso con el compilador CCS; A NOT no me gusta este compilador por una variedad de razones, pero es lo que la mayoría de mis clientes usan porque su precio es el más bajo entre sus competidores.

#device PIC24F32KA304 ADC=12
#device ANSI
#include <24f32ka304.h>

#fuses OSCIO, NOPROTECT, NOWDT

#use delay(OSC=8MHz, CLOCK=32MHz)
#use standard_io(all)

#include <stdlib.h>
#include <math.h>
#include <stdio.h>


/* I hate mixed case types */
typedef BOOLEAN bool;


/* pin definitions */
#define PIN_FOO     (PIN_C8)
#define PIN_BAR     (PIN_A4)
#define PIN_BAZ     (PIN_A9)

#define VREFP       (0)
#define VREFN       (1)
#define CHAN1       (4)
#define CHAN2       (5)

#define FILTER_POINTS       (8)


/*
 * 10mV per degree F.
 * 2.048V reference, 4096 counts, for 0.5mV per count
 * therefore 10mV/0.5mV or 20 counts per degree F
 */
#define COUNTS_PER_DEGREE       (20)
#define COUNTS_PER_DEG_TENTHS       (COUNTS_PER_DEGREE / 10)


/* globals */
volatile bool one_ms_flag;
volatile bool onehundred_ms_flag;
volatile bool one_second_flag;

unsigned int32 chan1_sum, chan2_sum;        /* summing values for the averaging filter */
unsigned int16 chan1_counts, chan2_counts;  /* raw ADC values for temp sensors */
unsigned int16 chan1_temp, chan2_temp;      /* temperatures, in 0.1 degrees F steps */


/*
 * Timer ISR
 */
#INT_TIMER1 level=7
void system_isr(void)
{
    static int ticks = 0;

    one_ms_flag = TRUE;

    if ((ticks % 100) == 0) {
        onehundred_ms_flag = TRUE;
    }

    if (++ticks > 999) {

        one_second_flag = TRUE;
        ticks = 0;
    }
}


/*
 * stupid simple sliding average (FILTER_POINTS data points)
 * runsum is the running average (which is basically the sum of the last FILTER_POINTS values)
 * function returns the new average
 */
static unsigned int16 filter_analog(unsigned int32 *runsum, unsigned int16 new)
{
    *runsum -= *runsum / FILTER_POINTS;
    *runsum += new;

    return *runsum / FILTER_POINTS;
}



/*
 * counts are 0.5mV/count, and sensor is 10mV/oF
 * returns in 1/10 degrees (60F = 600)
 * rounds to half a degree
 */
int to_degrees_f(int counts)
{
    int deg_f;
    int tenths;

    deg_f = counts / COUNTS_PER_DEG_TENTHS;
    tenths = deg_f % 10;
    deg_f /= 10;
    deg_f *= 10;

    if (tenths >= 5) {
        deg_f += 5;
    }

    return deg_f;
}


/*
 * ADC loop
 * meant to be called every 100ms or so.
 * if reset is true, will reset the ADC state machine and reconfigure the ADC.
 */
void adc_loop(bool reset)
{
    static enum { ADC_INIT=0, SMPL_CHAN1, SMPL_CHAN2 } adc_state = ADC_INIT;
    unsigned int16 adc_value;

    if (reset) {
        adc_state = ADC_INIT;
    }

    switch(adc_state) {
    case ADC_INIT:
        setup_adc(ADC_CLOCK_DIV_128);
        setup_adc_ports(sAN0|sAN1, VREF_VREF);
        set_adc_channel(CHAN1);
        read_adc(ADC_START_ONLY);
        chan1_sum = chan2_sum = FILTER_SEED;
        chan1_counts = chan2_counts = 0;
        chan1_temp = chan2_temp = 0;
        adc_state = SMPL_CHAN1;
        break;

    case SMPL_CHAN1:
        adc_value = read_adc(ADC_READ_ONLY);
        chan1_counts = filter_analog(&chan1_sum, adc_value);
        chan1_temp = to_degrees_f(chan1_counts);
        set_adc_channel(CHAN2);
        read_adc(ADC_START_ONLY);
        adc_state = SMPL_CHAN2;
        break;

    case SMPL_CHAN2:
        adc_value = read_adc(ADC_READ_ONLY);
        chan2_counts = filter_analog(&chan2_sum, adc_value);
        chan2_temp = to_degrees_f(chan2_counts);
        set_adc_channel(CHAN1);
        read_adc(ADC_START_ONLY);
        adc_state = SMPL_CHAN1;
        break;

    default:
        adc_state = ADC_INIT;
    };
}


void main(void)
{

/* Set up timer1 for 1ms interrupts. Tcy = Fosc/2 = 16MHz, /64 is 4us. 250 4us ticks is 1ms. */
    setup_timer1(TMR_INTERNAL | TMR_DIV_BY_64, 250);

/* set up I/O */
    output_low(PIN_FOO);
    output_low(PIN_BAR);
    output_float(PIN_BAZ);

/* reset the ADC subsystem */
    adc_loop(TRUE);

/* variable setup */
    one_second_flag = onehundred_ms_flag = one_ms_flag = FALSE;

    enable_interrupts(INT_TIMER1);

/* main loop */
    while (1) {
        if (one_ms_flag) {
            /* do stuff every 1ms */

            one_ms_flag = FALSE;
        }

        if (onehundred_ms_flag) {
            adc_loop(FALSE);

            onehundred_ms_flag = FALSE;
        }

        if (one_second_flag) {
            /* do stuff every 1s */

            one_second_flag = FALSE;
        }
    }
}
    
respondido por el akohlsmith

Lea otras preguntas en las etiquetas