Advertisement
Guest User

Untitled

a guest
Jan 12th, 2023
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 29.83 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. /*------------------------------ SSD1306 128x64 definitions ---------------------------------*/
  582.  
  583. #define SSD1306_I2C_ADDRESS      (0x3C << 1)
  584.  
  585. #define SSD1306_LCDWIDTH             128
  586. #define SSD1306_LCDHEIGHT            64
  587.  
  588. #define SSD1306_NORMALDISPLAY        0xA6
  589. #define SSD1306_INVERTDISPLAY        0xA7
  590. #define SSD1306_DISPLAYOFF           0xAE
  591. #define SSD1306_DISPLAYON            0xAF
  592. #define SSD1306_SETDISPLAYOFFSET     0xD3
  593. #define SSD1306_SETCOMPINS           0xDA
  594. #define SSD1306_SETVCOMDETECT        0xDB
  595. #define SSD1306_SETDISPLAYCLOCKDIV   0xD5
  596. #define SSD1306_SETPRECHARGE         0xD9
  597. #define SSD1306_SETCONTRAST          0x81
  598. #define SSD1306_DISPLAYALLON_RESUME  0xA4
  599. #define SSD1306_SETMULTIPLEX         0xA8
  600. #define SSD1306_SETLOWCOLUMN         0x00
  601. #define SSD1306_SETHIGHCOLUMN        0x10
  602. #define SSD1306_SETSTARTLINE         0x40
  603. #define SSD1306_MEMORYMODE           0x20
  604. #define SSD1306_COLUMNADDR           0x21
  605. #define SSD1306_PAGEADDR             0x22
  606. #define SSD1306_COMSCANINC           0xC0
  607. #define SSD1306_COMSCANDEC           0xC8
  608. #define SSD1306_SEGREMAP             0xA0
  609. #define SSD1306_CHARGEPUMP           0x8D
  610. #define SSD1306_EXTERNALVCC          0x01
  611. #define SSD1306_SWITCHCAPVCC         0x02
  612.  
  613. // Scrolling #defines
  614. #define SSD1306_ACTIVATE_SCROLL      0x2F
  615. #define SSD1306_DEACTIVATE_SCROLL                    0x2E
  616. #define SSD1306_SET_VERTICAL_SCROLL_AREA             0xA3
  617. #define SSD1306_RIGHT_HORIZONTAL_SCROLL              0x26
  618. #define SSD1306_LEFT_HORIZONTAL_SCROLL               0x27
  619. #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
  620. #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL  0x2A
  621.  
  622. #define Set_Page_Start_Address_CMD                   0xB0
  623.  
  624. #define y_max   8
  625.  
  626. #define CMD 0x00
  627. #define DAT 0x40
  628.  
  629. // Init sequence for Adafruit 128x64 OLED module
  630. uint8_t ssd1306_init_sequence[25] = {
  631.     SSD1306_DISPLAYOFF,
  632.     SSD1306_SETDISPLAYCLOCKDIV,
  633.     0x80,                             // the suggested ratio 0x80
  634.     SSD1306_SETMULTIPLEX,
  635.     0x3F,                             // ratio 64
  636.     SSD1306_SETDISPLAYOFFSET,
  637.     0x0,                              // no offset
  638.     SSD1306_SETSTARTLINE | 0x0,       // line #0
  639.     SSD1306_CHARGEPUMP,
  640.     0x14,                             // internal vcc
  641.     SSD1306_MEMORYMODE,
  642.     0x02,                             // page mode
  643.     SSD1306_SEGREMAP | 0x1,           // column 127 mapped to SEG0
  644.     SSD1306_COMSCANDEC,               // column scan direction reversed
  645.     SSD1306_SETCOMPINS,
  646.     0x12,                             // alt COM pins, disable remap
  647.     SSD1306_SETCONTRAST,
  648.     0x7F,                             // contrast level 127
  649.     SSD1306_SETPRECHARGE,
  650.     0xF1,                             // pre-charge period (1, 15)
  651.     SSD1306_SETVCOMDETECT,
  652.     0x40,                             // vcomh regulator level
  653.     SSD1306_DISPLAYALLON_RESUME,
  654.     SSD1306_NORMALDISPLAY,
  655.     SSD1306_DISPLAYON
  656. };
  657.  
  658. void ssd1306_write(uint8_t addr, uint8_t cmd)
  659. {
  660.     write_to_i2c(SSD1306_I2C_ADDRESS, addr, cmd);
  661. }
  662.  
  663. void ssd1306_init(void)
  664. {
  665.     uint8_t i;
  666.    
  667.     for (i=0; i < 25; ++i)
  668.         ssd1306_write(CMD, ssd1306_init_sequence[i]);
  669. }
  670.  
  671. #define FONT_WIDTH 21
  672. #define FONT_HEIGHT 32
  673.  
  674. // run-length encoded fonts
  675. // https://eleif.net/rle.html
  676. const uint8_t font_bitmap[] = {
  677.     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
  678.     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
  679.     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
  680.     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
  681.     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
  682.     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
  683.     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
  684.     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
  685.     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
  686.     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
  687. };
  688.  
  689. const uint16_t font_bitmap_offsets[] = {0, 0x4e, 0x6a, 0xa6, 0xf0, 0x120, 0x15c, 0x1ac, 0x1d8, 0x232};
  690.  
  691. void ssd1306_draw_font(uint8_t x, uint8_t y, uint16_t num)
  692. {
  693.     size_t tt = 0;
  694.     uint8_t x_pos = x;
  695.     uint8_t y_pos = y;
  696.  
  697.     uint8_t num_bytes = 0;
  698.     uint8_t bytes = 0;
  699.     uint16_t ii = 0;
  700.     uint16_t ofset = font_bitmap_offsets[num];;
  701.  
  702.     // run length decoded font size = 84
  703.     for(tt=0; tt<84;)
  704.     {
  705.         num_bytes = font_bitmap[ofset++];
  706.         bytes = font_bitmap[ofset++];
  707.  
  708.         for (ii=0; ii<num_bytes; ++ii)
  709.         {
  710.             if (x_pos >= (x + FONT_WIDTH))
  711.             {
  712.                 x_pos = x;
  713.                 y_pos++;
  714.             }
  715.  
  716.             ssd1306_write(CMD, Set_Page_Start_Address_CMD + y_pos);        // set row
  717.             ssd1306_write(CMD, SSD1306_SETLOWCOLUMN | (x_pos & 0xf));      // set lower column address
  718.             ssd1306_write(CMD, SSD1306_SETHIGHCOLUMN | (x_pos >> 4));      // set higher column address
  719.  
  720.             ssd1306_write(DAT, (uint8_t)bytes);
  721.             tt++;
  722.             x_pos++;
  723.         }
  724.     }
  725. }
  726.  
  727. void draw_temperature(uint8_t x, uint8_t y, uint16_t temp)
  728. {
  729.     if (temp == 0)
  730.     {
  731.         ssd1306_draw_font(x, y, 0);
  732.         ssd1306_draw_font(x+FONT_WIDTH, y, 0);
  733.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, 0);
  734.     }
  735.     else if (temp > 0 && temp < 10)
  736.     {
  737.         ssd1306_draw_font(x, y, 0);
  738.         ssd1306_draw_font(x+FONT_WIDTH, y, 0);
  739.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp);
  740.     }
  741.     else if (temp >= 10 && temp < 100)
  742.     {
  743.         ssd1306_draw_font(x, y, 0);
  744.         ssd1306_draw_font(x+FONT_WIDTH, y, (temp/10)%10);
  745.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp%10);
  746.     }
  747.     else if (temp >= 100 && temp < 1000)
  748.     {
  749.         ssd1306_draw_font(x, y, (temp/100)%10);
  750.         ssd1306_draw_font(x+FONT_WIDTH, y, (temp/10)%10);
  751.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp%10);
  752.     }
  753.     else
  754.     {
  755.         ssd1306_draw_font(x, y, 9);
  756.         ssd1306_draw_font(x+FONT_WIDTH, y, 9);
  757.         ssd1306_draw_font(x+(2*FONT_WIDTH), y, 9);
  758.     }
  759. }
  760.  
  761. void ssd1306_fill(uint8_t bmp_data)
  762. {                                                    
  763.     uint8_t x_pos = 0;
  764.     uint8_t page = 0;
  765.  
  766.     for (page=0; page < y_max; ++page)
  767.     {
  768.         ssd1306_write(CMD, (Set_Page_Start_Address_CMD + page));
  769.         ssd1306_write(CMD, SSD1306_SETLOWCOLUMN);
  770.         ssd1306_write(CMD, SSD1306_SETHIGHCOLUMN);
  771.  
  772.         for (x_pos=0; x_pos < SSD1306_LCDWIDTH; ++x_pos)
  773.         {
  774.             ssd1306_write(DAT, bmp_data);
  775.         }                                                                                  
  776.     }  
  777. }
  778.  
  779. #define ADS1115_I2C_ADDRESS    (0x48 << 1)
  780.  
  781. uint16_t ADS1115_Read(void)
  782. {
  783.     uint8_t timeout;
  784.     uint8_t buffer[2];
  785.  
  786.     I2C_Start();
  787.     I2C_Write(ADS1115_I2C_ADDRESS);
  788.     I2C_Write(1);  // config register
  789.     I2C_Write(0b11000101); // start conversion, AIN0 and GND, FSR=2.048, single shot mode
  790.     I2C_Write(0b10100011); // 250 SPS, Traditional comparator, alert pin active low, nonlatching comparator, disable comparator, alert pin high impedance
  791.     I2C_Stop();
  792.  
  793.     // wait for conversion complete (10ms max)
  794.     timeout = 100;
  795.     do {
  796.         I2C_Start();
  797.         I2C_Write(ADS1115_I2C_ADDRESS+1);
  798.         buffer[0] = I2C_Read(1);
  799.         buffer[1] = I2C_Read(0);
  800.         I2C_Stop();
  801.         __delay_us(100);
  802.     } while (!(buffer[0] & 0x80) && --timeout);
  803.  
  804.     // read conversion register
  805.     I2C_Start();
  806.     I2C_Write(ADS1115_I2C_ADDRESS);
  807.     I2C_Write(0x00);    // conversion register is 0
  808.     I2C_Stop();
  809.     I2C_Start();
  810.     I2C_Write(ADS1115_I2C_ADDRESS+1);
  811.     buffer[0] = I2C_Read(1);
  812.     buffer[1] = I2C_Read(0);
  813.     I2C_Stop();
  814.  
  815.     return buffer[0] << 8 | buffer[1];
  816. }
  817.  
  818. #define JBC_MAX_TEMP 350
  819.  
  820. uint16_t read_temp(void)
  821. {
  822.     float temperature;
  823.  
  824.     // temperatura = (VOUT - VREF)/(5 mV/ C)
  825.     // LSB = FSR / 32767;
  826.     // temperatura = ((advalue * LSB) - VREF) / 0.005
  827.     temperature = (float)(((ADS1115_Read() * (2.048 / 32767.0)) - 1.24) / 0.005);
  828.  
  829.     return (uint16_t)temperature;
  830. }
  831.  
  832. __EEPROM_DATA(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
  833.  
  834. // 8bit timer
  835. void timer0_initialise(void)
  836. {
  837.     //1.2 ms x (xtail / 4)
  838.     // 0.0012 * 8000000 = 9600 ticks ; prescaler=64 = 9600/64 = 150 ticks for 1.2ms
  839.  
  840.     // writing to TMR0 resets prescaler, so you need to set prescaler every time!
  841.     TMR0 = 105; // start at 105 ticks (255 - 150)
  842.  
  843.     OPTION_REGbits.TMR0CS = 0; //Internal instruction cycle clock (FOSC/4)
  844.     OPTION_REGbits.PSA = 0; // Prescaler is assigned to the Timer0 module
  845.     OPTION_REGbits.PS = 0b101; //prescaler 64
  846.     //000 1 : 2
  847.     //001 1 : 4
  848.     //010 1 : 8
  849.     //011 1 : 16
  850.     //100 1 : 32
  851.     //101 1 : 64
  852.     //110 1 : 128
  853.     //111 1 : 256
  854.  
  855.     INTCONbits.TMR0IE = 1; //enable timer0
  856. }
  857.  
  858. volatile bool okinuo = false;
  859.  
  860. void __interrupt() ISR(void)
  861. {
  862.     if (INTCONbits.IOCIE == 1 && INTCONbits.IOCIF == 1)
  863.     {
  864.         if (IOCAFbits.IOCAF4 == 1)
  865.         {
  866.             // interrupt on change for group IOCAF
  867.             IOCAFbits.IOCAF4 = 0;
  868.  
  869.             // interrupt on change for group IOCAN
  870.             IOCANbits.IOCAN4 = 0;
  871.  
  872.             // interrupt on change for group IOCAP
  873.             IOCAPbits.IOCAP4 = 1;
  874.  
  875.             timer0_initialise();
  876.             IO_RA5_SetHigh();
  877.             okinuo = true;
  878.  
  879.             INTCONbits.IOCIE = 0; // disable IOCI interrUPT
  880.         }
  881.     }
  882.  
  883.     if (INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)
  884.     {
  885.         IO_RA5_SetLow();
  886.         okinuo = false;
  887.         INTCONbits.TMR0IE = 0; // disable timer0
  888.     }
  889. }
  890.  
  891. void main(void)
  892. {
  893.     bool tempset_changed = false;
  894.     uint16_t temperature = 350; //max temp
  895.     uint16_t temperature_set = eeprom_read(0) << 8 | eeprom_read(1);
  896.  
  897.     // initialize the device
  898.     SYSTEM_Initialize();
  899.  
  900.     // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
  901.     // Use the following macros to:
  902.  
  903.     // Enable the Global Interrupts
  904.     INTERRUPT_GlobalInterruptEnable();
  905.  
  906.     // Enable the Peripheral Interrupts
  907.     INTERRUPT_PeripheralInterruptEnable();
  908.  
  909.     // Disable the Global Interrupts
  910.     //INTERRUPT_GlobalInterruptDisable();
  911.  
  912.     // Disable the Peripheral Interrupts
  913.     //INTERRUPT_PeripheralInterruptDisable();
  914.  
  915.     I2C_Init(400000);    // initialize I2C bus with clock frequency of 400kHz
  916.    
  917.     ssd1306_init();
  918.     ssd1306_fill(0);
  919.  
  920.     draw_temperature(33, 0, temperature_set);
  921.  
  922.     while(1)
  923.     {
  924.         if (IO_RA5_GetValue() == LOW)
  925.         {
  926.             temperature = read_temp();
  927.             draw_temperature(33, 4, temperature);
  928.         }
  929.  
  930.         while(IO_RA0_GetValue() == LOW)
  931.         {
  932.             if (temperature_set < JBC_MAX_TEMP)
  933.             {
  934.                 temperature_set += 5;
  935.                 draw_temperature(33, 0, temperature_set);
  936.                 tempset_changed = true;
  937.             }
  938.         }
  939.  
  940.         while(IO_RA3_GetValue() == LOW)
  941.         {
  942.             if (temperature_set >= 5)
  943.             {
  944.                 temperature_set -= 5;
  945.                 draw_temperature(33, 0, temperature_set);
  946.                 tempset_changed = true;
  947.             }
  948.         }
  949.  
  950.         if (tempset_changed)
  951.         {
  952.             eeprom_write(0, (temperature_set >> 8) & 0xff);
  953.             eeprom_write(1, temperature_set & 0xff);
  954.             tempset_changed = false;
  955.         }
  956.  
  957.         if (temperature < temperature_set && okinuo == false)
  958.         {
  959.             // interrupt on change for group IOCAF - flag
  960.             IOCAFbits.IOCAF4 = 0; // Pin : RA4
  961.  
  962.             // interrupt on change for group IOCAN - negative
  963.             IOCANbits.IOCAN4 = 0; // Pin : RA4
  964.  
  965.             // interrupt on change for group IOCAP - positive
  966.             IOCAPbits.IOCAP4 = 1; // Pin : RA4
  967.  
  968.             INTCONbits.IOCIE = 1; // Enable IOCI interrupt
  969.         }
  970.     }
  971. }
  972.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement