rwth-4sempro/controller/lcd.c

237 lines
4.8 KiB
C
Raw Permalink Normal View History

2012-11-15 22:04:14 +01:00
/**
* Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
*
* Die Pinbelegung ist über defines in lcd.h einstellbar
*
* @copyright 2012 Institute Automation of Complex Power Systems (ACS), RWTH Aachen University
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
* @link http://www.mikrocontroller.net/articles/HD44780
* @link http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
*/
#include <stdlib.h>
#include <string.h>
#include <avr/eeprom.h>
#include "lcd.h"
/**
* Erzeugt einen Enable-Puls
*/
static void lcd_enable() {
LCD_PORT |= (1<<LCD_EN); // Enable auf 1 setzen
_delay_us( LCD_ENABLE_US ); // kurze Pause
LCD_PORT &= ~(1<<LCD_EN); // Enable auf 0 setzen
}
/**
* Sendet eine 4-bit Ausgabeoperation an das LCD
*/
static void lcd_out(uint8_t data) {
data &= 0xF0; // obere 4 Bit maskieren
LCD_PORT &= ~(0xF0>>(4-LCD_DB)); // Maske l<>schen
LCD_PORT |= (data>>(4-LCD_DB)); // Bits setzen
lcd_enable();
}
/**
* Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
*/
void lcd_init() {
// verwendete Pins auf Ausgang schalten
uint8_t pins = (0x0F << LCD_DB) | // 4 Datenleitungen
(1<<LCD_RS) | // R/S Leitung
(1<<LCD_EN); // Enable Leitung
LCD_DDR |= pins;
// initial alle Ausgänge auf Null
LCD_PORT &= ~pins;
// warten auf die Bereitschaft des LCD
_delay_ms( LCD_BOOTUP_MS );
// Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
lcd_out( LCD_SOFT_RESET );
_delay_ms( LCD_SOFT_RESET_MS1 );
lcd_enable();
_delay_ms( LCD_SOFT_RESET_MS2 );
lcd_enable();
_delay_ms( LCD_SOFT_RESET_MS3 );
// 4-bit Modus aktivieren
lcd_out( LCD_SET_FUNCTION |
LCD_FUNCTION_4BIT );
_delay_ms( LCD_SET_4BITMODE_MS );
// 4-bit Modus / 2 Zeilen / 5x7
lcd_command( LCD_SET_FUNCTION |
LCD_FUNCTION_4BIT |
LCD_FUNCTION_2LINE |
LCD_FUNCTION_5X7 );
// Display ein / Cursor aus / Blinken aus
lcd_command( LCD_SET_DISPLAY |
LCD_DISPLAY_ON |
LCD_CURSOR_OFF |
LCD_BLINKING_OFF);
// Cursor inkrement / kein Scrollen
lcd_command( LCD_SET_ENTRY |
LCD_ENTRY_INCREASE |
LCD_ENTRY_NOSHIFT );
lcd_clear();
}
/**
* Sendet ein Datenbyte an das LCD
*/
void lcd_data(uint8_t data) {
LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
lcd_out(data); // zuerst die oberen,
lcd_out(data<<4); // dann die unteren 4 Bit senden
_delay_us( LCD_WRITEDATA_US );
}
/**
* Sendet einen Befehl an das LCD
*/
void lcd_command(uint8_t data) {
LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen
lcd_out(data); // zuerst die oberen,
lcd_out(data<<4); // dann die unteren 4 Bit senden
_delay_us(LCD_COMMAND_US);
}
/**
* Sendet den Befehl zur L<EFBFBD>schung des Displays
*/
void lcd_clear() {
lcd_command(LCD_CLEAR_DISPLAY);
_delay_ms(LCD_CLEAR_DISPLAY_MS);
}
/**
* Sendet den Befehl: Cursor Home
*/
void lcd_home() {
lcd_command(LCD_CURSOR_HOME);
_delay_ms(LCD_CURSOR_HOME_MS);
}
/**
* Setzt den Cursor in Spalte x (0..15) Zeile y (1..4)
*/
void lcd_setcursor(uint8_t x, uint8_t y) {
uint8_t data;
switch (y) {
case 0: // 1. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
break;
case 1: // 2. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
break;
case 2: // 3. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
break;
case 3: // 4. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
break;
default:
return; // f<>r den Fall einer falschen Zeile
}
lcd_command(data);
}
/**
* Schreibt einen String auf das LCD
*/
void lcd_string(const char *data) {
while (*data != '\0') {
lcd_data(*data++);
}
}
/**
* Schreibt ein Zeichen in den Character Generator RAM
*/
void lcd_generatechar(uint8_t code, const uint8_t *data) {
// Startposition des Zeichens einstellen
lcd_command(LCD_SET_CGADR | (code<<3));
// Bitmuster <20>bertragen
for (uint8_t i=0; i<8; i++) {
lcd_data(data[i]);
}
}
/**
* Ausgabe Balkenanzeige
*/
void lcd_bar(uint8_t startx, uint8_t starty, uint8_t length, uint8_t percent) {
uint8_t i;
if (percent > 100) return;
lcd_setcursor(startx, starty);
lcd_data(0b00111100); // <
for (i=0; i < length-2; i++) {
lcd_setcursor( startx+1+i , starty );
if (percent*(length-2)/100 <= i ) {
lcd_data('-');
}
else {
lcd_data(0b11111111);
}
}
lcd_setcursor(startx+length-1, starty );
lcd_data(0b00111110); // >
}
/**
* Ausgabe einer Ganzzahl mit f<EFBFBD>hrenden Leerzeichen
*/
void lcd_int(int16_t number, uint8_t length) {
char buffer[length+1];
bool vz = true;
bool zf = true;
bool neg = (number < 0);
buffer[length] = '\0';
for (int8_t counter = length-1; counter >= 0; counter--) {
if (zf) {
buffer[counter] = '0' + (abs(number) % 10);
number /= 10;
zf = (bool) number;
}
else if (vz && neg) {
buffer[counter] = '-';
vz = false;
}
else {
buffer[counter] = ' ';
}
}
lcd_string(buffer);
}