Saturday, June 3, 2017

Library for interfacing AVR microcontrollers with ET16312N VFD (Vacuum Fluorescent Display) driver

I had a broken Philips DVP5960 DVD player and I thought it's a good idea to salvage and use the VFD display in some project. And so this code was born.



Vacuum Fluorescent Display (VFD) from a DVD Player controlled by AVR MCU
Vacuum Fluorescent Display (VFD) from a DVD Player controlled by AVR MCU

To know more about the communication protocol between the microcontroller and the VFD driver chip, visit this post Salvage a VFD from a broken DVD.





Currently supported VFD - Vacuum Fluorescent Display chip drivers by OnVFD:

 

- ET16312N
Supports:
4 digits, 16 segments
5 digits, 16 segments
6 digits, 16 segments
7 digits, 15 segments
8 digits, 14 segments
9 digits, 13 segments
10 digits, 12 segments
11 digits, 11 segments

You only need three pins from the MCU to communicate with the VFD driver: CS, SCLK and DATA. I've described what each one does in the above linked post.

Included functions


void VFDInitialise(void);
- used to initialise the display. This function sets the MCU pins and the number of VFD digits and segments, clears the display and sets the cursor to first digit.

void VFDWriteString(const char *string);
- a function to display string data type
The macro VFDWriteStringPosition(string, position) can be used to write a string to a specific position (only on X axes).

void VFDWriteInt(int16_t number, int8_t nrOfDigits, bool displayColonSymbol);
- a function for displaying int data type.
int16_t number - the first parameter is the number to be displayed
int8_t nrOfDigits - number of digits the number is formed by. If this number is greater than the actual number of digits, the displayed number will be padded with zeros.
bool displayColonSymbol - it can be true or false and indicates whether you want the colon symbol to be displayed or not. Note that the colon is only available at a certain digit position and depends on the type of VFD display.
The macro  VFDWriteIntPosition(number, nrOfDigits, position, displayColonSymbol) can be used to write an int to a specific position (only on X axes).

void VFDClear(void);
- clears the display by writing a space on all the digits and sets the cursor back to position 1.

void VFDSetCursorPosition(uint8_t position);
- accepts a number from 1 to VFD's maximum number of digits. If position is 0 the cursor will be set at the last digit, if the position is greater than the maximum digits the cursor will be set to first digit.
The macro VFDHome() can be used to move the cursor to first digit.

VFDdisplayOn(DIMMING);
- macro. Turn on the display. Dimming parameter can be a number from 0 to 7 - 0 is minimum and 7 is maximum.

VFDdisplayOff();
 - maco. Turns off the display. Key scan continues.

VFDSetBrightness(BRIGHTNESS);
 - macro. Change the display's brightness/dimming. Brightness parameter can be a number from 0 to 7 - 0 is minimum and 7 is maximum.

Functions related to VFD driver chip


uint8_t VFDReadKey(void);
- reads the key matrix and return a byte with the key button that is currently pressed. On my DVD's front panel there are only 4 buttons so they are not really arranged in a full matrix.

uint8_t VFDReadKeyButton(uint8_t delay);
- this function uses the above function to read the key matrix with some functions added. It returns 0 if no button is pressed or the number of the button pressed. In my case the returned byte from the VFD chip driver looks like this 0b0000 0001 if no button is pressed. The first LSB is always 1. If button 1 is pressed the byte is 0b0000 0011, button 2 is 0b0000 0101. So this function counts from the LSB not including the first bit and returns the button number. How the buttons correspond to numbers depends on the board layout.
uint8_t delay - this number depends on the delay time in your code. All this number is used for is to increment a global variable each time the function runs and when the number of the variable match this parameter the function returns the pressed button. Is like debouncing. I didn't add the delay inside the function so the main code doesn't have to wait for this function to terminate. The proper way would be to use an interrupt but this is easier to implement. You could add a 1ms delay in the main loop for example and make the delay equal to 50 and the button will be read every 50 ms.

uint8_t VFDReadSW(void); 
most VFD driver chips include 4-bit general purpose input port and can be used to attach 4 buttons. It returns 1 byte binary data. The first bit represents button 0, second bit button 2, third bit button 3 and fourth bit button 4.

void VFDControlLEDs(uint8_t leds);
- control up to 4 leds. First bit represents led 0 and bit 4 represents led 4. For the VFD driver chip 0 means led ON and 1 means led OFF but the function takes care of bit flipping.


Other extra functions


void VFDdisplayAllFonts(void);
- display all available characters by scrolling them. The speed can be changed by modifying VFD_SCROLL_SPEED.

void VFDscrollText(const char *string);
- pass a string to this function to be scrolled on the display. The speed can be changed by modifying VFD_SCROLL_SPEED. After the function completes, the cursor is set to first digit. Clearing the display is not necessary.

VFDDegreeSymbol();
- macro. Display the degree symbol without C or F.

void VFDBusySpinningCircle(void);
- busy indicator formed by 4 segments at 45 degrees, each one fading behind the other and spinning in circle at the same time at about 1 revolution per second. Text can be displayed in the mean time. Check the video to see it.

void VFDSegmentsTest(void);
- lights up a segment from 1 to 16 every 2 seconds and displays the number. Useful if the screen is not supported by the library and you want to modify the code.

void VFDBlinkUserInput(uint8_t cursorStartPosition, uint8_t length);
- i have made this function for myself and i left it in the code i case someone want to use it and is not too confusing. It is useful for a menu. When the user selects something to modify e.g. time, temperature, etc., you can make a function that enters in a loop until the user presses a button. In that loop you can put this function and the characters at the cursor position will blink showing to the user what is about to modify. If there is a space than an underscore will be blinked. To keep track of the cursor position you can use cursorPositionX because the code will correct for 0 or over the number of digits values.
uint8_t cursorStartPosition - from what position to blink the display.
uint8_t length - how many characters to blink.


How to use OnVFD

Open the OnVFD.h file and in the SETUP section modify the MCU IO replacing the DDR and PORT and PIN data according to your setup.


Then bellow that you have the display configurations.
// VFD Display settings
 
// Number of segments for each digits 
#define VFD_SEGMENTS    15
 
// Number of digits
#define VFD_DIGITS      7

// The scroll speed in milliseconds used by the VFDscrollText function
#define VFD_SCROLL_SPEED  400 // In milliseconds

To save space many extra functions are skipped by the compiler using defines. If you need any of those functions write 1 to that define.

// Write 1 to enable the following functions
#define ENABLE_READ_SW_AND_KEY        0 // Enables functions to read SW and KEYs
#define ENABLE_TEXT_SCROLL            0 // Function for scrolling a text
#define ENABLE_DISPLAY_ALL_FONTS      0 // Display and scroll all available characters
#define ENABLE_MENU_INTERFACE_RELATED 0 // Enables VFDBlinkUserInput function
#define ENABLE_BUSY_INDICATOR         0 // Enables VFDBusySpinningCircle function
#define ENABLE_SEGMENTS_TEST          0 // A function to test segment numbering

Example:
/*************************************************************
 INCLUDES
**************************************************************/
#include "ET16312N.h"

/*************************************************************
 GLOBAL VARIABLES
**************************************************************/
uint8_t hours = 0, minutes = 0, seconds = 0;


/*************************************************************
 FUNCTION PROTOTYPES
**************************************************************/
void displayTime(uint8_t nr_of_loops); 
 
 
/*************************************************************
 MAIN FUNCTION
**************************************************************/
int main(void){
    uint8_t pressedButton = 0, blinkLength = 0, blinkStartPos = 1;
    uint16_t i;
    uint8_t buttonReleased = true;
    bool up = false, down = false, blink = true;
 
    VFDInitialise();

    
    // Display text
    VFDWriteString("ON VFD");
    _delay_ms(5000);
    VFDClear();
 
    // Display time with colon
    // On my VFD display the colon is available when cursor 
    // is on digits 3 and 5. So we start from position 2 and display
    // two digits 21 so digit 1 will be on position 3 and the colon 
    // will be available.
    VFDWriteInt(21, 2, true); // hours
    // Minutes will be 01 even if we pass 1, the second parameter is 2 
    // meaning that two digits will be displayed 01.
    VFDWriteInt(1, 2, true); // minutes
    VFDWriteInt(10, 2, false); // seconds
    _delay_ms(5000);
    VFDClear(); 

    // Dim the display
    VFDscrollText("DIMMING THE DISPLAY TO SAVE POWER");
    VFDSetBrightness(1);
    _delay_ms(2000);
    VFDSetBrightness(7);
    _delay_ms(2000);
 
    // Turn off and on the display
    VFDdisplayOff();
    _delay_ms(3000);
    VFDdisplayOn(7);
 
    // Busy indicator example
    VFDscrollText("BUSY INDICATOR");
    for(i=0; i<8000; i++){
        VFDHome();
        VFDBusySpinningCircle();
        VFDSetCursorPosition(3);
        VFDWriteString("WAIT");
    }
    VFDClear();
    _delay_ms(2000);
 
    displayTime(10);   
    VFDSetCursorPosition(2);
 

    while(1){

 
 
        // The following code is just an example on how to use VFDBlinkUserInput
        // function. Ignore it if you don't need it.
        pressedButton = VFDReadKeyButton(30);
  
        // Next key
        if(pressedButton == 3){
            cursorPositionX++;
     blink = true;
 // Previous key
 }else if(pressedButton == 4){
     cursorPositionX--;
     blink = true;
 }
  
 // Up key
 if(pressedButton == 2 && buttonReleased){
     up = true;
     down = false;
 // Down key
 }else if(pressedButton == 1 && buttonReleased){
     up = false;
     down = true;
 }
  
 
 if(cursorPositionX <= 1){   
     blinkLength = 1;
     blinkStartPos = 1;
 }else if(cursorPositionX <= 3){
     if(up) hours++;
     else if(down) hours--;
   
     if(hours > 23){
  hours = 0;
     }
   
     blinkLength = 2;
     blinkStartPos = 2;
 }else if(cursorPositionX <= 5){
    if(up) minutes++;
    else if(down) minutes--;
   
    if(minutes > 59){
  minutes = 0;
    }
   
    blinkLength = 2;
    blinkStartPos = 4;
 }else if(cursorPositionX <= 7){
    if(up) seconds++;
    else if(down) seconds--;
   
    if(seconds > 59){
        seconds = 0;
    }
  
    blinkLength = 2;
    blinkStartPos = 6;  
 }
  
 if(up || down){
  buttonReleased = false;
  up = false;
  down = false;
  blink = false; // Stop blinking after value is changed
   
  VFDSetCursorPosition(2);  
  VFDWriteInt(hours, 2, false);
  VFDWriteInt(minutes, 2, false);
  VFDWriteInt(seconds, 2, false);
  VFDSetCursorPosition(blinkStartPos);
 }
  
 if(VFDReadKey() == 1) buttonReleased = true;     
  
 if(blink) VFDBlinkUserInput(blinkStartPos, blinkLength);  
    }
}

/*************************************************************
 FUNCTIONS
**************************************************************/
void displayTime(uint8_t nr_of_loops){
 uint8_t i = nr_of_loops;
 
 while(i--){
  VFDSetCursorPosition(2);
  // Display time without colon
  VFDWriteInt(hours, 2, false);
  VFDWriteInt(minutes, 2, false);
  VFDWriteInt(seconds, 2, false);
  _delay_ms(500);
  VFDSetCursorPosition(2);
  // Blink colon every second
  VFDWriteInt(hours, 2, true);
  VFDWriteInt(minutes, 2, true);
  
  seconds++;
  if(seconds > 59){
   seconds = 0;
   minutes++;
  }
  if(minutes > 59){
   minutes = 0;
   hours++;
  }
  
  _delay_ms(500);
 }
}


Download OnVFD library:

ET16312N v1.0


No comments:

Post a Comment

AddToAny

Related Posts Plugin for WordPress, Blogger...