yngndrw
New Member
Hi,
I'm used to writing applications for normal PC's in C++, not PICs.
I'm using MPLABs C18 compiler, with no optimisations. (Trial ran out.)
The code I'm trying to compile is for a K-Type thermometer. It is ment to just output the temp to an LCD. The code works fine in a C++ application for the PC.
The error I get is:
I think this means that it's run out of memory in a bank, but I thought C18 was ment to handle banks for me. To be honest, I can't remember much about banks. (Not touched PICs in a while.) The PIC I'm using is a PIC18f452.
Here is Main.c:
Any ideas on how to fix this ?
Thanks,
-Andrew.
I'm used to writing applications for normal PC's in C++, not PICs.
I'm using MPLABs C18 compiler, with no optimisations. (Trial ran out.)
The code I'm trying to compile is for a K-Type thermometer. It is ment to just output the temp to an LCD. The code works fine in a C++ application for the PC.
The error I get is:
Executing: "C:\MCC18\bin\mplink.exe" /l"C:\MCC18\lib" "C:\MCC18\lkr\18f452.lkr" "C:\PIC Projects\HZ Thermometer\Main.o" "C:\PIC Projects\HZ Thermometer\Util.o" "C:\PIC Projects\HZ Thermometer\LCD.o" /m"HZ Thermometer.map" /w /o"HZ Thermometer.cof"
MPLINK 4.12, Linker
Copyright (c) 2007 Microchip Technology Inc.
Error - section 'MATH_DATA' can not fit the section. Section 'MATH_DATA' length=0x00000014
Errors : 1
I think this means that it's run out of memory in a bank, but I thought C18 was ment to handle banks for me. To be honest, I can't remember much about banks. (Not touched PICs in a while.) The PIC I'm using is a PIC18f452.
Here is Main.c:
Code:
// Includes
#include <P18F452.h>
#include <math.h>
#include "Defines.h"
#include "Util.h"
#include "LCD.h"
// Setup
#pragma config OSCS=OFF, OSC=HS
#pragma config BOR=OFF, PWRT=ON, WDT=OFF
//#pragma config CCP2MX=OFF
#pragma config STVR=ON, LVP=OFF, DEBUG=OFF
#pragma config CP0=OFF, CP1=OFF, CP2=OFF, CP3=OFF, CPB=OFF, CPD=OFF
#pragma config WRT0=OFF, WRT1=OFF, WRT2=OFF, WRT3=OFF, WRTC=OFF, WRTB=OFF, WRTD=OFF
#pragma config EBTR0=OFF, EBTR1=OFF, EBTR2=OFF, EBTR3=OFF, EBTRB=OFF
// Defines
#ifdef CLOCK_20MHZ
#define TMR0_START 0xFE // 2 steps
#else
#define TMR0_START 0x9C // 100 steps
#endif
#define PWM_MAX 0x64 // 100 PWM steps, 10KHz clock, 10ms per cycle (100Hz)
#define ADC_MAX 0x3E8 // 1000 clocks per step, 10KHz clock, 100ms per cycle (10Hz)
#define ADC_DIVIDER 204.60 // ( 1023.00 / 5.00 )
#define ADC_KTYPE_REF 0x00
#define ADC_THERMISTOR 0x01
#define ADC_KTYPE_0 0x02
#define ADC_KTYPE_1 0x03
#define ADC_KTYPE_2 0x04
#define ADC_KTYPE_3 0x05
// Math Constants
const float kMathE = 2.71828182845904523536;
// Thermistor Conversion Constants
const float kThermistorA1 = 3.354016e-3;
const float kThermistorB1 = 2.569850e-4;
const float kThermistorC1 = 2.620131e-6;
const float kThermistorD1 = 6.383091e-8;
const float kThermistorRefResistance = 4700.00;
// K-Type Conversion Constants
const float kKTypeA1 = 0.00;
const float kKTypeB1 = 2.5173462e+1;
const float kKTypeC1 = -1.1662878;
const float kKTypeD1 = -1.0833638;
const float kKTypeE1 = -8.9773540e-1;
const float kKTypeF1 = -3.7342377e-1;
const float kKTypeG1 = -8.6632643e-2;
const float kKTypeH1 = -1.0450598e-2;
const float kKTypeI1 = -5.1920577e-4;
const float kKTypeA2 = 0.00;
const float kKTypeB2 = 2.508355e+1;
const float kKTypeC2 = 7.860106e-2;
const float kKTypeD2 = -2.503131e-1;
const float kKTypeE2 = 8.315270e-2;
const float kKTypeF2 = -1.228034e-2;
const float kKTypeG2 = 9.804036e-4;
const float kKTypeH2 = -4.413030e-5;
const float kKTypeI2 = 1.057734e-6;
const float kKTypeJ2 = -1.052755e-8;
// Globals
unsigned int g_iTaskPWMCount = 0x00;
unsigned int g_iTaskADCCount = 0x00;
volatile unsigned int g_iPWMChannel[] = { 0x00 };
volatile unsigned int g_iADCCurrentChannel = 0x00;
volatile float g_fADCChannel[] = { 0.00, 0.00, 0.00, 0.00, 0.00, 0.00 };
volatile unsigned char g_iDisplayDirty = 0x01;
// Prototypes
void main( void );
void InterruptHandlerHigh( void );
void InterruptHandlerLow( void );
void Init( void );
void EnableInterrupts( void );
float ThermistorResistanceToTemperature( float fResistance );
float KTypeVoltageToTemperature( float fVoltage );
// High Priority Interrupt Entry Point
#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh( void )
{
_asm
goto InterruptHandlerHigh
_endasm
}
#pragma code
#pragma interrupt InterruptHandlerHigh
void InterruptHandlerHigh( void )
{
// TMR0 - Every 0.1ms (10KHz)
if( IS_SET( INTCON, 2 ) )
{
CLEAR( INTCON, 2 );
TMR0L = TMR0_START;
// PWM Task
g_iTaskPWMCount++;
if( g_iTaskPWMCount > PWM_MAX )
{
g_iTaskPWMCount = 0x00;
}
// Channel 0 (LCD, Pin B1)
if( g_iTaskPWMCount < g_iPWMChannel[0] )
{
PIN_ON( PORTB, PIN( 1 ) );
}
else
{
PIN_OFF( PORTB, PIN( 1 ) );
}
// ADC Task
g_iTaskADCCount++;
if( g_iTaskADCCount > ADC_MAX )
{
// No ADC Conversion In Progress
if( IS_NOT_SET( ADCON0, 2 ) )
{
g_iTaskADCCount = 0x00;
g_iADCCurrentChannel++;
if( g_iADCCurrentChannel > ADC_KTYPE_3 )
{
g_iADCCurrentChannel = 0x00;
}
// Channel 0 (K-Type Ref, Pin AN0)
if( g_iADCCurrentChannel == ADC_KTYPE_REF )
{
ADC_CHANNEL_0;
}
// Channel 1 (Thermistor, Pin AN1)
else if( g_iADCCurrentChannel == ADC_THERMISTOR )
{
ADC_CHANNEL_1;
}
// Channel 2 (K-Type Channel 0, Pin AN4)
else if( g_iADCCurrentChannel == ADC_KTYPE_0 )
{
ADC_CHANNEL_4;
}
// Channel 3 (K-Type Channel 1, Pin AN5)
else if( g_iADCCurrentChannel == ADC_KTYPE_1 )
{
ADC_CHANNEL_5;
}
// Channel 4 (K-Type Channel 2, Pin AN6)
else if( g_iADCCurrentChannel == ADC_KTYPE_2 )
{
ADC_CHANNEL_6;
}
// Channel 5 (K-Type Channel 3, Pin AN7)
else if( g_iADCCurrentChannel == ADC_KTYPE_3 )
{
ADC_CHANNEL_7;
}
SET( ADCON0, 2 ); // Start ADC Conversion
}
}
}
}
// Low Priority Interrupt Entry Point
#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow( void )
{
_asm
goto InterruptHandlerLow
_endasm
}
#pragma code
#pragma interruptlow InterruptHandlerLow
void InterruptHandlerLow( void )
{
// ADC Conversion Complete
if( IS_SET( PIR1, 6 ) )
{
CLEAR( PIR1, 6 );
g_fADCChannel[g_iADCCurrentChannel] = (float)ADRES / ADC_DIVIDER;
g_iDisplayDirty = 1;
}
}
// Main Entry Point
void main( void )
{
float fThermistorResistance = 0.00;
float fKTypeVoltage0 = 0.00;
Init();
// LCD Backlight
while( g_iPWMChannel[0] <= PWM_MAX )
{
g_iPWMChannel[0]++;
Delay( 0x08 );
}
g_iPWMChannel[0] = PWM_MAX;
while( 1 )
{
if( g_iDisplayDirty == 1 )
{
fThermistorResistance = ( 1000.00 * 5.00 / g_fADCChannel[ADC_THERMISTOR] ) - 1000.00;
LCDLine( 0 );
LCDPrint( "Thermistor: " );
LCDFloatNumber2DP( ThermistorResistanceToTemperature( fThermistorResistance ) );
LCDLine( 1 );
LCDPrint( "K-Type Ref: " );
LCDFloatNumber2DP( g_fADCChannel[ADC_KTYPE_REF] );
fKTypeVoltage0 = g_fADCChannel[ADC_KTYPE_0] / 250.00 - 6.458; //todo - constants
LCDLine( 2 );
LCDPrint( "K-Type 0: " );
LCDFloatNumber2DP( KTypeVoltageToTemperature( fKTypeVoltage0 ) );
LCDLine( 3 );
LCDPrint( "K-Type 4: " );
LCDFloatNumber2DP( g_fADCChannel[ADC_KTYPE_3] );
}
Delay( 0x10 );
}
}
void Init( void )
{
// Set Port A as all inputs
TRISA = 0x7F;
// Disable all interrupts
RCON = 0x00;
INTCON = 0x00;
INTCON2 = 0x00;
INTCON3 = 0x00;
PIR1 = 0x00;
PIR2 = 0x00;
PIE1 = 0x00;
PIE2 = 0x00;
IPR1 = 0x00;
IPR2 = 0x00;
// Setup the ADC
ADRESL = 0x00;
ADRESH = 0x00;
ADCON0 = 0x81;
ADCON1 = 0x88;
//todo - remove:
// CLEAR( ADCON1, 3 );//temp - removes the ADC ref's
// Initialise the LCD
LCDInit();
// Enable interrupts for multi-tasking
EnableInterrupts();
}
void EnableInterrupts( void )
{
// Setup TMR0
TMR0L = TMR0_START;
#ifdef CLOCK_4MHZ
T0CON = 0xC8; // 1:1 prescaler
#else
#ifdef CLOCK_8MHZ
T0CON = 0xC0; // 1:2 prescaler
#else
#ifdef CLOCK_20MHZ
T0CON = 0xC7; // 1:256 prescaler
#endif
#endif
#endif
/*
4 / ms @ 1:256
8 / ms @ 1:128
16 / ms @ 1:64
32 / ms @ 1:32
64 / ms @ 1:16
128 / ms @ 1:8
256 / ms @ 1:4
512 / ms @ 1:2
1024 / ms @ 1 <-- selected
256 / 4 = 64ms = 15.625hz
1 / 4 = 0.25ms = 4khz
1 / 8 = 0.125ms = 8khz
1 / 16 = 0.0625ms = 16khz
1 / 32 = 0.03125ms = 32khz
1 / 64 = 0.015625ms = 64khz
1 / 128 = 0.0078125ms = 128khz
1 / 256 = 0.00390625ms = 256khz
1 / 512 = 0.001953125ms = 512khz
1 / 1024 = 0.0009765625ms = 1024khz
8 / 1024 = 0.0078125ms = 128khz
9 / 1024 = 0.0087890625ms = 114khz
10 / 1024 = 0.009765625ms = 102khz
2 / 4 = 0.5ms = 2khz
100 / 512 = 0.1953125ms = 5khz
100 / 1024 = 0.09765625ms = 10khz <-- selected
255 / 256 = 0.99609375ms = 1khz
255 / 1024 = 0.2490234375ms = 4khz
1khz = 1ms
4khz = 0.25ms
10khz = 0.1ms <-- target
100khz = 0.01ms
*/
RCON |= 0x80; // Enable Priorities
// Enable interrupts for TMR0
INTCON |= 0xA0; // We need high priority interrupts and the TMR0 overflow interrupt
INTCON2 |= 0x04; // Set TMR0 as high priority
// Enable interrupt for ADC
INTCON |= 0x40; // We need low priority interrupts
PIE1 |= 0x40; // Enable the ADC interrupt
}
float ThermistorResistanceToTemperature( float fResistance )
{
float fLnR = log( fResistance / kThermistorRefResistance );
float fTemperatureKelvin = 1.00 / ( ( kThermistorA1 + kThermistorB1 * fLnR + kThermistorC1 * pow( fLnR, 2.00 ) + kThermistorD1 * pow( fLnR, 3.00 ) ) );
return fTemperatureKelvin - 273.15;
}
float KTypeVoltageToTemperature( float fVoltage )
{
float fVoltageMilivolts = fVoltage / 1000.00;
if( fVoltageMilivolts < 0.00 )
{
// Range: -200C -> 0C
return kKTypeA1
+ kKTypeB1 * fVoltageMilivolts
+ kKTypeC1 * pow( fVoltageMilivolts, 2.00 )
+ kKTypeD1 * pow( fVoltageMilivolts, 3.00 )
+ kKTypeE1 * pow( fVoltageMilivolts, 4.00 )
+ kKTypeF1 * pow( fVoltageMilivolts, 5.00 )
+ kKTypeG1 * pow( fVoltageMilivolts, 6.00 )
+ kKTypeH1 * pow( fVoltageMilivolts, 7.00 )
+ kKTypeI1 * pow( fVoltageMilivolts, 8.00 );
}
else
{
// Range: 0C -> 500C
return kKTypeA2
+ kKTypeB2 * fVoltageMilivolts
+ kKTypeC2 * pow( fVoltageMilivolts, 2.00 )
+ kKTypeD2 * pow( fVoltageMilivolts, 3.00 )
+ kKTypeE2 * pow( fVoltageMilivolts, 4.00 )
+ kKTypeF2 * pow( fVoltageMilivolts, 5.00 )
+ kKTypeG2 * pow( fVoltageMilivolts, 6.00 )
+ kKTypeH2 * pow( fVoltageMilivolts, 7.00 )
+ kKTypeI2 * pow( fVoltageMilivolts, 8.00 )
+ kKTypeJ2 * pow( fVoltageMilivolts, 9.00 );
}
}
Any ideas on how to fix this ?
Thanks,
-Andrew.