pi_clock

Crude and unpolished clock for Raspberry Pi
git clone https://git.e1e0.net/pi_clock.git
Log | Files | Refs | README | LICENSE

lcd_i2c.c (5353B)


      1 // ------------------------------------------------------------------------------
      2 // Copyright 2018 Stephen Stebbing. telecnatron.com
      3 //
      4 //    Licensed under the Telecnatron License, Version 1.0 (the “License”);
      5 //    you may not use this file except in compliance with the License.
      6 //    You may obtain a copy of the License at
      7 //
      8 //        https://telecnatron.com/software/licenses/
      9 //
     10 //    Unless required by applicable law or agreed to in writing, software
     11 //    distributed under the License is distributed on an “AS IS” BASIS,
     12 //    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 //    See the License for the specific language governing permissions and
     14 //    limitations under the License.
     15 // ------------------------------------------------------------------------------
     16 
     17 #include "lcd_i2c.h"
     18 
     19 #include <wiringPi.h>
     20 #include <wiringPiI2C.h>
     21 #include <stdarg.h>
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 
     25 // pcf8574 bit positions of the lcd control pins 
     26 // bits 4 to 7 are the data bits
     27 #define LCD_I2C_RS 0
     28 #define LCD_I2C_RW 1
     29 #define LCD_I2C_E  2
     30 #define LCD_I2C_BACKLIGHT 3
     31 
     32 // convenience macros
     33 // write current value of output variable to device
     34 #define LCD_I2C_WRITE(lcd_p) wiringPiI2CWrite(lcd_p->fd, lcd_p->output);
     35 // enable
     36 #define LCD_I2C_E_HI(lcd_p)  lcd_p->output |= (1<<LCD_I2C_E)
     37 #define LCD_I2C_E_LO(lcd_p)  lcd_p->output &=~ (1<<LCD_I2C_E)
     38 // set data or instruction mode
     39 #define LCD_I2C_RS_D(lcd_p) lcd_p->output |= (1<<LCD_I2C_RS)
     40 #define LCD_I2C_RS_I(lcd_p) lcd_p->output &=~ (1<<LCD_I2C_RS)
     41 // set the data nibble -
     42 // note: will need to change this for devices with different wiring.
     43 #define LCD_I2C_DATA_NIBBLE(lcd_p, x) lcd_p->output= (x<<4 | (lcd_p->output & 0x0f))
     44 //! set the lcd data ram address to that passed, only lower 7 bits are used.
     45 #define LCD_I2C_SET_DD_RAM_ADDRESS(lcd_p, address) lcd_i2c_write_i(lcd_p, 0x80 | ((address) & 0x7f) )
     46 
     47 // -----------------------------------------------------
     48 // static functions
     49 // -----------------------------------------------------
     50 static void lcd_i2c_e_assert(lcd_i2c_t *lcd)
     51 {
     52     LCD_I2C_E_LO(lcd);
     53     LCD_I2C_WRITE(lcd);
     54     LCD_I2C_E_HI(lcd);
     55     LCD_I2C_WRITE(lcd);
     56     LCD_I2C_E_LO(lcd);
     57     LCD_I2C_WRITE(lcd);
     58 }
     59 
     60 //! Write passed data to device
     61 //! Note: RS must be set prior to calling
     62 static void lcd_i2c_write(lcd_i2c_t *lcd, uint8_t data)
     63 {
     64    // high nibble
     65    LCD_I2C_DATA_NIBBLE(lcd, (data >> 4));
     66    lcd_i2c_e_assert(lcd);
     67    // low nibble
     68    LCD_I2C_DATA_NIBBLE(lcd, (data & 0x0f));
     69    lcd_i2c_e_assert(lcd);
     70    // delay for command to be executed
     71    delayMicroseconds(50);
     72 }
     73 
     74 // -----------------------------------------------------
     75 // user callable functions
     76 // -----------------------------------------------------
     77 void lcd_i2c_gotoxy(lcd_i2c_t *lcd, uint8_t x, uint8_t y)
     78 {
     79     // note: on two line devices, second line begins at address 0x40
     80     // XXX so this will work with 1 and 2 line devices, but probabaly not with 4.
     81     LCD_I2C_SET_DD_RAM_ADDRESS( lcd,  y*0x40 + x  );
     82     lcd->x=x;
     83     lcd->y=y;
     84 }
     85 
     86 void lcd_i2c_printf(lcd_i2c_t *lcd,  char* format, ...)
     87 {
     88     va_list args;
     89     char *spp=NULL;
     90 
     91     va_start(args, format);
     92     int r=vasprintf(&spp, format, args);
     93     if(r!=-1){
     94 	lcd_i2c_puts(lcd, spp);
     95 	free(spp);
     96     }
     97     va_end(args);
     98 }
     99 
    100 int lcd_i2c_setup( lcd_i2c_t *lcd,int address)
    101 {
    102     lcd->output=0;
    103     lcd->fd=wiringPiI2CSetup(address);
    104     // XXX for now, alway use a 1602 display
    105     lcd->rows=2;
    106     lcd->cols=16;
    107     return lcd->fd;
    108 }
    109 
    110 void lcd_i2c_write_i(lcd_i2c_t *lcd, uint8_t data)
    111 {
    112    LCD_I2C_RS_I(lcd);
    113    lcd_i2c_write(lcd,data);
    114 }
    115 
    116 void lcd_i2c_write_d(lcd_i2c_t *lcd, uint8_t data)
    117 {
    118    LCD_I2C_RS_D(lcd);
    119    lcd_i2c_write(lcd,data);
    120 }
    121 
    122 void lcd_i2c_clear(lcd_i2c_t *lcd)
    123 {
    124     lcd_i2c_write_i(lcd, 0x1);
    125     delay(2); // delay for command to take effect
    126 }
    127 
    128 void lcd_i2c_home(lcd_i2c_t *lcd)
    129 {
    130     lcd_i2c_write_i(lcd, 0x02);
    131     lcd->x=0;
    132     lcd->y=0;
    133     delay(2); // delay for command to take effect
    134 }
    135 
    136 void lcd_i2c_putc(lcd_i2c_t *lcd, char c)
    137 {
    138     lcd_i2c_write_d(lcd, c);
    139 //    printf("c: %c (%i,%i)\n",c, lcd->x, lcd->y);
    140     if(++lcd->x == lcd->cols){
    141 	lcd->x=0;
    142 	if(++lcd->y == lcd->rows){
    143 	    lcd->y=0;
    144 	}
    145 	lcd_i2c_gotoxy(lcd,lcd->x,lcd->y);
    146     }
    147 }
    148 
    149 void lcd_i2c_puts(lcd_i2c_t *lcd, const char* str)
    150 {
    151     while(*str!='\x0'){
    152 	lcd_i2c_putc(lcd,*str++);
    153     }
    154 }
    155 
    156 void lcd_i2c_init(lcd_i2c_t *lcd)
    157 {
    158     LCD_I2C_E_LO(lcd);
    159     LCD_I2C_RS_I(lcd);
    160     LCD_I2C_WRITE(lcd);
    161 
    162     // software reset
    163     LCD_I2C_DATA_NIBBLE(lcd,0x3);
    164     lcd_i2c_e_assert(lcd);
    165     delay(5); // ms
    166     lcd_i2c_e_assert(lcd);
    167     delayMicroseconds(150);
    168     lcd_i2c_e_assert(lcd);
    169     delayMicroseconds(150);
    170     
    171     // set 4 bit mode
    172     LCD_I2C_DATA_NIBBLE(lcd,0x02);
    173     lcd_i2c_e_assert(lcd);
    174 
    175     // entry mode - 0x06 is display shift on, increment address counter
    176     lcd_i2c_write_i(lcd,0x06);
    177 
    178     // set cursor
    179     LCD_I2C_CURSOR_BLINK_OFF(lcd);
    180     LCD_I2C_CURSOR_OFF(lcd);
    181 
    182     // clear and home 
    183     lcd_i2c_clear(lcd);
    184     lcd_i2c_home(lcd);
    185        
    186 }
    187 
    188 /** 
    189  * Turn backlight on or off
    190  * @param ct lcd_i2c_t control structure for the device
    191  * @param on Turn on if non-zero, off otherwise
    192  */
    193 void lcd_i2c_backlight(lcd_i2c_t *lcd, uint8_t on)
    194 {
    195     if(on)
    196 	lcd->output |= (1<<LCD_I2C_BACKLIGHT);
    197     else
    198 	lcd->output &=~ (1<<LCD_I2C_BACKLIGHT);
    199     LCD_I2C_WRITE(lcd);
    200 }