Examples from mikroC Pro compile nicely,others not

General discussion on mikroC.
Post Reply
Author
Message
Tom1303
Posts: 5
Joined: 25 Jan 2011 19:18
Location: Croatia

Examples from mikroC Pro compile nicely,others not

#1 Post by Tom1303 » 25 Jan 2011 19:45

Hi everybody,
I fight with this for a few days now,and can't figure out what the problem is.When I open any of the examples out of mikroC Pro,they compile without problems,but when I do copy/paste some other code,it compiles only void main.I think it's only void main because I always get very small exe file and it's always the same.I think that I do something wrong with that void main that I get at the first line.What should I do with that,or how to copy/paste codes the proper way?

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: Examples from mikroC Pro compile nicely,others not

#2 Post by filip » 28 Jan 2011 12:50

Hi,

Can you explain your problem a bit better, because I cannot fully understand it ?

Regards,
Filip.

Tom1303
Posts: 5
Joined: 25 Jan 2011 19:18
Location: Croatia

Re: Examples from mikroC Pro compile nicely,others not

#3 Post by Tom1303 » 28 Jan 2011 19:29

Hi Filip,
this is what I do,I give the name to the project,and then new window in MikroC opens,and project name with .c extension.But in the first line I always find "void main",and I don't know how to paste source code properly.I've tried paste it in the front of"void main" and other places also but no success,I always,as a result,get exactly the same hex file,which is very small file by the way.When I open some of example projects out of mikroC folders,they work without problems.I make some stupid mistake when I paste code,or when I open code file other than mikroC file.I don't write my own code,because I don't know how to do it (yet).I hope this is a little bit more understandable.Thank you for your help.

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: Examples from mikroC Pro compile nicely,others not

#4 Post by filip » 02 Feb 2011 14:27

Hi,

If you have a complete code(which compiles in the other project successfully), you should paste it in the blank file (the void main() should be deleted prior to pasting).

Regards,
Filip.

Tom1303
Posts: 5
Joined: 25 Jan 2011 19:18
Location: Croatia

Re: Examples from mikroC Pro compile nicely,others not

#5 Post by Tom1303 » 03 Feb 2011 12:34

Yes,this is what happens now.I make separate folder,put .asm file in it,give name to the project,delete the "void main",call asm file,and click "build project".The messages I get on the bottom are all green,such as "compilation started","compiled succesfully",but two last messages at the end are red-"main function is not defined" and "finished with errors".The most frustrating to me is that I've had it all working fine maybe two years ago,but I didn't use it often,and I forgot how to do it correctly.Thanks Filip for trying to help me......

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: Examples from mikroC Pro compile nicely,others not

#6 Post by filip » 07 Feb 2011 15:36

Hi,

To include the asm statements into the source file, you should write something like this :

Code: Select all

void main() {
 asm {
   nop
   ... // asm code
 }
}
You didn't specify which code are you pasting, asm or C, so I guessed you are talking about C code.
So, every asm block must begin with asm { and end with }.

For more information, please read the asm Statement from he Help file.

Regards,
Filip.

Tom1303
Posts: 5
Joined: 25 Jan 2011 19:18
Location: Croatia

Re: Examples from mikroC Pro compile nicely,others not

#7 Post by Tom1303 » 17 Mar 2011 12:08

Finally,Filip, I have it working!I still don't know what exctly the problem was,but last night I've installed a new version mokroC v4.60,and now everything works fine.Except,when the error message appears,I don't know where to look for solution because I have no experience with C language.I do have one project I'm working on now,but I always get error messages,and I can't help myself with it:

Code: Select all

/*
speedometer for PIC16F648A
Copyright 2007-2010 by Jeff Hiner
version: 0.21, 19 Feb 2010

This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.



This program should compile under SourceBoost.  Feel free to modify it
to compile with any program you wish, for any platform you wish.

KNOWN BUGS:

Decreases in speed register immediately and are not affected by averaging.
This is deliberate; otherwise, speed decreases are not registered quickly
and accurately.  However, this can cause the display to oscillate rapidly
between two speeds, for example 38 and 40.


The most recent version can be found at:
http://www.randomwisdom.com/2007/10/digital-speedometer-using-pic-microcontroller/

*/

#include <system.h>
#define _DEBUG

#pragma DATA _CONFIG, _LVP_OFF & _BOREN_ON & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSC_OSC_NOCLKOUT

// This macro translates the order of the 7-segment bits to whatever the hardware pins are actually assigned to.
// input is from H to A, H being the decimal and A being the top LED, etc (see 7 segment documentation)
// This lets us change the wiring without altering all the bitwise code.
#define SEVSEG_BITFIELD(H,G,F,E,D,C,B,A)        0b ## E ## A ## D ## G ## F ## C ## B ## H
// mask the SEVSEG_BITFIELD with the following to decide what bits get written to when writing out to display.
#define SEVSEG_PORTA_MASK                                        0b11001110
#define SEVSEG_PORTB_MASK                                        0b00110000
#define SEVSEG_DECIMAL_MASK                                        SEVSEG_BITFIELD(1,0,0,0,0,0,0,0)
#define SEVSEG_DECIMAL_BIT                                        portb.1
#define SPEEDO_INPUT                                                portb.3
#define        BUTTON_INPUT                                                porta.5
#define hundreds_driver                                                portb.7
#define tens_driver                                                 portb.6
#define ones_driver                                                        portb.0
#define CALIBRATION_SPEED_KPH                                50
#define        DEFAULT_CALIB_FACTOR                                48094
#define DEFAULT_PULSES_IN_QTRMILE                        941


// how many overflows of tmr1 before a pulse is considered "stale" (invalid)
#define PULSE_LIFETIME                        7
#define MENU_TIMEOUT                        12
// 62 bigticks = 1.98ms
#define SPEEDO_BOUNCE_THRESHOLD        62

typedef struct _uns24 {
        unsigned char low8;
        unsigned char mid8;
        unsigned char high8;
} uns24;

#define gie                                intcon.GIE
#define t0if                        intcon.T0IF
#define tmr1if                        pir1.TMR1IF
#define tmr2if                        pir1.TMR2IF
#define ccp1if                        pir1.CCP1IF

unsigned char sevenseg_lookup(unsigned char digit);
void sevenseg_text(unsigned char message);
void refresh_sevenseg();
void display_number(unsigned int num);
void calculate_speed(bit forceupdate);
unsigned int make16(uns24 bigtimer);
unsigned int make16i(uns24 bigtimer);        // same thing, just used only in interrupts
unsigned long makelong(uns24 bigtimer);
unsigned char eeprom_read(unsigned char address);
void eeprom_write(unsigned char address, unsigned char data);

// The display unit's current task is defined by a state machine.  Normally on boot it defaults to MODE_SPD
// which displays the current speed as a normal speedometer.
// MSG_EEE is not a real mode, but it's here to prevent an overflow bug in sevenseg_text
typedef enum { MODE_MENU_DRAG, MODE_MENU_CAL, MODE_MENU_TEST, MSG_GO, MSG_EEE,
                                        MODE_SPD, MODE_DRAG, MODE_CAL, MODE_TEST, MODE_TEST2, MODE_TEST3 } mainmode;

#define MODE_DEFAULT        MODE_SPD

// max eeprom space: 256 bytes
#define eeprom_calib_factor_kph_lo        0
#define eeprom_calib_factor_kph_hi        1
#define        eeprom_calib_factor_mph_lo        2
#define eeprom_calib_factor_mph_hi        3
#define eeprom_pulses_in_qtrmile_lo        4
#define eeprom_pulses_in_qtrmile_hi        5
#define eeprom_options                                6
        // bit 0 is 0 if displaying mph, 1 if displaying kph.  NOT YET IMPLEMENTED.
        // bit 7 is 0 if this eeprom has ever been written to, 1 if cleanly erased (load all from defaults)
        // all others are undefined

// max ram space: 256 bytes
unsigned int calib_factor;                        // calibration factor used to calculate speed
unsigned int pulses_in_qtrmile;                // we use an actual quarter mile: about 402.25 meters
unsigned char sevenseg_bits[3];                // a buffer telling which LEDs we light up on each digit
unsigned int speed;                                        // our current speed, calculated in main loop (unsigned char only goes to 255)
unsigned int pulsecount;                        // updated on each pulse.  Used for drag timing.
uns24 lastpulses[2];                                // the last two pulses received.  index 0 is last, index 1 is the one before that.
bit lastpulse_stale0;
bit lastpulse_stale1;                                // if a pulse happened too long ago, it's stale and we can't do anything with it
bit blink_enable;                                        // set by software: blinking enabled on all displays
bit flag_buttonpressed;                                // used to pass the message that a button press was registered
bit flag_buttonheld;                                // ... or a button was held.  Clear manually before and after use.

unsigned char button_heldcount;                // how many tmr0 ticks the button has been held
unsigned char dim_factor;                        // inserts (0xFF - dim_factor) delays in the 7seg refresh to dim the display.
                                                                        // if 0xFF, we don't dim displays at all.  If less than that, we dim.
                                                                        // (e.g. 0xFC for half power, 0xF9 for 1/3 power, etc)
mainmode current_mode;                                // tells our state machine which task the main loop is trying to execute
unsigned char tmr1_upper;                        // since 0.5 seconds isn't long enough, we increment this with tmr1 overflows
                                                                        //   and use it for top byte of lastpulses.
uns24 now;                                                        // last sampled tmr1/tmr1_upper "now" time.
                                                                        //   "When will then be now?"  "Soon!"

// converts smalltimer "ticks" to tenths of a second
// (one smalltimer tick is 8 microseconds)
inline unsigned int to_millisecs(unsigned long bigtimer)
{
        return (unsigned int)((bigtimer + 6250) / 12500); // let's at least try to round it
}

// Looks up digit in the lookup table, then returns the 7 segment bits.
// These shouldn't need to be changed; if your wiring is different, change the SEVSEG macros at the start.
unsigned char sevenseg_lookup(unsigned char digit)
{
        rom unsigned char* lookuptable = {SEVSEG_BITFIELD(0,0,1,1,1,1,1,1), SEVSEG_BITFIELD(0,0,0,0,0,1,1,0),
                                                        SEVSEG_BITFIELD(0,1,0,1,1,0,1,1), SEVSEG_BITFIELD(0,1,0,0,1,1,1,1),
                                                        SEVSEG_BITFIELD(0,1,1,0,0,1,1,0), SEVSEG_BITFIELD(0,1,1,0,1,1,0,1),
                                                        SEVSEG_BITFIELD(0,1,1,1,1,1,0,1), SEVSEG_BITFIELD(0,0,0,0,0,1,1,1),
                                                        SEVSEG_BITFIELD(0,1,1,1,1,1,1,1), SEVSEG_BITFIELD(0,1,1,0,1,1,1,1)        };

        if (digit > 9)
                return 0;
        return lookuptable[digit];
}

// writes "text" on the 7 segment display by setting BCD position bits
void sevenseg_text(unsigned char message)
{
        gie = 0;
        // block interrupts while we're writing sevenseg_bits

        switch (message)
        {
                case MODE_MENU_DRAG:        // dragstrip mode (drG)
                        sevenseg_bits[2] = SEVSEG_BITFIELD(0,1,0,1,1,1,1,0);
                        sevenseg_bits[1] = SEVSEG_BITFIELD(0,1,0,1,0,0,0,0);
                        sevenseg_bits[0] = SEVSEG_BITFIELD(0,0,1,1,1,1,0,1);
                        break;
                case MODE_MENU_CAL:                // calibration (CAL)
                        sevenseg_bits[2] = SEVSEG_BITFIELD(0,0,1,1,1,0,0,1);
                        sevenseg_bits[1] = SEVSEG_BITFIELD(0,1,1,1,0,1,1,1);
                        sevenseg_bits[0] = SEVSEG_BITFIELD(0,0,1,1,1,0,0,0);
                        break;
                case MSG_GO:                        // during drag (Go!)
                        sevenseg_bits[2] = SEVSEG_BITFIELD(0,0,1,1,1,1,0,1);
                        sevenseg_bits[1] = SEVSEG_BITFIELD(0,1,0,1,1,1,0,0);
                        sevenseg_bits[0] = SEVSEG_BITFIELD(1,0,0,0,0,0,1,0);
                        break;
                case MSG_EEE:                        // error (EEE)
                        sevenseg_bits[2] = SEVSEG_BITFIELD(0,1,1,1,1,0,0,1);
                        sevenseg_bits[1] = SEVSEG_BITFIELD(0,1,1,1,1,0,0,1);
                        sevenseg_bits[0] = SEVSEG_BITFIELD(0,1,1,1,1,0,0,1);
                        break;
#ifdef _DEBUG
                case MODE_MENU_TEST:        // test mode (tSt)
                        sevenseg_bits[2] = SEVSEG_BITFIELD(0,1,1,1,1,0,0,0);
                        sevenseg_bits[1] = SEVSEG_BITFIELD(0,1,1,0,1,1,0,1);
                        sevenseg_bits[0] = SEVSEG_BITFIELD(0,1,1,1,1,0,0,0);
                        break;
#endif // #ifdef _DEBUG
        }
        gie = 1;
}

// refreshes a single seven segment element, and increments the digit
// This func is run a lot, so it must be fast!
void refresh_sevenseg()
{
        static unsigned char current_digit;

        // turn off all digit driver transistors
        ones_driver = 0;
        tens_driver = 0;
        hundreds_driver = 0;

        porta &= ~(SEVSEG_PORTA_MASK);
        portb &= ~(SEVSEG_PORTB_MASK);
        SEVSEG_DECIMAL_BIT = 0;

        if ((!blink_enable) || (tmr1h & 0x80))
        {
                // assign proper bits to the ports
                porta |= (SEVSEG_PORTA_MASK & sevenseg_bits[current_digit]);
                portb |= (SEVSEG_PORTB_MASK & sevenseg_bits[current_digit]);
                if (sevenseg_bits[current_digit] & SEVSEG_DECIMAL_MASK)
                        SEVSEG_DECIMAL_BIT = 1;        // don't forget decimal

                // turn on the current digit driver transistor
                switch (current_digit)
                {
                        case 0:
                                ones_driver = 1;
                                break;
                        case 1:
                                tens_driver = 1;
                                break;
                        case 2:
                                hundreds_driver = 1;
                                // normally dim_factor is 0xFF, which means start again at case 0 next pass.
                                // if less, we skip lighting up for 0xFF - dim_factor passes.
                                // A hack, because current_digit maybe isn't a legal array index...
                                current_digit = dim_factor;
                                break;
                }
        }

        // next pass, we'll update this digit
        current_digit++;
}

// translate "num" to BCD.  Blank leading zeroes, but if num is zero show 0 in ones digit.
void display_number(unsigned int num)
{
        // If you're going faster than 512, send me a video.  I'd like to see it.
        if (num > 512)
        {
                sevenseg_text(MSG_EEE);
                return;
        }
        else
        {
                unsigned char temp_digit[3];

                // we need to BCD decode a 9 bit number.

                // normally I'd use a for loop, but 8 bit division is much faster than 16 bit and we need the speed.
                temp_digit[0] = num % 10;
                unsigned char temp_num = num / 10;
                temp_digit[1] = temp_num % 10;
                temp_digit[2] = temp_num / 10;

                gie = 0;
                sevenseg_bits[2] = 0x00;
                sevenseg_bits[1] = 0x00;

                if (temp_digit[2] != 0)
                {
                        sevenseg_bits[2] = sevenseg_lookup(temp_digit[2]);
                        sevenseg_bits[1] = sevenseg_lookup(temp_digit[1]);
                }
                else if (temp_digit[1] != 0)
                {
                        sevenseg_bits[1] = sevenseg_lookup(temp_digit[1]);
                }
                sevenseg_bits[0] = sevenseg_lookup(temp_digit[0]);
                gie = 1;

                // Faster way?  Save the answer and remainder simultaneously, only compute as much as we need.
                // But it would need to be implemented in asm.
        }
}

// calculate our speed and write it to the "speed" variable
// "forceupdate" means ignore hysteresis and return raw speed
void calculate_speed(bit forceupdate)
{
        unsigned int twopulse_delta, lastpulse_delta, temp_lastpulses[2];

        static unsigned char lastupdatedtime = 0;
        static unsigned int rollingsum[6] = {0, 0, 0, 0, 0, 0};        // a rolling sum of the last 2, 4, 8, 16, 32, and 64 pulseswidths (estimated)
        static unsigned char lastpulsecount = 0;                // the last known pulsecount, based on least significant 8 bits
                                                                                                        // (only recalculate speed if we have another pulse)

        int newspeed;        // signed int

        // if we don't have two valid pulses, we're done. Speed is zero.
        if (lastpulse_stale1 || lastpulse_stale0)
        {
                unsigned char i;
                for (i = 0; i < 6; i++)
                        rollingsum[i] = 0;        // clear all rolling sums
                speed = 0;
                return;
        }

        SampleNow:
        // stop interrupts for a sec... we don't want the clocks messed with
        gie = 0;

        // This time, we cannot stop captures, so we should check consistency.
        now.mid8 = tmr1h;
        now.high8 = tmr1_upper;
        now.low8 = tmr1l;

        // if mid8 has changed, then low8 overflowed and high8 is also suspect.
        if (now.mid8 != tmr1h)
        {
                if (tmr1if)
                {
                        // one in a million chance... tmr1 overflowed! oh noes!
                        // tmr1_upper hasn't had a chance to update. We need to enable interrupts, go back, and try again.
                        gie = 1;
                        goto SampleNow;
                }
                // if we copy again, it should be fast enough to not overflow this time.
                now.mid8 = tmr1h;
                now.high8 = tmr1_upper;
                now.low8 = tmr1l;
        }

        temp_lastpulses[1] = make16(lastpulses[1]);
        temp_lastpulses[0] = make16(lastpulses[0]);
        // start the interrupts again
        gie = 1;

        // now.low16 = make16(now);
        lastpulse_delta = make16(now);

        // calculate difference between last 2 pulses' clock
        twopulse_delta = temp_lastpulses[0] - temp_lastpulses[1];
        // calculate difference between last pulse and now
        // lastpulse_delta = now.low16 - temp_lastpulses[0];
        lastpulse_delta -= temp_lastpulses[0];

        if (lastpulsecount != (unsigned char)pulsecount)        // NOTE: only update rolling average of times between two pulses
        {
                // we have a new pulse so we can update antijitter
                lastpulsecount = (unsigned char)pulsecount;
                // rollingsum[n] = ((2^n - 1) * rollingsum[n] / (2^n)) + (twopulse_delta)
                unsigned char i;
                for (i = 0; i < 6; i++)
                {
                        rollingsum[i] -= (rollingsum[i] >> (i+1));
                        rollingsum[i] += twopulse_delta;
                }
        }

        // whichever of those is greater, call that "period"
        // speed is calibfactor / period
        if (twopulse_delta > lastpulse_delta)
                newspeed = calib_factor / twopulse_delta;
        else if (lastpulse_delta == 0) // if (lastpulse_delta==0) && (twopulse_delta==0) catch the edge case so we don't divide by zero
                newspeed = 0;
        else        // in this case, our speed is lower because we haven't got a pulse yet as expected...
                newspeed = calib_factor / lastpulse_delta;

        // n = calib_factor / (twopulse_delta * 10)

        unsigned char n = (unsigned int)newspeed / 10;

        if (n)        // if going faster than 10kph, use an appropriate rolling average
        {
                unsigned char i = 0;        // "i" will tell us how many speed estimates to blend (2 for 10kph, 4 for 20, 8 for 40, and so on)
                while (n)
                {
                        n = n >> 1;
                        i++;
                }
                unsigned int sumpulse = (rollingsum[i-1] >> i);
                if (sumpulse)        // if (rollingsum[i-1] >> i) gets glitched to be zero, we'd be in serious trouble
                        newspeed = calib_factor / sumpulse;
        }

        int t = (int)newspeed - speed;
        // we don't want to update the display if it hasn't changed much and it was already updated recently (within the last 0.25sec)
        if ((2 > t) && (t > -2) && (lastupdatedtime == (tmr1h & 0x80)) && !forceupdate)
                return;
        else
        {
                lastupdatedtime = tmr1h & 0x80;
                speed = (unsigned int)newspeed;
        }
}

// turns a 24 bit "long timer" entry into a 16 bit "short timer"
// equivalent to (word)(bigtimer >> 2)
unsigned int make16(uns24 bigtimer)
{
        unsigned int rval;
        // roll high8, mid8, low8; do it twice
        asm {
                rrf _bigtimer+2, 1
                rrf _bigtimer+1, 1
                rrf _bigtimer, 1
                rrf _bigtimer+2, 1
                rrf _bigtimer+1, 1
                rrf _bigtimer, 1
        }
        MAKESHORT(rval, bigtimer, bigtimer+1);
        return rval;
}

// turns a 24 bit "long timer" entry into a 16 bit "short timer"
// (Use this one inside interrupts to avoid static memory limitations)
unsigned int make16i(uns24 bigtimer)
{
        unsigned int rval;
        asm {
                rrf _bigtimer+2, 1
                rrf _bigtimer+1, 1
                rrf _bigtimer, 1
                rrf _bigtimer+2, 1
                rrf _bigtimer+1, 1
                rrf _bigtimer, 1
        }
        MAKESHORT(rval, bigtimer, bigtimer+1);
        return rval;
}

// synthesize an "unsigned long" from an "uns24" (cc5x style 24 bit unsigned int)
unsigned long makelong(uns24 bigtimer)
{
        unsigned long foo;
/*        *((unsigned char *)(&foo)) = 0;
        *((unsigned char *)(&foo) + 1) = bigtimer.high8;
        *((unsigned char *)(&foo) + 2) = bigtimer.mid8;
        *((unsigned char *)(&foo) + 3) = bigtimer.low8;
*/
        asm
        {
                movlw 0
                movwf _foo+3
                movf _bigtimer+2,0
                movwf _foo+2
                movf _bigtimer+1,0
                movwf _foo+1
                movf _bigtimer,0
                movwf _foo
        }
        return foo;
}

void main(void)
{
        // initialization of ports, timers, interrupts, variables, etc
        cmcon = 0b00000111;
        trisa = 0b00110001;                // 1 means high impedance (input)
        trisb = 0b00001100;
        porta = 0b00010000;                // 0 is low (gnd), 1 is high (5V)
        portb = 0b00000000;


        clear_wdt();        // do this to avoid a reset
        option_reg = 0b11010110;        // tmr0 triggers off internal clock, tmr0 prescaler to 1:128
        tmr0 = 0x00;                        // in case we want to use it later, it's reset.

        dim_factor = 0xFF;
        {
                unsigned char temp1, temp2;
                temp1 = eeprom_read(eeprom_calib_factor_kph_lo);
                temp2 = eeprom_read(eeprom_calib_factor_kph_hi);
                MAKESHORT(calib_factor, temp1, temp2);
                temp1 = eeprom_read(eeprom_pulses_in_qtrmile_lo);
                temp2 = eeprom_read(eeprom_pulses_in_qtrmile_hi);
                MAKESHORT(pulses_in_qtrmile, temp1, temp2);
        }
        if (calib_factor == 0xFFFF || pulses_in_qtrmile == 0)
        {
                calib_factor = DEFAULT_CALIB_FACTOR;
                pulses_in_qtrmile = DEFAULT_PULSES_IN_QTRMILE;
        }
        lastpulse_stale0 = 1;        // both pulses are invalid on reset; we need to get TWO pulses in a reasonable time
        lastpulse_stale1 = 1;        // before doing any calculating.
        button_heldcount = 0;
        blink_enable = 0;
        current_mode = MODE_DEFAULT;        // can set MODE_DEFAULT to MODE_TEST for PIC testing
        sevenseg_bits[2] = sevenseg_bits[1] = sevenseg_bits[0] = 0xFF;
        now.low8 = 0;
        now.mid8 = 0;
        now.high8 = 0;

        tmr1l = 0x00;                        // reset tmr1
        tmr1h = 0x00;
        tmr1_upper = 0;
        ccpr1l = 0x00;                        // and CCP cap timer
        ccpr1h = 0x00;
        t1con = 0b00110001;                // ===Start tmr1=== with 1:8 prescale; 125000 increments per second
        ccp1con = 0b00000100;        // CCP capture mode ON, every falling edge of RB3 we capture the contents of tmr1 into CCPR1

        // tweak pr2 or t2con postscaler to adjust LED refresh rate; too high a refresh means less time for speed calcs
        tmr2 = 0x00;                        // reset tmr2
        pr2 = 125;                                // wrap when you hit this number
        t2con = 0b00001101;        // ===Start tmr2=== with prescaler 1:4, postscaler 1:2 (pr2 = 125 means interrupt every 1ms)


        pir1 = 0b00000000;        // clear the rest of the interrupt flags
        pie1 = 0b00000011;        // enable interrupts: tmr1, tmr2
        intcon = 0b01100000;        // enable interrupts: tmr0 and PEIE
        clear_wdt();
        gie = 1;                                // enable global interrupts, now the display can start updating

        // set all LEDs on (lamp test mode) for about 1 second

        while (tmr1_upper < 2)
        {
                sevenseg_bits[2] = sevenseg_bits[1] = sevenseg_bits[0] = 0xFF;
        }
        clear_wdt();

        // set all LEDs off (lamp blank mode) for about 0.5 seconds
        while (tmr1_upper < 3)
        {
                sevenseg_bits[2] = sevenseg_bits[1] = sevenseg_bits[0] = 0x00;
        }
        clear_wdt();

        // by now we should have collected enough pulses (or not collected any) to get an idea of how fast we're going

        while (1)
        {
                uns24 start_time, end_time;
                unsigned char gen_timer;        // a general variable we can set to tmr1_upper + whatever, and break when they match. Simple software timer.

                flag_buttonpressed = 0;
                flag_buttonheld = 0;
                blink_enable = 0;        // just in case we broke out and didn't switch it off

                // When control enters a new state, the button flags are cleared, blink is turned off.
                // Display bits are however the last state left them.  Handy for blinking our selection when exiting a menu.

                switch (current_mode)
                {
                        case MODE_SPD:        // calculate and show current speed until a button is held
                                while (!flag_buttonheld)
                                {
                                        calculate_speed(0);
                                        display_number(speed);
                                }
                                // switch to first menu state
                                current_mode = MODE_MENU_DRAG;
                                break;
                        case MODE_CAL:                        // calibration mode
                                // user should be driving 50kph
                                // flash CAL a couple times for a couple seconds to let the driver get ready
                                gen_timer = tmr1_upper + 4;
                                blink_enable = 1;
                                while (tmr1_upper != gen_timer)
                                        ;        // delay

                                // wait for first pulse
                                pulsecount = 0;
                                gen_timer = tmr1_upper + 10;
                                while (pulsecount == 0 && tmr1_upper != gen_timer)
                                {
                                        if (flag_buttonpressed || flag_buttonheld)
                                        {
                                                current_mode = MODE_SPD;
                                                break;
                                        }
                                }

                                if (pulsecount == 0)
                                {
                                        current_mode = MODE_SPD;
                                        break;        // a button was pressed before the first pulse was received, abort MODE_CAL.
                                }

                                // blank the display except blinking decimals while reading/calibrating
                                sevenseg_bits[2] = sevenseg_bits[1] = sevenseg_bits[0] = SEVSEG_DECIMAL_MASK;

                                // log time, handily "now" was just updated by CCP1 interrupt!
                                pulsecount = 0;
                                start_time = now;
                                while (pulsecount < 256)
                                {
                                        if (flag_buttonpressed || flag_buttonheld)
                                        {
                                                current_mode = MODE_SPD;
                                                break;
                                        }
                                }

                                end_time = now;

                                if (pulsecount < 256)
                                {
                                        current_mode = MODE_SPD;
                                        break;        // a button was pressed before the last pulse was received, abort MODE_CAL.
                                }

                                sevenseg_bits[2] = sevenseg_bits[1] = sevenseg_bits[0] = 0x00;        // shut off display while writing

                                // our general strategy is counting a fixed number of pulses in a short time, and then
                                // multiplying that time by a value to obtain calib_factor, and another to get pulses_in_qtrmile
                                // reminder: 125000 smallticks per second, 4 smallticks per bigtick
                                // at 50kph, we're going 13.89 m/s
                                // say we have a wheel circumference of 1.75m (typical kei car small wheel) and 4 pulses per revolution
                                // therefore it takes us about 8 seconds (1000000 smallticks) to get 256 pulses
                                // end_time - small_time gives us number of smallticks for 256 pulses, so shift right 8 to divide
                                // foo is in bigtick*km per pulse*hr
                                unsigned char to_write = 0xFF;
                                unsigned long foo = ((makelong(end_time) - makelong(start_time)) * CALIBRATION_SPEED_KPH) >> 8;

                                if (foo)
                                {
                                        // 3600 sec/hr * 125000 bigticks/sec * 1.609km/mi * 1/4 mi => 181012500 smallticks * km / hr
                                        pulses_in_qtrmile = 181012500 / foo;
                                        // pulses_in_qtrmile = 112500000 / foo; // use this one for mph

                                        LOBYTE(to_write, pulses_in_qtrmile);
                                        eeprom_write(eeprom_pulses_in_qtrmile_lo, to_write);
                                        HIBYTE(to_write, pulses_in_qtrmile);
                                        eeprom_write(eeprom_pulses_in_qtrmile_hi, to_write);
                                }

                                // calib_factor = speed in km/hr * period in bigticks
                                // divide foo by 4 to convert smallticks to bigticks
                                calib_factor = (unsigned int)(foo >> 2);
                                LOBYTE(to_write, calib_factor);
                                eeprom_write(eeprom_calib_factor_kph_lo, to_write);
                                HIBYTE(to_write, calib_factor);
                                eeprom_write(eeprom_calib_factor_kph_hi, to_write);

                                // unfortunately our calib_factor for mph as-is will overflow, so it's commented out
                                /*
                                calib_factor = (unsigned int)((foo * 8 / 5) >> 2);
                                LOBYTE(to_write, calib_factor);
                                eeprom_write(eeprom_calib_factor_mph_lo, to_write);
                                HIBYTE(to_write, calib_factor);
                                eeprom_write(eeprom_calib_factor_mph_hi, to_write);
                                */

                                // we've burned those values to flash
                                current_mode = MODE_SPD;
                                break;
                        case MODE_DRAG:                        // measure quarter mile speed, then display it and time taken
                                // target number of pulses have been set by MODE_CAL

                                // turn on blinking
                                gen_timer = tmr1_upper + 10;
                                blink_enable = 1;
                                // wait for speed to reach 0, or timeout after 5 seconds or button press.
                                while (speed != 0 && tmr1_upper != gen_timer)
                                {
                                        // (meanwhile, calculate and show speed)
                                        calculate_speed(0);
                                        display_number(speed);
                                        if (flag_buttonpressed || flag_buttonheld)
                                        {
                                                break;
                                        }
                                }
                                // turn off blinking
                                blink_enable = 0;

                                // if speed didn't hit zero or if button was pressed before speed got to zero, set MODE_SPD and break.
                                if (speed != 0)
                                {
                                        current_mode = MODE_SPD;
                                        break;
                                }
                                else
                                {
                                        // reset pulsecount, watch carefully for the first pulse (up to 60 seconds)
                                        pulsecount = 0;
                                        gen_timer = tmr1_upper + 120;
                                        sevenseg_text(MSG_GO);
                                        while (pulsecount == 0 && tmr1_upper != gen_timer)
                                        {
                                                if (flag_buttonpressed || flag_buttonheld)
                                                {
                                                        break;
                                                }
                                        }
                                }

                                // log time, handily "now" was just updated by CCP1 interrupt!
                                start_time = now;

                                if (pulsecount == 0)
                                {
                                        current_mode = MODE_SPD;
                                        break;
                                }

                                gen_timer = tmr1_upper + 100; // after about 50 seconds we'll give up

                                while ((pulsecount < pulses_in_qtrmile) && (tmr1_upper != gen_timer) && !(flag_buttonpressed || flag_buttonheld))
                                {
                                        // keep calculating/showing the speed!
                                        calculate_speed(1);        // force updates, ignore hysteresis (we want a nice accurate trap speed)
                                        display_number(speed);
                                }
                                // mark stop time
                                end_time = now;
                                // if we timed out or chickened out, return to SPD
                                if (pulsecount < pulses_in_qtrmile)
                                {
                                        current_mode = MODE_SPD;
                                        break;
                                }
                                else
                                {
                                        // else, we're already showing the trap speed; blink for about 2 seconds
                                        blink_enable = 1;
                                        gen_timer = tmr1_upper + 4;
                                        while (tmr1_upper != gen_timer)
                                        {
                                                ;
                                        }

                                        // turn off blink and keep showing trap speed another ~2 seconds
                                        blink_enable = 0;
                                        gen_timer = tmr1_upper + 4;

                                        while (tmr1_upper != gen_timer)
                                        {
                                                ;
                                        }

                                        // now calculate and show the time for ~4 seconds (and add decimal)
                                        display_number(to_millisecs(makelong(end_time) - makelong(start_time)));
                                        sevenseg_bits[1] |= SEVSEG_DECIMAL_MASK;
                                        gen_timer = tmr1_upper + 8;

                                        while (tmr1_upper != gen_timer)
                                        {
                                                ;
                                        }
                                }
                                current_mode = MODE_SPD;        // we're done here
                                break;
                        case MODE_MENU_DRAG:        // show menu
                        case MODE_MENU_CAL:                // show menu
                        case MODE_MENU_TEST:        // show menu
                                sevenseg_text(current_mode);
                                gen_timer = tmr1_upper + MENU_TIMEOUT;
                                while (tmr1_upper != gen_timer)
                                {
                                        if (flag_buttonpressed)
                                        {
                                                current_mode++;
                                                break;
                                        }
                                        else if (flag_buttonheld)
                                        {
                                                current_mode = current_mode + (MODE_SPD + 1);
                                                break;
                                        }
                                }
#ifdef _DEBUG
                                if (current_mode == MODE_MENU_TEST + 1)
#else
                                if (current_mode == MODE_MENU_CAL + 1)
#endif
                                        current_mode = MODE_MENU_DRAG;                // let's wrap around.
                                if (tmr1_upper == gen_timer)
                                        current_mode = MODE_SPD;
                                break;
#ifdef _DEBUG
                        case MODE_TEST:                        // display test mode
                                // TEST: running numbers. display tmr1_upper on the LED until button is pressed
                                while (!(flag_buttonpressed || flag_buttonheld))
                                {
                                        display_number(tmr1_upper);
                                        if (tmr1h.7)        // blink all dots on and off to show we are in test mode
                                        {
                                                sevenseg_bits[2] |= SEVSEG_DECIMAL_MASK;
                                        }
                                        sevenseg_bits[0] |= (BUTTON_INPUT ? SEVSEG_DECIMAL_MASK : 0);
                                        sevenseg_bits[1] |= (SPEEDO_INPUT ? SEVSEG_DECIMAL_MASK : 0);
                                }
                                current_mode = MODE_TEST2;
                                break;
                        case MODE_TEST2:                        // button input test mode for 15 seconds, button doesn't change modes
                                // TEST2: Check our button
                                gen_timer = tmr1_upper + 30;
                                display_number(0);
                                while (gen_timer != tmr1_upper)
                                {
                                        if (button_heldcount > 0)
                                                display_number(button_heldcount);
                                        if (tmr1h.7)        // blink all dots on and off to show we are in test mode
                                        {
                                                sevenseg_bits[1] |= SEVSEG_DECIMAL_MASK;
                                                sevenseg_bits[0] |= SEVSEG_DECIMAL_MASK;
                                        }
                                        sevenseg_bits[2] |= (BUTTON_INPUT ? SEVSEG_DECIMAL_MASK : 0);
                                }
                                current_mode = MODE_TEST3;
                                break;
                        case MODE_TEST3:                        // speedo input test mode
                                // TEST3: count pulses to test speedometer input
                                pulsecount = 0;
                                while (!(flag_buttonpressed || flag_buttonheld))
                                {
                                        if (pulsecount > 512)
                                                pulsecount = 0;                // wrap because we don't display numbers higher than 512
                                        display_number(pulsecount);
                                        if (tmr1h.7)        // blink all dots on and off to show we are in test mode
                                        {
                                                sevenseg_bits[2] |= SEVSEG_DECIMAL_MASK;
                                                sevenseg_bits[1] |= SEVSEG_DECIMAL_MASK;
                                                sevenseg_bits[0] |= SEVSEG_DECIMAL_MASK;
                                        }
                                }
                                current_mode = MODE_SPD;
                                break;
#endif // #ifdef _DEBUG
                        default:
                                // We should never arrive here.
                                // if we're debugging, we want to know about this; print MSG_EEE and lockup.
                                sevenseg_text(MSG_EEE);
                                while (!flag_buttonpressed)
                                        ;
                                // if we're not debugging, just get us back into MODE_SPD.
                                current_mode = MODE_SPD;
                }

                clear_wdt();
        }
}

// handles ALL interrupts
void interrupt(void)
{
        // Determine which interrupt(s) we've gotten, and act accordingly.

        // tmr2 overflow, refresh next LED cluster
        if (tmr2if)
        {
                refresh_sevenseg();
                tmr2if = 0;
        }

        // tmr1 overflow, increment tmr1 "most significant bits" global var (since we can't set the prescaler high enough)
        // THIS MUST COME BEFORE CCP HANDLER
        if (tmr1if)
        {
                tmr1_upper++;
                // expire stale pulses
                if (tmr1_upper - lastpulses[1].high8 > PULSE_LIFETIME)
                        lastpulse_stale1 = 1;
                if (tmr1_upper - lastpulses[0].high8 > PULSE_LIFETIME / 2)
                        lastpulse_stale0 = 1;

                tmr1if = 0;
        }

        // tmr1 could roll over here! tmr1_upper would be inconsistent.

        // CCP trigger, happens when we get a speedometer pulse.
        if (ccp1if)
        {
                now.high8 = tmr1_upper;

                // Normally, stopping captures would be bad, but since we just triggered,
                // any captures that happen now are bounces.
                ccp1con = 0b00000000;                // stop it from capturing while we're reading the value
                now.mid8 = ccpr1h;
                now.low8 = ccpr1l;
                ccp1con = 0b00000100;

                // If tmr1if is uncleared, it means tmr1_upper we got is inconsistent.
                // Don't clear the ccp1if flag, we'll catch it on the next pass.
                if(!tmr1if)
                {
                        // if it's too close to the last pulse, ignore it, it's just a bouncy switch

                        if ((make16i(now) - make16i(lastpulses[0])) > SPEEDO_BOUNCE_THRESHOLD) // 2ms => 250 ticks => 62.5 bigticks
                        {
                                pulsecount++;
                                lastpulses[1] = lastpulses[0];
                                lastpulse_stale1 = lastpulse_stale0;
                                lastpulses[0] = now;
                                lastpulse_stale0 = 0;
                        }
                        ccp1if = 0;
                }        // else: don't worry about "now", as soon as we return from interrupt we'll hop back in again.
        }

        if (t0if)        // button polling routine (every 32.768 ms)
        {
                // the flags will be cleared externally
                if (!BUTTON_INPUT)        // if button is pressed, BUTTON_INPUT is held low.
                {
                        button_heldcount++;
                        // if the button has been on 30 times in a row (about 1 second), flag it as being held
                        if (button_heldcount == 30)
                                flag_buttonheld = 1;
                        // if the button has been on more than 30 times in a row, we've already flagged it as held
                        // if the button has been on THIS long, the user is obviously on drugs
                        else if (button_heldcount == 0xFF)
                                button_heldcount--;        // so as not to overflow
                }
                else
                {
                        // if the button hasn't been pressed, nothing to report.
                        // if the button was released after being on once or twice, it was a glitch.
                        // if the button was released after being on between 2 and 29 times in a row, it was pressed
                        if ((button_heldcount > 1) && (button_heldcount < 30))
                                flag_buttonpressed = 1;
                        // if the button was released after being on more than that, we already flagged it as held.
                        button_heldcount = 0;
                }
                t0if = 0;
        }
}

unsigned char eeprom_read(unsigned char address)
{
        eeadr = address;
        eecon1.RD = 1;
        return eedata;
}

// Write a byte of data to the given EEPROM address.
// This function will block execution if a previous write hasn't finished yet.

void eeprom_write(unsigned char address, unsigned char data)
{
        while (eecon1.WR)
                ;
        eeadr = address;
        eedata = data;
        gie = 0;
        eecon1.WREN = 1;        // enable writes
        // write sequence
        eecon2 = 0x55;
        eecon2 = 0xAA;
        eecon1.WR = 1;

        eecon1.WREN = 0;        // disable writes
        gie = 1;

}
Please,give me just a clue where the problem could be.Thanks a lot in advance

Post Reply

Return to “mikroC General”