1 // ********************************************************************* 2 // Custom DPA Handler code example - DDC-SE-01 and/or DDC-RE-01 * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-DDC-Core.c,v $ 7 // Version: $Revision: 1.16 $ 8 // Date: $Date: 2019/05/06 07:13:14 $ 9 // 10 // Revision history: 11 // 2017/03/13 Release for DPA 3.00 12 // 2016/12/22 Release for DPA 2.28 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 17 18 /* This example implements HWP for DDC-SE-01 and/or DDC-RE-01 19 The example will not work at demo DPA version because demo DPA does not support PCMD != 0 20 21 DDC-SE-01: HWPID=0x001F 22 DDC-RE-01: HWPID=0x002F 23 DDC-SE-01 & DDC-RE-01: HWPID=0x003F 24 25 ----------- DDC-SE-01 26 Request: PNUM = 0x20, PCMD = 0x31 27 Response: 28 PData[0]=Temperature at [C] 29 PData[1]=Photoresistor value 0x00-0xFF 30 PData[2]=Potentiometer value 0x00-0xFF 31 returns ERROR_FAIL when error reading temperature 32 33 FRC=0xC0, returns temperature at C, 127 for 0 C, 0x80 for error reading temperature 34 FRC=0xC1, returns photoresistor value, returns 1 instead of 0 35 FRC=0xC2, returns potentiometer value, returns 1 instead of 0 36 37 ----------- DDC-RE-01 38 Request: PNUM = 0x20, PCMD = 0x32 39 PData[0]=Relay1Ctrl 40 PData[1]=Relay2Ctrl 41 42 Response: 43 PData[0]=Relay1State 44 PData[1]=Relay2State 45 46 RelayCtrl: 0=Switch the Relay off, 1=Switch the Relay on, Other=Do not control the Relay 47 RelayState: 0=Relay was off, 1=Relay was on 48 */ 49 50 // ********************************************************************* 51 52 // Default IQRF include (modify the path according to your setup) 53 #include "IQRF.h" 54 55 // Default DPA header (modify the path according to your setup) 56 #include "DPA.h" 57 // Default Custom DPA Handler header (modify the path according to your setup) 58 #include "DPAcustomHandler.h" 59 60 #if defined( DDC_SE_01 ) && defined( DDC_RE_01 ) 61 #define ThisHWPID 0x003F 62 #elif defined( DDC_SE_01 ) 63 #define ThisHWPID 0x001F 64 #elif defined( DDC_RE_01 ) 65 #define ThisHWPID 0x002F 66 #else 67 #error Symbol(s) DDC_SE_01 and/or DDC_RE_01 must be defined 68 #endif 69 70 //############################################################################################ 71 72 #if defined( DDC_SE_01 ) 73 74 // Special temperature value to indicate a sensor error 75 #define ERROR_TEMPERATURE 0xF800 76 77 // Sensor connected to PORT C.3 (compatible with DDC-SE-01) 78 #define OneWire_TRIS TRISC.3 79 #define OneWire_IO_IN PORTC.3 80 #define OneWire_IO_OUT LATC.3 81 82 // Writes sensor configuration (resolution) 83 bit Ds18B20WriteConfig( uns8 value ); 84 85 // Resets OneWire 86 bit OneWireReset(); 87 // Reads OneWire byte 88 uns8 OneWireReadByte(); 89 // Writes OneWire byte 90 void OneWireWriteByte( uns8 byte ); 91 92 // DS18B20 commands 93 #define CMD_READROM 0x33 94 #define CMD_CONVERTTEMP 0x44 95 #define CMD_CPYSCRATCHPAD 0x48 96 #define CMD_WSCRATCHPAD 0x4e 97 #define CMD_MATCHROM 0x55 98 #define CMD_RPWRSUPPLY 0xb4 99 #define CMD_RECEEPROM 0xb8 100 #define CMD_RSCRATCHPAD 0xbe 101 #define CMD_SKIPROM 0xcc 102 #define CMD_ALARMSEARCH 0xec 103 #define CMD_SEARCHROM 0xf0 104 105 // I2C routines 106 void i2c_init(); 107 void i2c_shutdown(); 108 void i2c_waitForIdle(); 109 void i2c_start(); 110 void i2c_repStart(); 111 void i2c_stop(); 112 uns8 i2c_read( bit ack ); 113 void i2c_write( uns8 i2cWriteData ); 114 115 // MCP9802 address 116 #define I2C_ADR 0b10010110 117 // Power pin 118 #define PWR_SENSOR_TRIS TRISC.7 119 #define PWR_SENSOR_IO LATC.7 120 121 // Sensors read routines 122 uns16 GetTemperature(); 123 uns8 ReadAdcPhotoresistor(); 124 uns8 ReadAdcPotentiometer(); 125 126 // TRUE if DS18B20 is enabled, FALSE in case of MCP9802 127 bit isDS18B20; 128 // Final DS18B20 temperature value 129 static uns16 temperature; 130 131 #endif 132 133 #if defined( DDC_RE_01 ) 134 135 // C.5 = C8 = Relay#1 136 #define RELAY1_LAT LATC.5 137 #define RELAY1_TRIS TRISC.5 138 139 // C.2 = C2 = Relay#2 140 #define RELAY2_LAT LATC.2 141 #define RELAY2_TRIS TRISC.2 142 143 #endif 144 145 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 146 //############################################################################################ 147 bit CustomDpaHandler() 148 //############################################################################################ 149 { 150 #if defined( DDC_SE_01 ) 151 // Finite machine states 152 typedef enum 153 { 154 S_ResetConvertT = 0, 155 S_SkipRomConvertT, 156 S_CmdConvertT, 157 158 S_WaitConvertT, 159 160 S_ResetReadTemp, 161 S_SkipRomReadTemp, 162 S_CmdReadTemp, 163 S_Byte1ReadTemp, 164 S_Byte2ReadTemp 165 } TState; 166 167 #endif 168 169 // Handler presence mark 170 clrwdt(); 171 172 #if defined( DDC_SE_01 ) 173 // Finite machine state 174 static uns8 state; // = S_ResetConvertT = 0 175 // Pre-read lower temperature byte 176 static uns8 temperatureByteLow; 177 // Conversion timeout counter 178 static uns8 timeout; 179 #endif 180 181 // Detect DPA event to handle 182 switch ( GetDpaEvent() ) 183 { 184 // ------------------------------------------------- 185 case DpaEvent_Interrupt: 186 // Do an extra quick background interrupt work 187 // ! 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. 188 // ! 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. 189 // ! 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. 190 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 191 // ! Make sure race condition does not occur when accessing those variables at other places. 192 // ! 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. 193 // ! Do not call any OS functions except setINDFx(). 194 // ! Do not use any OS variables especially for writing access. 195 // ! 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. 196 197 #if defined( DDC_SE_01 ) 198 #define TICKS_LEN 10 199 200 // If TMR6 interrupt occurred 201 if ( TMR6IF ) 202 { 203 // Unmask interrupt 204 TMR6IF = 0; 205 // Decrement count 206 if ( timeout != 0 ) 207 timeout--; 208 } 209 #endif 210 return Carry; 211 212 #if defined( DDC_SE_01 ) 213 // ------------------------------------------------- 214 case DpaEvent_Idle: 215 // Do a quick background work when RF packet is not received 216 217 // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC 218 if ( !isDS18B20 ) 219 break; 220 221 // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation 222 OneWire_IO_OUT = 0; 223 224 skip( state ); 225 #pragma computedGoto 1 226 goto _S_ResetConvertT; 227 goto _S_SkipRomConvertT; 228 goto _S_CmdConvertT; 229 goto _S_WaitConvertT; 230 goto _S_ResetReadTemp; 231 goto _S_SkipRomReadTemp; 232 goto _S_CmdReadTemp; 233 goto _S_Byte1ReadTemp; 234 goto _S_Byte2ReadTemp; 235 #pragma computedGoto 0 236 ; 237 // -------------- 238 _S_Byte2ReadTemp: 239 temperature.high8 = OneWireReadByte(); 240 temperature.low8 = temperatureByteLow; 241 242 ResetMachine: 243 state = S_ResetConvertT; 244 goto ExitMachine; 245 246 // -------------- 247 _S_ResetConvertT: 248 _S_ResetReadTemp: 249 if ( !OneWireReset() ) 250 { 251 _S_Error_Reset: 252 temperature = ERROR_TEMPERATURE; 253 goto ResetMachine; 254 } 255 goto NextState; 256 257 // -------------- 258 _S_SkipRomConvertT: 259 _S_SkipRomReadTemp: 260 // OneWire: Skip ROM 261 OneWireWriteByte( CMD_SKIPROM ); 262 goto NextState; 263 264 // -------------- 265 _S_CmdConvertT: 266 // OneWire: Convert temperature 267 OneWireWriteByte( CMD_CONVERTTEMP ); 268 // Setup timeout for approx 750 ms (the longest conversion time) 269 timeout = 2 + 750 / TICKS_LEN; 270 goto NextState; 271 272 // -------------- 273 _S_WaitConvertT: 274 if ( OneWireReadByte() == 0xff ) 275 goto NextState; 276 277 // Timeout? 278 if ( timeout == 0 ) 279 goto _S_Error_Reset; 280 281 goto ExitMachine; 282 283 // -------------- 284 _S_CmdReadTemp: 285 // OneWire: Read scratchpad 286 OneWireWriteByte( CMD_RSCRATCHPAD ); 287 goto NextState; 288 289 // -------------- 290 _S_Byte1ReadTemp: 291 temperatureByteLow = OneWireReadByte(); 292 goto NextState; 293 294 // -------------- 295 NextState: 296 ++state; 297 298 ExitMachine: 299 break; 300 301 // ------------------------------------------------- 302 case DpaEvent_FrcValue: 303 // Called to get FRC value 304 305 // Which FRC command? 306 switch ( _PCMD ) 307 { 308 case FRC_USER_BYTE_FROM + 0: 309 // Returns temperature 310 uns16 curTemperature = GetTemperature(); 311 if ( curTemperature == ERROR_TEMPERATURE ) 312 responseFRCvalue = 0x80; 313 else 314 { 315 responseFRCvalue = curTemperature.low8; 316 if ( responseFRCvalue == 0 ) 317 responseFRCvalue = 127; 318 } 319 break; 320 321 case FRC_USER_BYTE_FROM + 1: 322 // Returns photoresistor value 323 responseFRCvalue = ReadAdcPhotoresistor(); 324 _Zero2One: 325 if ( responseFRCvalue == 0 ) 326 responseFRCvalue |= 1; 327 break; 328 329 case FRC_USER_BYTE_FROM + 2: 330 // Returns potentiometer value 331 responseFRCvalue = ReadAdcPotentiometer(); 332 goto _Zero2One; 333 } 334 break; 335 336 // ------------------------------------------------- 337 case DpaEvent_FrcResponseTime: 338 // Called to get FRC response time 339 340 if ( DataOutBeforeResponseFRC[0] >= ( FRC_USER_BYTE_FROM + 0 ) && DataOutBeforeResponseFRC[0] <= ( FRC_USER_BYTE_FROM + 2 ) ) 341 responseFRCvalue = _FRC_RESPONSE_TIME_40_MS; 342 break; 343 #endif 344 345 // ------------------------------------------------- 346 case DpaEvent_DpaRequest: 347 { 348 // Called to interpret DPA request for peripherals 349 // ------------------------------------------------- 350 // Peripheral enumeration 351 if ( IsDpaEnumPeripheralsRequest() ) 352 { 353 // We implement 1 user peripheral 354 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 355 #ifdef FlagUserPer // Get ready for upcoming DPA 3.00 356 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 357 #endif 358 _DpaMessage.EnumPeripheralsAnswer.HWPID = ThisHWPID; 359 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000; 360 361 DpaHandleReturnTRUE: 362 return TRUE; 363 } 364 // ------------------------------------------------- 365 // Get information about peripheral 366 else if ( IsDpaPeripheralInfoRequest() ) 367 { 368 if ( _PNUM == PNUM_USER + 0 ) 369 { 370 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 371 #if !defined( DDC_RE_01 ) 372 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ; 373 #else 374 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 375 #endif 376 goto DpaHandleReturnTRUE; 377 } 378 379 break; 380 } 381 // ------------------------------------------------- 382 else 383 { 384 // Handle peripheral command 385 if ( _PNUM == PNUM_USER + 0 ) 386 { 387 switch ( _PCMD ) 388 { 389 #if defined( DDC_SE_01 ) 390 case 0x31: 391 // Read sensors 392 if ( _DpaDataLength != 0 ) 393 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 394 395 // Read temperature and check for an error 396 uns16 temperature = GetTemperature(); 397 if ( temperature == ERROR_TEMPERATURE ) 398 DpaApiReturnPeripheralError( ERROR_FAIL ); 399 _DpaMessage.Response.PData[0] = temperature.low8; 400 401 // Read other sensors 402 _DpaMessage.Response.PData[1] = ReadAdcPhotoresistor(); 403 _DpaMessage.Response.PData[2] = ReadAdcPotentiometer(); 404 405 // Return 3 bytes 406 _DpaDataLength = 3; 407 goto DpaHandleReturnTRUE; 408 #endif 409 410 #if defined( DDC_RE_01 ) 411 case 0x32: 412 // Control and return state of relays 413 if ( _DpaDataLength != 2 ) 414 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 415 416 // Relay #1 417 // Get 418 userReg0 = 0; 419 if ( RELAY1_LAT ) 420 userReg0.0 = 1; 421 422 // Set 423 switch ( _DpaMessage.Request.PData[0] ) 424 { 425 case 0: 426 RELAY1_LAT = 0; 427 break; 428 case 1: 429 RELAY1_LAT = 1; 430 break; 431 } 432 _DpaMessage.Response.PData[0] = userReg0; 433 434 // Relay #2 435 // Get 436 userReg0 = 0; 437 if ( RELAY2_LAT ) 438 userReg0.0 = 1; 439 440 // Set 441 switch ( _DpaMessage.Request.PData[1] ) 442 { 443 case 0: 444 RELAY2_LAT = 0; 445 break; 446 case 1: 447 RELAY2_LAT = 1; 448 break; 449 } 450 _DpaMessage.Response.PData[1] = userReg0; 451 // Receives and returns 2 bytes 452 goto DpaHandleReturnTRUE; 453 #endif 454 455 // Invalid command 456 default: 457 DpaApiReturnPeripheralError( ERROR_PCMD ); 458 break; 459 } 460 } 461 } 462 463 break; 464 } 465 466 // ------------------------------------------------- 467 case DpaEvent_Init: 468 // Do a one time initialization work before main loop starts 469 470 #if defined( DDC_SE_01 ) 471 // Initialize sensors 472 473 // C5 (AN4) as input 474 moduleInfo(); 475 // Connected TR pins? 476 if ( !bufferINFO[5].7 ) 477 { 478 TRISC.6 = 1; 479 TRISB.4 = 1; 480 } 481 TRISA.5 = 1; 482 483 // C1 (AN0) as input 484 TRISA.0 = 1; 485 486 // Setup TMR6 to generate ticks on the background (ticks every 10ms) 487 #if F_OSC == 16000000 488 PR6 = 250 - 1; 489 T6CON = 0b0.1001.1.10; // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 490 #else 491 #error Unsupported oscillator frequency 492 #endif 493 494 // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet) 495 if ( Ds18B20WriteConfig( 0b0.00.00000 ) ) 496 // DS18B20 is enabled 497 isDS18B20 = TRUE; 498 else 499 // Expect MCP9802 is enabled 500 i2c_init(); 501 #endif 502 503 #if defined( DDC_RE_01 ) 504 // Initialize relays 505 RELAY1_LAT = 0; 506 RELAY2_LAT = 0; 507 RELAY1_TRIS = 0; 508 RELAY2_TRIS = 0; 509 510 #endif 511 break; 512 513 #if defined( DDC_SE_01 ) 514 // ------------------------------------------------- 515 case DpaEvent_AfterSleep: 516 // Called after woken up after sleep 517 if ( !isDS18B20 ) 518 i2c_init(); 519 520 // Called on wake-up from sleep 521 TMR6IE = TRUE; 522 TMR6ON = TRUE; 523 break; 524 525 // ------------------------------------------------- 526 case DpaEvent_BeforeSleep: 527 // Called before going to sleep 528 if ( !isDS18B20 ) 529 i2c_shutdown(); 530 531 // ------------------------------------------------- 532 case DpaEvent_DisableInterrupts: 533 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 534 // Must not use TMR6 any more 535 TMR6ON = FALSE; 536 TMR6IE = FALSE; 537 break; 538 #endif 539 } 540 return FALSE; 541 } 542 543 //############################################################################################ 544 #if defined( DDC_SE_01 ) 545 546 //############################################################################################ 547 // OneWire and Dallas 18B20 routines 548 //############################################################################################ 549 550 //############################################################################################ 551 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0 552 //############################################################################################ 553 { 554 // 16 MHz 555 // + 0.75us ( W=val, Call ) 556 for ( ;; ) 557 { // loop time 558 nop2(); // 0.50us 559 nop2(); // 1.00us 560 nop2(); // 1.50us 561 nop2(); // 2.00us 562 nop2(); // 2.50us 563 nop2(); // 3.00us 564 nop(); // 3.25us 565 if ( --val == 0 ) // + 0.75us (W--, BTFS ) 566 return; // + 0.25us 567 nop2(); // 4.50us 568 } // 5.00us (Goto) 569 } 570 //############################################################################################ 571 572 #define OneWireData0() { OneWire_TRIS = 0; } // 0.5us @ 16MHz 573 #define OneWireData1() { OneWire_TRIS = 1; } // 0.5us @ 16MHz 574 575 //############################################################################################ 576 void OneWireWriteByte( uns8 byte ) 577 //############################################################################################ 578 { 579 uns8 bitLoop = 8; 580 do 581 { 582 // Next sequence is time precision critical 583 GIE = FALSE; 584 585 OneWireData0(); 586 nop2(); // 1 us [0.5 us] 587 nop2(); // [1.0 us] 588 if ( byte.0 ) // 2.5 us [1.75us] 589 OneWireData1(); 590 591 // End of time precision critical sequence 592 GIE = TRUE; 593 594 // 60us minimum in total, does not have to be precise 595 Delay5us( ( 60 - 3 ) / 5 + 1 ); 596 597 OneWireData1(); 598 599 byte >>= 1; 600 } while ( --bitLoop != 0 ); 601 } 602 603 //############################################################################################ 604 uns8 OneWireReadByte() 605 //############################################################################################ 606 { 607 uns8 result; 608 uns8 bitLoop = 8; 609 do 610 { 611 // Next sequence is time precision critical 612 GIE = FALSE; 613 614 OneWireData0(); 615 nop2(); // 1 us [0.5 us] 616 #if F_OSC == 16000000 617 nop2(); // [1.0 us] 618 #endif 619 OneWireData1(); // 2 us [1.5 us] 620 Delay5us( 15 / 5 ); // 17 us [16.5 us] 621 622 Carry = 0; // 17.5 us [16.75 us] 623 if ( OneWire_IO_IN ) // 18.5 us [ 17.25 us] (condition must not modify Carry) 624 Carry = 1; 625 626 // End of time precision critical sequence 627 GIE = TRUE; // must not modify Carry 628 result = rr( result ); 629 630 // 60us minimum in total, does not have to be precise 631 Delay5us( ( 60 - 20 ) / 5 + 1 ); 632 } while ( --bitLoop != 0 ); 633 634 return result; 635 } 636 637 //############################################################################################ 638 bit OneWireReset() 639 //############################################################################################ 640 { 641 // Setting the pin once to low is enough 642 OneWire_IO_OUT = 0; 643 // Reset pulse 644 OneWireData0(); 645 Delay5us( 500 / 5 ); 646 // Reset pulse end 647 OneWireData1(); 648 // Next sequence is time precision critical 649 GIE = FALSE; 650 // Wait for presence pulse 651 Delay5us( 70 / 5 ); 652 // End of time precision critical sequence 653 GIE = TRUE; 654 // Presence pulse? 655 if ( OneWire_IO_IN ) 656 { 657 // No presence, finish initialization sequence 658 Delay5us( ( 500 - 70 ) / 5 ); 659 return FALSE; 660 } 661 else 662 { 663 // Presence OK, finish initialization sequence 664 Delay5us( ( 500 - 70 ) / 5 ); 665 return TRUE; 666 } 667 } 668 669 //############################################################################################ 670 void OneWireCmd( uns8 cmd ) 671 //############################################################################################ 672 { 673 // OneWire: Skip ROM 674 OneWireWriteByte( CMD_SKIPROM ); 675 // OneWire: Send command 676 OneWireWriteByte( cmd ); 677 } 678 679 //############################################################################################ 680 bit Ds18B20WriteConfig( uns8 value ) 681 //############################################################################################ 682 { 683 if ( OneWireReset() ) 684 { 685 // Write Scratchpad 686 OneWireCmd( CMD_WSCRATCHPAD ); 687 688 // Write TL = ? (we dot not care the value) 689 OneWireWriteByte( W ); 690 // Write TH = ? (we dot not care the value) 691 OneWireWriteByte( W ); 692 // Write Config byte 693 OneWireWriteByte( value ); 694 695 if ( OneWireReset() ) 696 { 697 // Copy Scratchpad 698 OneWireCmd( CMD_CPYSCRATCHPAD ); 699 return TRUE; 700 } 701 } 702 return FALSE; 703 } 704 705 //############################################################################################ 706 void writeToSSPCON2( uns8 value @ param4.high8 ) 707 //############################################################################################ 708 { 709 writeToRAM( &SSPCON2, value ); 710 } 711 712 //############################################################################################ 713 void writeOredToSSPCON2( uns8 value @ param4.high8 ) 714 //############################################################################################ 715 { 716 writeToSSPCON2( SSPCON2 | value ); 717 } 718 719 //############################################################################################ 720 721 bit i2cTimeout; 722 723 //############################################################################################ 724 void i2c_init() 725 //############################################################################################ 726 { 727 // SCL as input (SIM C6) 728 TRISC.3 = 1; 729 // SDA as input (SIM C7) 730 TRISC.4 = 1; 731 732 // I2C master mode SSPCON = 0b00111000 733 writeToRAM( &SSPCON1, 0x38 ); 734 writeToSSPCON2( 0x00 ); 735 736 // 50 kHz SCL frequency 737 SSPADD = ( F_OSC / 50000 / 4 ) - 2; 738 // Disable slew rate control 739 SMP = 1; 740 } 741 742 //############################################################################################ 743 void i2c_shutdown() 744 //############################################################################################ 745 { 746 // I2C master mode SSPCON = 0 747 writeToRAM( &SSPCON1, 0x00 ); 748 } 749 750 //############################################################################################ 751 void i2c_waitForIdle() 752 //############################################################################################ 753 { 754 i2cTimeout = FALSE; 755 uns8 timeout; 756 // Wait for idle and not writing 757 timeout = 0; 758 while ( ( SSPCON2 & 0b0001.1111 ) != 0 || RW_ ) 759 if ( ++timeout == 0 ) 760 { 761 i2cTimeout = TRUE; 762 break; 763 } 764 } 765 766 //############################################################################################ 767 void i2c_start() 768 //############################################################################################ 769 { 770 i2c_waitForIdle(); 771 // SEN = 1 772 writeOredToSSPCON2( 0x01 ); 773 } 774 775 //############################################################################################ 776 void i2c_repStart() 777 //############################################################################################ 778 { 779 i2c_waitForIdle(); 780 // RSEN = 1 781 writeOredToSSPCON2( 0x02 ); 782 } 783 784 //############################################################################################ 785 void i2c_stop() 786 //############################################################################################ 787 { 788 i2c_waitForIdle(); 789 // PEN = 1 790 writeOredToSSPCON2( 0x04 ); 791 } 792 793 //############################################################################################ 794 uns8 i2c_read( bit ack ) 795 //############################################################################################ 796 { 797 i2c_waitForIdle(); 798 // RCEN = 1 799 writeOredToSSPCON2( 0x08 ); 800 801 i2c_waitForIdle(); 802 803 uns8 i2cReadData @ userReg0; 804 i2cReadData = SSPBUF; 805 806 i2c_waitForIdle(); 807 808 if ( ack ) 809 // Acknowledge, ACKDT = 0 810 writeToSSPCON2( SSPCON2 & 0xDF ); 811 else 812 // Not acknowledge, ACKDT = 1 813 writeOredToSSPCON2( 0x20 ); 814 815 // Send acknowledge sequence, ACKEN = 1 816 writeOredToSSPCON2( 0x10 ); 817 return i2cReadData; 818 } 819 820 //############################################################################################ 821 void i2c_write( uns8 i2cWriteData @ param2 ) 822 //############################################################################################ 823 { 824 i2c_waitForIdle(); 825 SSPBUF = i2cWriteData; 826 } 827 828 //############################################################################################ 829 uns16 MCP9802GetTemp() 830 //############################################################################################ 831 { 832 i2c_start(); 833 if ( i2cTimeout ) 834 return ERROR_TEMPERATURE; 835 836 // MCP9802 address 837 i2c_write( I2C_ADR ); 838 // pointer: 1 = configuration register 839 i2c_write( 0x01 ); 840 // configuration: 9-bit ADC 841 i2c_write( 0x00 ); 842 i2c_stop(); 843 844 i2c_start(); 845 // MCP9802 address 846 i2c_write( I2C_ADR ); 847 // pointer: 0 = temperature 848 i2c_write( 0 ); 849 i2c_stop(); 850 851 i2c_start(); 852 // MCP9802 address + read 853 i2c_write( I2C_ADR | 1 ); 854 uns16 temperature; 855 // store the result 856 temperature.high8 = i2c_read( TRUE ); 857 temperature.low8 = i2c_read( FALSE ); 858 i2c_stop(); 859 return temperature; 860 } 861 862 //############################################################################################ 863 uns16 GetTemperature() 864 //############################################################################################ 865 { 866 // Reads temperature from an enabled sensor 867 uns16 temperatureResult; 868 869 if ( isDS18B20 ) 870 { 871 // Temperature is ready at the background 872 temperatureResult = temperature; 873 if ( temperatureResult != ERROR_TEMPERATURE ) 874 { 875 temperatureResult += 0x08; 876 temperatureResult /= 0x10; 877 } 878 } 879 else 880 { 881 // Temperature value must be read from I2C sensor 882 temperatureResult = MCP9802GetTemp(); 883 if ( temperatureResult != ERROR_TEMPERATURE ) 884 { 885 temperatureResult += 0x80; 886 temperatureResult /= 0x100; 887 } 888 } 889 890 return temperatureResult; 891 } 892 893 //############################################################################################ 894 uns8 ReadAdc() 895 //############################################################################################ 896 { 897 // ADC result - left justified, Fosc/8 898 ADCON1 = 0b0001.0000; 899 // start ADC 900 GO = 1; 901 // wait for ADC finish 902 while ( GO ); 903 return ADRESH; 904 } 905 906 //############################################################################################ 907 uns8 ReadAdcPhotoresistor() 908 //############################################################################################ 909 { 910 // ADC initialization (for more info see PIC datasheet) pin C1 (AN0) as analog input 911 ANSELA.0 = 1; 912 // ADC setting (AN0 channel) 913 ADCON0 = 0b0.00000.01; 914 return ReadAdc(); 915 } 916 917 //############################################################################################ 918 uns8 ReadAdcPotentiometer() 919 //############################################################################################ 920 { 921 // ADC initialization (for more info see PIC datasheet) pin C5 (AN4) as analog input 922 ANSELA.5 = 1; 923 // ADC setting (AN4 channel) 924 ADCON0 = 0b0.00100.01; 925 return ReadAdc(); 926 } 927 //############################################################################################ 928 #endif 929 //############################################################################################ 930 // 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) 931 #include "DPAcustomHandler.h" 932 //############################################################################################