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