Topic: tech dcc pc src prev next

tech dcc pc src > lcd.c

#include "lcd.h"

#include <avr/io.h>
#include <util/delay.h>

#include "pins.h"

#define HERMES_LCD_REG_CMD 0
#define HERMES_LCD_REG_DATA 1

void LCD_Send4(unsigned char c, unsigned char reg)
{
    /*DDRD |= 0b01101111;*/
    // Set all the LCD outputs low.
    HERMES_PORT_LCD &= (unsigned char)~(
            (1 << HERMES_BIT_LCD_RS) | (1 << HERMES_BIT_LCD_E) |
            (1 << HERMES_BIT_LCD_D4) | (1 << HERMES_BIT_LCD_D5) |
            (1 << HERMES_BIT_LCD_D6) | (1 << HERMES_BIT_LCD_D7)
            );
    // Set LCD pins as outputs.
    HERMES_DDR_LCD |= (unsigned char)(
            (1 << HERMES_BIT_LCD_RS) | (1 << HERMES_BIT_LCD_E) |
            (1 << HERMES_BIT_LCD_D4) | (1 << HERMES_BIT_LCD_D5) |
            (1 << HERMES_BIT_LCD_D6) | (1 << HERMES_BIT_LCD_D7)
            );
    // Transfer register and data to the LCD.
    HERMES_PORT_LCD = (unsigned char)(
            (HERMES_PORT_LCD & 0b10010000) |
                ((reg ? 1 : 0) << HERMES_BIT_LCD_RS) |
                (((c >> 0) & 1) << HERMES_BIT_LCD_D4) |
                (((c >> 1) & 1) << HERMES_BIT_LCD_D5) |
                (((c >> 2) & 1) << HERMES_BIT_LCD_D6) |
                (((c >> 3) & 1) << HERMES_BIT_LCD_D7)
            );

    // Wait for lines to settle.
    _delay_us(30);
    // Enable the LCD for 2us to store the data.
    HERMES_PORT_LCD =
        (unsigned char)(HERMES_PORT_LCD & ~(1 << HERMES_BIT_LCD_E));
    _delay_us(2);
    HERMES_PORT_LCD =
        (unsigned char)(HERMES_PORT_LCD | (1 << HERMES_BIT_LCD_E));
    _delay_us(2);
    HERMES_PORT_LCD =
        (unsigned char)(HERMES_PORT_LCD & ~(1 << HERMES_BIT_LCD_E));
    _delay_us(50);
}

void LCD_Send(unsigned char c, unsigned char reg)
{
    LCD_Send4(c >> 4, reg);
    LCD_Send4(c, reg);
}

void LCD_Init()
{
    // Set LCD pins as outputs.
    HERMES_DDR_LCD |= (unsigned char)(
            (1 << HERMES_BIT_LCD_D4) |
            (1 << HERMES_BIT_LCD_D5) |
            (1 << HERMES_BIT_LCD_D6) |
            (1 << HERMES_BIT_LCD_D7) |
            (1 << HERMES_BIT_LCD_E) |
            (1 << HERMES_BIT_LCD_RS)
            );
    HERMES_PORT_LCD &= (unsigned char)~(
            (1 << HERMES_BIT_LCD_D4) |
            (1 << HERMES_BIT_LCD_D5) |
            (1 << HERMES_BIT_LCD_D6) |
            (1 << HERMES_BIT_LCD_D7) |
            (1 << HERMES_BIT_LCD_E) |
            (1 << HERMES_BIT_LCD_RS)
            );
    _delay_us(50000);
    // Set 8 bit mode.
    LCD_Send4(0b0011, 0);
    LCD_Send4(0b0011, 0);
    LCD_Send4(0b0011, 0);
    // Set 4 bit mode.
    LCD_Send4(0b0010, 0);

    // 4-bit, 2 lines, normal font.
    LCD_Send(0b00101000, 0);
    // Entry mode left to right, no display shift.
    LCD_Send(0b00000110, 0);
    // Display on, cursor off, not blinking.
    LCD_Send(0b00001100, 0);
    LCD_Clear();
}

void LCD_ReInit()
{
    // Set 8 bit mode.
    LCD_Send4(0b0011, 0);
    LCD_Send4(0b0011, 0);
    LCD_Send4(0b0011, 0);
    // Set 4 bit mode.
    LCD_Send4(0b0010, 0);

    // 4-bit, 2 lines, normal font.
    LCD_Send(0b00101000, 0);
    // Entry mode left to right, no display shift.
    LCD_Send(0b00000110, 0);
    // Display on, cursor off, not blinking.
    LCD_Send(0b00001100, 0);
    LCD_Clear();
}

void LCD_Clear()
{
    // Clear the screen.
    LCD_Send(0b00000001, 0);
    _delay_us(2000);
    // Return home.
    LCD_Send(0b00000010, 0);
    _delay_us(2000);
    // Reset cursor mode.
    LCD_Send(0b00001100, 0);
    _delay_us(2000);
}

void LCD_PutC(char c)
{
    LCD_Send((unsigned char)c, 1);
}

void LCD_PutS(const char *s)
{
    while(*s != 0)
    {
        LCD_PutC((char)*s);
        ++s;
    }
}

void LCD_PutI(int i)
{
    if(i < 0)
    {
        LCD_PutC('-');
        LCD_PutI(-i);
        return;
    }
    if(i > 9)
        LCD_PutI((int)(i / 10));
    LCD_PutC((char)('0' + (i % 10)));
}

void LCD_Move(unsigned char col, unsigned char row)
{
    LCD_Send((unsigned char)(0x80 + 0x40 * row + col), 0);
}

void LCD_Cursor()
{
    // Enable cursor and cursor blinking.
    LCD_Send((unsigned char)0x0d, HERMES_LCD_REG_CMD);
}

void LCD_CursorMove(unsigned char col, unsigned char row)
{
    LCD_Cursor();
    LCD_Move(col, row);
}

void LCD_CursorHide()
{
    // Hide the cursor, leaving the display on.
    LCD_Send((unsigned char)0x0c, HERMES_LCD_REG_CMD);
}

unsigned char LCD_DigitCount(int n)
{
    unsigned char c = 1;
    if(n < 0)
    {
        ++c;
        n = -n;
    }
    while(n > 9)
    {
        ++c;
        n /= 10;
    }
    return c;
}

void LCD_PrintListIndex(int index, int length)
{
    LCD_Move((unsigned char)(13 - LCD_DigitCount(index) - LCD_DigitCount(length)), 0);
    LCD_PutI(index);
    LCD_PutS(" / ");
    LCD_PutI(length);
}

void LCD_DefineCustomChar(unsigned char index, const unsigned char *data)
{
    LCD_Send((unsigned char)(0b01000000 | ((index & 0b0000111) << 3)), HERMES_LCD_REG_CMD);
    for(unsigned char i = 0; i < 8; ++i)
        LCD_Send(data[i], HERMES_LCD_REG_DATA);
}

static const unsigned char character_up[8] = {
        0b00000,
        0b00000,
        0b01000,
        0b11100,
        0b01000,
        0b01111,
        0b00000,
        0b00000
};
static const unsigned char character_left[8] = {
        0b00000,
        0b00000,
        0b01000,
        0b11111,
        0b01000,
        0b00000,
        0b00000,
        0b00000
};
static const unsigned char character_right[8] = {
        0b00000,
        0b00000,
        0b00010,
        0b11111,
        0b00010,
        0b00000,
        0b00000,
        0b00000
};
static const unsigned char character_ok[8] = {
        0b00000,
        0b00000,
        0b00000,
        0b00001,
        0b10010,
        0b01100,
        0b00000,
        0b00000
};
static const unsigned char character_hb[8] = {
        0b10101,
        0b01010,
        0b10101,
        0b01010,
        0b10101,
        0b01010,
        0b10101,
        0b01010
};
static const unsigned char character_acw[8] = {
    0b00000,
    0b01110,
    0b11000,
    0b10000,
    0b10000,
    0b11010,
    0b01111,
    0b00010
};
static const unsigned char character_cw[8] = {
    0b00000,
    0b01110,
    0b00011,
    0b00001,
    0b00001,
    0b01011,
    0b11110,
    0b01000
};
static const unsigned char character_button_top[8] = {
    0b00000,
    0b01110,
    0b01110,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000
};
static const unsigned char character_button_bottom[8] = {
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b01110,
    0b01110,
    0b00000
};
static const unsigned char character_button_both[8] = {
    0b00000,
    0b01110,
    0b01110,
    0b00000,
    0b00000,
    0b01110,
    0b01110,
    0b00000
};


void LCD_DefineHermesChars(unsigned char mode)
{
    static unsigned char g_mode = HERMES_LCD_CUSTOM_MODE_UNDEFINED;

    if(mode == g_mode)
        return;

    g_mode = mode;

    switch(mode)
    {
        case HERMES_LCD_CUSTOM_MODE_OPS:
            LCD_DefineCustomChar(HERMES_LCD_CHAR_HB, character_hb);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_BUTTON_TOP, character_button_top);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_BUTTON_BOTTOM, character_button_bottom);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_BUTTON_BOTH, character_button_both);
            break;
        case HERMES_LCD_CUSTOM_MODE_MENU:
            LCD_DefineCustomChar(HERMES_LCD_CHAR_UP, character_up);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_L, character_left);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_R, character_right);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_OK, character_ok);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_ACW, character_acw);
            LCD_DefineCustomChar(HERMES_LCD_CHAR_CW, character_cw);
            break;
    };
}