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.23 $ 8 // Date: $Date: 2019/04/03 09:27:58 $ 9 // 10 // Revision history: 11 // 2018/10/25 Release for DPA 3.03 12 // 2017/11/16 Release for DPA 3.02 13 // 2017/08/14 Release for DPA 3.01 14 // 15 // ********************************************************************* 16 17 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 18 // IQRF Standards documentation https://www.iqrfalliance.org/techDocs/ 19 20 // This example implements 4 sensors according to the IQRF Sensors standard 21 // 1st sensor is on-board TR temperature sensor. 22 // 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. 23 // 3rd sensor is light intensity indicator at DDC-SE-01 board (value range is 0[max light]-127[max dark]). 24 // 4th sensor is potentiometer value at DDC-SE-01 board (value range is 0[left stop]-127[right stop]). 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-SE-01 sensor types 52 void GetTemperature(); 53 // Read preset PIC ADC for DDC-SE-01 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, LoadCode, Remove bond, and Run 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_IQRF_TECH__DEMO_DDC_SE01; 353 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0001; 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 setFRCerror() 622 //############################################################################################ 623 { 624 responseFRCvalue2B = 2; 625 return TRUE; 626 } 627 628 //############################################################################################ 629 bit sensorError; 630 bit AdjustFrcTemperature() 631 //############################################################################################ 632 { 633 // Test for supported FRC commands 634 switch ( _PCMD ) 635 { 636 default: 637 return FALSE; 638 639 case FRC_STD_SENSORS_1B: 640 // Return sensor FRC value 1B 641 // Check for out of limits 642 if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) ) 643 return setFRCerror(); 644 645 // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution 646 uns16 _sensorValue = sensorValue + 4; // Note: do rounding when /8 647 responseFRCvalue = (uns8)( _sensorValue / 8 ) + 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 sensorValue = 0x8000; 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 ( sensorValue == ERROR_TEMPERATURE ) 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 writeToSSPCON2( uns8 value ) 936 //############################################################################################ 937 { 938 writeToRAM( &SSPCON2, value ); 939 } 940 941 //############################################################################################ 942 void writeOredToSSPCON2( uns8 value ) 943 //############################################################################################ 944 { 945 writeToSSPCON2( SSPCON2 | value ); 946 } 947 948 //############################################################################################ 949 // I2C routines 950 //############################################################################################ 951 952 bit i2cTimeout; 953 954 //############################################################################################ 955 void i2c_init() 956 //############################################################################################ 957 { 958 // SCL as input (SIM C6) 959 TRISC.3 = 1; 960 // SDA as input (SIM C7) 961 TRISC.4 = 1; 962 963 // I2C master mode SSPCON = 0b00111000 964 writeToRAM( &SSPCON1, 0x38 ); 965 writeToSSPCON2( 0x00 ); 966 967 // 50 kHz SCL frequency 968 SSPADD = ( F_OSC / 50000 / 4 ) - 2; 969 // Disable slew rate control 970 SMP = 1; 971 } 972 973 //############################################################################################ 974 void i2c_shutdown() 975 //############################################################################################ 976 { 977 // I2C master mode SSPCON = 0 978 writeToRAM( &SSPCON1, 0x00 ); 979 } 980 981 //############################################################################################ 982 void i2c_waitForIdle() 983 //############################################################################################ 984 { 985 i2cTimeout = FALSE; 986 uns8 timeout; 987 // Wait for idle and not writing 988 timeout = 0; 989 while ( ( SSPCON2 & 0b0001.1111 ) != 0 || RW_ ) 990 if ( ++timeout == 0 ) 991 { 992 i2cTimeout = TRUE; 993 break; 994 } 995 } 996 997 //############################################################################################ 998 void i2c_start() 999 //############################################################################################ 1000 { 1001 i2c_waitForIdle(); 1002 // SEN = 1 1003 writeOredToSSPCON2( 0x01 ); 1004 } 1005 1006 //############################################################################################ 1007 void i2c_repStart() 1008 //############################################################################################ 1009 { 1010 i2c_waitForIdle(); 1011 // RSEN = 1 1012 writeOredToSSPCON2( 0x02 ); 1013 } 1014 1015 //############################################################################################ 1016 void i2c_stop() 1017 //############################################################################################ 1018 { 1019 i2c_waitForIdle(); 1020 // PEN = 1 1021 writeOredToSSPCON2( 0x04 ); 1022 } 1023 1024 //############################################################################################ 1025 uns8 i2c_read( bit ack ) 1026 //############################################################################################ 1027 { 1028 i2c_waitForIdle(); 1029 // RCEN = 1 1030 writeOredToSSPCON2( 0x08 ); 1031 1032 i2c_waitForIdle(); 1033 1034 uns8 i2cReadData @ userReg0; 1035 i2cReadData = SSPBUF; 1036 1037 i2c_waitForIdle(); 1038 1039 if ( ack ) 1040 // Acknowledge, ACKDT = 0 1041 writeToSSPCON2( SSPCON2 & 0xDF ); 1042 else 1043 // Not acknowledge, ACKDT = 1 1044 writeOredToSSPCON2( 0x20 ); 1045 1046 // Send acknowledge sequence, ACKEN = 1 1047 writeOredToSSPCON2( 0x10 ); 1048 return i2cReadData; 1049 } 1050 1051 //############################################################################################ 1052 void i2c_write( uns8 i2cWriteData ) 1053 //############################################################################################ 1054 { 1055 i2c_waitForIdle(); 1056 SSPBUF = i2cWriteData; 1057 } 1058 1059 //############################################################################################ 1060 void MCP9802GetTemp() 1061 //############################################################################################ 1062 { 1063 sensorValue = ERROR_TEMPERATURE; 1064 1065 i2c_start(); 1066 if ( i2cTimeout ) 1067 return; 1068 1069 // MCP9802 address 1070 i2c_write( I2C_ADR ); 1071 // pointer: 1 = configuration register 1072 i2c_write( 0x01 ); 1073 // configuration: 9-bit ADC 1074 i2c_write( 0x00 ); 1075 i2c_stop(); 1076 1077 i2c_start(); 1078 // MCP9802 address 1079 i2c_write( I2C_ADR ); 1080 // pointer: 0 = temperature 1081 i2c_write( 0 ); 1082 i2c_stop(); 1083 1084 i2c_start(); 1085 // MCP9802 address + read 1086 i2c_write( I2C_ADR | 1 ); 1087 // store the result 1088 sensorValue.high8 = i2c_read( TRUE ); 1089 sensorValue.low8 = i2c_read( FALSE ); 1090 i2c_stop(); 1091 } 1092 1093 //############################################################################################ 1094 // Other routines 1095 //############################################################################################ 1096 1097 //############################################################################################ 1098 void GetTemperature() 1099 //############################################################################################ 1100 { 1101 // Reads temperature from an enabled sensor 1102 if ( isDS18B20 ) 1103 // Temperature is ready at the background 1104 sensorValue = temperature; 1105 else 1106 { 1107 // Temperature value must be read from I2C sensor 1108 MCP9802GetTemp(); 1109 if ( sensorValue != ERROR_TEMPERATURE ) 1110 { 1111 sensorValue += 0x08; 1112 sensorValue /= 0x10; 1113 } 1114 } 1115 } 1116 1117 //############################################################################################ 1118 uns8 ReadAdc() 1119 //############################################################################################ 1120 { 1121 // ADC result - left justified, Fosc/8 1122 ADCON1 = 0b0001.0000; 1123 // Do a smallest delay for ADC ACQUISITION TIME 1124 waitMS( 1 ); 1125 // start ADC 1126 GO = 1; 1127 // wait for ADC finish 1128 while ( GO ); 1129 return ADRESH; 1130 } 1131 1132 //############################################################################################ 1133 // 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) 1134 #include "DPAcustomHandler.h" 1135 //############################################################################################