1 // ********************************************************************* 2 // Custom DPA Handler code example - Standard Sensors - DDC-SE01 * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: 0002_DDC-SE01.c,v $ 7 // Version: $Revision: 1.10 $ 8 // Date: $Date: 2017/12/11 19:26:49 $ 9 // 10 // Revision history: 11 // 2017/11/16 Release for DPA 3.02 12 // 2017/08/14 Release for DPA 3.01 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 17 18 // This example implements 4 sensors according to the IQRF Sensors standard 19 // 1st sensor is on-board TR temperature sensor. 20 // 2nd sensor is either Dallas 18B20 or MCP9802 temperature sensor at DDC-SE01 board (according to the HW jumper position) chosen at the runtime based on the SW detection. 21 // 3rd sensor is light intensity indicator at DDC-SE01 board (value range is 0[max light]-127[max dark]). 22 // 4th sensor is potentiometer value at DDC-SE01 board (value range is 0[left stop]-127[right stop]). 23 24 // The example will not work at demo DPA version because demo DPA does not support PCMD != 0 25 26 // Default IQRF include (modify the path according to your setup) 27 #include "IQRF.h" 28 29 // Default DPA header (modify the path according to your setup) 30 #include "DPA.h" 31 // Default Custom DPA Handler header (modify the path according to your setup) 32 #include "DPAcustomHandler.h" 33 // IQRF standards header (modify the path according to your setup) 34 #include "IQRFstandard.h" 35 #include "IQRF_HWPID.h" 36 37 //############################################################################################ 38 39 // Number of implemented sensors 40 #define SENSORS_COUNT 4 41 42 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data. 43 uns16 sensorValue @ param3; 44 45 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable 46 bit Get0_TemperatureTR(); 47 bit Get1_Temperature(); 48 bit Get2_BinaryData_Light(); 49 bit Get3_BinaryData_Potentiometer(); 50 51 // Temperature sensors read routine for both DDC-SE01 sensor types 52 void GetTemperature(); 53 // Read preset PIC ADC for DDC-SE01 54 uns8 ReadAdc(); 55 56 // Stores sensor value byte(s) to the FSR1[+1...], in case of PCMD_STD_SENSORS_READ_TYPES_AND_VALUES sensor type is stored before value byte(s) 57 void StoreValue( uns8 sensorType ); 58 59 // Sensor connected to PORT C.3 (compatible with DDC-SE-01) 60 #define OneWire_TRIS TRISC.3 61 #define OneWire_IO_IN PORTC.3 62 #define OneWire_IO_OUT LATC.3 63 64 // Writes sensor configuration (resolution) 65 bit Ds18B20WriteConfig( uns8 value ); 66 67 // Resets OneWire 68 bit OneWireReset(); 69 // Reads OneWire byte 70 uns8 OneWireReadByte(); 71 // Writes OneWire byte 72 void OneWireWriteByte( uns8 byte ); 73 74 // DS18B20 commands 75 #define CMD_READROM 0x33 76 #define CMD_CONVERTTEMP 0x44 77 #define CMD_CPYSCRATCHPAD 0x48 78 #define CMD_WSCRATCHPAD 0x4e 79 #define CMD_MATCHROM 0x55 80 #define CMD_RPWRSUPPLY 0xb4 81 #define CMD_RECEEPROM 0xb8 82 #define CMD_RSCRATCHPAD 0xbe 83 #define CMD_SKIPROM 0xcc 84 #define CMD_ALARMSEARCH 0xec 85 #define CMD_SEARCHROM 0xf0 86 87 // I2C routines 88 void i2c_init(); 89 void i2c_shutdown(); 90 void i2c_waitForIdle(); 91 void i2c_start(); 92 void i2c_repStart(); 93 void i2c_stop(); 94 uns8 i2c_read( bit ack ); 95 void i2c_write( uns8 i2cWriteData ); 96 97 // MCP9802 address 98 #define I2C_ADR 0b10010110 99 // Power pin 100 #define PWR_SENSOR_TRIS TRISC.7 101 #define PWR_SENSOR_IO LATC.7 102 103 // Special temperature value to indicate a sensor error, compatible with IQRF sensor standard 104 #define ERROR_TEMPERATURE 0x8000 105 106 // TRUE if DS18B20 is enabled at runtime at startup, FALSE in case of MCP9802 107 bit isDS18B20; 108 // Final DS18B20 temperature value read by state machine 109 uns16 temperature; 110 111 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 112 //############################################################################################ 113 bit CustomDpaHandler() 114 //############################################################################################ 115 { 116 // This forces CC5X to wisely use MOVLB instructions (doc says: The 'default' bank is used by the compiler for loops and labels when the algorithm gives up finding the optimal choice) 117 #pragma updateBank default = UserBank_01 118 119 // Finite machine states 120 typedef enum 121 { 122 S_ResetConvertT = 0, 123 S_SkipRomConvertT, 124 S_CmdConvertT, 125 126 S_WaitConvertT, 127 128 S_ResetReadTemp, 129 S_SkipRomReadTemp, 130 S_CmdReadTemp, 131 S_Byte1ReadTemp, 132 S_Byte2ReadTemp 133 } TState; 134 135 // Handler presence mark 136 clrwdt(); 137 138 // Sleeping parameters, valid when Time != 0 139 static TPerOSSleep_Request PerOSSleep_Request; 140 // Finite machine state 141 static uns8 state; // = S_ResetConvertT = 0 142 // Pre-read lower temperature byte 143 static uns8 temperatureByteLow; 144 // Conversion timeout counter 145 static uns8 timeout; 146 147 // Detect DPA event to handle 148 switch ( GetDpaEvent() ) 149 { 150 // ------------------------------------------------- 151 case DpaEvent_Interrupt: 152 // Do an extra quick background interrupt work 153 // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible. 154 // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one. 155 // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time. 156 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 157 // ! Make sure race condition does not occur when accessing those variables at other places. 158 // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt. 159 // ! Do not call any OS functions except setINDFx(). 160 // ! Do not use any OS variables especially for writing access. 161 // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage. 162 163 // ms per TMR6 interrupt 164 #define TICKS_LEN 10 165 166 // If TMR6 interrupt occurred 167 if ( TMR6IF ) 168 { 169 // Unmask interrupt 170 TMR6IF = 0; 171 // Decrement count 172 if ( timeout != 0 ) 173 timeout--; 174 } 175 return Carry; 176 177 // ------------------------------------------------- 178 case DpaEvent_Idle: 179 // Do a quick background work when RF packet is not received 180 181 // Should go to sleep? 182 if ( PerOSSleep_Request.Time != 0 ) 183 { 184 // Copy sleep parameters to the DPA request 185 _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time; 186 _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control; 187 // Switch off sleeping time=flag 188 PerOSSleep_Request.Time = 0; 189 // Finalize OS Sleep DPA Request 190 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 191 _PNUM = PNUM_OS; 192 _PCMD = CMD_OS_SLEEP; 193 // Perform local DPA Request to go to sleep 194 DpaApiLocalRequest(); 195 } 196 197 // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC 198 if ( !isDS18B20 ) 199 break; 200 201 // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation 202 OneWire_IO_OUT = 0; 203 204 skip( state ); 205 #pragma computedGoto 1 206 goto _S_ResetConvertT; 207 goto _S_SkipRomConvertT; 208 goto _S_CmdConvertT; 209 goto _S_WaitConvertT; 210 goto _S_ResetReadTemp; 211 goto _S_SkipRomReadTemp; 212 goto _S_CmdReadTemp; 213 goto _S_Byte1ReadTemp; 214 goto _S_Byte2ReadTemp; 215 #pragma computedGoto 0 216 ; 217 // -------------- 218 _S_Byte2ReadTemp: 219 temperature.high8 = OneWireReadByte(); 220 temperature.low8 = temperatureByteLow; 221 222 ResetMachine: 223 state = S_ResetConvertT; 224 goto ExitMachine; 225 226 // -------------- 227 _S_ResetConvertT: 228 _S_ResetReadTemp: 229 if ( !OneWireReset() ) 230 { 231 _S_Error_Reset: 232 temperature = ERROR_TEMPERATURE; 233 goto ResetMachine; 234 } 235 goto NextState; 236 237 // -------------- 238 _S_SkipRomConvertT: 239 _S_SkipRomReadTemp: 240 // OneWire: Skip ROM 241 OneWireWriteByte( CMD_SKIPROM ); 242 goto NextState; 243 244 // -------------- 245 _S_CmdConvertT: 246 // OneWire: Convert temperature 247 OneWireWriteByte( CMD_CONVERTTEMP ); 248 // Setup timeout for approx 750 ms (the longest conversion time) 249 timeout = 2 + 750 / TICKS_LEN; 250 goto NextState; 251 252 // -------------- 253 _S_WaitConvertT: 254 if ( OneWireReadByte() == 0xff ) 255 goto NextState; 256 257 // Timeout? 258 if ( timeout == 0 ) 259 goto _S_Error_Reset; 260 261 goto ExitMachine; 262 263 // -------------- 264 _S_CmdReadTemp: 265 // OneWire: Read scratchpad 266 OneWireWriteByte( CMD_RSCRATCHPAD ); 267 goto NextState; 268 269 // -------------- 270 _S_Byte1ReadTemp: 271 temperatureByteLow = OneWireReadByte(); 272 goto NextState; 273 274 // -------------- 275 NextState: 276 ++state; 277 278 ExitMachine: 279 break; 280 281 // ------------------------------------------------- 282 case DpaEvent_Init: 283 // Do a one time initialization work before main loop starts 284 285 // Initialize sensors 286 // C5 (AN4) as input 287 moduleInfo(); 288 // Connected TR pins? 289 if ( !bufferINFO[5].7 ) 290 { 291 TRISC.6 = 1; 292 TRISB.4 = 1; 293 } 294 TRISA.5 = 1; 295 296 // C1 (AN0) as input 297 TRISA.0 = 1; 298 299 // Setup TMR6 to generate ticks on the background (ticks every 10ms) 300 #if F_OSC == 16000000 301 PR6 = 250 - 1; 302 T6CON = 0b0.1001.1.10; // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 303 #else 304 #error Unsupported oscillator frequency 305 #endif 306 307 // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet) 308 if ( Ds18B20WriteConfig( 0b0.00.00000 ) ) 309 // DS18B20 is enabled 310 isDS18B20 = TRUE; 311 else 312 // Expect MCP9802 is enabled 313 i2c_init(); 314 315 break; 316 317 // ------------------------------------------------- 318 case DpaEvent_AfterSleep: 319 // Called after woken up after sleep 320 if ( !isDS18B20 ) 321 i2c_init(); 322 323 // Called on wake-up from sleep 324 TMR6IE = TRUE; 325 TMR6ON = TRUE; 326 break; 327 328 // ------------------------------------------------- 329 case DpaEvent_BeforeSleep: 330 // Called before going to sleep 331 if ( !isDS18B20 ) 332 i2c_shutdown(); 333 334 // ------------------------------------------------- 335 case DpaEvent_DisableInterrupts: 336 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart and RFPGM) 337 // Must not use TMR6 any more 338 TMR6ON = FALSE; 339 TMR6IE = FALSE; 340 break; 341 342 // ------------------------------------------------- 343 case DpaEvent_DpaRequest: 344 // Called to interpret DPA request for peripherals 345 // ------------------------------------------------- 346 // Peripheral enumeration 347 if ( IsDpaEnumPeripheralsRequest() ) 348 { 349 // We implement 1 standard user peripheral 350 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 351 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 352 _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_MICRORISC__DEMO_DDC_SE01; 353 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000; 354 355 DpaHandleReturnTRUE: 356 return TRUE; 357 } 358 // ------------------------------------------------- 359 // Get information about peripheral 360 else if ( IsDpaPeripheralInfoRequest() ) 361 { 362 if ( _PNUM == PNUM_STD_SENSORS ) 363 { 364 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS; 365 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 366 // Set standard version 367 _DpaMessage.PeripheralInfoAnswer.Par1 = 13; 368 goto DpaHandleReturnTRUE; 369 } 370 371 break; 372 } 373 // ------------------------------------------------- 374 else 375 { 376 // Handle peripheral command 377 378 // Supported peripheral number? 379 if ( _PNUM == PNUM_STD_SENSORS ) 380 { 381 // Supported commands? 382 switch ( _PCMD ) 383 { 384 // Invalid command 385 default: 386 // Return error 387 DpaApiReturnPeripheralError( ERROR_PCMD ); 388 389 // Sensor enumeration 390 case PCMD_STD_ENUMERATE: 391 if ( _DpaDataLength != 0 ) 392 goto _ERROR_DATA_LEN; 393 394 // Then just enumerate their types 395 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE; 396 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_TEMPERATURE; 397 _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_BINARYDATA7; 398 _DpaMessage.Response.PData[3] = STD_SENSOR_TYPE_BINARYDATA7; 399 W = SENSORS_COUNT; 400 goto _W2_DpaDataLength; 401 402 // Supported commands. They are handled the same way except one "if" at StoreValue() method 403 case PCMD_STD_SENSORS_READ_VALUES: 404 case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES: 405 { 406 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if 407 W = _DpaDataLength; 408 if ( W == 0 ) // Note: must not modify W 409 { 410 // Actually clears the bitmap 411 #if &_DpaMessage.Request.PData[0] != &bufferRF[0] 412 #error 413 #endif 414 clearBufferRF(); 415 // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care) 416 _DpaMessage.Request.PData[0].0 = 1; 417 // Bitmap is 32 bits long = 4 418 _DpaDataLength = W = 4; 419 } 420 421 // Invalid bitmap (data) length (W = _DpaDataLength)? 422 if ( W != 4 ) 423 { 424 _ERROR_DATA_LEN: 425 // Return error 426 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 427 } 428 429 // Now read the sensors 430 431 // Prepare pointer (minus 1, see below) to store sensor (types and) values to 432 // Note: 4 sensors at this example cannot return more than DPA_MAX_DATA_LENGTH bytes of data, so it does not have to be checked... 433 // ... If it would be the case, then ERROR_FAIL must be returned 434 FSR1 = &_DpaMessage.Response.PData[-1]; 435 436 // Store bitmap of sensors to get values from 437 uns8 sensorsBitmap = FSR1[1]; 438 439 // 1st sensor (index 0) selected? 440 if ( sensorsBitmap.0 ) 441 { 442 Get0_TemperatureTR(); 443 StoreValue( STD_SENSOR_TYPE_TEMPERATURE ); 444 } 445 446 // 2nd sensor (index 1) selected? 447 if ( sensorsBitmap.1 ) 448 { 449 Get1_Temperature(); 450 StoreValue( STD_SENSOR_TYPE_TEMPERATURE ); 451 } 452 453 // 3rd sensor (index 2) selected? 454 if ( sensorsBitmap.2 ) 455 { 456 Get2_BinaryData_Light(); 457 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 458 } 459 460 // 4th sensor (index 3) selected? 461 if ( sensorsBitmap.3 ) 462 { 463 Get3_BinaryData_Potentiometer(); 464 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 465 } 466 467 // Compute returned data bytes count 468 W = FSR1L - ( (uns16)&_DpaMessage.Response.PData[0] & 0xFF ) + 1; 469 // Optimization: return W long block of bytes at response 470 _W2_DpaDataLength: 471 _DpaDataLength = W; 472 goto DpaHandleReturnTRUE; 473 } 474 } 475 } 476 477 break; 478 } 479 480 // ------------------------------------------------- 481 case DpaEvent_FrcValue: 482 // Called to get FRC value 483 484 // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...] 485 FSR1 = &DataOutBeforeResponseFRC[0]; 486 // Check for correct FRC user data 487 if ( *FSR1++ /*DataOutBeforeResponseFRC[0]*/ == PNUM_STD_SENSORS ) 488 { 489 // Actually used sensor index 490 uns8 sensorIndex = FSR1[1] /*DataOutBeforeResponseFRC[2]*/ & 0x1f; 491 // Test sensor type 492 switch ( *FSR1++ /*DataOutBeforeResponseFRC[1]*/ ) 493 { 494 default: 495 goto DpaHandleReturnFALSE; 496 497 // No type specified, use specified index value 498 case 0x00: 499 goto _KeepSensorIndex; 500 501 // For other types make the index value based on the requested index value and sensor type 502 case STD_SENSOR_TYPE_TEMPERATURE: 503 if ( sensorIndex > 1 ) 504 goto DpaHandleReturnFALSE; 505 W = 0 + sensorIndex; 506 break; 507 508 case STD_SENSOR_TYPE_BINARYDATA7: 509 if ( sensorIndex > 1 ) 510 goto DpaHandleReturnFALSE; 511 W = 2 + sensorIndex; 512 break; 513 } 514 515 // New sensor index based on type and requested index 516 sensorIndex = W; 517 _KeepSensorIndex: 518 519 // Test for supported FRC commands 520 switch ( _PCMD ) 521 { 522 default: 523 goto DpaHandleReturnFALSE; 524 525 case FRC_STD_SENSORS_BIT: 526 case FRC_STD_SENSORS_1B: 527 case FRC_STD_SENSORS_2B: 528 switch ( sensorIndex ) 529 { 530 default: 531 goto DpaHandleReturnFALSE; 532 533 case 0: 534 Carry = Get0_TemperatureTR(); 535 break; 536 537 case 1: 538 Carry = Get1_Temperature(); 539 break; 540 541 case 2: 542 Carry = Get2_BinaryData_Light(); 543 break; 544 545 case 3: 546 Carry = Get3_BinaryData_Potentiometer(); 547 break; 548 } 549 550 // This type of FRC is not valid for the specified sensor 551 if ( !Carry ) 552 goto DpaHandleReturnFALSE; 553 554 break; 555 } 556 557 // Some sensor was measured by FRC, check if there is a sleep request 558 FSR1++; 559 if ( INDF1.0 ) // Note: same as DataOutBeforeResponseFRC[3].0 560 { 561 // Remember sleep parameters to go to sleep at the Idle event later 562 PerOSSleep_Request.Time.low8 = FSR1[4 - 3]; // Note: same as DataOutBeforeResponseFRC[4]; 563 PerOSSleep_Request.Time.high8 = FSR1[5 - 3]; // Note: same as DataOutBeforeResponseFRC[5]; 564 PerOSSleep_Request.Control = FSR1[6 - 3]; // Note: same as DataOutBeforeResponseFRC[6]; 565 } 566 } 567 568 break; 569 570 // ------------------------------------------------- 571 case DpaEvent_FrcResponseTime: 572 // Called to get FRC response time 573 574 // In this example the FRC commands are fast 575 switch ( DataOutBeforeResponseFRC[0] ) 576 { 577 case FRC_STD_SENSORS_BIT: 578 case FRC_STD_SENSORS_1B: 579 case FRC_STD_SENSORS_2B: 580 responseFRCvalue = _FRC_RESPONSE_TIME_40_MS; 581 break; 582 } 583 break; 584 } 585 DpaHandleReturnFALSE: 586 return FALSE; 587 } 588 589 //############################################################################################ 590 // Increases FSR1 and then stores the byte 591 void setPlusPlusINDF1( uns8 data @ W ) 592 //############################################################################################ 593 { 594 FSR1++; // Note: must not modify W 595 setINDF1( data ); 596 } 597 598 //############################################################################################ 599 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...] 600 void StoreValue( uns8 sensorType ) 601 //############################################################################################ 602 { 603 // Is the sensor type to be stored too? 604 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES ) 605 setPlusPlusINDF1( sensorType ); 606 607 // Store lower value byte 608 setPlusPlusINDF1( sensorValue.low8 ); 609 610 // No more value bytes to store? 611 if ( sensorType.7 != 0 ) 612 return; 613 614 // Store higher value byte 615 setPlusPlusINDF1( sensorValue.high8 ); 616 617 // Note: this example implements sensors returning only 1 or 2 bytes of data. If another data widths are returned, then it must be implemented explicitly. 618 } 619 620 //############################################################################################ 621 bit setFRCerror1B() 622 //############################################################################################ 623 { 624 responseFRCvalue = 2; 625 return TRUE; 626 } 627 628 //############################################################################################ 629 bit setFRCerror2B() 630 //############################################################################################ 631 { 632 responseFRCvalue2B = 2; 633 return TRUE; 634 } 635 636 //############################################################################################ 637 bit sensorError; 638 bit AdjustFrcTemperature() 639 //############################################################################################ 640 { 641 // Test for supported FRC commands 642 switch ( _PCMD ) 643 { 644 default: 645 return FALSE; 646 647 case FRC_STD_SENSORS_1B: 648 // Return sensor FRC value 1B 649 // Check for out of limits 650 if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) ) 651 return setFRCerror1B(); 652 653 // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution 654 uns16 _sensorValue = sensorValue + 4; // Note: do rounding when /8 655 responseFRCvalue = (uns8)( _sensorValue / 8 ) + 44; 656 break; 657 658 case FRC_STD_SENSORS_2B: 659 // Return sensor FRC value 2B 660 if ( sensorError ) 661 return setFRCerror2B(); 662 663 responseFRCvalue2B = sensorValue ^ 0x8000; 664 break; 665 } 666 667 return TRUE; 668 } 669 670 //############################################################################################ 671 // Sensor index 0: measure temperature using the TR sensor 672 bit Get0_TemperatureTR() 673 //############################################################################################ 674 { 675 // Make sure FSR1 is not modified 676 677 // When error, then adjust the standard error values 678 sensorError = FALSE; 679 // Measure temperature using TR sensor 680 if ( getTemperature() == -128 ) 681 { 682 sensorError = TRUE; 683 sensorValue = 0x8000; 684 } 685 686 // Return sensor value 687 sensorValue = param3; 688 // Handler FRC 689 return AdjustFrcTemperature(); 690 } 691 692 //############################################################################################ 693 // Sensor index 1: measure temperature using one of the DDC-SE01 sensors 694 bit Get1_Temperature() 695 //############################################################################################ 696 { 697 // Make sure FSR1 is not modified 698 699 // Measure temperature using DDC-SE01 sensors 700 sensorError = FALSE; 701 // Read temperature and check for an error 702 GetTemperature(); 703 // When error, return standard (FRC) error value(s) 704 if ( sensorValue == ERROR_TEMPERATURE ) 705 sensorError = TRUE; 706 707 // FrcValues 708 return AdjustFrcTemperature(); 709 } 710 711 //############################################################################################ 712 bit AdjustFrcBinaryData() 713 //############################################################################################ 714 { 715 // Test for supported FRC commands 716 switch ( _PCMD ) 717 { 718 default: 719 return FALSE; 720 721 case FRC_STD_SENSORS_BIT: 722 // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01] 723 724 // Number of shifts to get the bit out of the return value 725 uns8 bitLoop = ( INDF1 >> 5 ) + 1; 726 // Value to get the bit from 727 W = sensorValue.low8; 728 do 729 { 730 // Get the bit to Carry 731 W = rr( W ); 732 // Next bit 733 } while ( --bitLoop != 0 ); // Note: must not modify W and Carry 734 // Current (prepared by DPA) FRC value is [01], change it to [11] (means bit is set) 735 responseFRCvalue.1 = 1; // Note: must not modify Carry 736 // Is bit set? 737 if ( !Carry ) 738 // Bit is NOT set, return [10] 739 responseFRCvalue.0 = 0; 740 break; 741 742 case FRC_STD_SENSORS_1B: 743 responseFRCvalue = sensorValue.low8 + 4; 744 break; 745 } 746 return TRUE; 747 } 748 749 //############################################################################################ 750 // Sensor index 2: returns light intensity indicator value using DDC-SE01 751 bit Get2_BinaryData_Light() 752 //############################################################################################ 753 { 754 // Make sure FSR1 is not modified 755 756 // ADC initialization (for more info see PIC datasheet) pin C1 (AN0) as analog input 757 ANSELA.0 = 1; 758 // ADC setting (AN0 channel) 759 ADCON0 = 0b0.00000.01; 760 // Read ADC 761 sensorValue.low8 = ReadAdc() / 2; 762 // Return sensor FRC value 763 return AdjustFrcBinaryData(); 764 } 765 766 //############################################################################################ 767 // Sensor index 3: returns potentiometer value using DDC-SE01 768 bit Get3_BinaryData_Potentiometer() 769 //############################################################################################ 770 { 771 // Make sure FSR1 is not modified 772 773 // ADC initialization (for more info see PIC datasheet) pin C5 (AN4) as analog input 774 ANSELA.5 = 1; 775 // ADC setting (AN4 channel) 776 ADCON0 = 0b0.00100.01; 777 // Read ADC 778 sensorValue.low8 = ReadAdc() / 2; 779 // Return sensor FRC value 780 return AdjustFrcBinaryData(); 781 } 782 783 //############################################################################################ 784 // OneWire and Dallas 18B20 routines 785 //############################################################################################ 786 787 //############################################################################################ 788 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0 789 //############################################################################################ 790 { 791 // 16 MHz 792 // + 0.75us ( W=val, Call ) 793 for ( ;; ) 794 { // loop time 795 nop2(); // 0.50us 796 nop2(); // 1.00us 797 nop2(); // 1.50us 798 nop2(); // 2.00us 799 nop2(); // 2.50us 800 nop2(); // 3.00us 801 nop(); // 3.25us 802 if ( --val == 0 ) // + 0.75us (W--, BTFS ) 803 return; // + 0.25us 804 nop2(); // 4.50us 805 } // 5.00us (Goto) 806 } 807 //############################################################################################ 808 809 #define OneWireData0() { OneWire_TRIS = 0; } // 1us [0.5us @ 16MHz] 810 #define OneWireData1() { OneWire_TRIS = 1; } // 1us [0.5us @ 16MHz] 811 812 //############################################################################################ 813 void OneWireWriteByte( uns8 byte ) 814 //############################################################################################ 815 { 816 uns8 bitLoop = 8; 817 do 818 { 819 // Next sequence is time precision critical 820 GIE = FALSE; 821 822 OneWireData0(); 823 nop2(); // 1 us [0.5 us] 824 nop2(); // [1.0 us] 825 if ( byte.0 ) // 2.5 us [1.75us] 826 OneWireData1(); 827 828 // End of time precision critical sequence 829 GIE = TRUE; 830 831 // 60us minimum in total, does not have to be precise 832 Delay5us( ( 60 - 3 ) / 5 + 1 ); 833 834 OneWireData1(); 835 836 byte >>= 1; 837 } while ( --bitLoop != 0 ); 838 } 839 840 //############################################################################################ 841 uns8 OneWireReadByte() 842 //############################################################################################ 843 { 844 uns8 result; 845 uns8 bitLoop = 8; 846 do 847 { 848 // Next sequence is time precision critical 849 GIE = FALSE; 850 851 OneWireData0(); 852 nop2(); // 1 us [0.5 us] 853 #if F_OSC == 16000000 854 nop2(); // [1.0 us] 855 #endif 856 OneWireData1(); // 2 us [1.5 us] 857 Delay5us( 15 / 5 ); // 17 us [16.5 us] 858 859 Carry = 0; // 17.5 us [16.75 us] 860 if ( OneWire_IO_IN ) // 18.5 us [ 17.25 us] (condition must not modify Carry) 861 Carry = 1; 862 863 // End of time precision critical sequence 864 GIE = TRUE; // must not modify Carry 865 result = rr( result ); 866 867 // 60us minimum in total, does not have to be precise 868 Delay5us( ( 60 - 20 ) / 5 + 1 ); 869 } while ( --bitLoop != 0 ); 870 871 return result; 872 } 873 874 //############################################################################################ 875 bit OneWireReset() 876 //############################################################################################ 877 { 878 // Setting the pin once to low is enough 879 OneWire_IO_OUT = 0; 880 // Reset pulse 881 OneWireData0(); 882 Delay5us( 500 / 5 ); 883 // Reset pulse end 884 OneWireData1(); 885 // Next sequence is time precision critical 886 GIE = FALSE; 887 // Wait for presence pulse 888 Delay5us( 70 / 5 ); 889 // End of time precision critical sequence 890 GIE = TRUE; 891 // Presence pulse? 892 if ( OneWire_IO_IN ) 893 { 894 // No presence, finish initialization sequence 895 Delay5us( ( 500 - 70 ) / 5 ); 896 return FALSE; 897 } 898 else 899 { 900 // Presence OK, finish initialization sequence 901 Delay5us( ( 500 - 70 ) / 5 ); 902 return TRUE; 903 } 904 } 905 906 //############################################################################################ 907 void OneWireCmd( uns8 cmd ) 908 //############################################################################################ 909 { 910 // OneWire: Skip ROM 911 OneWireWriteByte( CMD_SKIPROM ); 912 // OneWire: Send command 913 OneWireWriteByte( cmd ); 914 } 915 916 //############################################################################################ 917 bit Ds18B20WriteConfig( uns8 value ) 918 //############################################################################################ 919 { 920 if ( OneWireReset() ) 921 { 922 // Write Scratchpad 923 OneWireCmd( CMD_WSCRATCHPAD ); 924 925 // Write TL = ? (we dot not care the value) 926 OneWireWriteByte( W ); 927 // Write TH = ? (we dot not care the value) 928 OneWireWriteByte( W ); 929 // Write Config byte 930 OneWireWriteByte( value ); 931 932 if ( OneWireReset() ) 933 { 934 // Copy Scratchpad 935 OneWireCmd( CMD_CPYSCRATCHPAD ); 936 return TRUE; 937 } 938 } 939 return FALSE; 940 } 941 942 //############################################################################################ 943 void writeToSSPCON2( uns8 value @ param4.high8 ) 944 //############################################################################################ 945 { 946 writeToRAM( &SSPCON2, value ); 947 } 948 949 //############################################################################################ 950 void writeOredToSSPCON2( uns8 value @ param4.high8 ) 951 //############################################################################################ 952 { 953 writeToSSPCON2( SSPCON2 | value ); 954 } 955 956 //############################################################################################ 957 // I2C routines 958 //############################################################################################ 959 960 bit i2cTimeout; 961 962 //############################################################################################ 963 void i2c_init() 964 //############################################################################################ 965 { 966 // SCL as input (SIM C6) 967 TRISC.3 = 1; 968 // SDA as input (SIM C7) 969 TRISC.4 = 1; 970 971 // I2C master mode SSPCON = 0b00111000 972 writeToRAM( &SSPCON1, 0x38 ); 973 writeToSSPCON2( 0x00 ); 974 975 // 50 kHz SCL frequency 976 SSPADD = ( F_OSC / 50000 / 4 ) - 2; 977 // Disable slew rate control 978 SMP = 1; 979 } 980 981 //############################################################################################ 982 void i2c_shutdown() 983 //############################################################################################ 984 { 985 // I2C master mode SSPCON = 0 986 writeToRAM( &SSPCON1, 0x00 ); 987 } 988 989 //############################################################################################ 990 void i2c_waitForIdle() 991 //############################################################################################ 992 { 993 i2cTimeout = FALSE; 994 uns8 timeout; 995 // Wait for idle and not writing 996 timeout = 0; 997 while ( ( SSPCON2 & 0b0001.1111 ) != 0 || RW_ ) 998 if ( ++timeout == 0 ) 999 { 1000 i2cTimeout = TRUE; 1001 break; 1002 } 1003 } 1004 1005 //############################################################################################ 1006 void i2c_start() 1007 //############################################################################################ 1008 { 1009 i2c_waitForIdle(); 1010 // SEN = 1 1011 writeOredToSSPCON2( 0x01 ); 1012 } 1013 1014 //############################################################################################ 1015 void i2c_repStart() 1016 //############################################################################################ 1017 { 1018 i2c_waitForIdle(); 1019 // RSEN = 1 1020 writeOredToSSPCON2( 0x02 ); 1021 } 1022 1023 //############################################################################################ 1024 void i2c_stop() 1025 //############################################################################################ 1026 { 1027 i2c_waitForIdle(); 1028 // PEN = 1 1029 writeOredToSSPCON2( 0x04 ); 1030 } 1031 1032 //############################################################################################ 1033 uns8 i2c_read( bit ack ) 1034 //############################################################################################ 1035 { 1036 i2c_waitForIdle(); 1037 // RCEN = 1 1038 writeOredToSSPCON2( 0x08 ); 1039 1040 i2c_waitForIdle(); 1041 1042 uns8 i2cReadData @ userReg0; 1043 i2cReadData = SSPBUF; 1044 1045 i2c_waitForIdle(); 1046 1047 if ( ack ) 1048 // Acknowledge, ACKDT = 0 1049 writeToSSPCON2( SSPCON2 & 0xDF ); 1050 else 1051 // Not acknowledge, ACKDT = 1 1052 writeOredToSSPCON2( 0x20 ); 1053 1054 // Send acknowledge sequence, ACKEN = 1 1055 writeOredToSSPCON2( 0x10 ); 1056 return i2cReadData; 1057 } 1058 1059 //############################################################################################ 1060 void i2c_write( uns8 i2cWriteData @ param2 ) 1061 //############################################################################################ 1062 { 1063 i2c_waitForIdle(); 1064 SSPBUF = i2cWriteData; 1065 } 1066 1067 //############################################################################################ 1068 void MCP9802GetTemp() 1069 //############################################################################################ 1070 { 1071 sensorValue = ERROR_TEMPERATURE; 1072 1073 i2c_start(); 1074 if ( i2cTimeout ) 1075 return; 1076 1077 // MCP9802 address 1078 i2c_write( I2C_ADR ); 1079 // pointer: 1 = configuration register 1080 i2c_write( 0x01 ); 1081 // configuration: 9-bit ADC 1082 i2c_write( 0x00 ); 1083 i2c_stop(); 1084 1085 i2c_start(); 1086 // MCP9802 address 1087 i2c_write( I2C_ADR ); 1088 // pointer: 0 = temperature 1089 i2c_write( 0 ); 1090 i2c_stop(); 1091 1092 i2c_start(); 1093 // MCP9802 address + read 1094 i2c_write( I2C_ADR | 1 ); 1095 // store the result 1096 sensorValue.high8 = i2c_read( TRUE ); 1097 sensorValue.low8 = i2c_read( FALSE ); 1098 i2c_stop(); 1099 } 1100 1101 //############################################################################################ 1102 // Other routines 1103 //############################################################################################ 1104 1105 //############################################################################################ 1106 void GetTemperature() 1107 //############################################################################################ 1108 { 1109 // Reads temperature from an enabled sensor 1110 if ( isDS18B20 ) 1111 // Temperature is ready at the background 1112 sensorValue = temperature; 1113 else 1114 { 1115 // Temperature value must be read from I2C sensor 1116 MCP9802GetTemp(); 1117 if ( sensorValue != ERROR_TEMPERATURE ) 1118 { 1119 sensorValue += 0x08; 1120 sensorValue /= 0x10; 1121 } 1122 } 1123 } 1124 1125 //############################################################################################ 1126 uns8 ReadAdc() 1127 //############################################################################################ 1128 { 1129 // ADC result - left justified, Fosc/8 1130 ADCON1 = 0b0001.0000; 1131 // Do a smallest delay for ADC ACQUISITION TIME 1132 waitMS( 1 ); 1133 // start ADC 1134 GO = 1; 1135 // wait for ADC finish 1136 while ( GO ); 1137 return ADRESH; 1138 } 1139 1140 //############################################################################################ 1141 // Default Custom DPA Handler header; 2nd include to implement Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 1142 #include "DPAcustomHandler.h" 1143 //############################################################################################