0,0 → 1,733 |
/**************************************************************************//** |
* \brief Snootlab Deuligne library |
* \author Copyright (C) 2012 Julien Le Sech - www.idreammicro.com |
* \version 1.0 |
* \date 20121026 |
* |
* This file is part of the iDreamMicro library. |
* |
* This library is free software: you can redistribute it and/or modify it under |
* the terms of the GNU Lesser General Public License as published by the Free |
* Software Foundation, either version 3 of the License, or (at your option) any |
* later version. |
* |
* This library is distributed in the hope that it will be useful, but WITHOUT |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
* details. |
* |
* You should have received a copy of the GNU Lesser General Public License |
* along with this program. If not, see http://www.gnu.org/licenses/ |
******************************************************************************/ |
|
/**************************************************************************//** |
* \headerfile deuligne.c |
******************************************************************************/ |
|
/****************************************************************************** |
* Header file inclusions. |
******************************************************************************/ |
|
#include "../deuligne.h" |
|
#include <adc/adc.h> |
#include <mcp23008/mcp23008.h> |
|
#include <util/delay.h> |
|
#include <assert.h> |
#include <stdbool.h> |
#include <stdint.h> |
#include <stdlib.h> |
|
/****************************************************************************** |
* Private macro definitions. |
******************************************************************************/ |
|
/**************************************************************************//** |
* \def DEULIGNE__HARDWARE_ADDRESS |
* \brief MCP23008 hardware address. Pins A0 to A3. |
******************************************************************************/ |
#define DEULIGNE__HARDWARE_ADDRESS 0x07 |
|
#define DEULIGNE__GPIO_E 4 |
#define DEULIGNE__GPIO_RW 5 |
#define DEULIGNE__GPIO_RS 6 |
#define DEULIGNE__GPIO_BACKLIGHT 7 |
|
/**************************************************************************//** |
* \def LCD__CMD_CLEAR_DISPLAY |
* \brief Clear display. |
******************************************************************************/ |
#define LCD__CMD_CLEAR_DISPLAY 0x01 |
|
/**************************************************************************//** |
* \def LCD__CMD_RETURN_HOME |
* \brief Return Home (execution time = 1.52 ms). |
******************************************************************************/ |
#define LCD__CMD_RETURN_HOME 0x02 |
|
// Function set (execution time = 37 s). |
#define LCD__CMD_FUNCTION_SET 0x20 |
#define LCD__CMD_DATA_LENGTH_4_BIT 0x00 |
#define LCD__CMD_DATA_LENGTH_8_BIT 0x10 |
#define LCD__CMD_DISPLAY_LINE_1 0x00 |
#define LCD__CMD_DISPLAY_LINE_2 0x08 |
#define LCD__CMD_CHARACTER_FONT_5x8_DOTS 0x00 |
#define LCD__CMD_CHARACTER_FONT_5x10_DOTS 0x04 |
|
// Set entry mode (execution time = 37 s). |
#define LCD__CMD_ENTRY_MODE_SET 0x04 |
#define LCD__CMD_INCREMENT_ADDRESS 0x02 |
#define LCD__CMD_DECREMENT_ADDRESS 0x00 |
#define LCD__CMD_DISPLAY_SHIFT_DISABLED 0x00 |
#define LCD__CMD_DISPLAY_SHIFT_RIGHT 0x01 |
#define LCD__CMD_DISPLAY_SHIFT_LEFT 0x03 |
|
// Display on/off control (execution time = 37 s). |
#define LCD__CMD_DISPLAY_CONTROL 0x08 |
#define LCD__CMD_ENABLE_DISPLAY 0x04 |
#define LCD__CMD_DISABLE_DISPLAY 0x00 |
#define LCD__CMD_ENABLE_CURSOR_DISPLAY 0x02 |
#define LCD__CMD_DISABLE_CURSOR_DISPLAY 0x00 |
#define LCD__CMD_ENABLE_CURSOR_BLINK 0x01 |
#define LCD__CMD_DISABLE_CURSOR_BLINK 0x00 |
|
// Cursor or display shift (execution time = 37 s). |
#define LCD__CMD_CURSOR_OR_DISPLAY_SHIFT 0x10 |
#define LCD__CMD_SHIFT_CURSOR 0x00 |
#define LCD__CMD_SHIFT_DISPLAY 0x08 |
#define LCD__CMD_SHIFT_RIGHT 0x04 |
#define LCD__CMD_SHIFT_LEFT 0x00 |
|
// CGRAM address. |
#define LCD__CMD_SET_CGRAM_ADDRESS 0x40 |
|
// DDRAM address. |
#define LCD__CMD_SET_DDRAM_ADDRESS 0x80 |
|
// Line addresses. |
#define LCD__LINE_1_ADDRESS 0x40 |
#define LCD__LINE_2_ADDRESS 0x80 |
#define LCD__LINE_3_ADDRESS 0x54 |
#define LCD__LINE_4_ADDRESS 0x94 |
|
/****************************************************************************** |
* Private function prototypes. |
******************************************************************************/ |
|
/**************************************************************************//** |
* \fn static void deuligne__write_command(uint8_t command) |
* |
* \brief Write a command on LCD port. |
* |
* \param command Command to write. |
******************************************************************************/ |
static |
void |
deuligne__write_command |
( |
uint8_t command |
); |
|
/**************************************************************************//** |
* \fn static void deuligne__write_byte(uint8_t data) |
* |
* \brief Write a byte on LCD port. |
* |
* \param data Byte to write. |
******************************************************************************/ |
static |
void |
deuligne__write_byte |
( |
uint8_t data |
); |
|
/**************************************************************************//** |
* \fn static void deuligne__write_high_nibble(uint8_t data) |
* |
* \brief Write the high nibble of a byte on LCD port. |
* |
* \param data Byte which write high nibble. |
******************************************************************************/ |
static |
void |
deuligne__write_high_nibble |
( |
uint8_t data |
); |
|
/**************************************************************************//** |
* \fn static void deuligne__enable_data(void) |
* |
* \brief Enable data on LCD port. |
******************************************************************************/ |
static |
void |
deuligne__enable_data |
( |
void |
); |
|
/****************************************************************************** |
* Private constant definitions. |
******************************************************************************/ |
|
/**************************************************************************//** |
* |
******************************************************************************/ |
static const uint16_t deuligne__adc_values[] = |
{ |
[DEULIGNE__KEY__RIGHT] = 50, |
[DEULIGNE__KEY__UP] = 190, |
[DEULIGNE__KEY__DOWN] = 400, |
[DEULIGNE__KEY__LEFT] = 540, |
[DEULIGNE__KEY__SELECT] = 770, |
[DEULIGNE__KEY__NONE] = 1024 |
}; |
|
/****************************************************************************** |
* Public function definitions. |
******************************************************************************/ |
|
/**************************************************************************//** |
* \fn void deuligne__initialize(void) |
* |
* \brief Initialize Deuligne. |
******************************************************************************/ |
void |
deuligne__initialize |
( |
void |
){ |
// Initialize MCP23008. |
mcp23008__initialize(DEULIGNE__HARDWARE_ADDRESS); |
|
// Configure all GPIOs in output. |
mcp23008__configure_port(0x00); |
|
mcp23008__set_pin_level(DEULIGNE__GPIO_RW, MCP23008__LEVEL__LOW); |
|
// Wait for LCD display power-up initialization. |
_delay_ms(45); |
|
// Initialize LCD display. |
|
// Set interface. |
deuligne__write_high_nibble(LCD__CMD_FUNCTION_SET | LCD__CMD_DATA_LENGTH_8_BIT); |
deuligne__write_high_nibble(LCD__CMD_FUNCTION_SET | LCD__CMD_DATA_LENGTH_8_BIT); |
deuligne__write_high_nibble(LCD__CMD_FUNCTION_SET | LCD__CMD_DATA_LENGTH_8_BIT); |
deuligne__write_high_nibble(LCD__CMD_FUNCTION_SET | LCD__CMD_DATA_LENGTH_4_BIT); |
|
// Set function. |
deuligne__set_function(DEULIGNE__DISPLAY_LINE_2, DEULIGNE__CHARACTER_FONT_5x8_DOTS); |
|
// Set entry mode. |
deuligne__set_entry_mode(DEULIGNE__INCREMENT_ADDRESS, DEULIGNE__DISPLAY_SHIFT_DISABLED); |
|
// Clear display. |
deuligne__clear_display(); |
|
// Initialize ADC. |
adc__single_channel_initialize(ADC__CHANNEL_0); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__switch_on_backlight(void) |
* |
* \brief Switch on backlight. |
******************************************************************************/ |
void |
deuligne__switch_on_backlight |
( |
void |
){ |
mcp23008__set_pin_level(DEULIGNE__GPIO_BACKLIGHT, MCP23008__LEVEL__HIGH); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__switch_off_backlight(void) |
* |
* \brief Switch off backlight. |
******************************************************************************/ |
void |
deuligne__switch_off_backlight |
( |
void |
){ |
mcp23008__set_pin_level(DEULIGNE__GPIO_BACKLIGHT, MCP23008__LEVEL__LOW); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__set_function( |
* deuligne__display_line_t display_line, |
* deuligne__character_font_t character_font) |
* |
* \brief Set the number of lines available on LCD display and the character font. |
* |
* \param display_line number of lines |
* \param character_font character font |
******************************************************************************/ |
void |
deuligne__set_function |
( |
deuligne__display_line_t display_line, |
deuligne__character_font_t character_font |
){ |
uint8_t command = LCD__CMD_FUNCTION_SET; |
|
switch (display_line) |
{ |
case DEULIGNE__DISPLAY_LINE_1: |
{ |
command |= LCD__CMD_DISPLAY_LINE_1; |
} |
break; |
|
case DEULIGNE__DISPLAY_LINE_2: |
{ |
command |= LCD__CMD_DISPLAY_LINE_2; |
} |
break; |
|
default: |
break; |
} |
|
switch (character_font) |
{ |
case DEULIGNE__CHARACTER_FONT_5x8_DOTS: |
{ |
command |= LCD__CMD_CHARACTER_FONT_5x8_DOTS; |
} |
break; |
|
case DEULIGNE__CHARACTER_FONT_5x10_DOTS: |
{ |
command |= LCD__CMD_CHARACTER_FONT_5x10_DOTS; |
} |
break; |
|
default: |
break; |
} |
|
deuligne__write_command(command); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__set_entry_mode( |
* deuligne__address_mode_t address_mode, |
* deuligne__display_shift_t display_shift) |
* |
* \brief Set LCD display entry mode. |
* |
* \param address_mode specify if DDRAM address is incremented or decremented |
* when a character code is written |
* \param display_shift set the display shift when a character code is written |
******************************************************************************/ |
void |
deuligne__set_entry_mode |
( |
deuligne__address_mode_t address_mode, |
deuligne__display_shift_t display_shift |
){ |
uint8_t command = LCD__CMD_ENTRY_MODE_SET; |
|
switch (address_mode) |
{ |
case DEULIGNE__INCREMENT_ADDRESS: |
{ |
command |= LCD__CMD_INCREMENT_ADDRESS; |
} |
break; |
|
case DEULIGNE__DECREMENT_ADDRESS: |
{ |
command |= LCD__CMD_DECREMENT_ADDRESS; |
} |
break; |
|
default: |
break; |
} |
|
switch (display_shift) |
{ |
case DEULIGNE__DISPLAY_SHIFT_DISABLED: |
{ |
command |= LCD__CMD_DISPLAY_SHIFT_DISABLED; |
} |
break; |
|
case DEULIGNE__DISPLAY_SHIFT_RIGHT: |
{ |
command |= LCD__CMD_DISPLAY_SHIFT_RIGHT; |
} |
break; |
|
case DEULIGNE__DISPLAY_SHIFT_LEFT: |
{ |
command |= LCD__CMD_DISPLAY_SHIFT_LEFT; |
} |
break; |
|
default: |
break; |
} |
|
deuligne__write_command(command); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__set_display( |
* bool enable_display, |
* bool enable_cursor_display, |
* bool enable_cursor_blink) |
* |
* \brief Set LCD display. |
* Enable or disable display, cursor display and cursor blink. |
* |
* \param enable_display true to enable display or false in contrary case |
* \param enable_cursor_display true to enable cursor display or false in |
* contrary case |
* \param enable_cursor_blink true to enable cursor blink or false in contrary |
* case |
******************************************************************************/ |
void |
deuligne__set_display |
( |
bool enable_display, |
bool enable_cursor_display, |
bool enable_cursor_blink |
){ |
uint8_t command = LCD__CMD_DISPLAY_CONTROL; |
if (enable_display) |
{ |
command |= LCD__CMD_ENABLE_DISPLAY; |
} |
if (enable_cursor_display) |
{ |
command |= LCD__CMD_ENABLE_CURSOR_DISPLAY; |
} |
if (enable_cursor_blink) |
{ |
command |= LCD__CMD_ENABLE_CURSOR_BLINK; |
} |
deuligne__write_command(command); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__clear_display(void) |
* |
* \brief Clear LCD display. |
* Wait time of 2 ms. |
******************************************************************************/ |
void |
deuligne__clear_display |
( |
void |
){ |
deuligne__write_command(LCD__CMD_CLEAR_DISPLAY); |
_delay_ms(2); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__return_home(void) |
* |
* \brief Set cursor on the first column of the first line. |
* Wait time of 2 ms. |
******************************************************************************/ |
void |
deuligne__return_home |
( |
void |
){ |
deuligne__write_command(LCD__CMD_RETURN_HOME); |
_delay_ms(2); |
} |
|
/**************************************************************************//** |
*\fn void deuligne__set_cursor_position( |
* deuligne__line_t line, |
* uint8_t column) |
* |
* \brief Set cursor position. |
* |
* \param line destination line |
* \param column destination column |
******************************************************************************/ |
void |
deuligne__set_cursor_position |
( |
deuligne__line_t line, |
uint8_t column |
){ |
uint8_t address = 0; |
|
switch (line) |
{ |
case DEULIGNE__LINE_1: |
{ |
address = LCD__LINE_1_ADDRESS; |
} |
break; |
|
case DEULIGNE__LINE_2: |
{ |
address = LCD__LINE_2_ADDRESS; |
} |
break; |
|
case DEULIGNE__LINE_3: |
{ |
address = LCD__LINE_3_ADDRESS; |
} |
break; |
|
case DEULIGNE__LINE_4: |
{ |
address = LCD__LINE_4_ADDRESS; |
} |
break; |
|
default: |
{ |
address = LCD__LINE_1_ADDRESS; |
} |
break; |
} |
|
address += column; |
|
deuligne__write_command(LCD__CMD_SET_CGRAM_ADDRESS + address); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__shift_display(deuligne__shift_direction_t shift_direction) |
* |
* \brief Shift the display on the right or on the left. |
* |
* \param shift_direction display shift direction |
******************************************************************************/ |
void |
deuligne__shift_display |
( |
deuligne__shift_direction_t shift_direction |
){ |
uint8_t command = LCD__CMD_CURSOR_OR_DISPLAY_SHIFT | LCD__CMD_SHIFT_DISPLAY; |
|
switch (shift_direction) |
{ |
case DEULIGNE__SHIFT_DIRECTION_RIGHT: |
{ |
command |= LCD__CMD_SHIFT_RIGHT; |
} |
break; |
|
case DEULIGNE__SHIFT_DIRECTION_LEFT: |
{ |
command |= LCD__CMD_SHIFT_LEFT; |
} |
break; |
|
default: |
break; |
} |
|
deuligne__write_command(command); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__shift_cursor(deuligne__shift_direction_t shift_direction) |
* |
* \brief Shift the cursor on the right or on the left. |
* |
* \param shift_direction cursor shift direction |
******************************************************************************/ |
void |
deuligne__shift_cursor |
( |
deuligne__shift_direction_t shift_direction |
){ |
uint8_t command = LCD__CMD_CURSOR_OR_DISPLAY_SHIFT | LCD__CMD_SHIFT_CURSOR; |
|
switch (shift_direction) |
{ |
case DEULIGNE__SHIFT_DIRECTION_RIGHT: |
{ |
command |= LCD__CMD_SHIFT_RIGHT; |
} |
break; |
|
case DEULIGNE__SHIFT_DIRECTION_LEFT: |
{ |
command |= LCD__CMD_SHIFT_LEFT; |
} |
break; |
|
default: |
break; |
} |
|
deuligne__write_command(command); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__write_char(char data) |
* |
* \brief Write a character on LCD. |
* |
* \param data Character to write. |
******************************************************************************/ |
void |
deuligne__write_char |
( |
char data |
){ |
mcp23008__set_pin_level(DEULIGNE__GPIO_RS, MCP23008__LEVEL__HIGH); |
deuligne__write_byte(data); |
} |
|
/**************************************************************************//** |
* \fn void deuligne__write_string(const char* string_to_write) |
* |
* \brief Write a string on LCD display from current cursor position. |
* |
* \param string_to_write string to write |
******************************************************************************/ |
void |
deuligne__write_string |
( |
const char* string_to_write |
){ |
// Check the preconditions. |
assert(NULL != string_to_write); |
|
while (*string_to_write != '\0') |
{ |
deuligne__write_char(*string_to_write++); |
} |
} |
|
/**************************************************************************//** |
* \fn void deuligne__get_key(void) |
* |
* \brief Get key. |
* |
* \return Key. |
******************************************************************************/ |
deuligne__key_t |
deuligne__get_key |
( |
void |
){ |
deuligne__key_t key = DEULIGNE__KEY__NONE; |
|
// Read ADC0 value. |
uint16_t value = adc__single_channel_read(); |
|
// Find key. |
for (deuligne__key_t i = DEULIGNE__KEY__RIGHT; i <= DEULIGNE__KEY__NONE; i++) |
{ |
if (value < deuligne__adc_values[i]) |
{ |
key = i; |
break; |
} |
} |
|
return key; |
} |
|
/****************************************************************************** |
* Private function definitions. |
******************************************************************************/ |
|
/**************************************************************************//** |
* \fn static void deuligne__write_command(uint8_t command) |
* |
* \brief Write a command on LCD port. |
* |
* \param command Command to write. |
******************************************************************************/ |
static |
void |
deuligne__write_command |
( |
uint8_t command |
){ |
mcp23008__set_pin_level(DEULIGNE__GPIO_RS, MCP23008__LEVEL__LOW); |
deuligne__write_byte(command); |
} |
|
/**************************************************************************//** |
* \fn static void deuligne__write_byte(uint8_t data) |
* |
* \brief Write a byte on LCD port. |
* |
* \param data Byte to write. |
******************************************************************************/ |
static |
void |
deuligne__write_byte |
( |
uint8_t data |
){ |
// Get current port value. |
uint8_t port_value = mcp23008__get_port_value() & 0xF0; |
|
// Write high nibble. |
port_value |= data >> 4; |
mcp23008__set_port_value(port_value); |
deuligne__enable_data(); |
_delay_ms(1); |
|
// Write low nibble. |
port_value &= 0xF0; |
port_value |= data & 0x0F; |
mcp23008__set_port_value(port_value); |
deuligne__enable_data(); |
_delay_ms(1); |
} |
|
/**************************************************************************//** |
* \fn static void deuligne__write_high_nibble(uint8_t data) |
* |
* \brief Write the high nibble of a byte on LCD port. |
* |
* \param data Byte which write high nibble. |
******************************************************************************/ |
static |
void |
deuligne__write_high_nibble |
( |
uint8_t data |
){ |
// Get current port value. |
uint8_t port_value = mcp23008__get_port_value() & 0xF0; |
|
// Write high nibble. |
port_value |= data >> 4; |
mcp23008__set_port_value(port_value); |
deuligne__enable_data(); |
_delay_ms(1); |
} |
|
/**************************************************************************//** |
* \fn static void deuligne__enable_data(void) |
* |
* \brief Enable data on LCD port. |
******************************************************************************/ |
static |
void |
deuligne__enable_data |
( |
void |
){ |
mcp23008__set_pin_level(DEULIGNE__GPIO_E, MCP23008__LEVEL__HIGH); |
_delay_ms(1); |
mcp23008__set_pin_level(DEULIGNE__GPIO_E, MCP23008__LEVEL__LOW); |
_delay_ms(1); |
} |