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