Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Sava @ 2022
- * JBC Soldering Station Contrloler / PIC12F1840
- * This is a free software with NO WARRANTY
- */
- // CONFIG1
- #pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
- #pragma config WDTE = OFF // Watchdog Timer Enable->WDT disabled
- #pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled
- #pragma config MCLRE = OFF // MCLR Pin Function Select->MCLR/VPP pin function is digital input
- #pragma config CP = ON // Flash Program Memory Code Protection->Program memory code protection is enabled
- #pragma config CPD = ON // Data Memory Code Protection->Data memory code protection is enabled
- #pragma config BOREN = ON // Brown-out Reset Enable->Brown-out Reset enabled
- #pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
- #pragma config IESO = ON // Internal/External Switchover->Internal/External Switchover mode is enabled
- #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled
- // CONFIG2
- #pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off
- #pragma config PLLEN = OFF // PLL Enable->4x PLL disabled
- #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
- #pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
- #pragma config LVP = OFF // Low-Voltage Programming Enable->High-voltage on MCLR/VPP must be used for programming
- #include <xc.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <stdio.h>
- #pragma warning disable 520
- #define _XTAL_FREQ 32000000
- #define ENABLE_UART_DEBUG 0
- #define INPUT 1
- #define OUTPUT 0
- #define HIGH 1
- #define LOW 0
- #define ANALOG 1
- #define DIGITAL 0
- #define PULL_UP_ENABLED 1
- #define PULL_UP_DISABLED 0
- // get/set IO_RA0 aliases
- #define IO_RA0_TRIS TRISAbits.TRISA0
- #define IO_RA0_LAT LATAbits.LATA0
- #define IO_RA0_PORT PORTAbits.RA0
- #define IO_RA0_WPU WPUAbits.WPUA0
- #define IO_RA0_ANS ANSELAbits.ANSA0
- #define IO_RA0_SetHigh() do { LATAbits.LATA0 = 1; } while(0)
- #define IO_RA0_SetLow() do { LATAbits.LATA0 = 0; } while(0)
- #define IO_RA0_Toggle() do { LATAbits.LATA0 = ~LATAbits.LATA0; } while(0)
- #define IO_RA0_GetValue() PORTAbits.RA0
- #define IO_RA0_SetDigitalInput() do { TRISAbits.TRISA0 = 1; } while(0)
- #define IO_RA0_SetDigitalOutput() do { TRISAbits.TRISA0 = 0; } while(0)
- #define IO_RA0_SetPullup() do { WPUAbits.WPUA0 = 1; } while(0)
- #define IO_RA0_ResetPullup() do { WPUAbits.WPUA0 = 0; } while(0)
- #define IO_RA0_SetAnalogMode() do { ANSELAbits.ANSA0 = 1; } while(0)
- #define IO_RA0_SetDigitalMode() do { ANSELAbits.ANSA0 = 0; } while(0)
- // get/set SCL aliases
- #define SCL_TRIS TRISAbits.TRISA1
- #define SCL_LAT LATAbits.LATA1
- #define SCL_PORT PORTAbits.RA1
- #define SCL_WPU WPUAbits.WPUA1
- #define SCL_ANS ANSELAbits.ANSA1
- #define SCL_SetHigh() do { LATAbits.LATA1 = 1; } while(0)
- #define SCL_SetLow() do { LATAbits.LATA1 = 0; } while(0)
- #define SCL_Toggle() do { LATAbits.LATA1 = ~LATAbits.LATA1; } while(0)
- #define SCL_GetValue() PORTAbits.RA1
- #define SCL_SetDigitalInput() do { TRISAbits.TRISA1 = 1; } while(0)
- #define SCL_SetDigitalOutput() do { TRISAbits.TRISA1 = 0; } while(0)
- #define SCL_SetPullup() do { WPUAbits.WPUA1 = 1; } while(0)
- #define SCL_ResetPullup() do { WPUAbits.WPUA1 = 0; } while(0)
- #define SCL_SetAnalogMode() do { ANSELAbits.ANSA1 = 1; } while(0)
- #define SCL_SetDigitalMode() do { ANSELAbits.ANSA1 = 0; } while(0)
- // get/set SDA aliases
- #define SDA_TRIS TRISAbits.TRISA2
- #define SDA_LAT LATAbits.LATA2
- #define SDA_PORT PORTAbits.RA2
- #define SDA_WPU WPUAbits.WPUA2
- #define SDA_ANS ANSELAbits.ANSA2
- #define SDA_SetHigh() do { LATAbits.LATA2 = 1; } while(0)
- #define SDA_SetLow() do { LATAbits.LATA2 = 0; } while(0)
- #define SDA_Toggle() do { LATAbits.LATA2 = ~LATAbits.LATA2; } while(0)
- #define SDA_GetValue() PORTAbits.RA2
- #define SDA_SetDigitalInput() do { TRISAbits.TRISA2 = 1; } while(0)
- #define SDA_SetDigitalOutput() do { TRISAbits.TRISA2 = 0; } while(0)
- #define SDA_SetPullup() do { WPUAbits.WPUA2 = 1; } while(0)
- #define SDA_ResetPullup() do { WPUAbits.WPUA2 = 0; } while(0)
- #define SDA_SetAnalogMode() do { ANSELAbits.ANSA2 = 1; } while(0)
- #define SDA_SetDigitalMode() do { ANSELAbits.ANSA2 = 0; } while(0)
- // get/set IO_RA3 aliases
- #define IO_RA3_TRIS TRISAbits.TRISA3
- #define IO_RA3_PORT PORTAbits.RA3
- #define IO_RA3_WPU WPUAbits.WPUA3
- #define IO_RA3_GetValue() PORTAbits.RA3
- #define IO_RA3_SetDigitalInput() do { TRISAbits.TRISA3 = 1; } while(0)
- #define IO_RA3_SetDigitalOutput() do { TRISAbits.TRISA3 = 0; } while(0)
- #define IO_RA3_SetPullup() do { WPUAbits.WPUA3 = 1; } while(0)
- #define IO_RA3_ResetPullup() do { WPUAbits.WPUA3 = 0; } while(0)
- // get/set IO_RA4 aliases
- #define IO_RA4_TRIS TRISAbits.TRISA4
- #define IO_RA4_LAT LATAbits.LATA4
- #define IO_RA4_PORT PORTAbits.RA4
- #define IO_RA4_WPU WPUAbits.WPUA4
- #define IO_RA4_ANS ANSELAbits.ANSA4
- #define IO_RA4_SetHigh() do { LATAbits.LATA4 = 1; } while(0)
- #define IO_RA4_SetLow() do { LATAbits.LATA4 = 0; } while(0)
- #define IO_RA4_Toggle() do { LATAbits.LATA4 = ~LATAbits.LATA4; } while(0)
- #define IO_RA4_GetValue() PORTAbits.RA4
- #define IO_RA4_SetDigitalInput() do { TRISAbits.TRISA4 = 1; } while(0)
- #define IO_RA4_SetDigitalOutput() do { TRISAbits.TRISA4 = 0; } while(0)
- #define IO_RA4_SetPullup() do { WPUAbits.WPUA4 = 1; } while(0)
- #define IO_RA4_ResetPullup() do { WPUAbits.WPUA4 = 0; } while(0)
- #define IO_RA4_SetAnalogMode() do { ANSELAbits.ANSA4 = 1; } while(0)
- #define IO_RA4_SetDigitalMode() do { ANSELAbits.ANSA4 = 0; } while(0)
- // get/set IO_RA5 aliases
- #define IO_RA5_TRIS TRISAbits.TRISA5
- #define IO_RA5_LAT LATAbits.LATA5
- #define IO_RA5_PORT PORTAbits.RA5
- #define IO_RA5_WPU WPUAbits.WPUA5
- #define IO_RA5_SetHigh() do { LATAbits.LATA5 = 1; } while(0)
- #define IO_RA5_SetLow() do { LATAbits.LATA5 = 0; } while(0)
- #define IO_RA5_Toggle() do { LATAbits.LATA5 = ~LATAbits.LATA5; } while(0)
- #define IO_RA5_GetValue() PORTAbits.RA5
- #define IO_RA5_SetDigitalInput() do { TRISAbits.TRISA5 = 1; } while(0)
- #define IO_RA5_SetDigitalOutput() do { TRISAbits.TRISA5 = 0; } while(0)
- #define IO_RA5_SetPullup() do { WPUAbits.WPUA5 = 1; } while(0)
- #define IO_RA5_ResetPullup() do { WPUAbits.WPUA5 = 0; } while(0)
- typedef void (*interruptHandler)(void);
- void (*i2c_driver_busCollisionISR)(void);
- void (*i2c_driver_i2cISR)(void);
- inline void i2c_driver_close(void)
- {
- SSP1CON1bits.SSPEN = 0;
- }
- /* Interrupt Control */
- inline void mssp_enableIRQ(void)
- {
- PIE1bits.SSP1IE = 1;
- }
- inline __bit mssp_IRQisEnabled(void)
- {
- return PIE1bits.SSP1IE;
- }
- inline void mssp_disableIRQ(void)
- {
- PIE1bits.SSP1IE = 0;
- }
- inline void mssp_clearIRQ(void)
- {
- PIR1bits.SSP1IF = 0;
- }
- inline __bit mssp_IRQisSet(void)
- {
- return PIR1bits.SSP1IF;
- }
- inline void mssp_waitForEvent(uint16_t timeout)
- {
- uint16_t to = timeout;
- if (PIR1bits.SSP1IF == 0)
- {
- while(to--)
- {
- if (PIR1bits.SSP1IF) break;
- __delay_us(100);
- }
- }
- }
- __bit i2c_driver_open(void)
- {
- if (!SSP1CON1bits.SSPEN)
- {
- SSP1STAT = 0x00;
- SSP1CON1 = 0x28;
- SSP1CON2 = 0x00;
- SSP1ADD = 0x13;
- return true;
- }
- else
- return false;
- }
- __bit i2c_driver_initSlaveHardware(void)
- {
- if(!SSP1CON1bits.SSPEN)
- {
- /* NOTE on AHEN:
- * If multiple slaves are to be emulated, then AHEN must be set. It must be set
- * because the driver needs to selectively ACK/NACK the address depending on its
- * ability to handle the address.
- */
- /* NOTE on DHEN:
- * DHEN must be set so that the data is not automatically NACK'ed if it is not read
- * from the SSPBUF. This driver will ALWAYS read the SSPBUF so that it can pass
- * the value to the appropriate slave handler. Because the data is ALWAYS read
- * the data will always be ACK'd if DHEN is cleared. If the slave does not want
- * the data byte from the master then it will return false and a NACK will be returned.
- */
- /* NOTE on SEN:
- * SEN will be set enabling clock stretching. This is because we don't know how
- * long the user will take to process data bytes in their callbacks. If they are fast,
- * we may not need to stretch the clock. If they are slow, we need to stretch the clock.
- * If we ALWAYS stretch the clock, we will release the clock when the ISR is complete.
- */
- /* NOTE on PCIE:
- * PCIE will be set to enable interrupts on STOP. This will allow us know when
- * the master is finished
- */
- /* NOTE on SCIE:
- * SCIE will be set to enable interrupts on START. This will allow us to detect
- * both a START and a RESTART event and prepare to restart communications.
- */
- SSP1CON1 |= 0x06; //setup I2C Slave (7-bit Addressing)
- SSP1STAT = 0x00;
- SSP1CON2 = 0x00;
- SSP1CON1bits.SSPEN = 1;
- return true;
- }
- return false;
- }
- inline void i2c_driver_resetBus(void)
- {
- }
- inline void i2c_driver_start(void)
- {
- SSP1CON2bits.SEN = 1;
- }
- inline void i2c_driver_restart(void)
- {
- SSP1CON2bits.RSEN = 1;
- }
- inline void i2c_driver_stop(void)
- {
- SSP1CON2bits.PEN = 1;
- }
- inline __bit i2c_driver_isNACK(void)
- {
- return SSP1CON2bits.ACKSTAT;
- }
- inline void i2c_driver_startRX(void)
- {
- SSP1CON2bits.RCEN = 1;
- }
- inline char i2c_driver_getRXData(void)
- {
- return SSP1BUF;
- }
- inline void i2c_driver_setAddr(char addr)
- {
- SSP1ADD = addr;
- }
- inline void i2c_driver_setMask(char mask)
- {
- SSP1MSK = mask;
- }
- inline void i2c_driver_TXData(char d)
- {
- SSP1BUF = d;
- }
- inline char i2c_driver_getAddr(void)
- {
- return SSP1ADD;
- }
- inline void i2c_driver_sendACK(void)
- {
- SSP1CON2bits.ACKDT = 0;
- SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
- }
- inline void i2c_driver_sendNACK(void)
- {
- SSP1CON2bits.ACKDT = 1;
- SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
- }
- inline void i2c_driver_releaseClock(void)
- {
- SSP1CON1bits.CKP = 1;
- }
- inline __bit i2c_driver_isBufferFull(void)
- {
- return SSP1STATbits.BF;
- }
- inline __bit i2c_driver_isStart(void)
- {
- return SSP1STATbits.S;
- }
- inline __bit i2c_driver_isAddress(void)
- {
- return !SSP1STATbits.D_nA;
- }
- inline __bit i2c_driver_isStop(void)
- {
- return SSP1STATbits.P;
- }
- inline __bit i2c_driver_isData(void)
- {
- return SSP1STATbits.D_nA;
- }
- inline __bit i2c_driver_isRead(void)
- {
- return SSP1STATbits.R_nW;
- }
- inline __bit i2c_driver_isWriteCollision(void)
- {
- return SSP1CON1bits.WCOL;
- }
- inline __bit i2c_driver_isReceiveOverflow(void)
- {
- return SSP1CON1bits.SSPOV;
- }
- inline void i2c_driver_clearBusCollision(void)
- {
- PIR2bits.BCL1IF = 0; // clear the bus collision.
- }
- inline void i2c_driver_setBusCollisionISR(interruptHandler handler)
- {
- i2c_driver_busCollisionISR = handler;
- }
- inline void i2c_driver_setI2cISR(interruptHandler handler)
- {
- i2c_driver_i2cISR = handler;
- }
- void I2C_Init(uint32_t i2c_clk_freq)
- {
- SSP1STAT = 0x00;
- SSP1CON1 = 0x28;
- SSP1CON2 = 0x00;
- SSP1ADD = (_XTAL_FREQ / (4 * i2c_clk_freq)) - 1; // set I2C clock frequency
- }
- void I2C_Start(void)
- {
- mssp_clearIRQ();
- i2c_driver_start();
- mssp_waitForEvent(500);
- }
- void I2C_Stop(void)
- {
- mssp_clearIRQ();
- i2c_driver_stop();
- mssp_waitForEvent(500);
- }
- void I2C_Write(uint8_t i2c_data)
- {
- mssp_clearIRQ();
- SSP1BUF = i2c_data;
- mssp_waitForEvent(500);
- }
- uint8_t I2C_Read(uint8_t ack)
- {
- uint8_t _data;
- while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); // wait for MSSP module to be free (not busy)
- RCEN = 1;
- while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); // wait for MSSP module to be free (not busy)
- _data = SSPBUF; // read data from buffer
- while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); // wait for MSSP module to be free (not busy)
- // send acknowledge pulse ? (depends on ack, if 1 send, otherwise don't send)
- ACKDT = !ack;
- ACKEN = 1;
- return _data; // return data read
- }
- void write_to_i2c(uint8_t i2c_address, uint8_t command, uint8_t chr)
- {
- I2C_Start();
- I2C_Write(i2c_address);
- I2C_Write(command);
- I2C_Write(chr);
- I2C_Stop();
- }
- /**
- @Param
- none
- @Returns
- none
- @Description
- GPIO and peripheral I/O initialization
- @Example
- PIN_MANAGER_Initialize();
- */
- void PIN_MANAGER_Initialize(void)
- {
- /**
- LATx registers
- */
- LATA = 0x00;
- /**
- TRISx registers
- */
- TRISA = 0b00011111;
- // RA5 is output
- /**
- ANSELx registers
- */
- ANSELA = 0x00;
- /**
- WPUx registers
- */
- WPUA = 0b00001111;
- // RA0 is button_up, pullup
- // RA1 is SCL, pullup
- // RA2 is SDA, pullup
- // RA3 is button_down, pullup
- // RA4 is zerocross detection, no pullup
- // RA5 is mosfet driver, no pullup
- // Global WPUEN bit of the OPTION register must be cleared for individual pull-ups to be enabled
- // in our case we want to disable global pull-ups
- OPTION_REGbits.nWPUEN = 0;
- /**
- APFCONx registers
- */
- APFCON = 0x00;
- }
- /**
- * @Param
- none
- * @Returns
- none
- * @Description
- This macro will enable global interrupts.
- * @Example
- INTERRUPT_GlobalInterruptEnable();
- */
- #define INTERRUPT_GlobalInterruptEnable() (INTCONbits.GIE = 1)
- /**
- * @Param
- none
- * @Returns
- none
- * @Description
- This macro will disable global interrupts.
- * @Example
- INTERRUPT_GlobalInterruptDisable();
- */
- #define INTERRUPT_GlobalInterruptDisable() (INTCONbits.GIE = 0)
- /**
- * @Param
- none
- * @Returns
- none
- * @Description
- This macro will enable peripheral interrupts.
- * @Example
- INTERRUPT_PeripheralInterruptEnable();
- */
- #define INTERRUPT_PeripheralInterruptEnable() (INTCONbits.PEIE = 1)
- /**
- * @Param
- none
- * @Returns
- none
- * @Description
- This macro will disable peripheral interrupts.
- * @Example
- INTERRUPT_PeripheralInterruptDisable();
- */
- #define INTERRUPT_PeripheralInterruptDisable() (INTCONbits.PEIE = 0)
- /**
- * @Param
- none
- * @Returns
- none
- * @Description
- Initializes the oscillator to the default states configured in the
- * MCC GUI
- * @Example
- OSCILLATOR_Initialize(void);
- */
- void OSCILLATOR_Initialize(void)
- {
- // SPLLEN enabled; IRCF 32MHz_HF; SCS Clock determined by FOSC<2:0> in Configuration Word 1;
- OSCCON = 0b11110000;
- // TUN 0;
- OSCTUNE = 0x00;
- // SBOREN disabled;
- BORCON = 0x00;
- }
- /**
- * @Param
- none
- * @Returns
- none
- * @Description
- Initializes the WDT module to the default states configured in the
- * MCC GUI
- * @Example
- WDT_Initialize(void);
- */
- void WDT_Initialize(void)
- {
- // WDTPS 1:65536; SWDTEN OFF;
- WDTCON = 0x16;
- }
- /**
- * @Param
- none
- * @Returns
- none
- * @Description
- Initializes the device to the default states configured in the
- * MCC GUI
- * @Example
- SYSTEM_Initialize(void);
- */
- void SYSTEM_Initialize(void)
- {
- PIN_MANAGER_Initialize();
- OSCILLATOR_Initialize();
- WDT_Initialize();
- }
- /*------------------------------ OLED 128x64 definitions ---------------------------------*/
- //#define SSD1306
- #define SSD1306_I2C_ADDRESS (0x3C << 1)
- #define SSD1306_LCDWIDTH 128
- #define SSD1306_LCDHEIGHT 64
- #ifdef SSD1306
- #define SSD1306_NORMALDISPLAY 0xA6
- #define SSD1306_INVERTDISPLAY 0xA7
- #define SSD1306_DISPLAYOFF 0xAE
- #define SSD1306_DISPLAYON 0xAF
- #define SSD1306_SETDISPLAYOFFSET 0xD3
- #define SSD1306_SETCOMPINS 0xDA
- #define SSD1306_SETVCOMDETECT 0xDB
- #define SSD1306_SETDISPLAYCLOCKDIV 0xD5
- #define SSD1306_SETPRECHARGE 0xD9
- #define SSD1306_SETCONTRAST 0x81
- #define SSD1306_DISPLAYALLON_RESUME 0xA4
- #define SSD1306_SETMULTIPLEX 0xA8
- #define SSD1306_SETLOWCOLUMN 0x00
- #define SSD1306_SETHIGHCOLUMN 0x10
- #define SSD1306_SETSTARTLINE 0x40
- #define SSD1306_MEMORYMODE 0x20
- #define SSD1306_COLUMNADDR 0x21
- #define SSD1306_PAGEADDR 0x22
- #define SSD1306_COMSCANINC 0xC0
- #define SSD1306_COMSCANDEC 0xC8
- #define SSD1306_SEGREMAP 0xA0
- #define SSD1306_CHARGEPUMP 0x8D
- #define SSD1306_EXTERNALVCC 0x01
- #define SSD1306_SWITCHCAPVCC 0x02
- // Scrolling #defines
- #define SSD1306_ACTIVATE_SCROLL 0x2F
- #define SSD1306_DEACTIVATE_SCROLL 0x2E
- #define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
- #define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
- #define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
- #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
- #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
- #define Set_Page_Start_Address_CMD 0xB0
- #define y_max 8
- #define CMD 0x00
- #define DAT 0x40
- // Init sequence for Adafruit 128x64 OLED module
- uint8_t ssd1306_init_sequence[] = {
- SSD1306_DISPLAYOFF,
- SSD1306_SETDISPLAYCLOCKDIV,
- 0x80, // the suggested ratio 0x80
- SSD1306_SETMULTIPLEX,
- 0x3F, // ratio 64
- SSD1306_SETDISPLAYOFFSET,
- 0x0, // no offset
- SSD1306_SETSTARTLINE | 0x0, // line #0
- SSD1306_CHARGEPUMP,
- 0x14, // internal vcc
- SSD1306_MEMORYMODE,
- 0x02, // page mode
- SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0
- SSD1306_COMSCANDEC, // column scan direction reversed
- SSD1306_SETCOMPINS,
- 0x12, // alt COM pins, disable remap
- SSD1306_SETCONTRAST,
- 0x7F, // contrast level 127
- SSD1306_SETPRECHARGE,
- 0xF1, // pre-charge period (1, 15)
- SSD1306_SETVCOMDETECT,
- 0x40, // vcomh regulator level
- SSD1306_DISPLAYALLON_RESUME,
- SSD1306_NORMALDISPLAY
- };
- #else // SH1106
- #define SSD1306_SETLOWCOLUMN 0x00
- #define SSD1306_SETHIGHCOLUMN 0x10
- uint8_t ssd1306_init_sequence[] = {
- 0xAE, // display off
- 0x02, // set lower column address
- 0x10, // set higher column address
- 0x40, // set display start line
- 0xB0, // set page address
- 0x81, // contract control
- 0xff, // 128
- 0xA1, // set segment remap
- 0xA6, // normal / reverse
- 0xA8, // multiplex ratio
- 0x3F, // duty = 1/64
- 0xad, // set charge pump enable
- 0x8b, // 0x8B internal VCC
- 0x32, // 0X30---0X33 set VPP 8.x V ???
- 0xC8, // Com scan direction
- 0xD3, // set display offset
- 0x00, // 0x20
- 0xD5, // set osc division
- 0x80,
- 0xD9, // set pre-charge period
- 0x1f, // 0x22
- 0xDA, // set COM pins
- 0x12,
- 0xdb, // set vcomh
- 0x40
- };
- #define Set_Page_Start_Address_CMD 0xB0
- #define y_max 8
- #define CMD 0x00
- #define DAT 0x40
- #endif
- void ssd1306_write(uint8_t addr, uint8_t cmd)
- {
- write_to_i2c(SSD1306_I2C_ADDRESS, addr, cmd);
- }
- void ssd1306_init(void)
- {
- uint8_t i;
- for (i=0; i < sizeof(ssd1306_init_sequence); ++i)
- ssd1306_write(CMD, ssd1306_init_sequence[i]);
- }
- #define FONT_WIDTH 21
- #define FONT_HEIGHT 32
- // run-length encoded fonts
- // https://eleif.net/rle.html
- const uint8_t font_bitmap[] = {
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- };
- const uint16_t font_bitmap_offsets[] = {0, 0x4e, 0x6a, 0xa6, 0xf0, 0x120, 0x15c, 0x1ac, 0x1d8, 0x232};
- void ssd1306_draw_font(uint8_t x, uint8_t y, uint16_t num)
- {
- size_t tt = 0;
- uint8_t x_pos = x;
- uint8_t y_pos = y;
- uint8_t num_bytes = 0;
- uint8_t bytes = 0;
- uint16_t ii = 0;
- uint16_t ofset = font_bitmap_offsets[num];;
- // run length decoded font size = 84
- for(tt=0; tt<84;)
- {
- num_bytes = font_bitmap[ofset++];
- bytes = font_bitmap[ofset++];
- for (ii=0; ii<num_bytes; ++ii)
- {
- if (x_pos >= (x + FONT_WIDTH))
- {
- x_pos = x;
- y_pos++;
- }
- ssd1306_write(CMD, Set_Page_Start_Address_CMD + y_pos); // set row
- ssd1306_write(CMD, SSD1306_SETLOWCOLUMN | (x_pos & 0xf)); // set lower column address
- ssd1306_write(CMD, SSD1306_SETHIGHCOLUMN | (x_pos >> 4)); // set higher column address
- ssd1306_write(DAT, (uint8_t)bytes);
- tt++;
- x_pos++;
- }
- }
- }
- void draw_temperature(uint8_t x, uint8_t y, uint16_t temp)
- {
- if (temp == 0)
- {
- ssd1306_draw_font(x, y, 0);
- ssd1306_draw_font(x+FONT_WIDTH, y, 0);
- ssd1306_draw_font(x+(2*FONT_WIDTH), y, 0);
- }
- else if (temp > 0 && temp < 10)
- {
- ssd1306_draw_font(x, y, 0);
- ssd1306_draw_font(x+FONT_WIDTH, y, 0);
- ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp);
- }
- else if (temp >= 10 && temp < 100)
- {
- ssd1306_draw_font(x, y, 0);
- ssd1306_draw_font(x+FONT_WIDTH, y, (temp/10)%10);
- ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp%10);
- }
- else if (temp >= 100 && temp < 1000)
- {
- ssd1306_draw_font(x, y, (temp/100)%10);
- ssd1306_draw_font(x+FONT_WIDTH, y, (temp/10)%10);
- ssd1306_draw_font(x+(2*FONT_WIDTH), y, temp%10);
- }
- else
- {
- ssd1306_draw_font(x, y, 9);
- ssd1306_draw_font(x+FONT_WIDTH, y, 9);
- ssd1306_draw_font(x+(2*FONT_WIDTH), y, 9);
- }
- }
- void ssd1306_fill(uint8_t bmp_data)
- {
- uint8_t x_pos;
- uint8_t page;
- for (page=0; page < y_max; ++page)
- {
- ssd1306_write(CMD, (Set_Page_Start_Address_CMD + page));
- #ifdef SSD1306
- ssd1306_write(CMD, SSD1306_SETLOWCOLUMN);
- #else
- ssd1306_write(CMD, SSD1306_SETLOWCOLUMN+2);
- #endif
- ssd1306_write(CMD, SSD1306_SETHIGHCOLUMN);
- for (x_pos=0; x_pos < SSD1306_LCDWIDTH; ++x_pos)
- {
- ssd1306_write(DAT, bmp_data);
- }
- }
- }
- #define ADS1115_I2C_ADDRESS (0x48 << 1)
- uint16_t ADS1115_Read(void)
- {
- uint8_t timeout;
- uint8_t buffer[2];
- I2C_Start();
- I2C_Write(ADS1115_I2C_ADDRESS);
- I2C_Write(1); // config register
- I2C_Write(0b11000101); // start conversion, AIN0 and GND, FSR=2.048, single shot mode
- I2C_Write(0b10100011); // 250 SPS, Traditional comparator, alert pin active low, nonlatching comparator, disable comparator, alert pin high impedance
- I2C_Stop();
- // wait for conversion complete (10ms max)
- timeout = 100;
- do {
- I2C_Start();
- I2C_Write(ADS1115_I2C_ADDRESS+1);
- buffer[0] = I2C_Read(1);
- buffer[1] = I2C_Read(0);
- I2C_Stop();
- __delay_us(100);
- } while (!(buffer[0] & 0x80) && --timeout);
- // read conversion register
- I2C_Start();
- I2C_Write(ADS1115_I2C_ADDRESS);
- I2C_Write(0x00); // conversion register is 0
- I2C_Stop();
- I2C_Start();
- I2C_Write(ADS1115_I2C_ADDRESS+1);
- buffer[0] = I2C_Read(1);
- buffer[1] = I2C_Read(0);
- I2C_Stop();
- return buffer[0] << 8 | buffer[1];
- }
- #define JBC_MAX_TEMP 350
- uint16_t read_temp(void)
- {
- float temperature;
- // temperatura = (VOUT - VREF)/(5 mV/ C)
- // LSB = FSR / 32767;
- // temperatura = ((advalue * LSB) - VREF) / 0.005
- temperature = (float)(((ADS1115_Read() * (2.048 / 32767.0)) - 1.24) / 0.005);
- return (uint16_t)temperature;
- }
- __EEPROM_DATA(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
- volatile uint16_t tt=0, bb=0;
- // 8bit timer
- void timer0_initialise(void)
- {
- // 1.2ms x (xtail / 4)
- // 0.0012 * 8000000 = 9600 ticks ; prescaler=64 = 9600/64 = 150 ticks for 1.2ms timer
- // writing to TMR0 resets prescaler, so you need to set prescaler every time!
- TMR0 = 105; // start at 105 ticks (255 - 150)
- OPTION_REGbits.TMR0CS = 0; // Internal instruction cycle clock (FOSC/4)
- OPTION_REGbits.TMR0SE = 0; // low to high
- OPTION_REGbits.PSA = 0; // Prescaler is assigned to the Timer0 module
- OPTION_REGbits.PS2 = 1; // prescaler 64 (PS2:PS1:PS0)
- OPTION_REGbits.PS1 = 0;
- OPTION_REGbits.PS0 = 1;
- // 000 1 : 2
- // 001 1 : 4
- // 010 1 : 8
- // 011 1 : 16
- // 100 1 : 32
- // 101 1 : 64
- // 110 1 : 128
- // 111 1 : 256
- INTCONbits.TMR0IE = 1; // enable timer0
- }
- volatile bool okinuo = false;
- void __interrupt() ISR(void)
- {
- if (INTCONbits.IOCIE == 1 && INTCONbits.IOCIF == 1)
- {
- if (IOCAFbits.IOCAF4 == 1)
- {
- // interrupt on change for group IOCAF, clear IOCAF4 so it will auto clear readonly IOCIF
- IOCAFbits.IOCAF4 = 0;
- // interrupt on change for group IOCAN
- IOCANbits.IOCAN4 = 0;
- // interrupt on change for group IOCAP
- IOCAPbits.IOCAP4 = 1;
- INTCONbits.IOCIE = 0; // disable IOCI interrUPT
- timer0_initialise();
- IO_RA5_SetHigh();
- }
- }
- if (INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)
- {
- tt+=1;
- IO_RA5_SetLow();
- INTCONbits.TMR0IE = 0; // disable timer0
- INTCONbits.TMR0IF = 0; // clear interupt, it will not selfclear!
- if (tt=12499)
- {
- tt=0;
- bb+=1;
- okinuo = false;
- }
- }
- return;
- }
- void main(void)
- {
- bool tempset_changed = false;
- uint16_t temperature = 350; //max temp
- uint16_t temperature_set = eeprom_read(0) << 8 | eeprom_read(1);
- // initialize the device
- SYSTEM_Initialize();
- // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
- // Use the following macros to:
- // Enable the Global Interrupts
- INTERRUPT_GlobalInterruptEnable();
- // Enable the Peripheral Interrupts
- INTERRUPT_PeripheralInterruptEnable();
- // Disable the Global Interrupts
- //INTERRUPT_GlobalInterruptDisable();
- // Disable the Peripheral Interrupts
- //INTERRUPT_PeripheralInterruptDisable();
- I2C_Init(400000); // initialize I2C bus with clock frequency of 400kHz
- __delay_ms(100);
- ssd1306_init();
- __delay_ms(100);
- ssd1306_fill(0);
- ssd1306_write(CMD, 0xAF /* display ON*/);
- while(1)
- {
- if (IO_RA5_GetValue() == LOW)
- {
- temperature = read_temp();
- draw_temperature(33, 4, temperature);
- }
- while(IO_RA0_GetValue() == LOW)
- {
- if (temperature_set < JBC_MAX_TEMP)
- {
- temperature_set += 5;
- draw_temperature(33, 0, temperature_set);
- tempset_changed = true;
- }
- }
- while(IO_RA3_GetValue() == LOW)
- {
- if (temperature_set >= 5)
- {
- temperature_set -= 5;
- draw_temperature(33, 0, temperature_set);
- tempset_changed = true;
- }
- }
- if (tempset_changed)
- {
- eeprom_write(0, (temperature_set >> 8) & 0xff);
- eeprom_write(1, temperature_set & 0xff);
- tempset_changed = false;
- }
- if (okinuo == false)
- {
- okinuo = true;
- // interrupt on change for group IOCAF - flag
- IOCAFbits.IOCAF4 = 0; // Pin : RA4
- // interrupt on change for group IOCAN - negative
- IOCANbits.IOCAN4 = 0; // Pin : RA4
- // interrupt on change for group IOCAP - positive
- IOCAPbits.IOCAP4 = 1; // Pin : RA4
- INTCONbits.IOCIE = 1; // Enable IOCI interrupt
- draw_temperature(33, 0, bb);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement