diff --git a/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.cpp b/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.cpp new file mode 100644 index 0000000..e64c54b --- /dev/null +++ b/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.cpp @@ -0,0 +1,295 @@ +// Based on the work by DFRobot upgraded by DVSProductions +#include "LiquidCrystal_I2C.h" +#include +/*********** mid level commands, for sending data/cmds */ +#define COMMAND(value) send(value, 0) +#define printIIC(args) i2c->write(_Addr, args, 1) +size_t LiquidCrystal_I2C::write(uint8_t value) { + send(value, Rs); + return 1; +} + +inline void LiquidCrystal_I2C::command(uint8_t value) { + send(value, 0); +} + +// When the display powers up, it is configured as follows: +// +// 1. Display clear +// 2. Function set: +// DL = 1; 8-bit interface data +// N = 0; 1-line display +// F = 0; 5x8 dot character font +// 3. Display on/off control: +// D = 0; Display off +// C = 0; Cursor off +// B = 0; Blinking off +// 4. Entry mode set: +// I/D = 1; Increment by 1 +// S = 0; No shift +// +// Note, however, that resetting the Arduino doesn't reset the LCD, so we +// can't assume that its in that state when a sketch starts (and the +// LiquidCrystal constructor is called). + +/*! +Creates a new LCD instance +!*/ +LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t lcd_cols, uint8_t lcd_rows, PinName sda, PinName scl) { + _Addr = lcd_Addr << 1; + _cols = lcd_cols; + _rows = lcd_rows; + _backlightval = LCD_NOBACKLIGHT; + i2c = new I2C(sda, scl); + i2c->frequency(1000000); +} + + void LiquidCrystal_I2C::init() { + init_priv(); +} + + void LiquidCrystal_I2C::init_priv() { + _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + begin_priv(); +} +void LiquidCrystal_I2C::begin_priv(uint8_t dotsize) { + if (_rows > 1) { + _displayfunction |= LCD_2LINE; + } + _numlines = _rows; + // for some 1 line displays you can select a 10 pixel high font + if ((dotsize != 0) && (_rows == 1)) { + _displayfunction |= LCD_5x10DOTS; + } + // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! + // according to datasheet, we need at least 40ms after power rises above 2.7V + // before sending commands. Nucleo can turn on way befer 4.5V so we'll wait + // 50 + wait_ms(50); + // Now we pull both RS and R/W low to begin commands + expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1) + wait_ms(1000); + // put the LCD into 4 bit mode + // this is according to the hitachi HD44780 datasheet + // figure 24, pg 46 + + // we start in 8bit mode, try to set 4 bit mode + write4bits(0x03 << 4); + wait_us(4100); // wait min 4.1ms + // second try + write4bits(0x03 << 4); + wait_us(4100); // wait min 4.1ms + // third go! + write4bits(0x03 << 4); + wait_us(150); + // finally, set to 4-bit interface + write4bits(0x02 << 4); + // set # lines, font size, etc. + COMMAND(LCD_FUNCTIONSET | _displayfunction); + // turn the display on with no cursor or blinking default + _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; + display(); + // clear it off + clear(); + // Initialize to default text direction (for roman languages) + _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; + // set the entry mode + COMMAND(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT); + home(); +} +void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { + _cols = cols; + _rows = lines; + begin_priv(); +} + +/********** high level commands, for the user! */ +void LiquidCrystal_I2C::clear() { + COMMAND(LCD_CLEARDISPLAY); // clear display, set cursor position to zero + wait_us(2000); // this command takes a long time! +} + +void LiquidCrystal_I2C::home() { + COMMAND(LCD_RETURNHOME); // set cursor position to zero + wait_us(2000); // this command takes a long time! +} + +void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row) { + int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; + if (row > _numlines) + row = _numlines - 1; // we count rows starting w/0 + COMMAND(LCD_SETDDRAMADDR | (col + row_offsets[row])); +} + +// Turn the display on/off (quickly) +void LiquidCrystal_I2C::noDisplay() { + _displaycontrol &= ~LCD_DISPLAYON; + COMMAND(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal_I2C::display() { + _displaycontrol |= LCD_DISPLAYON; + COMMAND(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns the underline cursor on/off +void LiquidCrystal_I2C::noCursor() { + _displaycontrol &= ~LCD_CURSORON; + COMMAND(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal_I2C::cursor() { + _displaycontrol |= LCD_CURSORON; + COMMAND(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turn on and off the blinking cursor +void LiquidCrystal_I2C::noBlink() { + _displaycontrol &= ~LCD_BLINKON; + COMMAND(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal_I2C::blink() { + _displaycontrol |= LCD_BLINKON; + COMMAND(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// These commands scroll the display without changing the RAM +void LiquidCrystal_I2C::scrollDisplayLeft(void) { + COMMAND(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); +} +void LiquidCrystal_I2C::scrollDisplayRight(void) { + COMMAND(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); +} + +// This is for text that flows Left to Right +void LiquidCrystal_I2C::leftToRight(void) { + _displaymode |= LCD_ENTRYLEFT; + COMMAND(LCD_ENTRYMODESET | _displaymode); +} + +// This is for text that flows Right to Left +void LiquidCrystal_I2C::rightToLeft(void) { + _displaymode &= ~LCD_ENTRYLEFT; + COMMAND(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'right justify' text from the cursor +void LiquidCrystal_I2C::autoscroll(void) { + _displaymode |= LCD_ENTRYSHIFTINCREMENT; + COMMAND(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'left justify' text from the cursor +void LiquidCrystal_I2C::noAutoscroll(void) { + _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; + COMMAND(LCD_ENTRYMODESET | _displaymode); +} + +// Allows us to fill the first 8 CGRAM locations +// with custom characters +void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) { + location &= 0x7; // we only have 8 locations 0-7 + COMMAND(LCD_SETCGRAMADDR | (location << 3)); + for (uint8_t i = 0; i != 8; i++) + write(charmap[i]); +} + +// Turn the (optional) backlight off/on +void LiquidCrystal_I2C::noBacklight(void) { + _backlightval = LCD_NOBACKLIGHT; + expanderWrite(0); +} + +void LiquidCrystal_I2C::backlight(void) { + _backlightval = LCD_BACKLIGHT; + expanderWrite(0); +} + +/************ low level data pushing commands **********/ + +// write either command or data +void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) { + uint8_t highnib = value & 0xf0; + uint8_t lownib = (value << 4) & 0xf0; + write4bits((highnib) | mode); + write4bits((lownib) | mode); +} + +void LiquidCrystal_I2C::write4bits(uint8_t value) { + expanderWrite(value); + pulseEnable(value); +} +char buff; +inline void LiquidCrystal_I2C::expanderWrite(uint8_t _data) { + buff = (_data) | _backlightval; + printIIC(&buff); +} + +void LiquidCrystal_I2C::pulseEnable(uint8_t _data) { + expanderWrite(_data | En); // En high + wait_us(1); // enable pulse must be >450ns + + expanderWrite(_data & ~En); // En low + wait_us(10); // commands need > 37us to settle +} + +// Alias functions + +inline void LiquidCrystal_I2C::cursor_on() { + cursor(); +} + +inline void LiquidCrystal_I2C::cursor_off() { + noCursor(); +} + +inline void LiquidCrystal_I2C::blink_on() { + blink(); +} + +inline void LiquidCrystal_I2C::blink_off() { + noBlink(); +} + +inline void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows) { + createChar(char_num, rows); +} + +void LiquidCrystal_I2C::setBacklight(uint8_t new_val) { + if (new_val) + backlight(); // turn backlight on + else + noBacklight(); // turn backlight off +} + +void LiquidCrystal_I2C::printstr(const char c[]) { + // This function is not identical to the function used for "real" I2C displays + // it's here so the use sketch doesn't have to be changed + print(c); +} + +// unsupported API functions +void LiquidCrystal_I2C::off() { + noBacklight(); +} +void LiquidCrystal_I2C::on() { + begin_priv(); + backlight(); +} +void LiquidCrystal_I2C::setDelay(int cmdDelay, int charDelay) {} +uint8_t LiquidCrystal_I2C::status() { + return 0; +} +uint8_t LiquidCrystal_I2C::keypad() { + return 0; +} +uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype) { + return 0; +} +void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, + uint8_t len, + uint8_t pixel_col_end) { +} +void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, + uint8_t len, + uint8_t pixel_row_end) { +} +void LiquidCrystal_I2C::setContrast(uint8_t new_val) {} diff --git a/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.h b/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.h new file mode 100644 index 0000000..2296ec0 --- /dev/null +++ b/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.h @@ -0,0 +1,127 @@ +// YWROBOT +#ifndef LiquidCrystal_I2C_h +#define LiquidCrystal_I2C_h +#include "Print.h" +#include "mbed.h" +#include + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +// flags for display entry mode +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +#define LCD_8BITMODE 0x10 +#define LCD_4BITMODE 0x00 +#define LCD_2LINE 0x08 +#define LCD_1LINE 0x00 +#define LCD_5x10DOTS 0x04 +#define LCD_5x8DOTS 0x00 + +// flags for backlight control +#define LCD_BACKLIGHT 0x08 +#define LCD_NOBACKLIGHT 0x00 + +#define En 0B00000100 // Enable bit +#define Rw 0B00000010 // Read/Write bit +#define Rs 0B00000001 // Register select bit + +class LiquidCrystal_I2C : public Print { +public: + LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t lcd_cols, uint8_t lcd_rows, + PinName sda, PinName scl); + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); + void clear(); + void home(); + void noDisplay(); + void display(); + void noBlink(); + void blink(); + void noCursor(); + void cursor(); + void scrollDisplayLeft(); + void scrollDisplayRight(); + void printLeft(); + void printRight(); + void leftToRight(); + void rightToLeft(); + void shiftIncrement(); + void shiftDecrement(); + void noBacklight(); + void backlight(); + void autoscroll(); + void noAutoscroll(); + void createChar(uint8_t, uint8_t[]); + void setCursor(uint8_t, uint8_t); + + virtual size_t write(uint8_t); + void command(uint8_t); + void init(); + + ////compatibility API function aliases + void blink_on(); // alias for blink() + void blink_off(); // alias for noBlink() + void cursor_on(); // alias for cursor() + void cursor_off(); // alias for noCursor() + void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight() + void load_custom_character(uint8_t char_num, + uint8_t *rows); // alias for createChar() + void printstr(const char[]); + + ////Unsupported API functions (not implemented in this library) + uint8_t status(); + void setContrast(uint8_t new_val); + uint8_t keypad(); + void setDelay(int, int); + void on(); + void off(); + uint8_t init_bargraph(uint8_t graphtype); + void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, + uint8_t pixel_col_end); + void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, + uint8_t pixel_col_end); + +private: + mbed::I2C *i2c; + void init_priv(); + void begin_priv(uint8_t charsize = LCD_5x8DOTS); + void send(uint8_t, uint8_t); + void write4bits(uint8_t); + void expanderWrite(uint8_t); + void pulseEnable(uint8_t); + uint8_t _Addr; + uint8_t _displayfunction; + uint8_t _displaycontrol; + uint8_t _displaymode; + uint8_t _numlines; + uint8_t _cols; + uint8_t _rows; + uint8_t _backlightval; +}; + +#endif diff --git a/lib/Print/Print.cpp b/lib/Print/Print.cpp new file mode 100644 index 0000000..a66e99c --- /dev/null +++ b/lib/Print/Print.cpp @@ -0,0 +1,230 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + 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 2.1 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 03 August 2015 by Chuck Todd + */ + +#include +#include + +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +/* default implementation: may be overridden */ +size_t Print::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + while (size--) { + if (write(*buffer++)) n++; + else break; + } + return n; +} + +size_t Print::print(const std::string &s) +{ + return write(s.c_str(), s.length()); +} + +size_t Print::print(const char str[]) +{ + return write(str); +} + +size_t Print::print(char c) +{ + return write(c); +} + +size_t Print::print(unsigned char b, int base) +{ + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) +{ + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) +{ + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) +{ + if (base == 0) { + return write(n); + } else if (base == 10) { + if (n < 0) { + int t = print('-'); + n = -n; + return printNumber(n, 10) + t; + } + return printNumber(n, 10); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(unsigned long n, int base) +{ + if (base == 0) return write(n); + else return printNumber(n, base); +} + +size_t Print::print(double n, int digits) +{ + return printFloat(n, digits); +} +size_t Print::println(void) +{ + return write("\r\n"); +} + +size_t Print::println(const std::string &s) +{ + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) +{ + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) +{ + size_t n = print(num, digits); + n += println(); + return n; +} + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) +{ + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if (base < 2) base = 10; + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) +{ + size_t n = 0; + + if (isnan(number)) return print("nan"); + if (isinf(number)) return print("inf"); + if (number > 4294967040.0) return print ("ovf"); // constant determined empirically + if (number <-4294967040.0) return print ("ovf"); // constant determined empirically + + // Handle negative numbers + if (number < 0.0) + { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i 0) { + n += print('.'); + } + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/lib/Print/Print.h b/lib/Print/Print.h new file mode 100644 index 0000000..464b0a4 --- /dev/null +++ b/lib/Print/Print.h @@ -0,0 +1,96 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + 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 2.1 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Print_h +#define Print_h + +#include +#include +#include + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 + +class Print { + private: + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + protected: + inline void setWriteError(int err = 1) { + write_error = err; + } + public: + Print() : + write_error(0) { + } + + int getWriteError() { + return write_error; + } + void clearWriteError() { + setWriteError(0); + } + + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if(str == NULL) + return 0; + return write((const uint8_t *) str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *) buffer, size); + } + // These handle ambiguity for write(0) case, because (0) can be a pointer or an integer + inline size_t write(short t) { return write((uint8_t)t); } + inline size_t write(unsigned short t) { return write((uint8_t)t); } + inline size_t write(int t) { return write((uint8_t)t); } + inline size_t write(unsigned int t) { return write((uint8_t)t); } + inline size_t write(long t) { return write((uint8_t)t); } + inline size_t write(unsigned long t) { return write((uint8_t)t); } + // Enable write(char) to fall through to write(uint8_t) + inline size_t write(char c) { return write((uint8_t) c); } + inline size_t write(int8_t c) { return write((uint8_t) c); } + + size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); + size_t print(const std::string &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(const std::string &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); + + virtual void flush() { /* Empty implementation for backward compatibility */ } +}; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 76b56ac..21ae4b7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,23 @@ #include #include #include - +#include + auto t_controller = PID(1, 1, 0, 2); auto t_sensor = DHT(PC_10, AM2302); -auto led = DigitalOut(PA_5); +auto led = DigitalOut(LED1); +auto lcd = LiquidCrystal_I2C(0x20, 20, 4, I2C_SDA, I2C_SCL); int main() { printf("Start\n"); - t_controller.setInputLimits(10,30); - t_controller.setOutputLimits(0,100); + t_controller.setInputLimits(10, 30); + t_controller.setOutputLimits(0, 100); t_controller.setSetPoint(29); while (true) - { - if (eError::ERROR_NONE != t_sensor.readData()){ + { + if (eError::ERROR_NONE != t_sensor.readData()) + { printf("Error\n"); continue; } @@ -22,7 +25,7 @@ int main() auto h = t_sensor.ReadHumidity(); t_controller.setProcessValue(t); auto c = t_controller.compute(); - printf("T:%3.1f\tH:%3.1f\tCV:%3.1f\n",t,h,c); + printf("T:%3.1f\tH:%3.1f\tCV:%3.1f\n", t, h, c); led = !led; ThisThread::sleep_for(2s); }