1 // ********************************************************************* 2 // Custom DPA Handler code example - Standard Sensors - DDC-SE01 * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: 0002_DDC-SE01.c,v $ 7 // Version: $Revision: 1.7 $ 8 // Date: $Date: 2017/08/31 08:29:50 $ 9 // 10 // Revision history: 11 // 2017/08/14 Release for DPA 3.01 12 // 13 // ********************************************************************* 14 15 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 16 17 // This example implements 4 sensors according to the IQRF Sensors standard 18 // 1st sensor is on-board TR temperature sensor. 19 // 2nd sensor is either Dallas 18B20 or MCP9802 temperature sensor at DDC-SE01 board (according to the HW jumper position) chosen at the runtime based on the SW detection. 20 // 3rd sensor is light intensity indicator at DDC-SE01 board (value range is 0[max light]-127[max dark]). 21 // 4th sensor is potentiometer value at DDC-SE01 board (value range is 0[left stop]-127[right stop]). 22 23 // The example will not work at demo DPA version because demo DPA does not support PCMD != 0 24 25 // Default IQRF include (modify the path according to your setup) 26 #include "IQRF.h" 27 28 // Default DPA header (modify the path according to your setup) 29 #include "DPA.h" 30 // Default Custom DPA Handler header (modify the path according to your setup) 31 #include "DPAcustomHandler.h" 32 // IQRF standards header (modify the path according to your setup) 33 #include "IQRFstandard.h" 34 #include "IQRF_HWPID.h" 35 36 //############################################################################################ 37 38 // Number of implemented sensors 39 #define SENSORS_COUNT 4 40 41 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data. 42 uns16 sensorValue @ param3; 43 44 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable 45 bit Get0_TemperatureTR(); 46 bit Get1_Temperature(); 47 bit Get2_BinaryData_Light(); 48 bit Get3_BinaryData_Potentiometer(); 49 50 // Temperature sensors read routine for both DDC-SE01 sensor types 51 void GetTemperature(); 52 // Read preset PIC ADC for DDC-SE01 53 uns8 ReadAdc(); 54 55 // 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) 56 void StoreValue( uns8 sensorType ); 57 58 // Sensor connected to PORT C.3 (compatible with DDC-SE-01) 59 #define OneWire_TRIS TRISC.3 60 #define OneWire_IO_IN PORTC.3 61 #define OneWire_IO_OUT LATC.3 62 63 // Writes sensor configuration (resolution) 64 bit Ds18B20WriteConfig( uns8 value ); 65 66 // Resets OneWire 67 bit OneWireReset(); 68 // Reads OneWire byte 69 uns8 OneWireReadByte(); 70 // Writes OneWire byte 71 void OneWireWriteByte( uns8 byte ); 72 73 // DS18B20 commands 74 #define CMD_READROM 0x33 75 #define CMD_CONVERTTEMP 0x44 76 #define CMD_CPYSCRATCHPAD 0x48 77 #define CMD_WSCRATCHPAD 0x4e 78 #define CMD_MATCHROM 0x55 79 #define CMD_RPWRSUPPLY 0xb4 80 #define CMD_RECEEPROM 0xb8 81 #define CMD_RSCRATCHPAD 0xbe 82 #define CMD_SKIPROM 0xcc 83 #define CMD_ALARMSEARCH 0xec 84 #define CMD_SEARCHROM 0xf0 85 86 // I2C routines 87 void i2c_init(); 88 void i2c_shutdown(); 89 void i2c_waitForIdle(); 90 void i2c_start(); 91 void i2c_repStart(); 92 void i2c_stop(); 93 uns8 i2c_read( bit ack ); 94 void i2c_write( uns8 i2cWriteData ); 95 96 // MCP9802 address 97 #define I2C_ADR 0b10010110 98 // Power pin 99 #define PWR_SENSOR_TRIS TRISC.7 100 #define PWR_SENSOR_IO LATC.7 101 102 // Special temperature value to indicate a sensor error, compatible with IQRF sensor standard 103 #define ERROR_TEMPERATURE 0x8000 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 temperature = 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 work 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 and 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_MICRORISC__DEMO_DDC_SE01; 352 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000; 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 = 12; 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.7 ) // Note: same as DataOutBeforeResponseFRC[3].7 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 setFRCerror1B() 621 //############################################################################################ 622 { 623 responseFRCvalue = 2; 624 return TRUE; 625 } 626 627 //############################################################################################ 628 bit setFRCerror2B() 629 //############################################################################################ 630 { 631 responseFRCvalue2B = 2; 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 setFRCerror1B(); 651 652 // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution 653 uns16 _sensorValue = sensorValue + 4; // Note: do rounding when /8 654 responseFRCvalue = (uns8)( _sensorValue / 8 ) + 44; 655 break; 656 657 case FRC_STD_SENSORS_2B: 658 // Return sensor FRC value 2B 659 if ( sensorError ) 660 return setFRCerror2B(); 661 662 responseFRCvalue2B = sensorValue ^ 0x8000; 663 break; 664 } 665 666 return TRUE; 667 } 668 669 //############################################################################################ 670 // Sensor index 0: measure temperature using the TR sensor 671 bit Get0_TemperatureTR() 672 //############################################################################################ 673 { 674 // Make sure FSR1 is not modified 675 676 // When error, then adjust the standard error values 677 sensorError = FALSE; 678 // Measure temperature using TR sensor 679 if ( getTemperature() == -128 ) 680 { 681 sensorError = TRUE; 682 sensorValue = 0x8000; 683 } 684 685 // Return sensor value 686 sensorValue = param3; 687 // Handler FRC 688 return AdjustFrcTemperature(); 689 } 690 691 //############################################################################################ 692 // Sensor index 1: measure temperature using one of the DDC-SE01 sensors 693 bit Get1_Temperature() 694 //############################################################################################ 695 { 696 // Make sure FSR1 is not modified 697 698 // Measure temperature using DDC-SE01 sensors 699 sensorError = FALSE; 700 // Read temperature and check for an error 701 GetTemperature(); 702 // When error, return standard (FRC) error value(s) 703 if ( sensorValue == ERROR_TEMPERATURE ) 704 sensorError = TRUE; 705 706 // FrcValues 707 return AdjustFrcTemperature(); 708 } 709 710 //############################################################################################ 711 bit AdjustFrcBinaryData() 712 //############################################################################################ 713 { 714 // Test for supported FRC commands 715 switch ( _PCMD ) 716 { 717 default: 718 return FALSE; 719 720 case FRC_STD_SENSORS_BIT: 721 // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01] 722 723 // Number of shifts to get the bit out of the return value 724 uns8 bitLoop = ( INDF1 >> 5 ) + 1; 725 // Value to get the bit from 726 W = sensorValue.low8; 727 do 728 { 729 // Get the bit to Carry 730 W = rr( W ); 731 // Next bit 732 } while ( --bitLoop != 0 ); // Note: must not modify W and Carry 733 // Current (prepared by DPA) FRC value is [01], change it to [11] (means bit is set) 734 responseFRCvalue.1 = 1; // Note: must not modify Carry 735 // Is bit set? 736 if ( !Carry ) 737 // Bit is NOT set, return [10] 738 responseFRCvalue.0 = 0; 739 break; 740 741 case FRC_STD_SENSORS_1B: 742 responseFRCvalue = sensorValue.low8 + 4; 743 break; 744 } 745 return TRUE; 746 } 747 748 //############################################################################################ 749 // Sensor index 2: returns light intensity indicator value using DDC-SE01 750 bit Get2_BinaryData_Light() 751 //############################################################################################ 752 { 753 // Make sure FSR1 is not modified 754 755 // ADC initialization (for more info see PIC datasheet) pin C1 (AN0) as analog input 756 ANSELA.0 = 1; 757 // ADC setting (AN0 channel) 758 ADCON0 = 0b0.00000.01; 759 // Read ADC 760 sensorValue.low8 = ReadAdc() / 2; 761 // Return sensor FRC value 762 return AdjustFrcBinaryData(); 763 } 764 765 //############################################################################################ 766 // Sensor index 3: returns potentiometer value using DDC-SE01 767 bit Get3_BinaryData_Potentiometer() 768 //############################################################################################ 769 { 770 // Make sure FSR1 is not modified 771 772 // ADC initialization (for more info see PIC datasheet) pin C5 (AN4) as analog input 773 ANSELA.5 = 1; 774 // ADC setting (AN4 channel) 775 ADCON0 = 0b0.00100.01; 776 // Read ADC 777 sensorValue.low8 = ReadAdc() / 2; 778 // Return sensor FRC value 779 return AdjustFrcBinaryData(); 780 } 781 782 //############################################################################################ 783 // OneWire and Dallas 18B20 routines 784 //############################################################################################ 785 786 //############################################################################################ 787 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0 788 //############################################################################################ 789 { 790 // 16 MHz 791 // + 0.75us ( W=val, Call ) 792 for ( ;; ) 793 { // loop time 794 nop2(); // 0.50us 795 nop2(); // 1.00us 796 nop2(); // 1.50us 797 nop2(); // 2.00us 798 nop2(); // 2.50us 799 nop2(); // 3.00us 800 nop(); // 3.25us 801 if ( --val == 0 ) // + 0.75us (W--, BTFS ) 802 return; // + 0.25us 803 nop2(); // 4.50us 804 } // 5.00us (Goto) 805 } 806 //############################################################################################ 807 808 #define OneWireData0() { OneWire_TRIS = 0; } // 1us [0.5us @ 16MHz] 809 #define OneWireData1() { OneWire_TRIS = 1; } // 1us [0.5us @ 16MHz] 810 811 //############################################################################################ 812 void OneWireWriteByte( uns8 byte ) 813 //############################################################################################ 814 { 815 uns8 bitLoop = 8; 816 do 817 { 818 // Next sequence is time precision critical 819 GIE = FALSE; 820 821 OneWireData0(); 822 nop2(); // 1 us [0.5 us] 823 nop2(); // [1.0 us] 824 if ( byte.0 ) // 2.5 us [1.75us] 825 OneWireData1(); 826 827 // End of time precision critical sequence 828 GIE = TRUE; 829 830 // 60us minimum in total, does not have to be precise 831 Delay5us( ( 60 - 3 ) / 5 + 1 ); 832 833 OneWireData1(); 834 835 byte >>= 1; 836 } while ( --bitLoop != 0 ); 837 } 838 839 //############################################################################################ 840 uns8 OneWireReadByte() 841 //############################################################################################ 842 { 843 uns8 result; 844 uns8 bitLoop = 8; 845 do 846 { 847 // Next sequence is time precision critical 848 GIE = FALSE; 849 850 OneWireData0(); 851 nop2(); // 1 us [0.5 us] 852 #if F_OSC == 16000000 853 nop2(); // [1.0 us] 854 #endif 855 OneWireData1(); // 2 us [1.5 us] 856 Delay5us( 15 / 5 ); // 17 us [16.5 us] 857 858 Carry = 0; // 17.5 us [16.75 us] 859 if ( OneWire_IO_IN ) // 18.5 us [ 17.25 us] (condition must not modify Carry) 860 Carry = 1; 861 862 // End of time precision critical sequence 863 GIE = TRUE; // must not modify Carry 864 result = rr( result ); 865 866 // 60us minimum in total, does not have to be precise 867 Delay5us( ( 60 - 20 ) / 5 + 1 ); 868 } while ( --bitLoop != 0 ); 869 870 return result; 871 } 872 873 //############################################################################################ 874 bit OneWireReset() 875 //############################################################################################ 876 { 877 // Setting the pin once to low is enough 878 OneWire_IO_OUT = 0; 879 // Reset pulse 880 OneWireData0(); 881 Delay5us( 500 / 5 ); 882 // Reset pulse end 883 OneWireData1(); 884 // Next sequence is time precision critical 885 GIE = FALSE; 886 // Wait for presence pulse 887 Delay5us( 70 / 5 ); 888 // End of time precision critical sequence 889 GIE = TRUE; 890 // Presence pulse? 891 if ( OneWire_IO_IN ) 892 { 893 // No presence, finish initialization sequence 894 Delay5us( ( 500 - 70 ) / 5 ); 895 return FALSE; 896 } 897 else 898 { 899 // Presence OK, finish initialization sequence 900 Delay5us( ( 500 - 70 ) / 5 ); 901 return TRUE; 902 } 903 } 904 905 //############################################################################################ 906 void OneWireCmd( uns8 cmd ) 907 //############################################################################################ 908 { 909 // OneWire: Skip ROM 910 OneWireWriteByte( CMD_SKIPROM ); 911 // OneWire: Send command 912 OneWireWriteByte( cmd ); 913 } 914 915 //############################################################################################ 916 bit Ds18B20WriteConfig( uns8 value ) 917 //############################################################################################ 918 { 919 if ( OneWireReset() ) 920 { 921 // Write Scratchpad 922 OneWireCmd( CMD_WSCRATCHPAD ); 923 924 // Write TL = ? (we dot not care the value) 925 OneWireWriteByte( W ); 926 // Write TH = ? (we dot not care the value) 927 OneWireWriteByte( W ); 928 // Write Config byte 929 OneWireWriteByte( value ); 930 931 if ( OneWireReset() ) 932 { 933 // Copy Scratchpad 934 OneWireCmd( CMD_CPYSCRATCHPAD ); 935 return TRUE; 936 } 937 } 938 return FALSE; 939 } 940 941 //############################################################################################ 942 void writeToSSPCON2( uns8 value @ param4.high8 ) 943 //############################################################################################ 944 { 945 writeToRAM( &SSPCON2, value ); 946 } 947 948 //############################################################################################ 949 void writeOredToSSPCON2( uns8 value @ param4.high8 ) 950 //############################################################################################ 951 { 952 writeToSSPCON2( SSPCON2 | value ); 953 } 954 955 //############################################################################################ 956 // I2C routines 957 //############################################################################################ 958 959 bit i2cTimeout; 960 961 //############################################################################################ 962 void i2c_init() 963 //############################################################################################ 964 { 965 // SCL as input (SIM C6) 966 TRISC.3 = 1; 967 // SDA as input (SIM C7) 968 TRISC.4 = 1; 969 970 // I2C master mode SSPCON = 0b00111000 971 writeToRAM( &SSPCON1, 0x38 ); 972 writeToSSPCON2( 0x00 ); 973 974 // 50 kHz SCL frequency 975 SSPADD = ( F_OSC / 50000 / 4 ) - 2; 976 // Disable slew rate control 977 SMP = 1; 978 } 979 980 //############################################################################################ 981 void i2c_shutdown() 982 //############################################################################################ 983 { 984 // I2C master mode SSPCON = 0 985 writeToRAM( &SSPCON1, 0x00 ); 986 } 987 988 //############################################################################################ 989 void i2c_waitForIdle() 990 //############################################################################################ 991 { 992 i2cTimeout = FALSE; 993 uns8 timeout; 994 // Wait for idle and not writing 995 timeout = 0; 996 while ( ( SSPCON2 & 0b0001.1111 ) != 0 || RW_ ) 997 if ( ++timeout == 0 ) 998 { 999 i2cTimeout = TRUE; 1000 break; 1001 } 1002 } 1003 1004 //############################################################################################ 1005 void i2c_start() 1006 //############################################################################################ 1007 { 1008 i2c_waitForIdle(); 1009 // SEN = 1 1010 writeOredToSSPCON2( 0x01 ); 1011 } 1012 1013 //############################################################################################ 1014 void i2c_repStart() 1015 //############################################################################################ 1016 { 1017 i2c_waitForIdle(); 1018 // RSEN = 1 1019 writeOredToSSPCON2( 0x02 ); 1020 } 1021 1022 //############################################################################################ 1023 void i2c_stop() 1024 //############################################################################################ 1025 { 1026 i2c_waitForIdle(); 1027 // PEN = 1 1028 writeOredToSSPCON2( 0x04 ); 1029 } 1030 1031 //############################################################################################ 1032 uns8 i2c_read( bit ack ) 1033 //############################################################################################ 1034 { 1035 i2c_waitForIdle(); 1036 // RCEN = 1 1037 writeOredToSSPCON2( 0x08 ); 1038 1039 i2c_waitForIdle(); 1040 1041 uns8 i2cReadData @ userReg0; 1042 i2cReadData = SSPBUF; 1043 1044 i2c_waitForIdle(); 1045 1046 if ( ack ) 1047 // Acknowledge, ACKDT = 0 1048 writeToSSPCON2( SSPCON2 & 0xDF ); 1049 else 1050 // Not acknowledge, ACKDT = 1 1051 writeOredToSSPCON2( 0x20 ); 1052 1053 // Send acknowledge sequence, ACKEN = 1 1054 writeOredToSSPCON2( 0x10 ); 1055 return i2cReadData; 1056 } 1057 1058 //############################################################################################ 1059 void i2c_write( uns8 i2cWriteData @ param2 ) 1060 //############################################################################################ 1061 { 1062 i2c_waitForIdle(); 1063 SSPBUF = i2cWriteData; 1064 } 1065 1066 //############################################################################################ 1067 void MCP9802GetTemp() 1068 //############################################################################################ 1069 { 1070 sensorValue = ERROR_TEMPERATURE; 1071 1072 i2c_start(); 1073 if ( i2cTimeout ) 1074 return; 1075 1076 // MCP9802 address 1077 i2c_write( I2C_ADR ); 1078 // pointer: 1 = configuration register 1079 i2c_write( 0x01 ); 1080 // configuration: 9-bit ADC 1081 i2c_write( 0x00 ); 1082 i2c_stop(); 1083 1084 i2c_start(); 1085 // MCP9802 address 1086 i2c_write( I2C_ADR ); 1087 // pointer: 0 = temperature 1088 i2c_write( 0 ); 1089 i2c_stop(); 1090 1091 i2c_start(); 1092 // MCP9802 address + read 1093 i2c_write( I2C_ADR | 1 ); 1094 // store the result 1095 sensorValue.high8 = i2c_read( TRUE ); 1096 sensorValue.low8 = i2c_read( FALSE ); 1097 i2c_stop(); 1098 } 1099 1100 //############################################################################################ 1101 // Other routines 1102 //############################################################################################ 1103 1104 //############################################################################################ 1105 void GetTemperature() 1106 //############################################################################################ 1107 { 1108 // Reads temperature from an enabled sensor 1109 if ( isDS18B20 ) 1110 // Temperature is ready at the background 1111 sensorValue = temperature; 1112 else 1113 { 1114 // Temperature value must be read from I2C sensor 1115 MCP9802GetTemp(); 1116 if ( sensorValue != ERROR_TEMPERATURE ) 1117 { 1118 sensorValue += 0x08; 1119 sensorValue /= 0x10; 1120 } 1121 } 1122 } 1123 1124 //############################################################################################ 1125 uns8 ReadAdc() 1126 //############################################################################################ 1127 { 1128 // ADC result - left justified, Fosc/8 1129 ADCON1 = 0b0001.0000; 1130 // Do a smallest delay for ADC ACQUISITION TIME 1131 waitMS( 1 ); 1132 // start ADC 1133 GO = 1; 1134 // wait for ADC finish 1135 while ( GO ); 1136 return ADRESH; 1137 } 1138 1139 //############################################################################################ 1140 // 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) 1141 #include "DPAcustomHandler.h" 1142 //############################################################################################