Advertisement
Guest User

Untitled

a guest
Jan 16th, 2023
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 31.38 KB | None | 0 0
  1. /*
  2.  * Sava @ 2022
  3.  * JBC Soldering Station Contrloler / PIC12F1840
  4.  * This is a free software with NO WARRANTY
  5.  */
  6.  
  7. // CONFIG1
  8. #pragma config FOSC = INTOSC    // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
  9. #pragma config WDTE = OFF    // Watchdog Timer Enable->WDT disabled
  10. #pragma config PWRTE = OFF    // Power-up Timer Enable->PWRT disabled
  11. #pragma config MCLRE = OFF    // MCLR Pin Function Select->MCLR/VPP pin function is digital input
  12. #pragma config CP = ON    // Flash Program Memory Code Protection->Program memory code protection is enabled
  13. #pragma config CPD = ON    // Data Memory Code Protection->Data memory code protection is enabled
  14. #pragma config BOREN = ON    // Brown-out Reset Enable->Brown-out Reset enabled
  15. #pragma config CLKOUTEN = OFF    // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
  16. #pragma config IESO = ON    // Internal/External Switchover->Internal/External Switchover mode is enabled
  17. #pragma config FCMEN = ON    // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled
  18.  
  19. // CONFIG2
  20. #pragma config WRT = OFF    // Flash Memory Self-Write Protection->Write protection off
  21. #pragma config PLLEN = OFF    // PLL Enable->4x PLL disabled
  22. #pragma config STVREN = ON    // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
  23. #pragma config BORV = LO    // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
  24. #pragma config LVP = OFF    // Low-Voltage Programming Enable->High-voltage on MCLR/VPP must be used for programming
  25.  
  26. #include <xc.h>
  27. #include <stdio.h>
  28. #include <stdint.h>
  29. #include <stdbool.h>
  30. #include <stdio.h>
  31.  
  32. #pragma warning disable 520
  33.  
  34. #define _XTAL_FREQ 32000000
  35.  
  36. #define ENABLE_UART_DEBUG 0
  37.  
  38. #define INPUT   1
  39. #define OUTPUT  0
  40.  
  41. #define HIGH    1
  42. #define LOW     0
  43.  
  44. #define ANALOG      1
  45. #define DIGITAL     0
  46.  
  47. #define PULL_UP_ENABLED      1
  48. #define PULL_UP_DISABLED     0
  49.  
  50. // get/set IO_RA0 aliases
  51. #define IO_RA0_TRIS                 TRISAbits.TRISA0
  52. #define IO_RA0_LAT                  LATAbits.LATA0
  53. #define IO_RA0_PORT                 PORTAbits.RA0
  54. #define IO_RA0_WPU                  WPUAbits.WPUA0
  55. #define IO_RA0_ANS                  ANSELAbits.ANSA0
  56. #define IO_RA0_SetHigh()            do { LATAbits.LATA0 = 1; } while(0)
  57. #define IO_RA0_SetLow()             do { LATAbits.LATA0 = 0; } while(0)
  58. #define IO_RA0_Toggle()             do { LATAbits.LATA0 = ~LATAbits.LATA0; } while(0)
  59. #define IO_RA0_GetValue()           PORTAbits.RA0
  60. #define IO_RA0_SetDigitalInput()    do { TRISAbits.TRISA0 = 1; } while(0)
  61. #define IO_RA0_SetDigitalOutput()   do { TRISAbits.TRISA0 = 0; } while(0)
  62. #define IO_RA0_SetPullup()          do { WPUAbits.WPUA0 = 1; } while(0)
  63. #define IO_RA0_ResetPullup()        do { WPUAbits.WPUA0 = 0; } while(0)
  64. #define IO_RA0_SetAnalogMode()      do { ANSELAbits.ANSA0 = 1; } while(0)
  65. #define IO_RA0_SetDigitalMode()     do { ANSELAbits.ANSA0 = 0; } while(0)
  66.  
  67. // get/set SCL aliases
  68. #define SCL_TRIS                 TRISAbits.TRISA1
  69. #define SCL_LAT                  LATAbits.LATA1
  70. #define SCL_PORT                 PORTAbits.RA1
  71. #define SCL_WPU                  WPUAbits.WPUA1
  72. #define SCL_ANS                  ANSELAbits.ANSA1
  73. #define SCL_SetHigh()            do { LATAbits.LATA1 = 1; } while(0)
  74. #define SCL_SetLow()             do { LATAbits.LATA1 = 0; } while(0)
  75. #define SCL_Toggle()             do { LATAbits.LATA1 = ~LATAbits.LATA1; } while(0)
  76. #define SCL_GetValue()           PORTAbits.RA1
  77. #define SCL_SetDigitalInput()    do { TRISAbits.TRISA1 = 1; } while(0)
  78. #define SCL_SetDigitalOutput()   do { TRISAbits.TRISA1 = 0; } while(0)
  79. #define SCL_SetPullup()          do { WPUAbits.WPUA1 = 1; } while(0)
  80. #define SCL_ResetPullup()        do { WPUAbits.WPUA1 = 0; } while(0)
  81. #define SCL_SetAnalogMode()      do { ANSELAbits.ANSA1 = 1; } while(0)
  82. #define SCL_SetDigitalMode()     do { ANSELAbits.ANSA1 = 0; } while(0)
  83.  
  84. // get/set SDA aliases
  85. #define SDA_TRIS                 TRISAbits.TRISA2
  86. #define SDA_LAT                  LATAbits.LATA2
  87. #define SDA_PORT                 PORTAbits.RA2
  88. #define SDA_WPU                  WPUAbits.WPUA2
  89. #define SDA_ANS                  ANSELAbits.ANSA2
  90. #define SDA_SetHigh()            do { LATAbits.LATA2 = 1; } while(0)
  91. #define SDA_SetLow()             do { LATAbits.LATA2 = 0; } while(0)
  92. #define SDA_Toggle()             do { LATAbits.LATA2 = ~LATAbits.LATA2; } while(0)
  93. #define SDA_GetValue()           PORTAbits.RA2
  94. #define SDA_SetDigitalInput()    do { TRISAbits.TRISA2 = 1; } while(0)
  95. #define SDA_SetDigitalOutput()   do { TRISAbits.TRISA2 = 0; } while(0)
  96. #define SDA_SetPullup()          do { WPUAbits.WPUA2 = 1; } while(0)
  97. #define SDA_ResetPullup()        do { WPUAbits.WPUA2 = 0; } while(0)
  98. #define SDA_SetAnalogMode()      do { ANSELAbits.ANSA2 = 1; } while(0)
  99. #define SDA_SetDigitalMode()     do { ANSELAbits.ANSA2 = 0; } while(0)
  100.  
  101. // get/set IO_RA3 aliases
  102. #define IO_RA3_TRIS                 TRISAbits.TRISA3
  103. #define IO_RA3_PORT                 PORTAbits.RA3
  104. #define IO_RA3_WPU                  WPUAbits.WPUA3
  105. #define IO_RA3_GetValue()           PORTAbits.RA3
  106. #define IO_RA3_SetDigitalInput()    do { TRISAbits.TRISA3 = 1; } while(0)
  107. #define IO_RA3_SetDigitalOutput()   do { TRISAbits.TRISA3 = 0; } while(0)
  108. #define IO_RA3_SetPullup()          do { WPUAbits.WPUA3 = 1; } while(0)
  109. #define IO_RA3_ResetPullup()        do { WPUAbits.WPUA3 = 0; } while(0)
  110.  
  111. // get/set IO_RA4 aliases
  112. #define IO_RA4_TRIS                 TRISAbits.TRISA4
  113. #define IO_RA4_LAT                  LATAbits.LATA4
  114. #define IO_RA4_PORT                 PORTAbits.RA4
  115. #define IO_RA4_WPU                  WPUAbits.WPUA4
  116. #define IO_RA4_ANS                  ANSELAbits.ANSA4
  117. #define IO_RA4_SetHigh()            do { LATAbits.LATA4 = 1; } while(0)
  118. #define IO_RA4_SetLow()             do { LATAbits.LATA4 = 0; } while(0)
  119. #define IO_RA4_Toggle()             do { LATAbits.LATA4 = ~LATAbits.LATA4; } while(0)
  120. #define IO_RA4_GetValue()           PORTAbits.RA4
  121. #define IO_RA4_SetDigitalInput()    do { TRISAbits.TRISA4 = 1; } while(0)
  122. #define IO_RA4_SetDigitalOutput()   do { TRISAbits.TRISA4 = 0; } while(0)
  123. #define IO_RA4_SetPullup()          do { WPUAbits.WPUA4 = 1; } while(0)
  124. #define IO_RA4_ResetPullup()        do { WPUAbits.WPUA4 = 0; } while(0)
  125. #define IO_RA4_SetAnalogMode()      do { ANSELAbits.ANSA4 = 1; } while(0)
  126. #define IO_RA4_SetDigitalMode()     do { ANSELAbits.ANSA4 = 0; } while(0)
  127.  
  128. // get/set IO_RA5 aliases
  129. #define IO_RA5_TRIS                 TRISAbits.TRISA5
  130. #define IO_RA5_LAT                  LATAbits.LATA5
  131. #define IO_RA5_PORT                 PORTAbits.RA5
  132. #define IO_RA5_WPU                  WPUAbits.WPUA5
  133. #define IO_RA5_SetHigh()            do { LATAbits.LATA5 = 1; } while(0)
  134. #define IO_RA5_SetLow()             do { LATAbits.LATA5 = 0; } while(0)
  135. #define IO_RA5_Toggle()             do { LATAbits.LATA5 = ~LATAbits.LATA5; } while(0)
  136. #define IO_RA5_GetValue()           PORTAbits.RA5
  137. #define IO_RA5_SetDigitalInput()    do { TRISAbits.TRISA5 = 1; } while(0)
  138. #define IO_RA5_SetDigitalOutput()   do { TRISAbits.TRISA5 = 0; } while(0)
  139. #define IO_RA5_SetPullup()          do { WPUAbits.WPUA5 = 1; } while(0)
  140. #define IO_RA5_ResetPullup()        do { WPUAbits.WPUA5 = 0; } while(0)
  141.  
  142. typedef void (*interruptHandler)(void);
  143. void (*i2c_driver_busCollisionISR)(void);
  144. void (*i2c_driver_i2cISR)(void);
  145.  
  146. inline void i2c_driver_close(void)
  147. {
  148.     SSP1CON1bits.SSPEN = 0;
  149. }
  150.  
  151. /* Interrupt Control */
  152. inline void mssp_enableIRQ(void)
  153. {
  154.     PIE1bits.SSP1IE = 1;
  155. }
  156.  
  157. inline __bit mssp_IRQisEnabled(void)
  158. {
  159.     return PIE1bits.SSP1IE;
  160. }
  161.  
  162. inline void mssp_disableIRQ(void)
  163. {
  164.     PIE1bits.SSP1IE = 0;
  165. }
  166.  
  167. inline void mssp_clearIRQ(void)
  168. {
  169.     PIR1bits.SSP1IF = 0;
  170. }
  171.  
  172. inline __bit mssp_IRQisSet(void)
  173. {
  174.     return PIR1bits.SSP1IF;
  175. }
  176.  
  177. inline void mssp_waitForEvent(uint16_t timeout)
  178. {
  179.     uint16_t to = timeout;
  180.  
  181.     if (PIR1bits.SSP1IF == 0)
  182.     {
  183.         while(to--)
  184.         {
  185.             if (PIR1bits.SSP1IF) break;
  186.             __delay_us(100);
  187.         }
  188.     }
  189. }
  190.  
  191. __bit i2c_driver_open(void)
  192. {
  193.     if (!SSP1CON1bits.SSPEN)
  194.     {
  195.         SSP1STAT = 0x00;
  196.         SSP1CON1 = 0x28;
  197.         SSP1CON2 = 0x00;
  198.         SSP1ADD = 0x13;
  199.         return true;
  200.     }
  201.     else
  202.         return false;
  203. }
  204.  
  205. __bit i2c_driver_initSlaveHardware(void)
  206. {
  207.     if(!SSP1CON1bits.SSPEN)
  208.     {
  209. /* NOTE on AHEN:
  210.  * If multiple slaves are to be emulated, then AHEN must be set.  It must be set
  211.  * because the driver needs to selectively ACK/NACK the address depending on its
  212.  * ability to handle the address.
  213. */
  214.  
  215. /* NOTE on DHEN:
  216.  * DHEN must be set so that the data is not automatically NACK'ed if it is not read
  217.  * from the SSPBUF.  This driver will ALWAYS read the SSPBUF so that it can pass
  218.  * the value to the appropriate slave handler.  Because the data is ALWAYS read
  219.  * the data will always be ACK'd if DHEN is cleared.  If the slave does not want
  220.  * the data byte from the master then it will return false and a NACK will be returned.
  221.  */
  222.  
  223. /* NOTE on SEN:
  224.  * SEN will be set enabling clock stretching.  This is because we don't know how
  225.  * long the user will take to process data bytes in their callbacks.  If they are fast,
  226.  * we may not need to stretch the clock.  If they are slow, we need to stretch the clock.
  227.  * If we ALWAYS stretch the clock, we will release the clock when the ISR is complete.
  228.  */
  229.  
  230. /* NOTE on PCIE:
  231.  * PCIE will be set to enable interrupts on STOP.  This will allow us know when
  232.  * the master is finished
  233.  */
  234.        
  235. /* NOTE on SCIE:
  236.  * SCIE will be set to enable interrupts on START.  This will allow us to detect
  237.  * both a START and a RESTART event and prepare to restart communications.
  238.  */
  239.         SSP1CON1 |= 0x06; //setup I2C Slave (7-bit Addressing)
  240.         SSP1STAT = 0x00;
  241.         SSP1CON2 = 0x00;
  242.        
  243.         SSP1CON1bits.SSPEN = 1;
  244.         return true;
  245.     }
  246.     return false;
  247. }
  248.  
  249. inline void i2c_driver_resetBus(void)
  250. {
  251.    
  252. }
  253.  
  254. inline void i2c_driver_start(void)
  255. {
  256.     SSP1CON2bits.SEN = 1;
  257. }
  258.  
  259. inline void i2c_driver_restart(void)
  260. {
  261.     SSP1CON2bits.RSEN = 1;
  262. }
  263.  
  264. inline void i2c_driver_stop(void)
  265. {
  266.     SSP1CON2bits.PEN = 1;
  267. }
  268.  
  269. inline __bit i2c_driver_isNACK(void)
  270. {
  271.     return SSP1CON2bits.ACKSTAT;
  272. }
  273.  
  274. inline void i2c_driver_startRX(void)
  275. {
  276.     SSP1CON2bits.RCEN = 1;
  277. }
  278.  
  279. inline char i2c_driver_getRXData(void)
  280. {
  281.     return SSP1BUF;
  282. }
  283.  
  284. inline void i2c_driver_setAddr(char addr)
  285. {
  286.     SSP1ADD = addr;
  287. }
  288.  
  289. inline void i2c_driver_setMask(char mask)
  290. {
  291.     SSP1MSK = mask;
  292. }
  293.  
  294. inline void i2c_driver_TXData(char d)
  295. {
  296.     SSP1BUF = d;
  297. }
  298.  
  299. inline char i2c_driver_getAddr(void)
  300. {
  301.     return SSP1ADD;
  302. }
  303.  
  304. inline void i2c_driver_sendACK(void)
  305. {
  306.     SSP1CON2bits.ACKDT = 0;
  307.     SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
  308. }
  309.  
  310. inline void i2c_driver_sendNACK(void)
  311. {
  312.     SSP1CON2bits.ACKDT = 1;
  313.     SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
  314. }
  315.  
  316. inline void i2c_driver_releaseClock(void)
  317. {
  318.     SSP1CON1bits.CKP = 1;
  319. }
  320.  
  321. inline __bit i2c_driver_isBufferFull(void)
  322. {
  323.     return SSP1STATbits.BF;
  324. }
  325.  
  326. inline __bit i2c_driver_isStart(void)
  327. {
  328.     return SSP1STATbits.S;
  329. }
  330.  
  331. inline __bit i2c_driver_isAddress(void)
  332. {
  333.     return !SSP1STATbits.D_nA;
  334. }
  335.  
  336. inline __bit i2c_driver_isStop(void)
  337. {
  338.     return SSP1STATbits.P;
  339. }
  340.  
  341. inline __bit i2c_driver_isData(void)
  342. {
  343.     return SSP1STATbits.D_nA;
  344. }
  345.  
  346. inline __bit i2c_driver_isRead(void)
  347. {
  348.     return SSP1STATbits.R_nW;
  349. }
  350.  
  351. inline __bit i2c_driver_isWriteCollision(void)
  352. {
  353.     return SSP1CON1bits.WCOL;
  354. }
  355.  
  356. inline __bit i2c_driver_isReceiveOverflow(void)
  357. {
  358.     return SSP1CON1bits.SSPOV;
  359. }
  360.  
  361. inline void i2c_driver_clearBusCollision(void)
  362. {
  363.     PIR2bits.BCL1IF = 0; // clear the bus collision.
  364. }
  365.  
  366. inline void i2c_driver_setBusCollisionISR(interruptHandler handler)
  367. {
  368.     i2c_driver_busCollisionISR = handler;
  369. }
  370.  
  371. inline void i2c_driver_setI2cISR(interruptHandler handler)
  372. {
  373.     i2c_driver_i2cISR = handler;
  374. }
  375.  
  376. void I2C_Init(uint32_t i2c_clk_freq)
  377. {
  378.     SSP1STAT = 0x00;
  379.     SSP1CON1 = 0x28;
  380.     SSP1CON2 = 0x00;
  381.     SSP1ADD = (_XTAL_FREQ / (4 * i2c_clk_freq)) - 1;  // set I2C clock frequency
  382. }
  383.  
  384. void I2C_Start(void)
  385. {
  386.     mssp_clearIRQ();
  387.     i2c_driver_start();
  388.     mssp_waitForEvent(500);
  389. }
  390.  
  391. void I2C_Stop(void)
  392. {
  393.     mssp_clearIRQ();
  394.     i2c_driver_stop();
  395.     mssp_waitForEvent(500);
  396. }
  397.  
  398. void I2C_Write(uint8_t i2c_data)
  399. {
  400.     mssp_clearIRQ();
  401.     SSP1BUF = i2c_data;
  402.     mssp_waitForEvent(500);
  403. }
  404.  
  405. uint8_t I2C_Read(uint8_t ack)
  406. {
  407.     uint8_t _data;
  408.     while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));  // wait for MSSP module to be free (not busy)
  409.     RCEN = 1;
  410.     while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));  // wait for MSSP module to be free (not busy)
  411.     _data = SSPBUF;  // read data from buffer
  412.     while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));  // wait for MSSP module to be free (not busy)
  413.     // send acknowledge pulse ? (depends on ack, if 1 send, otherwise don't send)
  414.     ACKDT = !ack;
  415.     ACKEN = 1;
  416.     return _data;  // return data read
  417. }
  418.  
  419. void write_to_i2c(uint8_t i2c_address, uint8_t command, uint8_t chr)
  420. {
  421.     I2C_Start();
  422.     I2C_Write(i2c_address);
  423.     I2C_Write(command);
  424.     I2C_Write(chr);
  425.     I2C_Stop();
  426. }
  427.  
  428. /**
  429.    @Param
  430.     none
  431.    @Returns
  432.     none
  433.    @Description
  434.     GPIO and peripheral I/O initialization
  435.    @Example
  436.     PIN_MANAGER_Initialize();
  437.  */
  438. void PIN_MANAGER_Initialize(void)
  439. {
  440.     /**
  441.     LATx registers
  442.     */
  443.     LATA = 0x00;
  444.  
  445.     /**
  446.     TRISx registers
  447.     */
  448.     TRISA = 0b00011111;
  449.     // RA5 is output
  450.  
  451.     /**
  452.     ANSELx registers
  453.     */
  454.     ANSELA = 0x00;
  455.  
  456.     /**
  457.     WPUx registers
  458.     */
  459.     WPUA = 0b00001111;
  460.     // RA0 is button_up, pullup
  461.     // RA1 is SCL, pullup
  462.     // RA2 is SDA, pullup
  463.     // RA3 is button_down, pullup
  464.     // RA4 is zerocross detection, no pullup
  465.     // RA5 is mosfet driver, no pullup
  466.  
  467.     // Global WPUEN bit of the OPTION register must be cleared for individual pull-ups to be enabled
  468.     // in our case we want to disable global pull-ups
  469.     OPTION_REGbits.nWPUEN = 0;
  470.  
  471.     /**
  472.     APFCONx registers
  473.     */
  474.     APFCON = 0x00;    
  475. }
  476.  
  477. /**
  478.  * @Param
  479.     none
  480.  * @Returns
  481.     none
  482.  * @Description
  483.     This macro will enable global interrupts.
  484.  * @Example
  485.     INTERRUPT_GlobalInterruptEnable();
  486.  */
  487. #define INTERRUPT_GlobalInterruptEnable() (INTCONbits.GIE = 1)
  488.  
  489. /**
  490.  * @Param
  491.     none
  492.  * @Returns
  493.     none
  494.  * @Description
  495.     This macro will disable global interrupts.
  496.  * @Example
  497.     INTERRUPT_GlobalInterruptDisable();
  498.  */
  499. #define INTERRUPT_GlobalInterruptDisable() (INTCONbits.GIE = 0)
  500. /**
  501.  * @Param
  502.     none
  503.  * @Returns
  504.     none
  505.  * @Description
  506.     This macro will enable peripheral interrupts.
  507.  * @Example
  508.     INTERRUPT_PeripheralInterruptEnable();
  509.  */
  510. #define INTERRUPT_PeripheralInterruptEnable() (INTCONbits.PEIE = 1)
  511.  
  512. /**
  513.  * @Param
  514.     none
  515.  * @Returns
  516.     none
  517.  * @Description
  518.     This macro will disable peripheral interrupts.
  519.  * @Example
  520.     INTERRUPT_PeripheralInterruptDisable();
  521.  */
  522. #define INTERRUPT_PeripheralInterruptDisable() (INTCONbits.PEIE = 0)
  523.  
  524. /**
  525.  * @Param
  526.     none
  527.  * @Returns
  528.     none
  529.  * @Description
  530.     Initializes the oscillator to the default states configured in the
  531.  *                  MCC GUI
  532.  * @Example
  533.     OSCILLATOR_Initialize(void);
  534.  */
  535. void OSCILLATOR_Initialize(void)
  536. {
  537.     // SPLLEN enabled; IRCF 32MHz_HF; SCS Clock determined by FOSC<2:0> in Configuration Word 1;
  538.     OSCCON = 0b11110000;
  539.     // TUN 0;
  540.     OSCTUNE = 0x00;
  541.     // SBOREN disabled;
  542.     BORCON = 0x00;
  543. }
  544.  
  545. /**
  546.  * @Param
  547.     none
  548.  * @Returns
  549.     none
  550.  * @Description
  551.     Initializes the WDT module to the default states configured in the
  552.  *                  MCC GUI
  553.  * @Example
  554.     WDT_Initialize(void);
  555.  */
  556. void WDT_Initialize(void)
  557. {
  558.     // WDTPS 1:65536; SWDTEN OFF;
  559.     WDTCON = 0x16;
  560. }
  561.  
  562. /**
  563.  * @Param
  564.     none
  565.  * @Returns
  566.     none
  567.  * @Description
  568.     Initializes the device to the default states configured in the
  569.  *                  MCC GUI
  570.  * @Example
  571.     SYSTEM_Initialize(void);
  572.  */
  573. void SYSTEM_Initialize(void)
  574. {
  575.  
  576.     PIN_MANAGER_Initialize();
  577.     OSCILLATOR_Initialize();
  578.     WDT_Initialize();
  579. }
  580.  
  581. /*------------------------------ OLED 128x64 definitions ---------------------------------*/
  582.  
  583. //#define SSD1306
  584. #define SSD1306_I2C_ADDRESS      (0x3C << 1)
  585.  
  586. #define SSD1306_LCDWIDTH             128
  587. #define SSD1306_LCDHEIGHT            64
  588.  
  589. #ifdef SSD1306
  590.  
  591. #define SSD1306_NORMALDISPLAY        0xA6
  592. #define SSD1306_INVERTDISPLAY        0xA7
  593. #define SSD1306_DISPLAYOFF           0xAE
  594. #define SSD1306_DISPLAYON            0xAF
  595. #define SSD1306_SETDISPLAYOFFSET     0xD3
  596. #define SSD1306_SETCOMPINS           0xDA
  597. #define SSD1306_SETVCOMDETECT        0xDB
  598. #define SSD1306_SETDISPLAYCLOCKDIV   0xD5
  599. #define SSD1306_SETPRECHARGE         0xD9
  600. #define SSD1306_SETCONTRAST          0x81
  601. #define SSD1306_DISPLAYALLON_RESUME  0xA4
  602. #define SSD1306_SETMULTIPLEX         0xA8
  603. #define SSD1306_SETLOWCOLUMN         0x00
  604. #define SSD1306_SETHIGHCOLUMN        0x10
  605. #define SSD1306_SETSTARTLINE         0x40
  606. #define SSD1306_MEMORYMODE           0x20
  607. #define SSD1306_COLUMNADDR           0x21
  608. #define SSD1306_PAGEADDR             0x22
  609. #define SSD1306_COMSCANINC           0xC0
  610. #define SSD1306_COMSCANDEC           0xC8
  611. #define SSD1306_SEGREMAP             0xA0
  612. #define SSD1306_CHARGEPUMP           0x8D
  613. #define SSD1306_EXTERNALVCC          0x01
  614. #define SSD1306_SWITCHCAPVCC         0x02
  615.  
  616. // Scrolling #defines
  617. #define SSD1306_ACTIVATE_SCROLL      0x2F
  618. #define SSD1306_DEACTIVATE_SCROLL                    0x2E
  619. #define SSD1306_SET_VERTICAL_SCROLL_AREA             0xA3
  620. #define SSD1306_RIGHT_HORIZONTAL_SCROLL              0x26
  621. #define SSD1306_LEFT_HORIZONTAL_SCROLL               0x27
  622. #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
  623. #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL  0x2A
  624.  
  625. #define Set_Page_Start_Address_CMD                   0xB0
  626.  
  627. #define y_max 8
  628.  
  629. #define CMD 0x00
  630. #define DAT 0x40
  631.  
  632. // Init sequence for Adafruit 128x64 OLED module
  633. uint8_t ssd1306_init_sequence[] = {
  634.     SSD1306_DISPLAYOFF,
  635.     SSD1306_SETDISPLAYCLOCKDIV,
  636.     0x80,                             // the suggested ratio 0x80
  637.     SSD1306_SETMULTIPLEX,
  638.     0x3F,                             // ratio 64
  639.     SSD1306_SETDISPLAYOFFSET,
  640.     0x0,                              // no offset
  641.     SSD1306_SETSTARTLINE | 0x0,       // line #0
  642.     SSD1306_CHARGEPUMP,
  643.     0x14,                             // internal vcc
  644.     SSD1306_MEMORYMODE,
  645.     0x02,                             // page mode
  646.     SSD1306_SEGREMAP | 0x1,           // column 127 mapped to SEG0
  647.     SSD1306_COMSCANDEC,               // column scan direction reversed
  648.     SSD1306_SETCOMPINS,
  649.     0x12,                             // alt COM pins, disable remap
  650.     SSD1306_SETCONTRAST,
  651.     0x7F,                             // contrast level 127
  652.     SSD1306_SETPRECHARGE,
  653.     0xF1,                             // pre-charge period (1, 15)
  654.     SSD1306_SETVCOMDETECT,
  655.     0x40,                             // vcomh regulator level
  656.     SSD1306_DISPLAYALLON_RESUME,
  657.     SSD1306_NORMALDISPLAY
  658. };
  659.  
  660. #else   // SH1106
  661.  
  662. #define SSD1306_SETLOWCOLUMN         0x00
  663. #define SSD1306_SETHIGHCOLUMN        0x10
  664.  
  665. uint8_t ssd1306_init_sequence[] = {
  666.     0xAE, // display off
  667.     0x02, // set lower column address
  668.     0x10, // set higher column address
  669.     0x40, // set display start line
  670.     0xB0, // set page address
  671.     0x81, // contract control
  672.     0xff, // 128
  673.     0xA1, // set segment remap
  674.     0xA6, // normal / reverse
  675.     0xA8, // multiplex ratio
  676.     0x3F, // duty = 1/64
  677.     0xad, // set charge pump enable
  678.     0x8b, // 0x8B internal VCC
  679.     0x32, // 0X30---0X33 set VPP 8.x V ???
  680.     0xC8, // Com scan direction
  681.     0xD3, // set display offset
  682.     0x00, // 0x20
  683.     0xD5, // set osc division
  684.     0x80,
  685.     0xD9, // set pre-charge period
  686.     0x1f, // 0x22
  687.     0xDA, // set COM pins
  688.     0x12,
  689.     0xdb, // set vcomh
  690.     0x40
  691. };
  692.  
  693. #define Set_Page_Start_Address_CMD 0xB0
  694. #define y_max 8
  695. #define CMD 0x00
  696. #define DAT 0x40
  697.  
  698. #endif
  699.  
  700. void ssd1306_write(uint8_t addr, uint8_t cmd)
  701. {
  702.     write_to_i2c(SSD1306_I2C_ADDRESS, addr, cmd);
  703. }
  704.  
  705. void ssd1306_init(void)
  706. {
  707.     uint8_t i;
  708.    
  709.     for (i=0; i < sizeof(ssd1306_init_sequence); ++i)
  710.         ssd1306_write(CMD, ssd1306_init_sequence[i]);
  711. }
  712.  
  713. #define FONT_WIDTH 21
  714. #define FONT_HEIGHT 32
  715.  
  716. // run-length encoded fonts
  717. // https://eleif.net/rle.html
  718. const uint8_t font_bitmap[] = {
  719.     0x04,0x00,0x01,0xC0,0x01,0xE0,0x01,0x70,0x01,0x30,0x05,0x18,0x01,0x30,0x01,0x70,0x01,0xE0,0x01,0xC0,0x06,0x00,0x01,0xF8,0x01,0xFF,0x01,0x07,0x0B,0x00,0x01,0x07,0x01,0xFF,0x01,0xF8,0x04,0x00,0x01,0x0F,0x01,0x7F,0x01,0xF0,0x01,0x80,0x09,0x00,0x01,0x80,0x01,0xF0,0x01,0x7F,0x01,0x0F,0x06,0x00,0x01,0x01,0x01,0x03,0x01,0x07,0x01,0x06,0x05,0x0C,0x01,0x06,0x01,0x07,0x01,0x03,0x01,0x01,0x04,0x00, //0
  720.     0x08,0x00,0x02,0x80,0x01,0xE0,0x02,0xF0,0x0D,0x00,0x03,0x03,0x02,0x01,0x01,0x00,0x02,0xFF,0x13,0x00,0x02,0xFF,0x13,0x00,0x02,0x0F,0x09,0x00, //1
  721.     0x04,0x00,0x01,0x40,0x01,0xE0,0x01,0x70,0x01,0x30,0x05,0x18,0x01,0x30,0x01,0x70,0x01,0xE0,0x01,0x80,0x0F,0x00,0x01,0x80,0x01,0xC0,0x01,0xE0,0x01,0x70,0x01,0x3F,0x01,0x0F,0x08,0x00,0x01,0x80,0x01,0xE0,0x01,0x78,0x01,0x1C,0x01,0x0E,0x01,0x06,0x01,0x03,0x01,0x01,0x0D,0x00,0x02,0x0F,0x0B,0x0C,0x04,0x00, //2
  722.     0x03,0x00,0x01,0x80,0x01,0xC0,0x01,0x60,0x01,0x30,0x01,0x38,0x05,0x18,0x01,0x30,0x01,0x70,0x01,0xE0,0x01,0x80,0x07,0x00,0x02,0x01,0x04,0x00,0x03,0xC0,0x02,0xE0,0x01,0xB0,0x01,0x3F,0x01,0x0F,0x07,0x00,0x02,0xC0,0x08,0x00,0x02,0x01,0x01,0x87,0x01,0xFF,0x01,0xFC,0x07,0x00,0x01,0x03,0x01,0x07,0x01,0x06,0x01,0x0E,0x05,0x0C,0x01,0x06,0x01,0x07,0x01,0x03,0x01,0x01,0x04,0x00, //3
  723.     0x09,0x00,0x01,0xC0,0x01,0xE0,0x01,0x70,0x02,0xF0,0x0B,0x00,0x01,0x80,0x01,0xE0,0x01,0x78,0x01,0x1C,0x01,0x0F,0x01,0x03,0x02,0x00,0x02,0xFF,0x09,0x00,0x01,0x1C,0x01,0x1F,0x01,0x1B,0x07,0x18,0x02,0xFF,0x04,0x18,0x0F,0x00,0x02,0x0F,0x07,0x00, //4
  724.     0x05,0x00,0x02,0xF0,0x0A,0x30,0x08,0x00,0x01,0xFC,0x01,0xFF,0x01,0x61,0x01,0x60,0x05,0x30,0x01,0x70,0x01,0x60,0x01,0xC0,0x01,0x80,0x07,0x00,0x02,0xC0,0x0A,0x00,0x01,0xC1,0x01,0xFF,0x01,0x7E,0x07,0x00,0x01,0x03,0x01,0x07,0x01,0x06,0x01,0x0E,0x05,0x0C,0x01,0x06,0x01,0x07,0x01,0x03,0x01,0x01,0x04,0x00, //5
  725.     0x04,0x00,0x01,0x80,0x01,0xE0,0x01,0xF0,0x01,0x70,0x01,0x38,0x04,0x18,0x01,0x38,0x01,0x70,0x01,0xE0,0x01,0xC0,0x07,0x00,0x01,0xFC,0x01,0xFF,0x01,0x87,0x02,0xC0,0x05,0x60,0x01,0xE0,0x01,0xC0,0x01,0x80,0x08,0x00,0x01,0x1F,0x01,0xFF,0x01,0xC1,0x01,0x01,0x07,0x00,0x01,0x01,0x01,0x83,0x01,0xFF,0x01,0x7E,0x08,0x00,0x01,0x03,0x01,0x07,0x01,0x06,0x05,0x0C,0x01,0x0E,0x01,0x07,0x01,0x03,0x01,0x01,0x04,0x00, //6
  726.     0x03,0x00,0x0C,0x30,0x01,0xB0,0x01,0xF0,0x01,0x70,0x0F,0x00,0x01,0x80,0x01,0xF0,0x01,0x7C,0x01,0x0F,0x01,0x03,0x0D,0x00,0x01,0xC0,0x01,0xF8,0x01,0x3E,0x01,0x07,0x01,0x01,0x0E,0x00,0x01,0x08,0x01,0x0F,0x01,0x07,0x0B,0x00, //7
  727.     0x04,0x00,0x01,0xC0,0x01,0xE0,0x01,0x70,0x01,0x30,0x05,0x18,0x01,0x30,0x01,0x70,0x01,0xE0,0x01,0xC0,0x08,0x00,0x01,0x07,0x01,0x1F,0x01,0x38,0x01,0xB0,0x02,0xE0,0x01,0xC0,0x02,0xE0,0x01,0xB0,0x01,0x38,0x01,0x1F,0x01,0x07,0x07,0x00,0x01,0xF8,0x01,0xFC,0x01,0x86,0x01,0x03,0x02,0x01,0x03,0x00,0x02,0x01,0x01,0x03,0x01,0x87,0x01,0xFE,0x01,0xF8,0x07,0x00,0x01,0x03,0x01,0x07,0x01,0x06,0x01,0x0E,0x05,0x0C,0x01,0x0E,0x01,0x06,0x01,0x07,0x01,0x03,0x04,0x00, //9
  728.     0x04,0x00,0x01,0xC0,0x01,0xE0,0x01,0x70,0x01,0x38,0x04,0x18,0x01,0x38,0x01,0x30,0x01,0xF0,0x01,0xE0,0x01,0x80,0x07,0x00,0x01,0x3F,0x01,0xFF,0x01,0xC1,0x01,0x80,0x08,0x00,0x01,0x83,0x01,0xFF,0x01,0xFC,0x06,0x00,0x02,0x80,0x01,0x01,0x01,0x03,0x01,0x07,0x05,0x06,0x01,0x03,0x01,0x83,0x01,0xF1,0x01,0xFF,0x01,0x1F,0x06,0x00,0x01,0x01,0x01,0x03,0x01,0x07,0x01,0x06,0x05,0x0C,0x01,0x0E,0x01,0x07,0x01,0x03,0x01,0x01,0x05,0x00 //9
  729. };
  730.  
  731. const uint16_t font_bitmap_offsets[] = {0, 0x4e, 0x6a, 0xa6, 0xf0, 0x120, 0x15c, 0x1ac, 0x1d8, 0x232};
  732.  
  733. void ssd1306_draw_font(uint8_t x, uint8_t y, uint16_t num)
  734. {
  735.     size_t tt = 0;
  736.     uint8_t x_pos = x;
  737.     uint8_t y_pos = y;
  738.  
  739.     uint8_t num_bytes = 0;
  740.     uint8_t bytes = 0;
  741.     uint16_t ii = 0;
  742.     uint16_t ofset = font_bitmap_offsets[num];;
  743.  
  744.     // run length decoded font size = 84
  745.     for(tt=0; tt<84;)
  746.     {
  747.         num_bytes = font_bitmap[ofset++];
  748.         bytes = font_bitmap[ofset++];
  749.  
  750.         for (ii=0; ii<num_bytes; ++ii)
  751.         {
  752.             if (x_pos >= (x + FONT_WIDTH))
  753.             {
  754.                 x_pos = x;
  755.                 y_pos++;
  756.             }
  757.  
  758.             ssd1306_write(CMD, Set_Page_Start_Address_CMD + y_pos);        // set row
  759.             ssd1306_write(CMD, SSD1306_SETLOWCOLUMN | (x_pos & 0xf));      // set lower column address
  760.             ssd1306_write(CMD, SSD1306_SETHIGHCOLUMN | (x_pos >> 4));      // set higher column address
  761.  
  762.             ssd1306_write(DAT, (uint8_t)bytes);
  763.             tt++;
  764.             x_pos++;
  765.         }
  766.     }
  767. }
  768.  
  769. void draw_temperature(uint8_t x, uint8_t y, uint16_t temp)
  770. {
  771.     if (temp == 0)
  772.     {
  773.         ssd1306_draw_font(x, y, 0);
  774.         ssd1306_draw_font(x+FONT_WIDTH, y, 0);
  775.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, 0);
  776.     }
  777.     else if (temp > 0 && temp < 10)
  778.     {
  779.         ssd1306_draw_font(x, y, 0);
  780.         ssd1306_draw_font(x+FONT_WIDTH, y, 0);
  781.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp);
  782.     }
  783.     else if (temp >= 10 && temp < 100)
  784.     {
  785.         ssd1306_draw_font(x, y, 0);
  786.         ssd1306_draw_font(x+FONT_WIDTH, y, (temp/10)%10);
  787.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp%10);
  788.     }
  789.     else if (temp >= 100 && temp < 1000)
  790.     {
  791.         ssd1306_draw_font(x, y, (temp/100)%10);
  792.         ssd1306_draw_font(x+FONT_WIDTH, y, (temp/10)%10);
  793.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp%10);
  794.     }
  795.     else
  796.     {
  797.         ssd1306_draw_font(x, y, 9);
  798.         ssd1306_draw_font(x+FONT_WIDTH, y, 9);
  799.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, 9);
  800.     }
  801. }
  802.  
  803. void ssd1306_fill(uint8_t bmp_data)
  804. {                                                    
  805.     uint8_t x_pos;
  806.     uint8_t page;
  807.  
  808.     for (page=0; page < y_max; ++page)
  809.     {
  810.         ssd1306_write(CMD, (Set_Page_Start_Address_CMD + page));
  811. #ifdef SSD1306
  812.         ssd1306_write(CMD, SSD1306_SETLOWCOLUMN);
  813. #else
  814.         ssd1306_write(CMD, SSD1306_SETLOWCOLUMN+2);
  815. #endif
  816.         ssd1306_write(CMD, SSD1306_SETHIGHCOLUMN);
  817.  
  818.         for (x_pos=0; x_pos < SSD1306_LCDWIDTH; ++x_pos)
  819.         {
  820.             ssd1306_write(DAT, bmp_data);
  821.         }                                                                                  
  822.     }  
  823. }
  824.  
  825. #define ADS1115_I2C_ADDRESS    (0x48 << 1)
  826.  
  827. uint16_t ADS1115_Read(void)
  828. {
  829.     uint8_t timeout;
  830.     uint8_t buffer[2];
  831.  
  832.     I2C_Start();
  833.     I2C_Write(ADS1115_I2C_ADDRESS);
  834.     I2C_Write(1);  // config register
  835.     I2C_Write(0b11000101); // start conversion, AIN0 and GND, FSR=2.048, single shot mode
  836.     I2C_Write(0b10100011); // 250 SPS, Traditional comparator, alert pin active low, nonlatching comparator, disable comparator, alert pin high impedance
  837.     I2C_Stop();
  838.  
  839.     // wait for conversion complete (10ms max)
  840.     timeout = 100;
  841.     do {
  842.         I2C_Start();
  843.         I2C_Write(ADS1115_I2C_ADDRESS+1);
  844.         buffer[0] = I2C_Read(1);
  845.         buffer[1] = I2C_Read(0);
  846.         I2C_Stop();
  847.         __delay_us(100);
  848.     } while (!(buffer[0] & 0x80) && --timeout);
  849.  
  850.     // read conversion register
  851.     I2C_Start();
  852.     I2C_Write(ADS1115_I2C_ADDRESS);
  853.     I2C_Write(0x00);    // conversion register is 0
  854.     I2C_Stop();
  855.     I2C_Start();
  856.     I2C_Write(ADS1115_I2C_ADDRESS+1);
  857.     buffer[0] = I2C_Read(1);
  858.     buffer[1] = I2C_Read(0);
  859.     I2C_Stop();
  860.  
  861.     return buffer[0] << 8 | buffer[1];
  862. }
  863.  
  864. #define JBC_MAX_TEMP 350
  865.  
  866. uint16_t read_temp(void)
  867. {
  868.     float temperature;
  869.  
  870.     // temperatura = (VOUT - VREF)/(5 mV/ C)
  871.     // LSB = FSR / 32767;
  872.     // temperatura = ((advalue * LSB) - VREF) / 0.005
  873.     temperature = (float)(((ADS1115_Read() * (2.048 / 32767.0)) - 1.24) / 0.005);
  874.  
  875.     return (uint16_t)temperature;
  876. }
  877.  
  878. __EEPROM_DATA(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
  879.  
  880. volatile uint16_t tt=0, bb=0;
  881.  
  882. // 8bit timer
  883. void timer0_initialise(void)
  884. {
  885.     // 1.2ms x (xtail / 4)
  886.     // 0.0012 * 8000000 = 9600 ticks ; prescaler=64 = 9600/64 = 150 ticks for 1.2ms timer
  887.  
  888.     // writing to TMR0 resets prescaler, so you need to set prescaler every time!
  889.     TMR0 = 105; // start at 105 ticks (255 - 150)
  890.  
  891.     OPTION_REGbits.TMR0CS = 0; // Internal instruction cycle clock (FOSC/4)
  892.     OPTION_REGbits.TMR0SE = 0; // low to high
  893.     OPTION_REGbits.PSA = 0; // Prescaler is assigned to the Timer0 module
  894.     OPTION_REGbits.PS2 = 1; // prescaler 64 (PS2:PS1:PS0)
  895.     OPTION_REGbits.PS1 = 0;
  896.     OPTION_REGbits.PS0 = 1;
  897.     // 000 1 : 2
  898.     // 001 1 : 4
  899.     // 010 1 : 8
  900.     // 011 1 : 16
  901.     // 100 1 : 32
  902.     // 101 1 : 64
  903.     // 110 1 : 128
  904.     // 111 1 : 256
  905.  
  906.     INTCONbits.TMR0IE = 1; // enable timer0
  907. }
  908.  
  909. volatile bool okinuo = false;
  910.  
  911. void __interrupt() ISR(void)
  912. {
  913.     if (INTCONbits.IOCIE == 1 && INTCONbits.IOCIF == 1)
  914.     {
  915.         if (IOCAFbits.IOCAF4 == 1)
  916.         {
  917.             // interrupt on change for group IOCAF, clear IOCAF4 so it will auto clear readonly IOCIF
  918.             IOCAFbits.IOCAF4 = 0;
  919.  
  920.             // interrupt on change for group IOCAN
  921.             IOCANbits.IOCAN4 = 0;
  922.  
  923.             // interrupt on change for group IOCAP
  924.             IOCAPbits.IOCAP4 = 1;
  925.  
  926.             INTCONbits.IOCIE = 0; // disable IOCI interrUPT
  927.  
  928.             timer0_initialise();
  929.             IO_RA5_SetHigh();
  930.         }
  931.     }
  932.  
  933.     if (INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)
  934.     {
  935.         tt+=1;    
  936.         IO_RA5_SetLow();
  937.         INTCONbits.TMR0IE = 0; // disable timer0
  938.         INTCONbits.TMR0IF = 0; // clear interupt, it will not selfclear!        
  939.         if (tt=12499)
  940.         {
  941.             tt=0;
  942.             bb+=1;
  943.             okinuo = false;
  944.         }        
  945.     }
  946.  
  947.     return;        
  948. }
  949.  
  950. void main(void)
  951. {
  952.     bool tempset_changed = false;
  953.     uint16_t temperature = 350; //max temp
  954.     uint16_t temperature_set = eeprom_read(0) << 8 | eeprom_read(1);
  955.  
  956.     // initialize the device
  957.     SYSTEM_Initialize();
  958.  
  959.     // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
  960.     // Use the following macros to:
  961.  
  962.     // Enable the Global Interrupts
  963.     INTERRUPT_GlobalInterruptEnable();
  964.  
  965.     // Enable the Peripheral Interrupts
  966.     INTERRUPT_PeripheralInterruptEnable();
  967.  
  968.     // Disable the Global Interrupts
  969.     //INTERRUPT_GlobalInterruptDisable();
  970.  
  971.     // Disable the Peripheral Interrupts
  972.     //INTERRUPT_PeripheralInterruptDisable();
  973.  
  974.     I2C_Init(400000);    // initialize I2C bus with clock frequency of 400kHz
  975.  
  976.     __delay_ms(100);    
  977.     ssd1306_init();
  978.     __delay_ms(100);
  979.     ssd1306_fill(0);
  980.     ssd1306_write(CMD, 0xAF /* display ON*/);
  981.  
  982.     while(1)
  983.     {
  984.         if (IO_RA5_GetValue() == LOW)
  985.         {
  986.             temperature = read_temp();
  987.             draw_temperature(33, 4, temperature);
  988.         }
  989.  
  990.         while(IO_RA0_GetValue() == LOW)
  991.         {
  992.             if (temperature_set < JBC_MAX_TEMP)
  993.             {
  994.                 temperature_set += 5;
  995.                 draw_temperature(33, 0, temperature_set);
  996.                 tempset_changed = true;
  997.             }
  998.         }
  999.  
  1000.         while(IO_RA3_GetValue() == LOW)
  1001.         {
  1002.             if (temperature_set >= 5)
  1003.             {
  1004.                 temperature_set -= 5;
  1005.                 draw_temperature(33, 0, temperature_set);
  1006.                 tempset_changed = true;
  1007.             }
  1008.         }
  1009.  
  1010.         if (tempset_changed)
  1011.         {
  1012.             eeprom_write(0, (temperature_set >> 8) & 0xff);
  1013.             eeprom_write(1, temperature_set & 0xff);
  1014.             tempset_changed = false;
  1015.         }
  1016.  
  1017.         if (okinuo == false)
  1018.         {
  1019.             okinuo = true;
  1020.  
  1021.             // interrupt on change for group IOCAF - flag
  1022.             IOCAFbits.IOCAF4 = 0; // Pin : RA4
  1023.  
  1024.             // interrupt on change for group IOCAN - negative
  1025.             IOCANbits.IOCAN4 = 0; // Pin : RA4
  1026.  
  1027.             // interrupt on change for group IOCAP - positive
  1028.             IOCAPbits.IOCAP4 = 1; // Pin : RA4
  1029.  
  1030.             INTCONbits.IOCIE = 1; // Enable IOCI interrupt
  1031.             draw_temperature(33, 0, bb);            
  1032.         }        
  1033.     }
  1034. }
  1035.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement