; CC5X Version 3.1G, Copyright (c) B Knudsen Data ; C compiler for the PICmicro family ; ************ 19. Nov 2009 7:54 ************* processor 16C54 radix DEC TMR0 EQU 0x01 PCL EQU 0x02 PORTA EQU 0x05 Carry EQU 0 Zero_ EQU 2 softTimer EQU 0x08 tTimeout EQU 0x0E previousTMR0 EQU 0x0F subClock EQU 0x10 sample EQU 0x07 decim EQU 0x11 highTemperature EQU 0 ventilation EQU 1 outPCM EQU 2 outPulse EQU 3 _TaskS1 EQU 0x12 pulses EQU 0x13 _TaskS2 EQU 0x14 _TaskS3 EQU 0x15 ; FILE test\delay.h ;/* ; ---------------------------------------------------------- ; TIMING/DELAY LIBRARY FOR LEANSLICE MULTITASKING ; ; Copyright (c) B Knudsen Data, Trondheim, Norway, 1999-2002 ; ---------------------------------------------------------- ; ; ==> The timer module (delay.h) implements 8, 16 or 24 bit software ; timers that can be used in the tasks to get precise delays. ; The timer increments must of course have to be much slower ; than the instruction cycles. This means that the software ; timer operates around 100 or 1000 Hz when the microcontroller ; run at 4 - 20 MHz. Around 1000 instruction cycles for each ; software timer decrement is normally sufficient. Note that ; math operations are time consuming. It is possible to modify ; module delay.h if the actual timing requirements is outside ; the implemented options. ; ; The module delay.h offers both simple delays or active waiting. It ; is possible to define a timer for each task. ; ; Required definitions in the application program: ; ; enum {TimerA, TimerB}; // Timer identifiers ; #define FreqOsc 4000000 // Oscillator frequenzy ; #define FreqTimer 1000 // Timer frequency, 1000 or 100 Hz ; #define TimerType uns16 // uns8, uns16 or uns24 ; #define NoOfTimers 2 // 1 .. 8 ; #define DELAY_TYPE 1 ; #include "delay.h" ; ; Initialization and increments: ; ; initTimers(); // initialization on application startup ; ; // The timers need to be incremented by making frequent calls ; // to timerTick()in main. The calls must not be more infrequent ; // than the timer decrement period ; timerTick(); ; ; Using the timers by active waiting or simple delays: ; ; // active waiting means starting the timer and checking for timeout: ; startTimer(TimerA, 100); ; if (timeout(TimerA)) .. ; ; // Simple delays with built-in task switching until timeout: ; delay(TimerA, 1000); // delay up to 1000 timer ticks ; ; Note that delay(1) will not be precise because the timer ; decrements depends on a single hardware timer, and it is not ; possible to tell when the next increment occurs. The duration of ; delay(1) will be in the interval 0.0 to 1.0 period. For example, ; if half of the period to the next hardware timer increment have ; expired, then the actual period will be 0.5. This means that a ; series of delays will be more precise than a single delay. The ; reason for this is that several task may need service at a ; timeout, and some tasks may have to wait a fraction of the next ; timer increment before the task is scheduled. On the other hand, ; if the timer is started because of an external IO event, then the ; duration of delay(100) will be in the interval 99.0 - 100.0. ; ; The software timers is implemented using the 8 bit hardware timer ; TMR0 and the prescaler. Up to 8 timers is allowed. ; ; timerTick() : 23+ instruction words. The size increases depending ; on the timer size (8, 16 or 24 bit) and the number of timers. ; Three 16 bit timers requires 46 instruction words. The function ; executes in minimum 12 instructions cycles when the next hardware ; timeout period have not expired. This increases when software ; timers needs to be decremented (around 49 instruction cycles when ; decrementing three active 16 bit timers). Required definitions in ; the application program: ; ; ; FreqOsc / (4*FreqTimer) = Cycles = PrescalerDivide * MaxTimerCount ; 20000000 / (4*1000) = 5000 = 32 * 156.25 ; 16000000 / (4*1000) = 4000 = 32 * 125 ; 12000000 / (4*1000) = 3000 = 16 * 187.5 ; 10000000 / (4*1000) = 2500 = 16 * 156.25 ; 8000000 / (4*1000) = 2000 = 16 * 125 ; 4000000 / (4*1000) = 1000 = 8 * 125 ; 4000000 / (4*100) = 10000 = 64 * 156.25 ; 2000000 / (4*1000) = 500 = 4 * 125 ; 2000000 / (4*100) = 5000 = 32 * 156.25 ; 1000000 / (4*100) = 2500 = 16 * 156.25 ; 400000 / (4*100) = 1000 = 8 * 125 ; 100000 / (4*100) = 250 = 2 * 125 ; 32768 / (4*20) = 409.6 = 2 * 204.8 ; 32768 / (4*10) = 819.2 = 4 * 204.8 ; ; 'Cycles' telles how many instructions can be executed between ; each timer increment. ;*/ ; ;#if !defined FreqOsc || !defined FreqTimer ; #error FreqOsc and FreqTimer must be properly defined ;#endif ; ; ;#if FreqOsc % (4*FreqTimer) != 0 ; #if FreqOsc == 32768 && FreqTimer == 10 ; #define PrescalerDivide 1 ; #define MaxTimerCount 204 ; #define TimerDecimals 205 ; #elif FreqOsc == 32768 && FreqTimer == 20 ; #define PrescalerDivide 0 ; #define MaxTimerCount 204 ; #define TimerDecimals 205 ; #else ; #error Combination of FreqOsc and FreqTimer is not implemented ; #endif ;#else ; #if FreqOsc / (4*FreqTimer) == 250 ; #define PrescalerDivide 0 ; #define MaxTimerCount 125 ; #elif FreqOsc / (4*FreqTimer) == 500 ; #define PrescalerDivide 1 ; #define MaxTimerCount 125 ; #elif FreqOsc / (4*FreqTimer) == 1000 ; #define PrescalerDivide 2 ; #define MaxTimerCount 125 ; #elif FreqOsc / (4*FreqTimer) == 2000 ; #define PrescalerDivide 3 ; #define MaxTimerCount 125 ; #elif FreqOsc / (4*FreqTimer) == 4000 ; #define PrescalerDivide 4 ; #define MaxTimerCount 125 ; #elif FreqOsc / (4*FreqTimer) == 8000 ; #define PrescalerDivide 5 ; #define MaxTimerCount 125 ; #elif FreqOsc / (4*FreqTimer) == 3000 ; #define PrescalerDivide 3 ; #define MaxTimerCount 187 ; #define TimerDecimals 0x80 ; #elif FreqOsc / (4*FreqTimer) == 2500 ; #define PrescalerDivide 3 ; #define MaxTimerCount 156 ; #define TimerDecimals 0x40 ; #elif FreqOsc / (4*FreqTimer) == 5000 ; #define PrescalerDivide 4 ; #define MaxTimerCount 156 ; #define TimerDecimals 0x40 ; #elif FreqOsc / (4*FreqTimer) == 10000 ; #define PrescalerDivide 5 ; #define MaxTimerCount 156 ; #define TimerDecimals 0x40 ; #else ; #error Combination of FreqOsc and FreqTimer is not implemented ; #endif ;#endif ; ; ; ;#ifndef DELAY_TYPE ; #error The DELAY_TYPE have to be defined (1,..) ;#endif ; ; ; ; ;// ------------------------------------------- ;#if DELAY_TYPE == 1 ; ;TimerType softTimer[NoOfTimers]; ;char tTimeout; ;char previousTMR0, subClock; ; ; ;#define initTimers() \ ;{ \ ; tTimeout = 0xFF; \ ; previousTMR0 = 0; \ ; subClock = 0; \ ; OPTION = PrescalerDivide; \ ;} ; ;#define startTimer(TimerNo, count) \ ;{ \ ; softTimer[TimerNo] = count; \ ; tTimeout.TimerNo = 0; \ ;} ; ;#define timeout(TimerNo) tTimeout.TimerNo ; ;#define delay(TimerNo, count) \ ;{ \ ; softTimer[TimerNo] = count; \ ; tTimeout.TimerNo = 0; \ ; while (!tTimeout.TimerNo) \ ; waitState(); \ ;} ; ; ;void timerTick( void) ;/* ; - decrements active software timers ;*/ ;{ timerTick ; char sample = TMR0; // sampling the timer MOVF TMR0,W MOVWF sample ; subClock -= sample - previousTMR0; MOVF previousTMR0,W SUBWF sample,W SUBWF subClock,1 ; previousTMR0 = sample; MOVF sample,W MOVWF previousTMR0 ; if ( Carry) BTFSC 0x03,Carry ; return; RETLW .0 ; ; /* new timer tick */ ; subClock += MaxTimerCount; MOVLW .156 ADDWF subClock,1 ; ; #ifdef TimerDecimals ; static char decim; ; decim += TimerDecimals; MOVLW .64 ADDWF decim,1 ; if (Carry) BTFSC 0x03,Carry ; subClock ++; INCF subClock,1 ; #endif ; ; #if NoOfTimers <= 3 ; ; if ( !tTimeout.0) { BTFSC tTimeout,0 GOTO m001 ; softTimer[0] -= 1; DECF softTimer,1 INCF softTimer,W BTFSC 0x03,Zero_ DECF softTimer+1,1 ; if ( softTimer[0] == 0) MOVF softTimer,W IORWF softTimer+1,W BTFSC 0x03,Zero_ ; tTimeout.0 = 1; BSF tTimeout,0 ; } ; ; #if NoOfTimers >= 2 ; if ( !tTimeout.1) { m001 BTFSC tTimeout,1 GOTO m002 ; softTimer[1] -= 1; DECF softTimer+2,1 INCF softTimer+2,W BTFSC 0x03,Zero_ DECF softTimer+3,1 ; if ( softTimer[1] == 0) MOVF softTimer+2,W IORWF softTimer+3,W BTFSC 0x03,Zero_ ; tTimeout.1 = 1; BSF tTimeout,1 ; } ; #endif ; ; #if NoOfTimers >= 3 ; if ( !tTimeout.2) { m002 BTFSC tTimeout,2 GOTO m003 ; softTimer[2] -= 1; DECF softTimer+4,1 INCF softTimer+4,W BTFSC 0x03,Zero_ DECF softTimer+5,1 ; if ( softTimer[2] == 0) MOVF softTimer+4,W IORWF softTimer+5,W BTFSC 0x03,Zero_ ; tTimeout.2 = 1; BSF tTimeout,2 ; } ; #endif ; ; #elif sizeof( TimerType) <= 3 && NoOfTimers <= 8 ; ; char i = NoOfTimers; ; char mask = 1; ; FSR = &softTimer[0] % 256; ; #if __IRP_RAM__ ; IRP = &softTimer[0] / 256; ; #endif ; ; do { ; if ( (mask & tTimeout) == 0) { ; INDF -= 1; ; #if sizeof( TimerType) >= 2 ; if ( INDF == 255) { ; FSR ++; ; INDF --; ; #if sizeof( TimerType) >= 3 ; if ( INDF == 255) { ; FSR ++; ; INDF --; ; FSR --; ; } ; #endif ; FSR --; ; } ; #endif ; ; W = INDF; ; #if sizeof( TimerType) >= 2 ; FSR ++; ; W |= INDF; ; #if sizeof( TimerType) >= 3 ; FSR ++; ; W |= INDF; ; #endif ; #endif ; if ( W == 0) ; tTimeout |= mask; ; #if sizeof( TimerType) >= 2 ; FSR --; ; #if sizeof( TimerType) >= 3 ; FSR --; ; #endif ; #endif ; } ; FSR += sizeof( TimerType); ; mask <<= 1; ; } while ( --i > 0); ; ; #else ; #error Not implemented ; #endif ;} m003 RETLW .0 ; FILE test\mventil.c ;// LEANSLICE - MULTITASKING ;// VENTILATION CONTROL ;// Task ventilationControl: control ventilation on/off, delayed off switching ;// Task generatePCM: send PCM pulses depending on ventilation on/off state ;// Task generatePulses: send 100 pulses when ventilation goes on or off ; ; ;#pragma taskOptions 2 ; ;enum { TimerVC, TimerPulse, TimerPCM }; // Timer identifiers ;#define FreqOsc 4000000 // Oscillator frequenzy ;#define FreqTimer 100 // Timer frequency, 100 Hz ;#define TimerType uns16 // uns8, uns16 or uns24 ;#define NoOfTimers 3 // 1 .. 8 ;#define DELAY_TYPE 1 ;#include "delay.h" ; ;enum { Off, On}; ; ;bit highTemperature @ PORTA.0; ;bit ventilation @ PORTA.1; ;bit outPCM @ PORTA.2; ;bit outPulse @ PORTA.3; ;#define INIT_PORTA 0b00000000 ;#define INIT_TRISA 0b00000001 ; ;Task generatePulses( void) ;{ generatePulses INCF _TaskS1,W ADDWF PCL,1 RETLW .255 GOTO m004 GOTO m006 GOTO m007 ; static char pulses; ; pulses = 100; m004 MOVLW .100 MOVWF pulses ; do { ; outPulse = 1; m005 BSF 0x05,outPulse ; delay( TimerPulse, 50); // 0.5 seconds MOVLW .50 MOVWF softTimer+2 CLRF softTimer+3 BCF tTimeout,1 m006 BTFSS tTimeout,1 RETLW .1 ; outPulse = 0; BCF 0x05,outPulse ; delay( TimerPulse, 50); // 0.5 seconds MOVLW .50 MOVWF softTimer+2 CLRF softTimer+3 BCF tTimeout,1 m007 BTFSS tTimeout,1 RETLW .2 ; } while (--pulses > 0); DECFSZ pulses,1 GOTO m005 ;} RETLW .255 ; ;Task ventilationControl( void) ;{ ventilationControl INCF _TaskS2,W ADDWF PCL,1 RETLW .255 GOTO m008 GOTO m009 GOTO m010 GOTO m011 ; ventilation = Off; m008 BCF 0x05,ventilation ; ; while (!highTemperature) m009 BTFSS 0x05,highTemperature ; waitState(); RETLW .1 ; ; ventilation = On; BSF 0x05,ventilation ; startTask( generatePulses); CLRF _TaskS1 ; ; VENTILATION_ON: ; while (highTemperature) m010 BTFSC 0x05,highTemperature ; waitState(); RETLW .2 ; ; startTimer(TimerVC, 10000); // 100 seconds MOVLW .16 MOVWF softTimer MOVLW .39 MOVWF softTimer+1 BCF tTimeout,0 ; while (!timeout(TimerVC)) { m011 BTFSC tTimeout,0 GOTO m012 ; if (highTemperature) BTFSC 0x05,highTemperature ; goto VENTILATION_ON; GOTO m010 ; waitState(); RETLW .3 ; } ; startTask( generatePulses); m012 CLRF _TaskS1 ; restartTask(); RETLW .0 ;} ; ;Task generatePCM( void) ;{ generatePCM INCF _TaskS3,W ADDWF PCL,1 RETLW .255 GOTO m013 GOTO m014 GOTO m015 ; /* NOTE: pulse width may not be correct when ; ventilation change state from 0 to 1 or from 1 to ; 0. Ensuring that PCM width is always correct will ; require more code. ; */ ; while (1) { ; outPCM = ventilation; m013 BTFSS 0x05,ventilation BCF 0x05,outPCM BTFSC 0x05,ventilation BSF 0x05,outPCM ; delay( TimerPCM, 10); // 0.1 seconds MOVLW .10 MOVWF softTimer+4 CLRF softTimer+5 BCF tTimeout,2 m014 BTFSS tTimeout,2 RETLW .1 ; outPCM = !ventilation; BTFSS 0x05,ventilation BSF 0x05,outPCM BTFSC 0x05,ventilation BCF 0x05,outPCM ; delay( TimerPCM, 90); // 0.9 seconds MOVLW .90 MOVWF softTimer+4 CLRF softTimer+5 BCF tTimeout,2 m015 BTFSC tTimeout,2 GOTO m013 RETLW .2 ; } ;} ; ; ;void main( void) ;{ main ; PORTA = INIT_PORTA; CLRF PORTA ; TRISA = INIT_TRISA; MOVLW .1 TRIS PORTA ; startTask( ventilationControl); CLRF _TaskS2 ; startTask( generatePCM); CLRF _TaskS3 ; clearTask( generatePulses); MOVLW .255 MOVWF _TaskS1 ; initTimers(); MOVWF tTimeout CLRF previousTMR0 CLRF subClock MOVLW .5 OPTION ; ; while (1) { ; timerTick(); m016 CALL timerTick ; taskSlicer(); CALL generatePulses MOVWF _TaskS1 CALL ventilationControl MOVWF _TaskS2 CALL generatePCM MOVWF _TaskS3 ; } GOTO m016 ORG 0x01FF GOTO main END ; *** KEY INFO *** ; RAM usage: 15 bytes (1 local), 10 bytes free ; Maximum call level: 1 ; Total of 145 code words (28 %) ; 46 word(s), 8 %: timerTick ; 25 word(s), 4 %: generatePulses ; 26 word(s), 5 %: ventilationControl ; 27 word(s), 5 %: generatePCM ; 20 word(s), 3 %: main