Author Topic: NHD Slim OLED Character Display Driver for STM32  (Read 1422 times)

WebMaka

  • Newbie
  • *
  • Posts: 4
  • Karma: 0
    • View Profile
NHD Slim OLED Character Display Driver for STM32
« on: March 24, 2019, 03:27:03 PM »
Thanks to some help from Saurabh Baxi at Newhaven, I was able to create a fully functional Arduino library for the slim OLED character display line. It works beautifully and only needs two lines from the Arduino to the display.

My current project has moved from "doable on an 8-bit MCU" to "needing more program space" to "an 8-bit MCU with enough flash memory costs more than a 32-bit ARM Cortex M0 with more than enough flash." And along with it, I need to drive a Newhaven slim OLED character display.

So I ported my library to STM32/HAL, and here's the first version if anyone else wants to have a go at it. Again, only two lines are required from the MCU and they don't need to be SPI - the driver bit-bangs SPI well enough that the display I'm using (NHD-0420CW) fired right up on the first try.

To use, select two pins and edit four lines in the header file to define the lines. The driver will automatically configure the pins for its use as part of its init process. Also, an include in the header will need to be edited as well.

The code tested successfully on a Nucleo-F070R dev board (STM32F070R), but thanks to using the HAL it should work on pretty much any STM32 MCU. The code was ported in Atollic TrueSTUDIO 9.3 - minimal changes may be required if using another IDE.

Here goes:

newhaven_slim_oled.h:

Code: [Select]
/*
 * Newhaven Display Slim OLED Driver
 * ---------------------------------
 *
 * Base SPI Code by Saurabh Baxi, Applications Engineer at Newhaven Display
 *   International, Inc.
 * Modifications and extensions by Tom Honaker.
 *
 *
 *
 * This is a comprehensive driver for running Newhaven's slim OLED character
 * displays from just about any STM32 MCU with enough free pins to connect to
 * one. The interface being used is SPI, but it's bit-banged on any two pins
 * so there's no requirement to use hardware SPI support.
 *
 * Check the datasheet for your display to wire it to the MCU in SPI mode.
 *
 * In order to save on precious memory, the library uses very little global
 * RAM. Variables are mainly declared inside functions so memory use is far
 * more local than global.
 *
 * The driver was designed and tested against a Newhaven NHD-0420CW-AB3 slim
 * OLED display module connected to a Nucleo-F070RB. The library should work
 * with few changes with any Newhaven slim OLED module and any STM32 MCU,
 * although some unused functions might need to be cut if memory space is at
 * a premium.
 *
 *
 *
 * IMPORTANT NOTE ON STRINGS/CHARS
 *
 * C/C++ strings end in nulls (0x00), but to a LCD or OLED display, character
 * code 0x00 is an actual character. When sending text to the display, remember
 * to NOT send a 0x00 unless displaying character #0 is the desired result!
 *
 *
 *
 * Software License Agreement (BSD License)
 *
 * Copyright (c) 2015-2017 by Newhaven Display International, Inc.
 * Copyright (c) 2017-2019 by Tom Honaker.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */



#ifndef NHD_OLED_DRIVER_H
#define NHD_OLED_DRIVER_H


#include <stdint.h>



// NOTE: Replace this line with the root HAL header for your specific MCU.
#include "stm32f0xx_hal.h"



// Pin Designations
//
// NOTE: EDIT THESE TO SUIT YOUR NEEDS. These pins don't have to be connected
// to an actual SPI module, and in fact it's probably best if they're not.
// The library will bit-bang SPI to the display, and thus doesn't need SPI
// hardware on the MCU.

// Data pin number     __________ - Change this as required.
#define OLED_MOSI_Pin  GPIO_PIN_8

// Data port                _____ - Change this as required.
#define OLED_MOSI_GPIO_Port GPIOB

// Clock pin number    __________ - Change this as required.
#define OLED_CLK_Pin   GPIO_PIN_9

// Clock port               _____ - Change this as required.
#define OLED_CLK_GPIO_Port  GPIOB



void NHD_OLED_begin(uint8_t rows, uint8_t columns);
void NHD_OLED_sendCommand(uint8_t command);
void NHD_OLED_sendData(uint8_t data);
void NHD_OLED_setupDisplaySize(uint8_t rows, uint8_t columns);
void NHD_OLED_setupPins();
void NHD_OLED_setupInit();
void NHD_OLED_displayControl(uint8_t display, uint8_t cursor, uint8_t block);
void NHD_OLED_displayOn();
void NHD_OLED_displayOff();
void NHD_OLED_textClear();
void NHD_OLED_cursorHome();
void NHD_OLED_cursorMoveToRow(uint8_t rowNumber);
void NHD_OLED_textClearRow(uint8_t rowNumber);
void NHD_OLED_shift(uint8_t dc, uint8_t rl);
void NHD_OLED_cursorPos(uint8_t row, uint8_t column);
void NHD_OLED_print_len(char *text, uint8_t len);
void NHD_OLED_print_char(char text);
void NHD_OLED_print_len_pos(char *text, uint8_t len, uint8_t r, uint8_t c);
void NHD_OLED_print_pos(char text, uint8_t r, uint8_t c);
void NHD_OLED_textPrintCentered(char *text, uint8_t length, uint8_t row);
void NHD_OLED_textPrintRightJustified(char *text, uint8_t length, uint8_t row);
void NHD_OLED_textSweep(char *text, uint8_t length, uint8_t row, char leftSweepChar, char rightSweepChar, uint8_t timeDelay);


// Display Geometry
uint8_t OLED_DISP_ROWS;
uint8_t OLED_DISP_COLUMNS;


// SPI Bit-Bang - This procedure shouldn't be called directly.
void NHD_OLED_SPIBitBang(uint8_t data, uint8_t isCommand);


#endif



/*
 * End of file!
 */


(Continued...)

WebMaka

  • Newbie
  • *
  • Posts: 4
  • Karma: 0
    • View Profile
Re: NHD Slim OLED Character Display Driver for STM32
« Reply #1 on: March 24, 2019, 03:28:42 PM »
(Continuing!)


newhaven_slim_oled.c:

Code: [Select]
/*
 * Newhaven Display Slim OLED Driver
 * ---------------------------------
 *
 * See header file for info and license
 *
 */



#include "newhaven_slim_oled.h"



// NHD_OLED_begin
//
// Performs all required initialization steps in a single command.
//
// NOTE: Define pin OLED_MOSI for data, and OLED_CLK for clock, in the
// header file.
//
// Parameters:
//    rows: number of rows/lines on the display.
//    columns: number of columns/characters per line on the display.
//
void NHD_OLED_begin(uint8_t rows, uint8_t columns)
{
NHD_OLED_setupPins();
NHD_OLED_setupDisplaySize(rows, columns);
NHD_OLED_setupInit();
}


// NHD_OLED_SPIBitBang
//
// This function performs a simple send-only SPI connection using any two
// pins on the STM32. These pins don't have to be hardware SPI pins, but do
// have to be available and not used by other hardware like UARTs or ADC
// inputs. Unless helper functions have been removed to reduce memory usage,
// there's no real reason to call this directly.
//
// Parameters:
//   data: uint8_t to send to display
//   isCommand: command/data flag, where 0 = data and !0 = command
//
void NHD_OLED_SPIBitBang(uint8_t data, uint8_t isCommand)
{
uint8_t i, cb;

// If var "isCommand" is zero, we're sending a data uint8_t.
// If it's NON-zero, we're sending a command uint8_t.
if (isCommand == 0)
cb = 0xFA; // Var "data" is just that, data.
else
cb = 0xF8; // Var "data" is a command/control uint8_t.

// Send the command-or-data type specifier...
for (i = 0; i < 8; i++) {
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 0);
HAL_GPIO_WritePin(OLED_MOSI_GPIO_Port, OLED_MOSI_Pin, (cb & 0x80) >> 7);
cb = cb << 1;
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 1);
}

// Then send the lowest 4 bits of the data uint8_t, in little-endian order...
for (i = 0; i < 4; i++) {
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 0);
HAL_GPIO_WritePin(OLED_MOSI_GPIO_Port, OLED_MOSI_Pin, (data & 0x01));
data = data >> 1;
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 1);
}

// Then send four zero bits...
for (i = 0; i < 4; i++) {
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 0);
HAL_GPIO_WritePin(OLED_MOSI_GPIO_Port, OLED_MOSI_Pin, 0);
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 1);
}

// Then send the highest 4 bits of the data uint8_t, in little-endian order...
for (i = 0; i < 4; i++) {
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 0);
HAL_GPIO_WritePin(OLED_MOSI_GPIO_Port, OLED_MOSI_Pin, (data & 0x01));
data = data >> 1;
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 1);
}

// And wrap up the send with four zero bits...
for (i = 0; i < 4; i++) {
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 0);
HAL_GPIO_WritePin(OLED_MOSI_GPIO_Port, OLED_MOSI_Pin, 0);
HAL_GPIO_WritePin(OLED_CLK_GPIO_Port, OLED_CLK_Pin, 1);
}
}


// NHD_OLED_sendCommand
//
// Provides an alternative means to send a command byte to the display.
//
// Parameters:
//   command: command uint8_t to send.
//
void NHD_OLED_sendCommand(uint8_t command)
{
NHD_OLED_SPIBitBang(command, 1);

HAL_Delay(1);
}


// NHD_OLED_sendData
//
// Provides an alternative means to send a data byte to the display.
//
// Parameters:
//   data: command uint8_t to send.
//
void NHD_OLED_sendData(uint8_t data)
{
NHD_OLED_SPIBitBang(data, 0);
}


// NHD_OLED_setupDisplaySize
//
// Instructs this driver on the geometry of the display, in row and column
// count. For example, a 16-character x 2-line display would be a rows value
// of 2 and a columns value of 16.
//
// Parameters:
//    rows: number of rows/lines on the display.
//    columns: number of columns/characters per line on the display.
//
void NHD_OLED_setupDisplaySize(uint8_t rows, uint8_t columns)
{
OLED_DISP_ROWS = rows;
OLED_DISP_COLUMNS = columns;
}


// NHD_OLED_setupPins
//
// Configures pins for driving the display. Note that these don't have to be
// hardware SPI - any two available pins should work as long as they're not
// doing something else.
//
// Parameters:
//    NONE. Define pin OLED_MOSI for data and OLED_CLK for clock in the header file.
//
void NHD_OLED_setupPins()
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };

GPIO_InitStruct.Pin = OLED_MOSI_Pin | OLED_CLK_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

HAL_Delay(50);
}


// NHD_OLED_setupInit
//
// Initializes and configures the display. Note that the command set provided
// below is for Newhaven's slim OLED line, and individual products may require
// different settings.
//
void NHD_OLED_setupInit()
{
// Internal voltage regulator configuration
NHD_OLED_sendCommand(0x2A); // Function set select > extended command set enable (RE = 1)
NHD_OLED_sendCommand(0x71);     // Internal Vdd regualtor control (function selection A) - command
NHD_OLED_sendData(0x5C);        // Internal Vdd regualtor control (function selection A) - value

// Display off
NHD_OLED_sendCommand(0x28); // Function set select > fundamental (default) command set (RE = 0)
NHD_OLED_sendCommand(0x08);     // Display off, cursor off, blink off

// Timing configuration
NHD_OLED_sendCommand(0x2A); // Function set select > extended command set enable (RE = 1)
NHD_OLED_sendCommand(0x79); // Function set select > OLED command set enable (SD = 1)
NHD_OLED_sendCommand(0xD5); // Set display clock divide ratio/oscillator frequency - command
NHD_OLED_sendCommand(0x70); // Set display clock divide ratio/oscillator frequency - value
NHD_OLED_sendCommand(0x78);     // Function set > OLED command set disable (SD = 0)

// Row count configuration
NHD_OLED_sendCommand(0x28); // Function set select > fundamental (default) command set (RE = 0)
if (OLED_DISP_ROWS < 3) {
NHD_OLED_sendCommand(0x08); // Set row/line count (extended function set) - 1-/2-lines
if (OLED_DISP_ROWS == 1)
NHD_OLED_sendCommand(0x20); // Set row/line count (extended function set) - 1 line
else
NHD_OLED_sendCommand(0x28); // Set row/line count (extended function set) - 2 lines
} else {
NHD_OLED_sendCommand(0x09); // Set row/line count (extended function set) - 3-/4-lines
if (OLED_DISP_ROWS == 3)
NHD_OLED_sendCommand(0x20); // Set row/line count (extended function set) - 3 lines
else
NHD_OLED_sendCommand(0x28); // Set row/line count (extended function set) - 4 lines
}

// CGROM select configuration
NHD_OLED_sendCommand(0x2A); // Function set select > extended command set enable (RE = 1)
NHD_OLED_sendCommand(0x72);     // CGROM selection (function selection B) - command
NHD_OLED_sendData(0x00);        // CGROM selection (function selection B) - value

// Segment control configuration
NHD_OLED_sendCommand(0x06);  // Direction control - Incrementing-COM/decrementing-SEG
NHD_OLED_sendCommand(0x20);     // Display order - Normal (non-mirrored)

// Internal hardware configuration
NHD_OLED_sendCommand(0x79); // Function set select > OLED command set enable (SD = 1)
NHD_OLED_sendCommand(0xDA);     // SEG pins hardware configuration - command
NHD_OLED_sendCommand(0x10); // SEG pins hardware configuration - value - NOTE: Some displays require 0x00 here.
NHD_OLED_sendCommand(0xDC);    // VSL & GPIO control (function selection C) - command
NHD_OLED_sendCommand(0x00);     // VSL & GPIO control (function selection C) - value
NHD_OLED_sendCommand(0x81);     // Contrast control - command
NHD_OLED_sendCommand(0x7F);     // Contrast control - value
NHD_OLED_sendCommand(0xD9);     // Phase length - command
NHD_OLED_sendCommand(0xF1);     // Phase length - value
NHD_OLED_sendCommand(0xDB);     // VCOMH deselect level - command
NHD_OLED_sendCommand(0x40);     // VCOMH deselect level - value
NHD_OLED_sendCommand(0x78); // Function set select > OLED command set disable (SD = 0)

// Wrapping up and switching on
NHD_OLED_sendCommand(0x28); // Function set select > fundamental (default) command set (RE = 0)
NHD_OLED_sendCommand(0x01);     // Clear display
NHD_OLED_sendCommand(0x80);   // Set DDRAM address to 0x00 (home on topmost row/line)
NHD_OLED_sendCommand(0x0C);     // Display ON

HAL_Delay(100);
}


// NHD_OLED_displayControl
//
// En/disables the entire display, the cursor, and whether the cursor is a
// flashing block.
//
// Parameters:
//   display: display on/off - non-zero for "on."
//   cursor: cursor on/off - non-zero for "on."
//   block: cursor block/line - non-zero for block.
//
void NHD_OLED_displayControl(uint8_t display, uint8_t cursor, uint8_t block)
{
uint8_t value = 0x08;

if (display != 0)
value = value + 4;

if (cursor != 0)
value = value + 2;

if (block != 0)
value = value + 1;

NHD_OLED_sendCommand(value);
}


// NHD_OLED_displayOn
//
// Switches the entire display on. Cursor and blink are disabled - to enable
// these, use the displayControl() function.
//
void NHD_OLED_displayOn()
{
NHD_OLED_sendCommand(0x0C);
HAL_Delay(10);
}


//NHD_OLED_dispOff
//
// Switches the entire display off.
//
void NHD_OLED_displayOff()
{
NHD_OLED_sendCommand(0x08);
HAL_Delay(10);
}


// NHD_OLED_textClear
//
// Sends a "clear" command to the display.
//
void NHD_OLED_textClear()
{
NHD_OLED_sendCommand(0x01);
HAL_Delay(10);
}


// NHD_OLED_cursorHome
//
// Sends a "home" command to the display, which moves the cursor without
// removing text from the display.
//
void NHD_OLED_cursorHome()
{
NHD_OLED_sendCommand(0x02);
HAL_Delay(10);
}


// NHD_OLED_cursorMoveToRow
//
// Move cursor to start of selected line.
//
// Parameters:
//   rowNumber: row/line number to move to (zero-indexed, where 0 is topmost).
//
void NHD_OLED_cursorMoveToRow(uint8_t rowNumber)
{
uint8_t row_command[4] = { 0x80, 0xA0, 0xC0, 0xE0 };

NHD_OLED_sendCommand(row_command[rowNumber]);
HAL_Delay(10);
}


// NHD_OLED_textClearRow
//
// Clears a line on the display by writing spaces to the entire row/line.
//
// Parameters:
//   rowNumber: row/line number to clear (zero-indexed, where 0 is topmost).
//
void NHD_OLED_textClearRow(uint8_t rowNumber)
{
char temp[OLED_DISP_COLUMNS];

for (int i = 0; i < OLED_DISP_COLUMNS; i++)
temp[i] = 0x20;

NHD_OLED_cursorMoveToRow(rowNumber);
NHD_OLED_print_len(temp, OLED_DISP_COLUMNS);
}


// NHD_OLED_shift
//
// Shifts the cursor or the displayed text one position right or left.
//
// Parameters:
//   dc: display or cursor - non-zero for display.
//   rl: direction right/left - non-zero for right.
//
void NHD_OLED_shift(uint8_t dc, uint8_t rl)
{
uint8_t value = 0x10;

if (dc != 0)
value = value + 8;

if (rl != 0)
value = value + 4;

NHD_OLED_sendCommand(value);
}


// NHD_OLED_cursorPos
//
// Moves the cursor to the given column on the given row/line.
//
// Parameters:
//   row: row/line number (0-1/2/3).
//   column: column number (0-16/20).
//
void NHD_OLED_cursorPos(uint8_t row, uint8_t column)
{
uint8_t row_command[4] = { 0x80, 0xA0, 0xC0, 0xE0 };

if (row >= OLED_DISP_ROWS)
row = OLED_DISP_ROWS - 1;
if (column >= OLED_DISP_COLUMNS)
column = OLED_DISP_COLUMNS - 1;

NHD_OLED_sendCommand(row_command[row] + column);
}

// NHD_OLED_print_len
//
// Sends text to the display to be, well, displayed. Note that the text is
// printed from the current cursor position, so calling NHD_OLED_home(),
// NHD_OLED_pos(), or NHD_OLED_cursorMoveToLine() functions first would
// probably be a good idea.
//
// Parameters:
//   text: text to display. This should be a full string if a length is
//         provided.
//   len: length of text to print, in characters.
//
void NHD_OLED_print_len(char *text, uint8_t len)
{
for (uint8_t i = 0; i < len; i++)
NHD_OLED_sendData(text[i]);
}


// NHD_OLED_print_char
//
// Sends a single character to the display. No length parameter is needed.
// Again, printing happens where the cursor is positioned.
//
// Parameters:
//   text: text to display. This must be a single character.
//
void NHD_OLED_print_char(char text)
{
NHD_OLED_sendData(text);
}


// NHD_OLED_print_len_pos
//
// This print subroutine accepts row/line and column numbers (zero-indexed -
// 0, 0 is home) and moves the cursor to the given position before
// printing the supplied text.
//
// Parameters:
//   text: text to display. This should be a full string.
//   len: length of text to print, in characters.
//   r: row/line number (0-1/2/3).
//   c: column number (0-16/20).
//
// ADDITIONAL USAGE NOTES:
//
// To right-justify text, determine the length of the text, e.g., with
// sizeof(text), and use (DISP-COLUMNS - length) as the column number.
//
// To center text, use ((DISP-COLUMNS - length) / 2) as the column number.
//
// In either of the above usage cases, clearing the line with NHD_OLED_clear()
// before printing text may be desirable.
//
void NHD_OLED_print_len_pos(char *text, uint8_t len, uint8_t r, uint8_t c)
{
NHD_OLED_cursorPos(r, c);

for (uint8_t i = 0; i < len; i++)
NHD_OLED_sendData(text[i]);
}


// NHD_OLED_print_pos
//
// This print subroutine accepts row/line and column numbers (zero-indexed -
// 0, 0 is home) and moves the cursor to the given position before printing
// the supplied character. Only one character is printed - no length
// parameter is needed.
//
// Parameters:
//   text: text to display. This must be a single character.
//   r: row/line number (0-1/2/3).
//   c: column number (0-16/20).
//
void NHD_OLED_print_pos(char text, uint8_t r, uint8_t c)
{
NHD_OLED_cursorPos(r, c);

NHD_OLED_sendData(text);
}


// NHD_OLED_textPrintCentered
//
// Prints the supplied text, centered, on the selected row/line. The row/line
// is cleared before printing.
//
// Parameters:
//   text: text to display. This should be a full string.
//   length: length of text to print, in characters.
//   row: row/line number (0-1/2/3).
//
void NHD_OLED_textPrintCentered(char *text, uint8_t length, uint8_t row)
{
uint8_t i;
char line[OLED_DISP_COLUMNS];

// Clear the text buffer.
for (i = 0; i < OLED_DISP_COLUMNS; i++)
line[i] = 0x20;

// Copy text into buffer, centering it relative to the line's width.
for (i = 0; i < length; i++)
line[((OLED_DISP_COLUMNS - length) / 2) + i] = text[i];

// Clear the line.
NHD_OLED_textClearRow(row);

// Move the cursor to the row/line.
NHD_OLED_cursorMoveToRow(row);

// Print the centered text.
NHD_OLED_print_len(line, OLED_DISP_COLUMNS);
}


// NHD_OLED_textPrintRightJustified
//
// Prints the supplied text, right-justified, on the selected row/line. The
// row/line is cleared before printing.
//
// Parameters:
//   text: text to display. This should be a full string.
//   length: length of text to print, in characters.
//   row: row/line number (0-1/2/3).
//
void NHD_OLED_textPrintRightJustified(char *text, uint8_t length, uint8_t row)
{
uint8_t i;
char line[OLED_DISP_COLUMNS];

// Clear the text buffer.
for (i = 0; i < OLED_DISP_COLUMNS; i++)
line[i] = 0x20;

// Copy text into buffer, centering it relative to the line's width.
for (i = 0; i < length; i++)
line[(OLED_DISP_COLUMNS - length) + i] = text[i];

// Clear the row/line.
NHD_OLED_textClearRow(row);

// Move the cursor to the row/line.
NHD_OLED_cursorMoveToRow(row);

// Print the centered text.
NHD_OLED_print_len(line, OLED_DISP_COLUMNS);
}


// NHD_OLED_textSweep
//
// Performs a simple animation that sweeps two characters into the center from
// the outermost columns, then back outward, drawing centered text between
// them as they separate. It's a simple but surprisingly eye-catching effect.
//
// Parameters:
//   text: text to display.
//         Note that this should be equal to or less than OLED_DISP_COLUMNS in
//         character count, or unexpected results like garbled wrapping text
//         can ensue.
//   length: length of text to print, in characters.
//   row: row/line number (0-1/2/3).
//   leftSweepChar: left-to-right sweep character.
//   rightSweepChar: right-to-left sweep character.
//   time_delay: time delay between steps (in milliseconds).
//
void NHD_OLED_textSweep(char *text, uint8_t length, uint8_t row,
    char leftSweepChar, char rightSweepChar,
                uint8_t time_delay)
{
uint8_t stepnum = 0;
uint8_t outer, inner, start;
uint8_t i, ii;
char line[OLED_DISP_COLUMNS];

// Clear the text buffer.
for (i = 0; i < OLED_DISP_COLUMNS; i++)
line[i] = 0x20;

// Copy text into buffer, centering it relative to the line's width.
for (i = 0; i < length; i++)
line[((OLED_DISP_COLUMNS - length) / 2) + i] = text[i];

// Time to do work. First things first: clear the line we'll print to.
NHD_OLED_textClearRow(row);

// The first half of the process: sweep into the center.
for (i = 0; i < (OLED_DISP_COLUMNS / 2); i++) {
NHD_OLED_cursorMoveToRow(row);

// Work out some starting positions and widths.
outer = stepnum;
inner = OLED_DISP_COLUMNS - 2 - (stepnum * 2);
start = stepnum + 2;

// Print leading spaces to pad the start of the line...
for (ii = 0; ii < outer; ii++)
NHD_OLED_print_char(0x20);

// ... then print the left-to-right character...
NHD_OLED_print_char(leftSweepChar);

// ... followed by spaces in the middle...
for (ii = 0; ii < inner; ii++)
NHD_OLED_print_char(0x20);

// ... then the right-to-left character...
NHD_OLED_print_char(rightSweepChar);

// ... and finish with more spaces to clear the rest of the line.
for (ii = 0; ii < outer; ii++)
NHD_OLED_print_char(0x20);

HAL_Delay(time_delay);

stepnum++;
}

// Decrement the step number so things stay properly aligned.
stepnum--;

// The second half: sweep out from the center, leaving text behind.
for (i = (OLED_DISP_COLUMNS / 2); i < OLED_DISP_COLUMNS; i++) {
NHD_OLED_cursorMoveToRow(row);

// More starts and widths.
outer = stepnum;
inner = OLED_DISP_COLUMNS - 2 - (stepnum * 2);
start = stepnum + 1;

// This pass is similar to the first, starting with padding...
for (ii = 0; ii < outer; ii++)
NHD_OLED_print_char(0x20);

// ... then the right-to-left character, as though it passed through its
// opposite...
NHD_OLED_print_char(rightSweepChar);

// ... then the centermost part of the text...
for (ii = 0; ii < inner; ii++)
NHD_OLED_print_char(line[start + ii]);

// ... then the left-to-right character...
NHD_OLED_print_char(leftSweepChar);

// ... then spaces to clear the line.
for (ii = 0; ii < outer; ii++)
NHD_OLED_print_char(0x20);

HAL_Delay(time_delay);

stepnum--;
}

// Finish by printing the text by itself with no side-to-side characters.
NHD_OLED_cursorMoveToRow(row);
NHD_OLED_print_len(line, OLED_DISP_COLUMNS);
}


/*
 * End of file!
 */

Ted_M

  • Administrator
  • Full Member
  • *****
  • Posts: 132
  • Karma: 5
    • View Profile
Re: NHD Slim OLED Character Display Driver for STM32
« Reply #2 on: March 25, 2019, 09:25:51 AM »
Thanks for your contribution!
This will be very useful for many users.

Best Regards,

 

Blank Display on NHD‐C0220BiZ‐FS(RGB)‐FBW‐3VM

Started by SteveCBoard Character LCDs

Replies: 3
Views: 11366
Last post May 13, 2014, 12:04:36 AM
by SteveC
Display NHD-4.3-480272EF-ASXN#-T and NHD-4.3-480272EF-ASXN#-T revA

Started by rvalorBoard TFTs

Replies: 1
Views: 1229
Last post April 25, 2019, 03:35:10 PM
by Ted_M
NHD‐C12864A1Z‐FSW‐FBW‐HTT display clears after draw

Started by EdAverillBoard Graphic LCDs

Replies: 6
Views: 13569
Last post November 07, 2014, 08:25:20 AM
by Michael_L
NHD‐4.3‐480272EF‐ATXL#‐CTP | FAN5333 | BBB | Nothing on the Display

Started by Alias_AliasBoard TFTs

Replies: 1
Views: 9962
Last post September 25, 2015, 03:09:24 PM
by Paul_B
Arduino LCD library not working with newhaven display NHD‐0420H1Z‐FL‐GWB-3V3

Started by c2hollowBoard Character LCDs

Replies: 9
Views: 20427
Last post July 10, 2014, 08:46:06 AM
by Michael_L