diff options
author | Stanley Huang <stanleyhuangyc@gmail.com> | 2013-03-25 00:57:28 +0800 |
---|---|---|
committer | Stanley Huang <stanleyhuangyc@gmail.com> | 2013-03-25 00:57:28 +0800 |
commit | 8e57c683d3d16f1dee320f10c411602ea38ba651 (patch) | |
tree | 75df3040d13c3f1850d93e29eb93a3836cae133c /samples | |
download | 2021-arduino-obd-8e57c683d3d16f1dee320f10c411602ea38ba651.tar.gz 2021-arduino-obd-8e57c683d3d16f1dee320f10c411602ea38ba651.tar.bz2 2021-arduino-obd-8e57c683d3d16f1dee320f10c411602ea38ba651.zip |
initial commit
Diffstat (limited to 'samples')
-rw-r--r-- | samples/dashboard_1602/LCD4Bit_mod.cpp | 233 | ||||
-rw-r--r-- | samples/dashboard_1602/LCD4Bit_mod.h | 27 | ||||
-rw-r--r-- | samples/dashboard_1602/dashboard_1602.ino | 172 | ||||
-rw-r--r-- | samples/dashboard_4884/LCD4884.cpp | 294 | ||||
-rw-r--r-- | samples/dashboard_4884/LCD4884.h | 67 | ||||
-rw-r--r-- | samples/dashboard_4884/dashboard_4884.ino | 468 | ||||
-rw-r--r-- | samples/dashboard_4884/font_6x8.h | 101 | ||||
-rw-r--r-- | samples/dashboard_4884/font_big.h | 141 | ||||
-rw-r--r-- | samples/dashboard_oled/ZtLib.cpp | 603 | ||||
-rw-r--r-- | samples/dashboard_oled/ZtLib.h | 127 | ||||
-rw-r--r-- | samples/dashboard_oled/dashboard_oled.ino | 158 | ||||
-rw-r--r-- | samples/obdtest/obdtest.ino | 243 | ||||
-rw-r--r-- | samples/rpm_led/rpm_led.ino | 31 |
13 files changed, 2665 insertions, 0 deletions
diff --git a/samples/dashboard_1602/LCD4Bit_mod.cpp b/samples/dashboard_1602/LCD4Bit_mod.cpp new file mode 100644 index 0000000..ef93daa --- /dev/null +++ b/samples/dashboard_1602/LCD4Bit_mod.cpp @@ -0,0 +1,233 @@ +/* +LCD4Bit v0.1 16/Oct/2006 neillzero http://abstractplain.net + +What is this? +An arduino library for comms with HD44780-compatible LCD, in 4-bit mode (saves pins) + +Sources: +- The original "LiquidCrystal" 8-bit library and tutorial + http://www.arduino.cc/en/uploads/Tutorial/LiquidCrystal.zip + http://www.arduino.cc/en/Tutorial/LCDLibrary +- DEM 16216 datasheet http://www.maplin.co.uk/Media/PDFs/N27AZ.pdf +- Massimo's suggested 4-bit code (I took initialization from here) http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1144924220/8 +See also: +- glasspusher's code (probably more correct): http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1160586800/0#0 + +Tested only with a DEM 16216 (maplin "N27AZ" - http://www.maplin.co.uk/Search.aspx?criteria=N27AZ) +If you use this successfully, consider feeding back to the arduino wiki with a note of which LCD it worked on. + +Usage: +see the examples folder of this library distribution. + +*/ + +#include "LCD4Bit_mod.h" + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +//command bytes for LCD +#define CMD_CLR 0x01 +#define CMD_RIGHT 0x1C +#define CMD_LEFT 0x18 +#define CMD_HOME 0x02 + +// --------- PINS ------------------------------------- +//is the RW pin of the LCD under our control? If we're only ever going to write to the LCD, we can use one less microcontroller pin, and just tie the LCD pin to the necessary signal, high or low. +//this stops us sending signals to the RW pin if it isn't being used. +int USING_RW = false; + +//RS, RW and Enable can be set to whatever you like +int RS = 8; +int RW = 11; +int Enable = 9; +//DB should be an unseparated group of pins - because of lazy coding in pushNibble() +int DB[] = {4, 5, 6, 7}; //wire these to DB4~7 on LCD. + +//-------------------------------------------------------- + +//how many lines has the LCD? (don't change here - specify on calling constructor) +int g_num_lines = 2; + +//pulse the Enable pin high (for a microsecond). +//This clocks whatever command or data is in DB4~7 into the LCD controller. +void LCD4Bit_mod::pulseEnablePin(){ + digitalWrite(Enable,LOW); + delayMicroseconds(1); + // send a pulse to enable + digitalWrite(Enable,HIGH); + delayMicroseconds(1); + digitalWrite(Enable,LOW); + delay(1); // pause 1 ms. TODO: what delay, if any, is necessary here? +} + +//push a nibble of data through the the LCD's DB4~7 pins, clocking with the Enable pin. +//We don't care what RS and RW are, here. +void LCD4Bit_mod::pushNibble(int value){ + int val_nibble= value & 0x0F; //clean the value. (unnecessary) + + for (int i=DB[0]; i <= DB[3]; i++) { + digitalWrite(i,val_nibble & 01); + val_nibble >>= 1; + } + pulseEnablePin(); +} + +//push a byte of data through the LCD's DB4~7 pins, in two steps, clocking each with the enable pin. +void LCD4Bit_mod::pushByte(int value){ + int val_lower = value & 0x0F; + int val_upper = value >> 4; + pushNibble(val_upper); + pushNibble(val_lower); +} + + +//stuff the library user might call--------------------------------- +//constructor. num_lines must be 1 or 2, currently. +LCD4Bit_mod::LCD4Bit_mod (int num_lines) { + g_num_lines = num_lines; + if (g_num_lines < 1 || g_num_lines > 2) + { + g_num_lines = 1; + } +} + +void LCD4Bit_mod::commandWriteNibble(int nibble) { + digitalWrite(RS, LOW); + if (USING_RW) { digitalWrite(RW, LOW); } + pushNibble(nibble); +} + + +void LCD4Bit_mod::commandWrite(int value) { + digitalWrite(RS, LOW); + if (USING_RW) { digitalWrite(RW, LOW); } + pushByte(value); + //TODO: perhaps better to add a delay after EVERY command, here. many need a delay, apparently. +} + + + + +//print the given character at the current cursor position. overwrites, doesn't insert. +void LCD4Bit_mod::print(int value) { + //set the RS and RW pins to show we're writing data + digitalWrite(RS, HIGH); + if (USING_RW) { digitalWrite(RW, LOW); } + + //let pushByte worry about the intricacies of Enable, nibble order. + pushByte(value); +} + + +//print the given string to the LCD at the current cursor position. overwrites, doesn't insert. +//While I don't understand why this was named printIn (PRINT IN?) in the original LiquidCrystal library, I've preserved it here to maintain the interchangeability of the two libraries. +void LCD4Bit_mod::printIn(const char* msg) { + uint8_t i; //fancy int. avoids compiler warning when comparing i with strlen()'s uint8_t + uint8_t l = strlen(msg); + for (i=0; i < l; i++){ + if (msg[i] >= 20) print(msg[i]); + } +} + + +//send the clear screen command to the LCD +void LCD4Bit_mod::clear(){ + commandWrite(CMD_CLR); + delay(1); +} + + +// initiatize lcd after a short pause +//while there are hard-coded details here of lines, cursor and blink settings, you can override these original settings after calling .init() +void LCD4Bit_mod::init () { + pinMode(Enable,OUTPUT); + pinMode(RS,OUTPUT); + if (USING_RW) { pinMode(RW,OUTPUT); } + pinMode(DB[0],OUTPUT); + pinMode(DB[1],OUTPUT); + pinMode(DB[2],OUTPUT); + pinMode(DB[3],OUTPUT); + + delay(50); + + //The first 4 nibbles and timings are not in my DEM16217 SYH datasheet, but apparently are HD44780 standard... + commandWriteNibble(0x03); + delay(5); + commandWriteNibble(0x03); + delayMicroseconds(100); + commandWriteNibble(0x03); + delay(5); + + // needed by the LCDs controller + //this being 2 sets up 4-bit mode. + commandWriteNibble(0x02); + commandWriteNibble(0x02); + //todo: make configurable by the user of this library. + //NFXX where + //N = num lines (0=1 line or 1=2 lines). + //F= format (number of dots (0=5x7 or 1=5x10)). + //X=don't care + + int num_lines_ptn = (g_num_lines - 1) << 3; + int dot_format_ptn = 0x00; //5x7 dots. 0x04 is 5x10 + + commandWriteNibble(num_lines_ptn | dot_format_ptn); + delayMicroseconds(60); + + //The rest of the init is not specific to 4-bit mode. + //NOTE: we're writing full bytes now, not nibbles. + + // display control: + // turn display on, cursor off, no blinking + commandWrite(0x0C); + delayMicroseconds(60); + + //clear display + commandWrite(0x01); + delay(3); + + // entry mode set: 06 + // increment automatically, display shift, entire shift off + commandWrite(0x06); + + delay(1);//TODO: remove unnecessary delays +} + + +//non-core stuff -------------------------------------- +//move the cursor to the given absolute position. line numbers start at 1. +//if this is not a 2-line LCD4Bit_mod instance, will always position on first line. +void LCD4Bit_mod::cursorTo(int line_num, int x){ + //first, put cursor home + commandWrite(CMD_HOME); + + //if we are on a 1-line display, set line_num to 1st line, regardless of given + if (g_num_lines==1){ + line_num = 1; + } + //offset 40 chars in if second line requested + if (line_num == 2){ + x += 40; + } + //advance the cursor to the right according to position. (second line starts at position 40). + for (int i=0; i<x; i++) { + commandWrite(0x14); + } +} + +//scroll whole display to left +void LCD4Bit_mod::leftScroll(int num_chars, int delay_time){ + for (int i=0; i<num_chars; i++) { + commandWrite(CMD_LEFT); + delay(delay_time); + } +} + +//Improvements ------------------------------------------------ +//Remove the unnecessary delays (e.g. from the end of pulseEnablePin()). +//Allow the user to pass the pins to be used by the LCD in the constructor, and store them as member variables of the class instance. +//------------------------------------------------------------- diff --git a/samples/dashboard_1602/LCD4Bit_mod.h b/samples/dashboard_1602/LCD4Bit_mod.h new file mode 100644 index 0000000..7318c32 --- /dev/null +++ b/samples/dashboard_1602/LCD4Bit_mod.h @@ -0,0 +1,27 @@ +#ifndef LCD4Bit_mod_h +#define LCD4Bit_mod_h + +#include <inttypes.h> + +class LCD4Bit_mod { +public: + LCD4Bit_mod(int num_lines); + void commandWrite(int value); + void init(); + void print(int value); + void printIn(const char* value); + void clear(); + //non-core--------------- + void cursorTo(int line_num, int x); + void leftScroll(int chars, int delay_time); + //end of non-core-------- + + //4bit only, therefore ideally private but may be needed by user + void commandWriteNibble(int nibble); +private: + void pulseEnablePin(); + void pushNibble(int nibble); + void pushByte(int value); +}; + +#endif diff --git a/samples/dashboard_1602/dashboard_1602.ino b/samples/dashboard_1602/dashboard_1602.ino new file mode 100644 index 0000000..563a0af --- /dev/null +++ b/samples/dashboard_1602/dashboard_1602.ino @@ -0,0 +1,172 @@ +/************************************************************************* +* Sample sketch based on OBD-II library for Arduino +* Using a LCD1602 shield to display realtime vehicle data +* Distributed under GPL v2.0 +* Copyright (c) 2012 Stanley Huang <stanleyhuangyc@gmail.com> +* All rights reserved. +*************************************************************************/ + +#include <arduino.h> +#include <LCD4Bit_mod.h> +#include <OBD.h> + +//create object to control an LCD. +LCD4Bit_mod lcd = LCD4Bit_mod(2); + +COBD obd; + +//Key message +unsigned int adc_key_val[5] ={30, 150, 360, 535, 760 }; +int NUM_KEYS = 5; +int adc_key_in; +char key=-1; +char oldkey=-1; +unsigned long lastTick = millis(); +uint8_t modes[2] = {0, 2}; + +const char modePids[] = {PID_RPM, PID_SPEED, PID_THROTTLE, PID_ENGINE_LOAD, + PID_COOLANT_TEMP, PID_INTAKE_TEMP, PID_AMBIENT_TEMP, PID_MAF_FLOW, + PID_ABS_ENGINE_LOAD, PID_FUEL_PRESSURE, PID_INTAKE_PRESSURE, PID_BAROMETRIC, + PID_TIMING_ADVANCE, PID_FUEL_LEVEL, PID_RUNTIME, PID_DISTANCE}; + +const char* modeLabels[] = { + "Engine rpm", "Speed km/h", "Throttle %", "Engine Load %", + "Coolant C", "Intake Air C", "Env. Temp C", "MAF Flow kpa", + "Abs. Load %", "Fuel kpa", "Intake kpa", "Barometer kpa", + "Timing Adv. ", "Fuel Level %", "Run Time", "Distance km"}; + +const char modePos[] = {8, 8, 11, 12, + 11, 11, 11, 9, + 11, 9, 9, 10, + 12, 11, 8, 10}; + +const char* modeFmts[] = {"%4u", "%3u", "%3u", "%u", + "%3d", "%3d", "%3d", "%3u", + "%3u", "%3u", "%3u", "%u", + "%3d", "%3u", "%4u:%02u", "%04u"}; + +#define TOTAL_PIDS (sizeof(modePids) / sizeof(modePids[0])) + +// Convert ADC value to key number +char get_key(unsigned int input) +{ + char k; + for (k = 0; k < NUM_KEYS; k++) { + if (input < adc_key_val[k]) + return k; + } + return -1; +} + +void updateMode() +{ + lcd.cursorTo(1, 0); + lcd.printIn((char*)modeLabels[modes[0]]); + lcd.cursorTo(2, 0); + lcd.printIn((char*)modeLabels[modes[1]]); +} + +bool showData(int index) +{ + char buf[16]; + int value; + uint8_t mode = modes[index]; + uint8_t pid = modePids[mode]; + digitalWrite(13, HIGH); // set the LED on + if (!obd.ReadSensor(pid, value)) { + // display received data on error + lcd.cursorTo(index + 1, 0); + lcd.printIn("Error"); + delay(2000); + updateMode(); + return false; + } + digitalWrite(13, LOW); // set the LED off + + if (pid == PID_RUNTIME) { + sprintf(buf, modeFmts[mode], (unsigned int)value / 60, (unsigned int)value % 60); + } else { + sprintf(buf, modeFmts[mode], value); + } + lcd.cursorTo(index + 1, modePos[mode]); + lcd.printIn(buf); + return true; +} + +bool setupConnection() +{ + uint8_t errors = 0; + char buf[16]; + lcd.clear(); + lcd.printIn("Connecting..."); + while (!obd.Init()) { + lcd.cursorTo(2, 0); + sprintf(buf, "Attempts #%d", ++errors); + lcd.printIn(buf); + } + lcd.clear(); + lcd.printIn("Connected!"); + delay(1000); + updateMode(); + return true; +} + +void setup() +{ + pinMode(13, OUTPUT); //we'll use the debug LED to output a heartbeat + lcd.init(); + OBDUART.begin(OBD_SERIAL_BAUDRATE); + setupConnection(); +} + +void loop() +{ + adc_key_in = analogRead(0); // read the value from the sensor + key = get_key(adc_key_in); // convert into key press + + if (key != oldkey) { + delay(50); // wait for debounce time + adc_key_in = analogRead(0); // read the value from the sensor + key = get_key(adc_key_in); // convert into key press + if (key != oldkey) + { + oldkey = key; + if (key >=0){ + switch (key) { + case 3: // left key + do { + modes[0] = modes[0] > 0 ? modes[0] - 1 : TOTAL_PIDS - 1; + } while (modes[0] == modes[1]); + break; + case 0: // right key + do { + modes[0] = modes[0] < TOTAL_PIDS - 1 ? modes[0] + 1 : 0; + } while (modes[0] == modes[1]); + break; + case 1: // up key + do { + modes[1] = modes[1] > 0 ? modes[1] - 1 : TOTAL_PIDS - 1; + } while (modes[0] == modes[1]); + break; + case 2: // down key + do { + modes[1] = modes[1] < TOTAL_PIDS - 1 ? modes[1] + 1 : 0; + } while (modes[0] == modes[1]); + break; + } + updateMode(); + } + } + } + + unsigned long curTick = millis(); + if (curTick - lastTick > 500) { + showData(0); + showData(1); + if (obd.errors > 10) { + setupConnection(); + } + lastTick = curTick; + } +} + diff --git a/samples/dashboard_4884/LCD4884.cpp b/samples/dashboard_4884/LCD4884.cpp new file mode 100644 index 0000000..522826d --- /dev/null +++ b/samples/dashboard_4884/LCD4884.cpp @@ -0,0 +1,294 @@ +/* +Modified by Lauren +version 0.3 + +Any suggestions are welcome. + +Editors : Lauren from DFRobot <Lauran.pan@gmail.com> + Stanley Huang <stanleyhuangyc@gmail.com> +Date : Feb. 11, 2012 + +* Added LCD_putchar for basic console display +* Have the back light under control. +* Update the library and sketch to compatible with IDE V1.0 and earlier + +*/ + +#include "LCD4884.h" +#include "font_6x8.h" +#include "font_big.h" + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#include "WConstants.h" +#endif + + +extern "C" +{ +#include <avr/pgmspace.h> +#include <avr/io.h> +} + +#define NUM_COL 14 +#define NUM_ROW 5 + +LCD4884::LCD4884():prev_char(0),char_mode(MENU_NORMAL) +{}; + +LCD4884 lcd = LCD4884(); + +void LCD4884::backlight(unsigned char dat) +{ + if(dat==1) + digitalWrite(LCD_BL,HIGH); + else + digitalWrite(LCD_BL,LOW); +} + +void LCD4884::LCD_init(void) +{ + for(unsigned char i = 2; i < 8; i++) { + pinMode(i,OUTPUT); + digitalWrite(i,LOW); + } + + digitalWrite(LCD_RST,LOW); + delayMicroseconds(1); + digitalWrite(LCD_RST,HIGH); + + digitalWrite(SPI_CS,LOW); + delayMicroseconds(1); + digitalWrite(SPI_CS,HIGH); + delayMicroseconds(1); + digitalWrite(LCD_BL,HIGH); + + LCD_write_byte(0x21, 0); + LCD_write_byte(0xc0, 0); + LCD_write_byte(0x06, 0); + LCD_write_byte(0x13, 0); + LCD_write_byte(0x20, 0); + LCD_clear(); + LCD_write_byte(0x0c, 0); + + digitalWrite(SPI_CS,LOW); +} + +void LCD4884::LCD_write_byte(unsigned char dat, unsigned char dat_type) +{ + digitalWrite(SPI_CS,LOW); + if (dat_type == 0) + digitalWrite(LCD_DC,LOW); + else + digitalWrite(LCD_DC,HIGH); + + for(unsigned char i=0; i<8; i++) { + if(dat & 0x80) { + digitalWrite(SPI_MOSI,HIGH); + } else { + digitalWrite(SPI_MOSI,LOW); + } + digitalWrite(SPI_SCK,LOW); + dat = dat << 1; + digitalWrite(SPI_SCK,HIGH); + } + digitalWrite(SPI_CS,HIGH); +} + +void LCD4884::LCD_draw_bmp_pixel(unsigned char X,unsigned char Y,unsigned char *map, + unsigned char Pix_x,unsigned char Pix_y) +{ + unsigned int i,n; + unsigned char row; + + if (Pix_y%8==0) + row=Pix_y/8; + else + row=Pix_y/8+1; + + for (n=0;n<row;n++) { + LCD_set_XY(X,Y); + for(i=0; i<Pix_x; i++) { + LCD_write_byte(map[i+n*Pix_x], 1); + } + Y++; + } +} + +void LCD4884::LCD_write_string(unsigned char X,unsigned char Y,char *s, char mode) + { + LCD_set_XY(X,Y); + while (*s) { + LCD_write_char(*s, mode); + s++; + } + } + +void LCD4884::LCD_write_string(char *s, char mode) + { + while (*s) { + LCD_write_char(*s, mode); + s++; + } + } + +void LCD4884::LCD_write_chinese(unsigned char X, unsigned char Y,unsigned char *c,unsigned char ch_with,unsigned char num,unsigned char line,unsigned char row) +{ + LCD_set_XY(X,Y); + for (unsigned char i=0;i<num;) { + for (unsigned char n=0; n<ch_with*2; n++) { + if (n==ch_with) { + if (i==0) + LCD_set_XY(X,Y+1); + else + LCD_set_XY((X+(ch_with+row)*i),Y+1); + } + LCD_write_byte(c[(i*ch_with*2)+n],1); + } + i++; + LCD_set_XY((X+(ch_with+row)*i),Y); + } +} + + +void LCD4884::LCD_write_string_big ( unsigned char X,unsigned char Y, char *string, char mode ) +{ + while ( *string ){ + LCD_write_char_big( X, Y, *string , mode ); + if(*string++ == '.') + X += 5; + else + X += 12; + } +} + +/* write char in big font */ +void LCD4884::LCD_write_char_big (unsigned char X,unsigned char Y, unsigned char ch, char mode) +{ + unsigned char i, j; + unsigned char *pFont; + unsigned char ch_dat; + + pFont = (unsigned char *) big_number; + + switch (ch) { + case '.': + ch = 10; + break; + case '+': + ch = 11; + break; + case '-': + ch = 12; + break; + case ' ': + for(i=0;i<3;i++) { + LCD_set_XY ( X, Y+i); + for(j=0; j<16; j++) { + LCD_write_byte( (mode == MENU_NORMAL)? 0 : 0xff, 1); + } + } + return; + break; + default: + ch = ch & 0x0f; + } + + for(i=0;i<3;i++) { + LCD_set_XY ( X, Y+i); + for(j=0; j<16; j++){ + ch_dat = pgm_read_byte(pFont+ch*48 + i*16 +j); + LCD_write_byte( (mode == MENU_NORMAL)? ch_dat : (ch_dat^0xff), 1); + } + } + + +} + +void LCD4884::LCD_write_char(unsigned char c, char mode) +{ + unsigned char line; + unsigned char *pFont; + byte ch; + + pFont = (unsigned char *)font6_8; + c -= 32; + + for (line=0; line<6; line++) { + ch = pgm_read_byte(pFont+c*6+line); + LCD_write_byte( (mode==MENU_NORMAL)? ch: (ch^ 0xff) , 1); + } + x = (x + 1) % NUM_COL; +} + + +void LCD4884::LCD_set_XY(unsigned char X, unsigned char Y) + { + LCD_write_byte(0x40 | Y, 0); // column + LCD_write_byte(0x80 | X, 0); // row + x = X; + } + + +void LCD4884::LCD_clear(void) + { + unsigned int i; + + LCD_write_byte(0x0c, 0); + LCD_write_byte(0x80, 0); + + for (i=0; i<504; i++) + LCD_write_byte(0, 1); + + x = 0; + } + +void LCD4884::LCD_write_title(char* title) +{ + LCD_set_XY(0, 0); + for (char n = 0; n < NUM_COL; n++) + LCD_write_char(' ', MENU_HIGHLIGHT); + LCD_write_string((NUM_COL - strlen(title)) * 3, 0, title, MENU_HIGHLIGHT); + LCD_set_XY(0, 1); +} + +void LCD4884::LCD_putchar(char c) +{ + if (prev_char == 27) { + switch (c) { + case '0': + LCD_clear(); + break; + case '1': + LCD_set_XY(0, 0); + break; + case '2': + char_mode = MENU_NORMAL; + break; + case '3': + char_mode = MENU_HIGHLIGHT; + break; + case '4': + backlight(ON); + break; + case '5': + backlight(OFF); + break; + } + } else { + switch (c) { + case '\r': + for (char n = x; n < NUM_COL; n++) { + LCD_write_char(' ', char_mode); + } + break; + case '\n': + break; + default: + LCD_write_char(c, char_mode); + } + } + prev_char = c; +}
\ No newline at end of file diff --git a/samples/dashboard_4884/LCD4884.h b/samples/dashboard_4884/LCD4884.h new file mode 100644 index 0000000..3145601 --- /dev/null +++ b/samples/dashboard_4884/LCD4884.h @@ -0,0 +1,67 @@ +/* +Modified by Lauren +version 0.3 + +Any suggestions are welcome. + +Editors : Lauren from DFRobot <Lauran.pan@gmail.com> + Stanley Huang <stanleyhuangyc@gmail.com> +Date : Feb. 11, 2012 + +* Added LCD_putchar for basic console display +* Have the back light under control. +* Update the library and sketch to compatible with IDE V1.0 and earlier + +*/ + +#ifndef LCD4884_h +#define LCD4884_h + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +#define SPI_SCK 2 +#define SPI_MOSI 3 +#define LCD_DC 4 +#define SPI_CS 5 +#define LCD_RST 6 +#define LCD_BL 7 + + +//display mode -- normal / highlight +#define MENU_NORMAL 0 +#define MENU_HIGHLIGHT 1 +#define OFF 0 +#define ON 1 +#define FLAG_TITLE 1 + +class LCD4884 +{ +public: + LCD4884(); + void LCD_init(void); + void backlight(unsigned char dat); + void LCD_write_byte(unsigned char dat, unsigned char dat_type); + void LCD_draw_bmp_pixel(unsigned char X,unsigned char Y,unsigned char *map,unsigned char Pix_x,unsigned char Pix_y); + void LCD_write_string(unsigned char X,unsigned char Y,char *s, char mode = MENU_NORMAL); + void LCD_write_string(char *s, char mode = MENU_NORMAL); + void LCD_write_chinese(unsigned char X, unsigned char Y,unsigned char *c,unsigned char ch_with,unsigned char num,unsigned char line,unsigned char row); + void LCD_write_string_big ( unsigned char X,unsigned char Y, char *string, char mode = MENU_NORMAL); + void LCD_write_char_big (unsigned char X,unsigned char Y, unsigned char ch, char mode = MENU_NORMAL); + void LCD_write_char(unsigned char c, char mode = MENU_NORMAL); + void LCD_set_XY(unsigned char X, unsigned char Y); + void LCD_clear(void); + void LCD_write_title(char* title); + void LCD_putchar(char c); + unsigned char x; +private: + char prev_char; + char char_mode; +}; + +extern LCD4884 lcd; + +#endif // diff --git a/samples/dashboard_4884/dashboard_4884.ino b/samples/dashboard_4884/dashboard_4884.ino new file mode 100644 index 0000000..8c44eeb --- /dev/null +++ b/samples/dashboard_4884/dashboard_4884.ino @@ -0,0 +1,468 @@ +/************************************************************************* +* Sample sketch based on OBD-II library for Arduino +* Using a LCD4884 shield to display realtime vehicle data +* Distributed under GPL v2.0 +* Copyright (c) 2012 Stanley Huang <stanleyhuangyc@gmail.com> +* All rights reserved. +*************************************************************************/ + +#include <Arduino.h> +#include <OBD.h> +#include <LCD4884.h> + +// the following line toggles between hardware serial and software serial +// #define USE_SOFTSERIAL + +#ifdef USE_SOFTSERIAL +#include <SoftwareSerial.h> +SoftwareSerial mySerial(11, 12); // RX, TX +#endif + +//keypad debounce parameter +#define DEBOUNCE_MAX 15 +#define DEBOUNCE_ON 10 +#define DEBOUNCE_OFF 3 + +#define NUM_KEYS 5 +#define NUM_MODES 3 + +// joystick number +#define LEFT_KEY 0 +#define CENTER_KEY 1 +#define DOWN_KEY 2 +#define RIGHT_KEY 3 +#define UP_KEY 4 + +int adc_key_val[5] ={ + 50, 200, 400, 600, 800 }; + +// debounce counters +byte button_count[NUM_KEYS]; +// button status - pressed/released +byte button_status[NUM_KEYS]; +// button on flags for user program +byte button_flag[NUM_KEYS]; +// initial gauge mode +char mode = 0; + +// The followinging are interrupt-driven keypad reading functions +// which includes DEBOUNCE ON/OFF mechanism, and continuous pressing detection + +// Convert ADC value to key number +char get_key(unsigned int input) +{ + char k; + + for (k = 0; k < NUM_KEYS; k++) + { + if (input < adc_key_val[k]) + { + + return k; + } + } + + if (k >= NUM_KEYS) + k = -1; // No valid key pressed + + return k; +} + +void update_adc_key(){ + int adc_key_in; + char key_in; + byte i; + + adc_key_in = analogRead(0); + key_in = get_key(adc_key_in); + for(i=0; i<NUM_KEYS; i++) + { + if(key_in==i) //one key is pressed + { + if(button_count[i]<DEBOUNCE_MAX) + { + button_count[i]++; + if(button_count[i]>DEBOUNCE_ON) + { + if(button_status[i] == 0) + { + button_flag[i] = 1; + button_status[i] = 1; //button debounced to 'pressed' status + } + + } + } + + } + else // no button pressed + { + if (button_count[i] >0) + { + button_flag[i] = 0; + button_count[i]--; + if(button_count[i]<DEBOUNCE_OFF){ + button_status[i]=0; //button debounced to 'released' status + } + } + } + + } +} + +void ShowProgressBarV(byte x, byte y, byte val /* 0~10 */) +{ + byte j = 10 - val; + for (char y1 = j >> 1; y1 >= 0; y1--) { + lcd.LCD_set_XY(x, y1 + y); + for (byte x = 0; x < 14; x++) { + lcd.LCD_write_byte(0, 1); + } + } + if (j & 1 == 1) { + j >>= 1; + lcd.LCD_set_XY(x, y + j); + for (byte x = 0; x < 14; x++) { + lcd.LCD_write_byte(0xE0, 1); + } + j++; + } else { + j >>= 1; + } + for (byte y1 = j; y1 <= 5; y1++) { + lcd.LCD_set_XY(x, y1 + y); + for (byte x = 0; x < 14; x++) { + lcd.LCD_write_byte(0xEE, 1); + } + } +} + +byte CheckPressedKey() +{ + for(int i=0; i<NUM_KEYS; i++){ + if(button_flag[i] !=0){ + button_flag[i]=0; // reset button flag + return i; + } + } + return -1; +} + +// waiting for center key press +void waitfor_OKkey(){ + byte i; + byte key = 0xFF; + update_adc_key(); + while (key!= CENTER_KEY){ + for(i=0; i<NUM_KEYS; i++){ + if(button_flag[i] !=0){ + button_flag[i]=0; // reset button flag + if(i== CENTER_KEY) key=CENTER_KEY; + } + } + } + +} + +class COBDDash : public COBD +{ +public: + void Connect() + { + lcd.LCD_clear(); + lcd.LCD_write_string(0, 0, "Connecting..", MENU_NORMAL); + for (int n = 0; !Init(); n++) { + lcd.LCD_putchar('.'); + if (n == 3) lcd.backlight(OFF); + } + + lcd.backlight(ON); //Turn on the backlight + lcd.LCD_clear(); + lcd.LCD_write_string(0, 0, "Connected!", MENU_NORMAL); + + int value; + lcd.LCD_write_string(0, 1, "Wait ECU start", MENU_NORMAL); + do { + delay(1000); + } while (!ReadSensor(PID_RPM, value)); + lcd.LCD_write_string(0, 2, "ECU started ", MENU_NORMAL); + lcd.LCD_write_string(0, 3, "Wait ignition ", MENU_NORMAL); + do { + delay(100); + } while (!ReadSensor(PID_RPM, value) || value == 0); + lcd.LCD_write_string(0, 4, "Engine started", MENU_NORMAL); + delay(1000); + } + void Loop() + { + unsigned long lastTime = millis(); + + Connect(); + + byte count = 0; + byte key; + DisplayBG(mode); + dataMode = 1; + lcd.backlight(ON); + for (;;) { + update_adc_key(); + key = CheckPressedKey(); + if (key != -1) { + switch (key) { + case CENTER_KEY: + mode = (mode + 1) % NUM_MODES; + DisplayBG(mode); + count = 0; + break; + case LEFT_KEY: + if (mode > 0) { + mode--; + DisplayBG(mode); + count = 0; + } + break; + case RIGHT_KEY: + if (mode < NUM_MODES - 1) { + mode++; + DisplayBG(mode); + count = 0; + } + break; + case UP_KEY: + lcd.backlight(ON); + break; + case DOWN_KEY: + lcd.backlight(OFF); + break; + } + } + if (millis() - lastTime < 250) { + continue; + } + lastTime = millis(); + + switch (mode) { + case 0: + DisplayData1(); + break; + case 1: + DisplayData2(); + switch (count) { + case 0: + DisplayData21(); + break; + case 5: + DisplayData22(); + break; + case 10: + DisplayData23(); + break; + } + break; + case 2: + DisplayData3(); + break; + } + if (errors > 5) { + lcd.backlight(OFF); + return; + } + count++; + } + } +private: + void DisplayData1() + { + if (ReadSensor(PID_RPM, value)) { + ShowRPM(value); + } + if (ReadSensor(PID_SPEED, value)) { + ShowSpeed(value); + } + if (ReadSensor(PID_ENGINE_LOAD, value)) { + ShowEngineLoad(value); + } + } + void DisplayData2() + { + if (ReadSensor(PID_RPM, value)) { + ShowRPM(value); + } + if (ReadSensor(PID_SPEED, value)) { + ShowSpeed2(value); + } + } + void DisplayData21() + { + if (ReadSensor(PID_COOLANT_TEMP, value)) { + ShowTemperature(value, 42, 3); + } + } + void DisplayData22() + { + if (ReadSensor(PID_INTAKE_TEMP, value)) { + ShowTemperature(value, 42, 4); + } + } + void DisplayData23() + { + if (ReadSensor(PID_AMBIENT_TEMP, value)) { + ShowTemperature(value, 42, 5); + } + } + void DisplayData3() + { + if (ReadSensor(PID_SPEED, value)) { + ShowSpeed2(value); + } + if (ReadSensor(PID_INTAKE_PRESSURE, value)) { + char buf[8]; + sprintf(buf, "%3u", value); + lcd.LCD_write_string(24, 4, buf, MENU_NORMAL); + int boost = (value - 101); + if (boost < 0) boost = 0; + sprintf(buf, "%d.%02d", boost / 100, boost % 100); + lcd.LCD_write_string_big(0, 0, buf, MENU_NORMAL); + } + if (ReadSensor(PID_FUEL_PRESSURE, value)) { + char buf[8]; + sprintf(buf, "%3u", value); + lcd.LCD_write_string(24, 5, buf, MENU_NORMAL); + } + } + void ShowEngineLoad(uint8_t value) + { + ShowProgressBarV(70, 1, value / 10); + lcd.LCD_write_string(78, 1, "%", MENU_NORMAL); + } + void ShowRPM(int value) + { + char buf[15]; + if (value <= 9999) { + sprintf(buf, "%4u", value); + lcd.LCD_write_string_big(0, 0, buf, MENU_NORMAL); + lcd.LCD_write_string(48, 2, "R", MENU_NORMAL); + } + } + void ShowSpeed(uint8_t value) + { + char buf[8]; + sprintf(buf, "%3u", value); + lcd.LCD_write_string_big(6, 3, buf, MENU_NORMAL); + lcd.LCD_write_string(42, 5, "k", MENU_NORMAL); + } + void ShowSpeed2(uint8_t value) + { + char buf[8]; + ShowProgressBarV(70, 1, value / 25); + sprintf(buf, "%3u", value); + lcd.LCD_write_string(66, 0, buf, MENU_NORMAL); + lcd.LCD_write_string(66, 1, "kph", MENU_NORMAL); + } + void ShowTemperature(uint8_t value, byte x, byte y) + { + char buf[8]; + sprintf(buf, "%3d", value); + lcd.LCD_write_string(x, y, buf, MENU_NORMAL); + } + void DisplayBG(char mode) + { + lcd.LCD_clear(); + switch (mode) { + case 0: + lcd.LCD_write_string(48, 2, "RPM", MENU_NORMAL); + lcd.LCD_write_string(42, 5, "kph", MENU_NORMAL); + lcd.LCD_write_string(66, 0, "ENG", MENU_NORMAL); + break; + case 1: + lcd.LCD_write_string(48, 2, "RPM", MENU_NORMAL); + lcd.LCD_write_string(0, 3, "COOLANT C", MENU_NORMAL); + lcd.LCD_write_string(0, 4, "INTAKE C", MENU_NORMAL); + lcd.LCD_write_string(0, 5, "AMBIENT C", MENU_NORMAL); + break; + case 2: + lcd.LCD_write_string(48, 2, "bar", MENU_NORMAL); + lcd.LCD_write_string(0, 3, "PRESSURES", MENU_NORMAL); + lcd.LCD_write_string(0, 4, "AIR kpa", MENU_NORMAL); + lcd.LCD_write_string(0, 5, "FUEL kpa", MENU_NORMAL); + break; + } + } +#ifdef USE_SOFTSERIAL + // override data communication functions + bool DataAvailable() { return mySerial.available(); } + char ReadData() + { + char c = mySerial.read(); + Serial.write(c); + return c; + } + void WriteData(const char* s) { mySerial.write(s); } + void WriteData(const char c) { mySerial.write(c); } +#endif + char displayMode; + int value; +}; + +COBDDash obd; + +void loop() +{ + obd.Loop(); +} + +void setup() +{ + + // setup interrupt-driven keypad arrays + // reset button arrays + for(byte i=0; i<NUM_KEYS; i++){ + button_count[i]=0; + button_status[i]=0; + button_flag[i]=0; + } + +#ifdef __AVR_ATmega32U4__ + // Setup timer2 -- Prescaler/256 + TCCR2A &= ~((1<<WGM21) | (1<<WGM20)); + TCCR2B &= ~(1<<WGM22); + TCCR2B = (1<<CS22)|(1<<CS21); + + ASSR |=(0<<AS2); + + // Use normal mode + TCCR2A =0; + //Timer2 Overflow Interrupt Enable + TIMSK2 |= (0<<OCIE2A); + TCNT2=0x6; // counting starts from 6; + TIMSK2 = (1<<TOIE2); + + SREG|=1<<SREG_I; +#endif + + lcd.LCD_init(); + lcd.LCD_clear(); + + lcd.backlight(ON); // Turn on the backlight + + pinMode(13, OUTPUT); + +#ifndef USE_SOFTSERIAL + OBDUART.begin(OBD_SERIAL_BAUDRATE); +#else + Serial.begin(9600); + mySerial.begin(OBD_SERIAL_BAUDRATE); +#endif +} + +// Timer2 interrupt routine - +// 1/(160000000/256/(256-6)) = 4ms interval + +#ifdef __AVR_ATmega32U4__ + +ISR(TIMER2_OVF_vect) { + TCNT2 = 6; + update_adc_key(); +} + +#endif + diff --git a/samples/dashboard_4884/font_6x8.h b/samples/dashboard_4884/font_6x8.h new file mode 100644 index 0000000..cc5855f --- /dev/null +++ b/samples/dashboard_4884/font_6x8.h @@ -0,0 +1,101 @@ +// 6 x 8 font +// 1 pixel space at left and bottom +// index = ASCII - 32 +#include <avr/pgmspace.h> + +unsigned char font6_8[][6] PROGMEM = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // sp + { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 }, // ! + { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 }, // " + { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // # + { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $ + { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 }, // % + { 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 }, // & + { 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 }, // ' + { 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 }, // ( + { 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 }, // ) + { 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 }, // * + { 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 }, // + + { 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 }, // , + { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 }, // - + { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 }, // . + { 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 }, // / + { 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0 + { 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1 + { 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2 + { 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3 + { 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4 + { 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5 + { 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6 + { 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7 + { 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8 + { 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9 + { 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 }, // : + { 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 }, // ; + { 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 }, // < + { 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 }, // = + { 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 }, // > + { 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 }, // ? + { 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E }, // @ + { 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C }, // A + { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B + { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C + { 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D + { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E + { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 }, // F + { 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A }, // G + { 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H + { 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I + { 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J + { 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K + { 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L + { 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // M + { 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N + { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O + { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P + { 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q + { 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R + { 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 }, // S + { 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T + { 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U + { 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V + { 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F }, // W + { 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 }, // X + { 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y + { 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z + { 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 }, // [ + { 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 }, // 55 + { 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 }, // ] + { 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^ + { 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 }, // _ + { 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 }, // ' + { 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 }, // a + { 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b + { 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 }, // c + { 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F }, // d + { 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 }, // e + { 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f + { 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C }, // g + { 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h + { 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i + { 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 }, // j + { 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 }, // k + { 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l + { 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m + { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n + { 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 }, // o + { 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 }, // p + { 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC }, // q + { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r + { 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 }, // s + { 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t + { 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u + { 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v + { 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w + { 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 }, // x + { 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C }, // y + { 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z + { 0x00,0x00, 0x06, 0x09, 0x09, 0x06 } // horiz lines +}; + diff --git a/samples/dashboard_4884/font_big.h b/samples/dashboard_4884/font_big.h new file mode 100644 index 0000000..099a69b --- /dev/null +++ b/samples/dashboard_4884/font_big.h @@ -0,0 +1,141 @@ +// big font +#include <avr/pgmspace.h> + + + +//******* VERY LARGE FONTS ********** +//used here for displaying temperature + +unsigned char big_number[13][3][16] PROGMEM = { + +0,128,192,224,224,96,224,224, //'0' +192,128,0,0,0,0,0,0 +, +112,255,255,1,0,0,0,0, +255,255,254,0,0,0,0,0 +, +0,15,31,60,56,48,56,56, +31,15,3,0,0,0,0,0 +, + +0,0,0,0,128,224,224,0, //'1' +0,0,0,0,0,0,0,0 +, +0,0,3,3,3,255,255,0, +0,0,0,0,0,0,0,0 +, +0,0,56,56,56,63,63,56, +56,56,0,0,0,0,0,0 +, + +0,192,192,224,96,96,224,224, //'2' +192,128,0,0,0,0,0,0 +, +0,1,0,0,128,192,224,249, +63,31,0,0,0,0,0,0 +, +0,60,62,63,63,59,57,56, +56,56,56,0,0,0,0,0 +, + +0,192,224,224,96,96,224,224, //'3' +192,192,0,0,0,0,0,0 +, +0,1,0,0,48,48,56,125, +239,207,0,0,0,0,0,0 +, +0,28,56,56,48,48,56,60, +31,15,1,0,0,0,0,0 +, + +0,0,0,0,0,128,192,224, //'4' +224,0,0,0,0,0,0,0 +, +224,240,248,222,207,199,193,255, +255,192,192,0,0,0,0,0 +, +0,0,0,0,0,0,0,63, +63,0,0,0,0,0,0,0 +, + +0,224,224,224,224,224,224,224, //'5' +224,224,224,0,0,0,0,0 +, +0,63,63,63,56,56,48,112, +240,224,0,0,0,0,0,0 +, +0,28,56,56,48,48,56,60, +31,15,1,0,0,0,0,0 +, + +0,0,128,192,192,224,96,96, //'6' +224,224,0,0,0,0,0,0 +, +224,254,255,55,57,24,24,56, +240,240,192,0,0,0,0,0 +, +0,15,31,28,56,48,48,56, +31,15,7,0,0,0,0,0 +, + +0,224,224,224,224,224,224,224, //'7' +224,224,224,0,0,0,0,0 +, +0,0,0,0,128,224,248,126, +31,7,1,0,0,0,0,0 +, +0,0,56,62,31,7,1,0, +0,0,0,0,0,0,0,0 +, + +0,128,192,224,224,96,96,224, //'8' +192,192,0,0,0,0,0,0 +, +0,207,255,127,56,48,112,112, +255,239,199,0,0,0,0,0 +, +3,15,31,60,56,48,48,56, +31,31,15,0,0,0,0,0 +, + +0,128,192,224,224,96,224,224, //'9' +192,128,0,0,0,0,0,0 +, +12,63,127,241,224,192,192,225, +255,255,254,0,0,0,0,0 +, +0,0,56,48,48,56,56,30, +15,7,0,0,0,0,0,0 +, + + +0,0,0,0,0,0,0,0, //'.' +0,0,0,0,0,0,0,0 +, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0 +, +60,60,60,0,0,0,0,0, +0,0,0,0,0,0,0,0 +, + +0,0,0,0,0,0,0,0, //'+' +0,0,0,0,0,0,0,0 +, +0,0,64,64,64,64,64,254, +254,64,64,64,64,64,0,0 +, +0,0,0,0,0,0,0,15, +15,0,0,0,0,0,0,0 +, + +0,0,0,0,0,0,0,0, //'-' +0,0,0,0,0,0,0,0 +, +0,64,64,64,64,64,64,0, +0,0,0,0,0,0,0,0 +, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0 +}; + diff --git a/samples/dashboard_oled/ZtLib.cpp b/samples/dashboard_oled/ZtLib.cpp new file mode 100644 index 0000000..8eaec6e --- /dev/null +++ b/samples/dashboard_oled/ZtLib.cpp @@ -0,0 +1,603 @@ +/* + ZtLib.cpp - ZT module Drive Library for Wiring & Arduino + Copyright (c) 2012 Alvin Li(Kozig/www.kozig.com). All right reserved. + This library is free software; + 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. + Version:V1.1 +*/ + +extern "C" { + #include <stdlib.h> + #include <string.h> + #include <inttypes.h> + #include "..\Wire\utility/twi.h" +} + +#include "ZtLib.h" + +///ZT.SEG8B4A036A PART///-------------------------------------------------------------------s +unsigned char codetable[] = +{ + 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F, 0x77, 0x7C,0x39,0x5E,0x79,0x71,0x00 +}; + +// Public Methods ////////////////////////////////////////////////////////////// +/* + * Function I2cInit + * Desc TWI/I2C init + * Input none + * Output none + */ +void ZtLib::I2cInit(void) +{ + twi_init(); +} +/* + * Function Seg8b4a036aSleep + * Desc Set ZT.SEG8B4A036A Go to Sleep + * Input addr:ZT.SEG8B4A036A Address + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aSleep(uint8_t addr) +{ + uint8_t buff[5]={REG_SLEEP, SLEEP_ON, 0, 0, 0}; + + return twi_writeTo(addr, buff, 5, 1, 1); +} +/* + * Function Seg8b4a036aUnSleep + * Desc Set ZT.SEG8B4A036A Wait Up From Sleep + * Input addr:ZT.SEG8B4A036A Address + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aUnSleep(uint8_t addr) +{ + uint8_t buff[5]={REG_SLEEP, SLEEP_OFF, 0, 0, 0}; + + return twi_writeTo(addr, buff, 5, 1, 1); +} +/* + * Function Seg8b4a036aReadState + * Desc Read ZT.SEG8B4A036A Status + * Input addr:ZT.SEG8B4A036A Address + * Output !=0xFF ZT.SC-I2CMx Status + * 0xFF .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aReadState(uint8_t addr) +{ + uint8_t state = 0xFF; + uint8_t temp; + uint8_t buff[1] = {REG_STATUS}; + temp = twi_writeTo(addr, buff, 1, 1, 0); // no stop + if (temp ==0) + { + temp = twi_readFrom(addr, buff, 1, 1); + } + if (temp==1) + { + state = buff[0]; + } + + return state; +} +/* + * Function Seg8b4a036aReadVersion + * Desc Read ZT.SEG8B4A036A Fireware Version + * Input addr:ZT.SEG8B4A036A Address + *buf:Version Buffer + * Output .. number bytes of Version Read out + */ +int ZtLib::Seg8b4a036aReadVersion(uint8_t addr, uint8_t *buf) +{ + uint8_t state = 0xFF; + uint8_t temp; + uint8_t regv[1] = {REG_VERSION}; + temp = twi_writeTo(addr, regv, 1, 1, 0); // no stop + if (temp ==0) + { + temp = twi_readFrom(addr, &(*buf), 19, 1); + } + return temp; +} +/* + * Function Seg8b4a036aDisplayDec + * Desc ZT.SEG8B4A036A Display decimal numeral + * Input addr:ZT.SEG8B4A036A Address + val: Display Val + bitnum:Display Bit Number + dotbit: Dot Display + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aDisplayDec(uint8_t addr,unsigned short val, uint8_t bitnum, uint8_t dotbit) +{ + uint8_t i; + uint8_t segnum[5]; + if (val>9999) return 0xFF; + + segnum[0] = REG_DAT; + segnum[1] = val%10; + segnum[2] = (val%100)/10; + segnum[3] = (val/100)%10; + segnum[4] = val/1000; + for (i=1; i<5; i++) + { + segnum[i] = codetable[segnum[i]]; + if (dotbit&0x01) + { + segnum[i] |= 0x80; + } + dotbit >>= 1; + } + + if (bitnum==DISP_0BIT) {segnum[4] = 0;segnum[3] = 0;segnum[2] = 0;segnum[1] = 0;} + else if (bitnum==DISP_1BIT) {segnum[4] = 0;segnum[3] = 0;segnum[2] = 0;} + else if (bitnum==DISP_2BIT) {segnum[4] = 0;segnum[3] = 0;} + else if (bitnum==DISP_3BIT) {segnum[4] = 0;} + else if (bitnum==DISP_AUTO) + { + if (val<10) {segnum[4] = 0;segnum[3] = 0;segnum[2] = 0;} + else if (val<100) {segnum[4] = 0;segnum[3] = 0;} + else if (val<1000) {segnum[4] = 0;} + } + + return twi_writeTo(addr, segnum, 5, 1, 1); +} +/* + * Function Seg8b4a036aDisplayHex + * Desc Read ZT.SEG8B4A036A Display hexadecimal number + * Input addr:ZT.SEG8B4A036A Address + val: Display Val + bitnum:Display Bit Number + dotbit: Dot Display + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aDisplayHex(uint8_t addr,unsigned short val, uint8_t bitnum, uint8_t dotbit) +{ + uint8_t i; + unsigned short temp; + uint8_t segnum[5]; + segnum[0] = REG_DAT; + temp = val; + for (i=1; i<5; i++) + { + segnum[i] = temp&0x000F; + temp >>= 4; + segnum[i] = codetable[segnum[i]]; + if (dotbit&0x01) + { + segnum[i] |= 0x80; + } + dotbit >>= 1; + } + + if (bitnum==DISP_0BIT) {segnum[4] = 0;segnum[3] = 0;segnum[2] = 0;segnum[1] = 0;} + else if (bitnum==DISP_1BIT) {segnum[4] = 0;segnum[3] = 0;segnum[2] = 0;} + else if (bitnum==DISP_2BIT) {segnum[4] = 0;segnum[3] = 0;} + else if (bitnum==DISP_3BIT) {segnum[4] = 0;} + else if (bitnum==DISP_AUTO) + { + if (!(val&0xFFF0)) {segnum[4] = 0;segnum[3] = 0;segnum[2] = 0;} + else if (!(val&0xFF00)) {segnum[4] = 0;segnum[3] = 0;} + else if (!(val&0xF000)) {segnum[4] = 0;} + } + + return twi_writeTo(addr, segnum, 5, 1, 1); +} +/* + * Function Seg8b4a036aSetBrightness + * Desc Set ZT.SEG8B4A036A Brightness + * Input addr:ZT.SEG8B4A036A Address + OnDelay: + OffDelay: + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aSetBrightness(uint8_t addr, uint8_t OnDelay, uint8_t OffDelay) +{ + uint8_t buff[5] = {REG_BRIGHTNESS, OnDelay, OffDelay, 0, 0}; + return twi_writeTo(addr, buff, 5, 1, 1); +} +/* + * Function Seg8b4a036aSetAddress + * Desc Set ZT.SEG8B4A036A New Address + * Input val:ZT.SEG8B4A036A Address New Address + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aSetAddress(uint8_t val) +{ + uint8_t buff[2] = {REG_ADDRESS, val}; + return twi_writeTo(ZTSEG8B4A036A_DADDR, buff, 2, 1, 1); +} +/* + * Function Seg8b4a036aDisplayBuff + * Desc Set ZT.SEG8B4A036A Brightness + * Input addr:ZT.SEG8B4A036A Address + *buf: Display buffer + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::Seg8b4a036aDisplayBuff(uint8_t addr,uint8_t *buf) +{ + uint8_t buff[5]={REG_DAT, buf[0], buf[1], buf[2], buf[3]}; + + return twi_writeTo(addr, buff, 5, 1, 1); +} + + +///ZT.ScI2cMx PART///------------------------------------------------------------------- +/* + * Function ScI2cMxReadState + * Desc Read ZT.SC-I2CMx Status + * Input addr:ZT.SC-I2CMx Address + * Output !=0xFF ZT.SC-I2CMx Status + * 0xFF .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxReadState(uint8_t addr) +{ + uint8_t state = 0xFF; + uint8_t temp; + uint8_t buff[1] = {REG_STATUS}; + temp = twi_writeTo(addr, buff, 1, 1, 0); // no stop + if (temp ==0) + { + temp = twi_readFrom(addr, buff, 1, 1); + } + if (temp==1) + { + state = buff[0]; + } + + return state; +} + +/* + * Function ScI2cMxReadVersion + * Desc Read ZT.SC-I2CMx Fireware Version + * Input addr:ZT.SC-I2CMx Address + *buf:Version Buffer + * Output !=0xFF ZT.SC-I2CMx Status + * othe .. number bytes of Version Read out + */ +int ZtLib::ScI2cMxReadVersion(uint8_t addr, uint8_t *buf) +{ + uint8_t state = 0xFF; + uint8_t temp; + uint8_t regv[1] = {REG_VERSION}; + temp = twi_writeTo(addr, regv, 1, 1, 0); // no stop + if (temp ==0) + { + temp = twi_readFrom(addr, &(*buf), 16, 1); + } + return temp; +} +/* + * Function ScI2cMxSetAddress + * Desc Set ZT.SC-I2CMx New Address + * Input val:ZT.SC-I2CMx Address New Address + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxSetAddress(uint8_t newaddr) +{ + uint8_t buff[2] = {REG_ADDRESS, newaddr}; + return twi_writeTo(ZTSCI2CMX_DADDRESS, buff, 2, 1, 1); +} + +/* + * Function ScI2cMxSetBrightness + * Desc Set ZT.SC-I2CMx Brightness + * Input addr:ZT.SC-I2CMx Address + val: Brightness 0~0xFF + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxSetBrightness(uint8_t addr, uint8_t val) +{ + uint8_t buff[2] = {REG_BRIGHTNESS, val}; + return twi_writeTo(addr, buff, 2, 1, 1); +} +/* + * Function ScI2cMxSetVcomH + * Desc Set ZT.SC-I2CMx VcomH + * Input addr:ZT.SC-I2CMx Address + val: Brightness 0~7 + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxSetVcomH(uint8_t addr, uint8_t val) +{ + uint8_t buff[2] = {REG_VCOMH, val}; + return twi_writeTo(addr, buff, 2, 1, 1); +} + +/* + * Function ScI2cMxDisplay8x16Str + * Desc ZT.SC-I2CMx Display 8x16 English String + * Input addr:ZT.SC-I2CMx Address + page: location page + column: location column + *str: 8X16 English String + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxDisplay8x16Str(uint8_t addr, uint8_t page, uint8_t column, const char *str) +{ + uint8_t i=0; + uint8_t buff[19]; + buff[0] = REG_8X16STR; + buff[1] = page; + buff[2] = column; + i=0; + while ((*str != '\0') && (i<16)) + { + buff[i+3] = (uint8_t)*str++; + i++; + } + return twi_writeTo(addr, buff, i+3, 1, 1); +} +/* + * Function ScI2cMxFillArea + * Desc ZT.SC-I2CMx Fill Area + * Input addr:ZT.SC-I2CMx Address + spage: start page + epage: end page + scolumn: start column + ecolumn: end column + filldata: fill data + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxFillArea(uint8_t addr, uint8_t spage, uint8_t epage,uint8_t scolumn, uint8_t ecolumn,uint8_t filldata) +{ + uint8_t buff[6] = {REG_FILL_AREA, spage, epage, scolumn, ecolumn, filldata}; + return twi_writeTo(addr, buff, 6, 1, 1); +} +/* + * Function ScI2cMxScrollingHorizontal + * Desc ZT.SC-I2CMx Scrolling Horizontal + * Input addr:ZT.SC-I2CMx Address + lr: Scroll direction + spage: start page + epage: end page + frames: Scroll fram + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxScrollingHorizontal(uint8_t addr, uint8_t lr, uint8_t spage, uint8_t epage,uint8_t frames) +{ + uint8_t buff[9] = {REG_CMD, 0x2E, 0x00, spage, frames, epage, 0x00, 0xFF, 0x2F}; + twi_writeTo(addr, buff, 2, 1, 1); + buff[0] = REG_CMD; + buff[1] = lr; + for (int i=0; i<10; i++); + return twi_writeTo(addr, buff, 9, 1, 1); +} +/* + * Function ScI2cMxScrollingHorizontal + * Desc ZT.SC-I2CMx Scrolling Vertical + * Input addr:ZT.SC-I2CMx Address + lr: Scroll direction + rowsfixed: rows fixed + rowsscroll: rows scroll + scrollstep: scroll step + stepdelay: step delay + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxScrollingVertical(uint8_t addr, uint8_t scrollupdown, uint8_t rowsfixed, uint8_t rowsscroll, uint8_t scrollstep, uint8_t stepdelay) +{ + uint8_t buff[6] = {REG_SCROVER, scrollupdown, rowsfixed, rowsscroll, scrollstep, stepdelay}; + return twi_writeTo(addr, buff, 6, 1, 1); +} +/* + * function ScI2cMxScrollingVerticalHorizontal + * Desc Continuous Vertical / Horizontal / Diagonal Scrolling (Partial or Full Screen) + * input : + Sdirection: Scrolling Direction + "0x00" (Vertical & Rightward) + "0x01" (Vertical & Leftward) + spage: Define Start Page Address (Horizontal / Diagonal Scrolling) + epage: Define End Page Address (Horizontal / Diagonal Scrolling) + fixedarea: Set Top Fixed Area (Vertical Scrolling) + scrollarea: Set Vertical Scroll Area (Vertical Scrolling) + frames: Set Time Interval between Each Scroll Step in Terms of Frame Frequency + offset: Set Numbers of Row Scroll per Step (Vertical / Diagonal Scrolling) + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxScrollingVerticalHorizontal(uint8_t addr, uint8_t Sdirection, uint8_t spage, uint8_t epage, uint8_t fixedarea, uint8_t scrollarea, uint8_t offset, uint8_t frames) +{ + uint8_t buff[8] = {REG_SCROVERHOR, Sdirection, spage, epage, fixedarea, scrollarea, offset, frames}; + return twi_writeTo(addr, buff, 8, 1, 1); +} +/* + * Function ScI2cMxDeactivateScroll + * Desc ZT.SC-I2CMx Deactivate Scroll + * Input addr:ZT.SC-I2CMx Address + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxDeactivateScroll(uint8_t addr) +{ + uint8_t buff[2] = {REG_CMD, 0x2E}; + return twi_writeTo(addr, buff, 2, 1, 1); +} + +/* + * Function ScI2cMxReset + * Desc ZT.SC-I2CMx Reset OLED + * Input addr:ZT.SC-I2CMx Address + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxReset(uint8_t addr) +{ + uint8_t buff[2] = {REG_RESET,RESET_OLED}; + return twi_writeTo(addr, buff, 2, 1, 1); +} + +/* + * Function ScI2cMxSetLocation + * Desc Set ZT.SC-I2CMx SetLocation + * Input addr:ZT.SC-I2CMx Address + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +int ZtLib::ScI2cMxSetLocation(uint8_t addr, uint8_t page,uint8_t column) +{ + uint8_t buff[4] = {REG_CMD, (0xB0|page), (column%16), (column/16+0x10)}; + return twi_writeTo(addr, buff, 4, 1, 1); +} +/* + * Function ScI2cMxDisplayDot16x16 + * Desc Set ZT.SC-I2CMx Display 16*16 Dot + * Input addr:ZT.SC-I2CMx Address + page:page + column:column + *str:16*16 Dot Data + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +void ZtLib::ScI2cMxDisplayDot16x16(uint8_t addr, uint8_t page, uint8_t column, const char *str) +{ + uint8_t buff[17]; + buff[0] = REG_DAT; + ScI2cMxSetLocation(addr, page, column); + for (int i=0; i<16; i++) + { + buff[i+1] = str[i]; + } + twi_writeTo(addr, buff, 17, 1, 1); + ScI2cMxSetLocation(addr, page+1, column); + for (int i=0; i<16; i++) + { + buff[i+1] = str[i+16]; + } + twi_writeTo(addr, buff, 17, 1, 1); +} +/* + * Function ScI2cMxDisplayArea + * Desc Set ZT.SC-I2CMx Display Area + * Input addr:ZT.SC-I2CMx Address + spage: start page + epage: end page + scolumn: start column + ecolumn: end column + *pt: Data + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +void ZtLib::ScI2cMxDisplayArea(uint8_t addr, uint8_t spage, uint8_t epage, uint8_t scolumn, uint8_t ecolumn, const char *pt) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t h = 0; + uint8_t w = 0; + uint16_t cnt = 0; + uint8_t buff[32]; + buff[0] = REG_DAT; + + h = epage - spage; + w = ecolumn - scolumn; + + while ( j<h ) + { + ScI2cMxSetLocation(addr, spage + j, scolumn); + uint8_t p=w; + while(p) + { + if(p>=31) + { + for (int n=0; n<31; n++) + { + buff[1+n] = pt[cnt++]; + } + twi_writeTo(addr, buff, 32, 1, 1); + p -= 31; + } + else + { + int n; + for (n=0; n<p; n++) + { + buff[1+n] = pt[cnt++]; + } + twi_writeTo(addr, buff, n+1, 1, 1); + p -= n; + } + } + j++; + } +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +ZtLib ZT; + diff --git a/samples/dashboard_oled/ZtLib.h b/samples/dashboard_oled/ZtLib.h new file mode 100644 index 0000000..b93ccc1 --- /dev/null +++ b/samples/dashboard_oled/ZtLib.h @@ -0,0 +1,127 @@ +/* + ZtLib.cpp - ZT module Drive Library for Wiring & Arduino + Copyright (c) 2012 Alvin Li(Kozig/www.kozig.com). All right reserved. + This library is free software; + 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. + Version:V1.1 +*/ + +#ifndef __ZTLIB_H__ +#define __ZTLIB_H__ + +#include <inttypes.h> + +////////////////// +#define ZTSEG8B4A036A_DADDR 0x51 +#define SET_ADDR 0x61 +#define WRITE_CODE 0xAA +#define WRITE_CMD 0x55 + +#define DOT_NONE (0) +#define DOT_BIT1 (1<<0) +#define DOT_BIT2 (1<<1) +#define DOT_BIT3 (1<<2) +#define DOT_BIT4 (1<<3) + +#define DISP_0BIT (0) +#define DISP_1BIT (1) +#define DISP_2BIT (2) +#define DISP_3BIT (3) +#define DISP_4BIT (4) +#define DISP_AUTO (5) +/////////////////////////////////// + +#define ZTSCI2CMX_DADDRESS 0x51 +// Ä£¿é¼Ä´æÆ÷µØÖ· +#define REG_CMD 0x01 +#define REG_DAT 0x02 +#define REG_RESET 0x03 + #define RESET_OLED 0x06 +#define REG_VERSION 0x1F +#define REG_SLEEP 0x04 + #define SLEEP_ON 0xA5 + #define SLEEP_OFF 0xA1 +#define REG_VCOMH 0x05 +#define REG_STATUS 0x06 + #define STATUS_RUN 0x00 + #define STATUS_RUN 0x00 + #define STATUS_SLEEP 0x01 + #define STATUS_SET_ADDRESS 0x02 + #define STATUS_TEST 0x04 + #define STATUS_BUSY 0x10 + +#define REG_ADDRESS 0x08 +#define REG_BRIGHTNESS 0x0A +#define REG_8X16STR 0x52 +#define REG_OLED_XY 0x60 +#define REG_FILL_AREA 0x61 +#define REG_SCROHOR 0x62 +#define REG_SCROVER 0x63 +#define REG_SCROVERHOR 0x64 + +#define PAGE0 0x00 +#define PAGE1 0x01 +#define PAGE2 0x02 +#define PAGE3 0x03 +#define PAGE4 0x04 +#define PAGE5 0x05 +#define PAGE6 0x06 +#define PAGE7 0x07 + +#define SCROLL_UP 0x01 +#define SCROLL_DOWN 0x00 +#define SCROLL_RIGHT 0x26 +#define SCROLL_LEFT 0x27 +#define SCROLL_VR 0x29 +#define SCROLL_VL 0x2A + +#define FRAMS_2 0x07 +#define FRAMS_3 0x04 +#define FRAMS_4 0x05 +#define FRAMS_5 0x00 +#define FRAMS_25 0x06 +#define FRAMS_64 0x01 +#define FRAMS_128 0x02 +#define FRAMS_256 0x03 + +class ZtLib +{ + private: + + public: + void I2cInit(void); +// Module ZT.SEG8B4A036A FUNCTION + int Seg8b4a036aSleep(uint8_t); + int Seg8b4a036aUnSleep(uint8_t); + int Seg8b4a036aReadState(uint8_t addr); + int Seg8b4a036aReadVersion(uint8_t addr, uint8_t *buf); + int Seg8b4a036aDisplayDec(uint8_t,unsigned short, uint8_t, uint8_t); + int Seg8b4a036aDisplayHex(uint8_t,unsigned short, uint8_t, uint8_t); + int Seg8b4a036aSetBrightness(uint8_t, uint8_t, uint8_t); + int Seg8b4a036aSetAddress(uint8_t); + int Seg8b4a036aDisplayBuff(uint8_t,uint8_t *); +// Module ZT.SC-I2CMx + int ScI2cMxReadState(uint8_t); + int ScI2cMxReadVersion(uint8_t, uint8_t *); + int ScI2cMxSetAddress(uint8_t); + int ScI2cMxSetBrightness(uint8_t, uint8_t); + int ScI2cMxSetVcomH(uint8_t, uint8_t); + int ScI2cMxDisplay8x16Str(uint8_t, uint8_t, uint8_t, const char *); + int ScI2cMxFillArea(uint8_t, uint8_t, uint8_t,uint8_t, uint8_t,uint8_t); + int ScI2cMxScrollingHorizontal(uint8_t, uint8_t, uint8_t, uint8_t,uint8_t); + int ScI2cMxScrollingVertical(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); + int ScI2cMxScrollingVerticalHorizontal(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); + int ScI2cMxDeactivateScroll(uint8_t); + int ScI2cMxReset(uint8_t); + int ScI2cMxSetLocation(uint8_t, uint8_t, uint8_t); + void ScI2cMxDisplayDot16x16(uint8_t, uint8_t, uint8_t, const char *); + void ScI2cMxDisplayArea(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, const char *); +}; + + +extern ZtLib ZT; + +#endif + diff --git a/samples/dashboard_oled/dashboard_oled.ino b/samples/dashboard_oled/dashboard_oled.ino new file mode 100644 index 0000000..96dd460 --- /dev/null +++ b/samples/dashboard_oled/dashboard_oled.ino @@ -0,0 +1,158 @@ +/************************************************************************* +* Sample sketch based on OBD-II library for Arduino +* Using a OLED module to display realtime vehicle data +* Distributed under GPL v2.0 +* Copyright (c) 2013 Stanley Huang <stanleyhuangyc@gmail.com> +* All rights reserved. +*************************************************************************/ + +#include <Arduino.h> +#include <OBD.h> +#include <ZtLib.h> +#include <Wire.h> + +#define OLED_ADDRESS 0x27 +#define LOOP_COUNT 50 + +const char PROGMEM font16x32[][32] = { +{0x00,0xE0,0xF8,0xFC,0xFE,0x1E,0x07,0x07,0x07,0x07,0x1E,0xFE,0xFC,0xF8,0xF0,0x00,0x00,0x07,0x0F,0x3F,0x3F,0x7C,0x70,0x70,0x70,0x70,0x7C,0x3F,0x1F,0x1F,0x07,0x00},/*0*/ +{0x00,0x00,0x00,0x06,0x07,0x07,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x7F,0x7F,0x7F,0x00,0x00,0x00,0x00,0x00,0x00},/*1*/ +{0x00,0x38,0x3C,0x3E,0x3E,0x0F,0x07,0x07,0x07,0xCF,0xFF,0xFE,0xFE,0x38,0x00,0x00,0x00,0x40,0x40,0x60,0x70,0x78,0x7C,0x7E,0x7F,0x77,0x73,0x71,0x70,0x70,0x00,0x00},/*2*/ +{0x00,0x18,0x1C,0x1E,0x1E,0x0F,0xC7,0xC7,0xE7,0xFF,0xFE,0xBE,0x9C,0x00,0x00,0x00,0x00,0x0C,0x1C,0x3C,0x3C,0x78,0x70,0x70,0x70,0x79,0x7F,0x3F,0x1F,0x0F,0x00,0x00},/*3*/ +{0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x1E,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x06,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x7F,0x7F,0x7F,0x7F,0x06,0x06,0x00},/*4*/ +{0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xE7,0xE7,0xE7,0xE7,0xC7,0x87,0x00,0x00,0x00,0x00,0x38,0x78,0x71,0x70,0x70,0x70,0x70,0x70,0x39,0x3F,0x3F,0x1F,0x0F,0x00},/*5*/ +{0x00,0x80,0xE0,0xF0,0xF8,0xFC,0x7F,0x7F,0x6F,0x67,0xE1,0xE1,0xC0,0x80,0x00,0x00,0x00,0x0F,0x1F,0x3F,0x3F,0x78,0x70,0x70,0x70,0x70,0x78,0x3F,0x3F,0x1F,0x0F,0x00},/*6*/ +{0x00,0x07,0x07,0x07,0x07,0x07,0xC7,0xE7,0xF7,0xFF,0x7F,0x3F,0x1F,0x07,0x03,0x01,0x00,0x20,0x38,0x7C,0x7E,0x3F,0x0F,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*7*/ +{0x00,0x00,0x00,0x1C,0xBE,0xFE,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFE,0xBE,0x1C,0x00,0x00,0x00,0x0E,0x3F,0x3F,0x7F,0x71,0x60,0x60,0x60,0x71,0x7F,0x3F,0x3F,0x0F,0x00},/*8*/ +{0x00,0x78,0xFC,0xFE,0xFE,0x8F,0x07,0x07,0x07,0x07,0x8F,0xFE,0xFE,0xFC,0xF8,0x00,0x00,0x00,0x00,0x01,0x43,0x43,0x73,0x7B,0x7F,0x7F,0x1F,0x0F,0x07,0x03,0x00,0x00},/*9*/ +}; + +class COBDDash : public COBD +{ +public: + void Connect() + { + char buf[16]; + + InitScreen(); + for (int n = 1; !Init(); n++) { + sprintf(buf, "Connecting [%d]", n); + if (n <= 20) + DisplayString(buf); + else if (n == 21) + ClearScreen(); // blank screen after a while + } + DisplayString("Connected! "); + + int value; + DisplayString("Wait ECU start", 0 , 2); + do { + delay(500); + } while (!ReadSensor(PID_RPM, value)); + DisplayString("ECU started ", 0 , 4); + delay(500); + DisplayString("Wait ignition ", 0 , 6); + delay(500); + do { + delay(500); + } while (!ReadSensor(PID_RPM, value) || value == 0); + DisplayString("Engine started!", 0 , 6); + delay(1000); + } + void Loop() + { + int value; + byte count = 0; + ClearScreen(); + DisplayString("rpm", 84, 0); + DisplayString("km/h", 84, 3); + for (;;) { + char buf[16]; + + if (count == 0) { + DisplayString("AIR: ", 0, 6); + if (ReadSensor(PID_INTAKE_TEMP, value)) { + sprintf(buf, "%4dC", value); + DisplayString(buf, 11 * 8, 6); + } + } else if (count == LOOP_COUNT / 2) { + DisplayString("ENGINE: ", 0, 6); + if (ReadSensor(PID_COOLANT_TEMP, value)) { + sprintf(buf, "%4dC", value); + DisplayString(buf, 11 * 8, 6); + } + } + if (count < LOOP_COUNT / 2) { + if (ReadSensor(PID_INTAKE_PRESSURE, value)) { + sprintf(buf, "%dkPa ", value); + DisplayString(buf, 5 * 8, 6); + } + } else { + if (ReadSensor(PID_ENGINE_LOAD, value)) { + sprintf(buf, "%d%% ", value); + DisplayString(buf, 8 * 8, 6); + } + } + + if (ReadSensor(PID_RPM, value)) { + sprintf(buf, "%4d", value); + DisplayLargeNumber(buf, 16, 0); + } + + if (ReadSensor(PID_SPEED, value)) { + sprintf(buf, "%3d", value); + DisplayLargeNumber(buf, 32, 3); + } + + if (errors > 5) { + return; + } + count = (count + 1) % LOOP_COUNT; + } + } +private: + void DisplayString(const char* s, char x = 0, char y = 0) + { + ZT.ScI2cMxDisplay8x16Str(OLED_ADDRESS, y, x, s); + } + void DisplayLargeNumber(const char* s, char x = 0, char y = 0) + { + char data[32]; + while (*s) { + if (*s >= '0' && *s <= '9') { + memcpy_P(data, font16x32[*s - '0'], 32); + ZT.ScI2cMxDisplayDot16x16(OLED_ADDRESS, y , x, data); + } else { + ZT.ScI2cMxFillArea(OLED_ADDRESS, y, y + 1, x, x + 16, 0); + } + x += 16; + s++; + } + } + void ClearScreen() + { + ZT.ScI2cMxFillArea(OLED_ADDRESS, 0, 7, 0, 127, 0); + delay(10); + } + void InitScreen() + { + ZT.I2cInit(); + ZT.ScI2cMxReset(OLED_ADDRESS); + delay(10); + ClearScreen(); + } +}; + +COBDDash dash; + +void loop() +{ + dash.Connect(); + dash.Loop(); +} + +void setup() +{ + OBDUART.begin(OBD_SERIAL_BAUDRATE); +} + diff --git a/samples/obdtest/obdtest.ino b/samples/obdtest/obdtest.ino new file mode 100644 index 0000000..27854eb --- /dev/null +++ b/samples/obdtest/obdtest.ino @@ -0,0 +1,243 @@ +#include <Arduino.h> +#include <Wire.h> +#include <MultiLCD.h> +#include <OBD.h> +#include <MPU6050.h> + +#define INIT_CMD_COUNT 8 +#define MAX_CMD_LEN 6 + +const char initcmd[INIT_CMD_COUNT][MAX_CMD_LEN] = {"ATZ\r","ATE0\r","ATL1\r","ATI\r","0100\r","0120\r","0140\r","0145\r"}; + +//SoftwareSerial softSerial(2, 3); // RX, TX + +unsigned int adc_key_val[5] ={30, 150, 360, 535, 760 }; +int NUM_KEYS = 5; +int adc_key_in; +char key=-1; +char oldkey=-1; + +byte index = 0; +uint16_t pid = 0x0145; +int stateMPU6050; + +//create object to control an LCD. +LCD_1602 lcd; + +class COBDTester : public COBD +{ +public: + bool Init(bool passive = false) + { + unsigned long currentMillis; + unsigned char n; + char prompted; + char buffer[OBD_RECV_BUF_SIZE]; + + for (unsigned char i = 0; i < INIT_CMD_COUNT; i++) { + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print(initcmd[i]); + lcd.setCursor(0, 1); + WriteData(initcmd[i]); + n = 0; + prompted = 0; + currentMillis = millis(); + for (;;) { + if (DataAvailable()) { + char c = ReadData(); + if (c == '>') { + buffer[n] = 0; + prompted++; + } else if (n < OBD_RECV_BUF_SIZE - 1) { + buffer[n++] = c; + + if (c == '\r' || c == '\n') + lcd.setCursor(0, 1); + else + lcd.write(c); + } + } else if (prompted) { + break; + } else { + unsigned long elapsed = millis() - currentMillis; + if (elapsed > OBD_TIMEOUT_INIT) { + // init timeout + //WriteData("\r"); + return false; + } + } + } + delay(200); + } + errors = 0; + return true; + } +}; + +COBDTester obd; + +// Convert ADC value to key number +char get_key(unsigned int input) +{ + char k; + for (k = 0; k < NUM_KEYS; k++) { + if (input < adc_key_val[k]) + return k; + } + return -1; +} + +void query() +{ + char buf[17]; + + switch (index) { + case 0: + sprintf(buf, "[%04X]", pid); + break; + case 1: + sprintf(buf, "%03X[%01X]", pid >> 4, pid & 0xf); + break; + case 2: + sprintf(buf, "%02X[%01X]%01X", pid >> 8, (pid >> 4) & 0xf, pid & 0xf); + break; + case 3: + sprintf(buf, "%01X[%01X]%02X", pid >> 12, (pid >> 8) & 0xf, pid & 0xff); + break; + case 4: + sprintf(buf, "[%01X]%03X", pid >> 12, pid & 0xfff); + break; + } + + lcd.setCursor(0, 0); + lcd.print(buf); + + obd.dataMode = (byte)(pid >> 8); + obd.Query((byte)pid); + + if (stateMPU6050 == 0) { + accel_t_gyro_union data; + char buf[20]; + int ret = MPU6050_readout(&data); + if (ret == 0) { + sprintf(buf, "%d/%d/%d", data.value.x_accel, data.value.y_accel, data.value.z_accel); + } else { + sprintf(buf, "6050 error: %d", ret); + } + } +} + +void setup() +{ + lcd.begin(); + pinMode(13, OUTPUT); //we'll use the debug LED to output a heartbeat + digitalWrite(13, LOW); + OBDUART.begin(38400); + digitalWrite(13, HIGH); + + + lcd.clear(); + lcd.print("Init MPU6050..."); + lcd.setCursor(0, 1); + stateMPU6050 = MPU6050_init(); + if (stateMPU6050 == 0) { + lcd.print("Success!"); + } else { + char buf[16]; + sprintf(buf, "Error: %d", stateMPU6050); + lcd.print(buf); + } + delay(1000); + + do { + lcd.clear(); + lcd.print("Init OBD..."); + delay(500); + } while(!obd.Init()); + + char buf[16]; + lcd.setCursor(0, 1); + lcd.print("CONNECTED! "); + delay(1000); + lcd.clear(); + query(); +} + +void loop() +{ + if (Serial.available()) { + char c = Serial.read(); + if (c == '\r' || c == '\n') { + lcd.setCursor(1, 6); + } else if (c == '>') { + lcd.setCursor(15, 0); + lcd.write(c); + lcd.setCursor(1, 6); + query(); + } else { + lcd.write(c); + } + } + + adc_key_in = analogRead(0); // read the value from the sensor + key = get_key(adc_key_in); // convert into key press + if (key != oldkey) { + delay(50); // wait for debounce time + adc_key_in = analogRead(0); // read the value from the sensor + key = get_key(adc_key_in); // convert into key press + if (key != oldkey) + { + oldkey = key; + if (key >=0){ + switch (key) { + case 2: // down key + switch (index) { + case 0: + pid--; + break; + case 1: + pid = (pid & 0xfff0) | (((pid & 0xf) - 1) & 0xf); + break; + case 2: + pid = (pid & 0xff0f) | (((pid & 0xf0) - 0x10) & 0xf0); + break; + case 3: + pid = (pid & 0xf0ff) | (((pid & 0xf00) - 0x100) & 0xf00); + break; + case 4: + pid = (pid & 0x0fff) | (((pid & 0xf000) - 0x1000) & 0xf000); + break; + } + break; + case 1: // up key + switch (index) { + case 0: + pid++; + break; + case 1: + pid = (pid & 0xfff0) | (((pid & 0xf) + 1) & 0xf); + break; + case 2: + pid = (pid & 0xff0f) | (((pid & 0xf0) + 0x10) & 0xf0); + break; + case 3: + pid = (pid & 0xf0ff) | (((pid & 0xf00) + 0x100) & 0xf00); + break; + case 4: + pid = (pid & 0x0fff) | (((pid & 0xf000) + 0x1000) & 0xf000); + } + break; + case 0: // right key + if (index > 0) index--; + break; + case 3: // left key + if (index < 4) index++; + break; + } + lcd.clear(); + query(); + } + } + } +} diff --git a/samples/rpm_led/rpm_led.ino b/samples/rpm_led/rpm_led.ino new file mode 100644 index 0000000..415f119 --- /dev/null +++ b/samples/rpm_led/rpm_led.ino @@ -0,0 +1,31 @@ +/************************************************************************* +* Sample sketch based on OBD-II library for Arduino +* Distributed under GPL v2.0 +* Copyright (c) 2012-2013 Stanley Huang <stanleyhuangyc@gmail.com> +* All rights reserved. +*************************************************************************/ + +#include <Arduino.h> +#include <OBD.h> + +COBD obd; + +void setup() +{ + // we'll use the debug LED as output + pinMode(13, OUTPUT); + // start serial communication at the adapter defined baudrate + OBDUART.begin(OBD_SERIAL_BAUDRATE); + // initiate OBD-II connection until success + while (!obd.Init()); +} + +void loop() +{ + int value; + if (obd.ReadSensor(PID_RPM, value)) { + // RPM is read and stored in 'value' + // light on LED when RPM exceeds 5000 + digitalWrite(13, value > 5000 ? HIGH : LOW); + } +} |