2019-03-20 05:34:51 +01:00
|
|
|
//#define DEBUG
|
|
|
|
|
|
|
|
#include "stc15.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "lcd.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define LCDINC 2
|
|
|
|
#define LCDDEC 0
|
|
|
|
#define LCDSHIFT 1
|
|
|
|
#define LCDNOSHIFT 0
|
|
|
|
#define LCDCURSOR 2
|
|
|
|
#define LCDNOCURSOR 0
|
|
|
|
#define LCDBLINK 1
|
|
|
|
#define LCDNOBLINK 0
|
|
|
|
#define LCDSCROLL 8
|
|
|
|
#define LCDNOSCROLL 0
|
|
|
|
#define LCDLEFT 0
|
|
|
|
#define LCDRIGHT 4
|
|
|
|
#define LCD2LINE 8
|
|
|
|
#define LCD1LINE 0
|
|
|
|
#define LCD10DOT 4
|
|
|
|
#define LCD7DOT 0
|
|
|
|
|
|
|
|
#define CR 13 // \r
|
|
|
|
#define TAB 9 // \n
|
|
|
|
#define LF 10 // \r
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int row, col;
|
|
|
|
static int OpenFlag = 0;
|
|
|
|
static int ErrorTimeout = 0;
|
|
|
|
static int Error = 0;
|
|
|
|
|
|
|
|
#define CLEAR_BIT(port, bit) (port &= ~(_BV(bit)))
|
|
|
|
#define CLEAR_BITS(port, bits) (port &= ~(bits))
|
|
|
|
#define SET_BIT(port, bit) (port |= _BV(bit))
|
|
|
|
|
|
|
|
//#define DISABLE_INTERRUPTS() __critical{
|
|
|
|
//#define ENABLE_INTERRUPTS() }
|
|
|
|
#define DISABLE_INTERRUPTS() {
|
|
|
|
#define ENABLE_INTERRUPTS() }
|
|
|
|
|
|
|
|
#define LCD_E P3_5
|
|
|
|
#define LCD_RW P3_6
|
|
|
|
#define LCD_RS P3_7
|
|
|
|
#define LCD_BUSY P2_7 //LCD D7
|
|
|
|
|
|
|
|
static void outCsrBlindNibble(unsigned char command);
|
|
|
|
static void outCsrBlind(unsigned char command);
|
|
|
|
static void outCsr(unsigned char command);
|
|
|
|
static char readBusy(void);
|
|
|
|
static void wait_busy(void);
|
|
|
|
static void to_row(unsigned char row_to);
|
|
|
|
static void LCD_OutChar(unsigned char c);
|
|
|
|
|
|
|
|
static void outCsrBlindNibble(unsigned char command) {
|
|
|
|
// CLEAR_BITS(PORTC, _BV(LCD_E) | _BV(LCD_RS) | _BV(LCD_RW));
|
|
|
|
P3 &= ~(0x7 << 5); //clear LCD_E, LCD_RS, LCD_RW
|
|
|
|
_delay_us(50);
|
|
|
|
P2 = ((command & 0xf) << 4);
|
|
|
|
//CLEAR_BIT(PORTC, LCD_E); //E = 0
|
|
|
|
//CLEAR_BIT(PORTC, LCD_RS); //control
|
|
|
|
//CLEAR_BIT(PORTC, LCD_RW); //write
|
|
|
|
_delay_us(100);
|
|
|
|
LCD_E = 1;
|
|
|
|
_delay_us(100);
|
|
|
|
LCD_E = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void outCsrBlind(unsigned char command) {
|
|
|
|
outCsrBlindNibble(command >> 4); // ms nibble, E=0, RS=0
|
|
|
|
_delay_us(100);
|
|
|
|
outCsrBlindNibble(command); // ls nibble, E=0, RS=0
|
|
|
|
_delay_us(100); // blind cycle 90 us wait
|
|
|
|
}
|
|
|
|
|
|
|
|
static void outCsr(unsigned char command) {
|
|
|
|
DISABLE_INTERRUPTS();
|
|
|
|
outCsrBlindNibble(command >> 4); // ms nibble, E=0, RS=0
|
|
|
|
outCsrBlindNibble(command); // ls nibble, E=0, RS=0
|
|
|
|
ENABLE_INTERRUPTS();
|
|
|
|
wait_busy();
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SET_BUSY_IN() do {P2M1 |= (1<<7); P2M0 &= ~(1<<7);} while(0)
|
|
|
|
#define SET_BUSY_OUT() do {P2M1 &= ~(1<<7); P2M0 |= (1<<7); } while(0)
|
|
|
|
|
|
|
|
//returns 1 if busy, 0 otherwise
|
|
|
|
static char readBusy() {
|
|
|
|
unsigned char oldP2 = P2;
|
|
|
|
__bit busy;
|
|
|
|
|
|
|
|
LCD_RS = 0; //control
|
|
|
|
LCD_RW = 1; //read
|
|
|
|
LCD_E = 1;
|
|
|
|
SET_BUSY_IN();
|
|
|
|
|
|
|
|
//wait
|
|
|
|
_delay_us(100); // blind cycle 100us wait
|
|
|
|
//read busy flag
|
|
|
|
busy = LCD_BUSY;
|
|
|
|
SET_BUSY_OUT();
|
|
|
|
LCD_E = 0;
|
|
|
|
LCD_E = 1;
|
|
|
|
//wait
|
|
|
|
_delay_us(100); // blind cycle 100us wait
|
|
|
|
LCD_E = 0;
|
|
|
|
P2 = oldP2;
|
|
|
|
|
|
|
|
return busy;
|
|
|
|
}
|
|
|
|
|
|
|
|
//sets ErrorTimeout flag if busy signal not cleared in time
|
|
|
|
static void wait_busy() {
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 100; i++){
|
|
|
|
if (!readBusy()){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_delay_ms(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorTimeout = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LCD_OutChar(unsigned char c) {
|
|
|
|
unsigned char lower = (c & 0x0f);
|
|
|
|
DISABLE_INTERRUPTS();
|
|
|
|
wait_busy();
|
|
|
|
//output upper 4 bits:
|
|
|
|
LCD_E = 0;
|
|
|
|
LCD_RS = 1; //data
|
|
|
|
LCD_RW = 0; //write
|
|
|
|
P2 = ((c & 0xf0));
|
|
|
|
LCD_E = 1;
|
|
|
|
_delay_us(100);
|
|
|
|
LCD_E = 0;
|
|
|
|
//output lower 4 bits:
|
|
|
|
P2 = ((c & 0xf) << 4);
|
|
|
|
LCD_E = 1;
|
|
|
|
_delay_us(100);
|
|
|
|
LCD_E = 0;
|
|
|
|
ENABLE_INTERRUPTS();
|
|
|
|
wait_busy();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LCD_Open(void) {
|
|
|
|
static int open_error = 0;
|
|
|
|
if (!OpenFlag) {
|
2019-03-20 08:21:11 +01:00
|
|
|
//set ports to push-pull output M[1:0] = b01
|
|
|
|
//P2 entire port
|
2019-03-20 05:34:51 +01:00
|
|
|
P2M1 = 0;
|
|
|
|
P2M0 = 0xff;
|
2019-03-20 08:21:11 +01:00
|
|
|
//P3 pins 7:4
|
|
|
|
P3M1 &= ~(0xf0);
|
|
|
|
P3M0 |= (0xf0);
|
2019-03-20 05:34:51 +01:00
|
|
|
|
|
|
|
_delay_ms(30); // to allow LCD powerup
|
|
|
|
outCsrBlindNibble(0x03); // (DL=1 8-bit mode)
|
|
|
|
_delay_ms(5); // blind cycle 5ms wait
|
|
|
|
outCsrBlindNibble(0x03); // (DL=1 8-bit mode)
|
|
|
|
_delay_us(100); // blind cycle 100us wait
|
|
|
|
outCsrBlindNibble(0x03); // (DL=1 8-bit mode)
|
|
|
|
_delay_us(100); // blind cycle 100us wait (not called for, but do it anyway)
|
|
|
|
outCsrBlindNibble(0x02); // DL=1 switch to 4 bit mode (only high 4 bits are sent)
|
|
|
|
_delay_us(100); // blind cycle 100 us wait
|
|
|
|
//set increment, no shift
|
|
|
|
outCsrBlind(0x4 + LCDINC + LCDNOSHIFT);
|
|
|
|
#ifdef DEBUG
|
|
|
|
//set display on, cursor on, blink on:
|
|
|
|
outCsrBlind(0x0c + LCDCURSOR + LCDBLINK);
|
|
|
|
#else
|
|
|
|
//set display on, cursor and blink off:
|
|
|
|
outCsrBlind(0x0c + LCDNOCURSOR + LCDNOBLINK);
|
|
|
|
#endif
|
|
|
|
//set display shift on and to the right
|
|
|
|
outCsrBlind(0x10 + LCDNOSCROLL + LCDRIGHT);
|
|
|
|
//set 4-bit mode, 2 line, 5x7 display:
|
|
|
|
outCsrBlind(0x20 + LCD2LINE + LCD7DOT);
|
|
|
|
//clear display
|
|
|
|
LCD_Clear();
|
|
|
|
_delay_ms(50);
|
|
|
|
if (!readBusy()) {
|
|
|
|
OpenFlag = 1;
|
|
|
|
} else {
|
|
|
|
open_error = 1;
|
|
|
|
}
|
|
|
|
} else { //display already open
|
|
|
|
open_error = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//row and columns indexed from 0
|
|
|
|
void LCD_GoTo(unsigned int row_to, unsigned int col_to) {
|
|
|
|
if (row_to < MAX_ROWS && col_to < MAX_CHARS_PER_LINE) {
|
|
|
|
outCsr(0x80 + 0x40 * row_to + col_to); //set ddram address to position
|
|
|
|
row = row_to;
|
|
|
|
col = col_to;
|
|
|
|
} else {
|
|
|
|
Error = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void to_row(unsigned char row_to) {
|
|
|
|
if (row_to == 0) {
|
|
|
|
outCsr(0x80);//set address to start of row 0
|
|
|
|
row = 0;
|
|
|
|
} else {
|
|
|
|
outCsr(0xc0);// set address to row 1
|
|
|
|
row = 1;
|
|
|
|
}
|
|
|
|
col = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//row indexed from 0
|
|
|
|
void LCD_SingleLineGoTo(unsigned int spot_to) {
|
|
|
|
LCD_GoTo(spot_to / MAX_CHARS_PER_LINE, spot_to % MAX_CHARS_PER_LINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LCD_OutString(const char *string) {
|
|
|
|
const char *s;
|
|
|
|
for (s = string; *s; s++) {
|
|
|
|
TERMIO_PutChar(*s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
short TERMIO_PutChar(unsigned char letter) {
|
|
|
|
if (letter == CR || letter == '\n') {
|
|
|
|
LCD_Clear();
|
|
|
|
} else if (letter == TAB || letter == '\t') {
|
|
|
|
if (row == 0) {
|
|
|
|
to_row(1);
|
|
|
|
} else {
|
|
|
|
to_row(0);
|
|
|
|
}
|
|
|
|
} else {
|
2019-03-22 02:01:53 +01:00
|
|
|
LCD_OutChar(letter);
|
|
|
|
col++;
|
2019-03-20 05:34:51 +01:00
|
|
|
if (col > MAX_CHARS_PER_LINE) {
|
|
|
|
if (row == 0) {
|
|
|
|
to_row(1);
|
|
|
|
} else {
|
|
|
|
to_row(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-03-22 02:01:53 +01:00
|
|
|
void LCD_ClearToEnd(void){
|
|
|
|
while (col != 0){
|
|
|
|
TERMIO_PutChar(' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-20 08:21:11 +01:00
|
|
|
void LCD_OutNibble(uint8_t x){
|
|
|
|
x &= 0xf; //ensure only bottom nibble
|
|
|
|
if (x <= 9){
|
|
|
|
TERMIO_PutChar(x + '0');
|
|
|
|
} else {
|
|
|
|
TERMIO_PutChar(x - 10 + 'a');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-20 05:34:51 +01:00
|
|
|
void LCD_Clear() {
|
|
|
|
if (OpenFlag) {
|
|
|
|
outCsr(0x01);
|
|
|
|
} else {
|
|
|
|
outCsrBlind(0x01);
|
|
|
|
}
|
|
|
|
row = 0;
|
|
|
|
col = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char LCD_Timeout_Error(void) {
|
|
|
|
if (ErrorTimeout != 0) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|