前言

一直看别人搞的 vfd 很漂亮,前段时间淘了个 vfd 模块来,但没有模块资料,还好芯片没有打磨的,良心商家啊。周末抽空来研究一下这个东西。

从零开始

打开外壳

测试线路

  1. 查看芯片是 HT16514,去搜索到芯片手册(博客没有找到上传附件的功能,不然肯定要放一个附件的)
  2. 根据芯片手册的引脚图,测试插针与引脚的电阻,从而确定每个引脚的功能
  3. 测试后发现用的是 M68 并行接口方式,而且电路上没有做跳线开关调整功能,要是串行该多好啊,这并行接口岂不是要用光 arudino uno 的引脚了。不过反正是试着驱动它,是串行还是并行都一样,以后真有需要再改硬件
  4. 下面就是根据芯片手册来写驱动程序了
    查看电平稳定时间都是用 ns 做单位的,对于 arduino 的执行效率来说应该是不需要考虑这个问题,因此驱动程序里没有加上延时处理,如果哪天用的板子速度太快,执行结果不正常的话,那就需要考虑加上延时了。

驱动编写

最主要就是根据时序图,及命令表来设置每个引脚的电平高低,以及电平变化时间,这就完成了:

驱动程序

没有找到上传附件的功能,那就把程序完整贴出来喽。

把驱动写成一个类的形式,方便使用。并行接口有 8 位和 4 位两种模式,用不同的构造函数来初始化实例来实现两种模式的区分。8 位模式的话,反正都要用这么多引脚了,直接使用 uno 的 PORTD 来当数据 IO 口,方便写程序操作,但下载程序的时候要注意拔掉 0 1 两脚接线以免下载失败。

头文件:

// ----------------------------------------------------------------------------
// driverHT16514Parallel.h
//
// Created 2015-07-04
// By seesea <seesea2517#gmail#com>
//
// HT16514 并行驱动
// 根据当前需要只实现部分功能
// ---------------------------------------------------------------------------- #ifndef _DRIVERHT16514PARALLEL_H_
#define _DRIVERHT16514PARALLEL_H_ #include <arduino.h> #define DATA_PORT PORTD
#define DDR_PORT DDRD class HT16514Parallel
{
private:
char RW; // RW
char E; // E
char RS; // RS
char dataPins[]; // 四位数据线的时候使用的引脚,数据引脚存放顺序由高到低,即 0:DB7 ... 3:DB4
static const byte dataPinMask[]; // 四位数据线时使用的引脚掩码 bool isDisplayOn; // 显示是否打开,是的话 true
bool isBlink; // 是否开启闪烁,是的话 true
bool isShowCursor; // 是否显示光标,是的话 true char dataLength; // 数据长度,使用 PORTD 的时候是 8 位,使用四位数据线的时候是 4 位
char rowNumber; // 显示器行数 char curRow; // 输出位置之当前行
char curCol; // 输出位置之当前列 public:
HT16514Parallel(char _RW, char _E, char _RS); // 构造函数,使用 PORTD 来做数据输出
HT16514Parallel(char _RW, char _E, char _RS, // 构造函数,使用四位并行方式,用指定的四个引脚来做数据输出
char D7, char D6, char D5, char D4); void sendCommand(byte cmd); // 发送命令
void sendData(byte data); // 发送数据 void init(char dl); // 初始化模块数据
void initDisplay(); // 初始化显示屏
void clear(); // 清屏
void moveCursorHome(); // 光标回左上角
void displayOn(); // 显示开
void displayOff(); // 显示关
void blinkOnCursor(); // 光标闪烁开
void blinkOffCursor(); // 光标闪烁关
void showCursor(); // 显示光标
void hideCursor(); // 隐藏光标
void shiftLeftDisplay(); // 左移显示内容
void shiftRightDisplay(); // 右移显示内容
void shiftLeftCursor(); // 左移光标
void shiftRightCursor(); // 右移光标
void setBrightLevel(char level); // 设置亮度,共有四级:0 级最亮,4 级最暗
void putChar(char ch, char row = -, char col = -); // 于指定位置显示指定字符,不指定位置则在当前位置显示
void print(char *str, char row = -, char col = -); // 于指定位置显示指定字符串,不指定位置则在当前位置显示
}; #endif

类实现文件:

// ----------------------------------------------------------------------------
// driverHT16514Parallel.cpp
//
// Created 2015-07-04
// By seesea <seesea2517#gmail#com>
//
// HT16514 并行驱动
// 根据当前需要只实现部分功能
// ---------------------------------------------------------------------------- #include "driverHT16514Parallel.h" const byte HT16514Parallel::dataPinMask[] = { 0x80, 0x40, 0x20, 0x10 }; // 构造函数
HT16514Parallel::HT16514Parallel(char _RW, char _E, char _RS)
{
RW = _RW;
E = _E;
RS = _RS; init();
} // 构造函数,使用四位并行方式,用指定的四个引脚来做数据输出
HT16514Parallel::HT16514Parallel(char _RW, char _E, char _RS, char D7, char D6, char D5, char D4)
{
RW = _RW;
E = _E;
RS = _RS; dataPins[] = D7;
dataPins[] = D6;
dataPins[] = D5;
dataPins[] = D4; init();
} // 发送命令给 HT16514
void HT16514Parallel::sendCommand(byte cmd)
{
char i; digitalWrite(RS, LOW);
digitalWrite(RW, LOW); if (dataLength == )
{
digitalWrite(E, HIGH);
DATA_PORT = cmd;
digitalWrite(E, LOW);
}
else
{
// 先写高四位
digitalWrite(E, HIGH);
for (i = ; i < ; ++i)
{
digitalWrite(dataPins[i], ((dataPinMask[i] & cmd) ? HIGH : LOW));
}
digitalWrite(E, LOW); // 低四位移高四位后,同上操作
cmd <<= ;
digitalWrite(E, HIGH);
for (i = ; i < ; ++i)
{
digitalWrite(dataPins[i], ((dataPinMask[i] & cmd) ? HIGH : LOW));
}
digitalWrite(E, LOW);
}
} // 发送数据给 HT16514
void HT16514Parallel::sendData(byte data)
{
char i; digitalWrite(RS, HIGH);
digitalWrite(RW, LOW); if (dataLength == )
{
digitalWrite(E, HIGH);
DATA_PORT = data;
digitalWrite(E, LOW);
}
else
{
// 先写高四位
digitalWrite(E, HIGH);
for (i = ; i < ; ++i)
{
digitalWrite(dataPins[i], ((dataPinMask[i] & data) ? HIGH : LOW));
}
digitalWrite(E, LOW); // 低四位移高四位后,同上操作
data <<= ;
digitalWrite(E, HIGH);
for (i = ; i < ; ++i)
{
digitalWrite(dataPins[i], ((dataPinMask[i] & data) ? HIGH : LOW));
}
digitalWrite(E, LOW);
}
} // 初始化
void HT16514Parallel::init(char dl)
{
pinMode(RW, OUTPUT);
pinMode(E, OUTPUT);
pinMode(RS, OUTPUT); if (dl == )
{
DDR_PORT = 0xFF;
}
else
{
for (char i = ; i < ; ++i)
{
pinMode(dataPins[i], OUTPUT);
}
} dataLength = dl;
rowNumber = ; // 针对当前的 1602 vfd 直接写 2 了,以后有需要再加扩展 curRow = ;
curCol = ; initDisplay();
} // 初始关闭闪烁和光标显示(这也是reset后的状态)
void HT16514Parallel::initDisplay()
{
isDisplayOn = true;
isBlink = false;
isShowCursor = false; // 如果是四位模式,则需要手工设置。因为默认是八位
// 并且由于初始时是八位模式,所以要先按八位发命令设置四位模式
if (dataLength == )
{
byte cmd = 0x20; if (rowNumber == )
cmd |= 0x08; // 临时设置为八位发送设置四位的命令
dataLength = ;
sendCommand(cmd);
dataLength = ;
} moveCursorHome();
displayOn(); // 开启显示,关闭闪烁和光标显示
} // 清屏
void HT16514Parallel::clear()
{
sendCommand(0x00);
} // 移动光标到左上角
void HT16514Parallel::moveCursorHome()
{
curRow = ;
curCol = ; sendCommand(0x02);
} // 开显示
void HT16514Parallel::displayOn()
{
byte cmd = 0x08; isDisplayOn = true; if (isDisplayOn)
cmd |= 0x04; if (isBlink)
cmd |= 0x01; if (isShowCursor)
cmd |= 0x02; sendCommand(cmd);
} // 关显示
void HT16514Parallel::displayOff()
{
byte cmd = 0x08; isDisplayOn = false; if (isDisplayOn)
cmd |= 0x04; if (isBlink)
cmd |= 0x01; if (isShowCursor)
cmd |= 0x02; sendCommand(cmd);
} // 光标开闪烁
void HT16514Parallel::blinkOnCursor()
{
byte cmd = 0x08; isBlink = true; if (isDisplayOn)
cmd |= 0x04; if (isBlink)
cmd |= 0x01; if (isShowCursor)
cmd |= 0x02; sendCommand(cmd);
} // 光标关闪烁
void HT16514Parallel::blinkOffCursor()
{
byte cmd = 0x08; isBlink = false; if (isDisplayOn)
cmd |= 0x04; if (isBlink)
cmd |= 0x01; if (isShowCursor)
cmd |= 0x02; sendCommand(cmd);
} // 开光标
void HT16514Parallel::showCursor()
{
byte cmd = 0x08; isShowCursor = true; if (isDisplayOn)
cmd |= 0x04; if (isBlink)
cmd |= 0x01; if (isShowCursor)
cmd |= 0x02; sendCommand(cmd);
} // 关光标
void HT16514Parallel::hideCursor()
{
byte cmd = 0x08; isShowCursor = false; if (isDisplayOn)
cmd |= 0x04; if (isBlink)
cmd |= 0x01; if (isShowCursor)
cmd |= 0x02; sendCommand(cmd);
} // 左移显示内容
void HT16514Parallel::shiftLeftDisplay()
{
sendCommand(0x18);
} // 右移显示内容
void HT16514Parallel::shiftRightDisplay()
{
sendCommand(0x1C);
} // 左移光标
void HT16514Parallel::shiftLeftCursor()
{
sendCommand(0x10);
} // 右移光标
void HT16514Parallel::shiftRightCursor()
{
sendCommand(0x14);
} // 设置亮度,共有四级:0 级最亮,4 级最暗
void HT16514Parallel::setBrightLevel(char level)
{
byte cmd = 0x20; if (level < || level > )
return; if (dataLength == )
cmd |= 0x10; if (rowNumber == )
cmd |= 0x08; cmd |= level; sendCommand(cmd);
} // 于指定位置显示指定字符,若未指定位置则以当前位置显示
void HT16514Parallel::putChar(char ch, char row, char col)
{
byte cmd = 0x80;
char pos = ;
bool isCtrlChar = false; switch(ch)
{
case '\r': curCol = ; isCtrlChar = true; break;
case '\n': ++curRow; isCtrlChar = true; break;
case '\b': --curCol; isCtrlChar = true; break;
case '\t': curCol += ; isCtrlChar = true; break;
case '\0': return;
default : break;
}; if (isCtrlChar)
{
pos = 0x40 * curRow + curCol;
sendCommand(cmd | pos);
return;
} if (row >= && col >= )
{
pos = 0x40 * row + col; sendCommand(cmd | pos); curRow = row;
curCol = col;
} sendData(ch);
++curCol;
} // 于指定位置显示指定字符串,若未指定位置则以当前位置显示
void HT16514Parallel::print(char *str, char row, char col)
{
char *p = str; putChar(*p, row, col);
for (p = str + ; *p != '\0'; ++p)
{
putChar(*p);
}
}

arduino 测试程序:

// ----------------------------------------------------------------------------
// vfdHT16514Parallel.ino
//
// Created 2015-07-04
// By seesea <seesea2517#gmail#com>
//
// HT16541 VFD 驱动测试程序
// ----------------------------------------------------------------------------
#include "driverHT16514Parallel.h" #define RW 10
#define E 9
#define RS 8 HT16514Parallel vfd(RW, E, RS, , , , );
// HT16514Parallel vfd(RW, E, RS); void setup()
{
vfd.clear();
vfd.moveCursorHome();
vfd.setBrightLevel();
vfd.print("Have a good day!", , );
vfd.print("09:45:00", , );
} void loop()
{
static unsigned char sec = ;
char str[]; sprintf(str, "%02d", sec);
vfd.print(str, , );
delay();
sec = (sec + ) % ;
}

显示效果

从零开始写驱动——vfd专用驱动芯片HT16514并行驱动程序编写的更多相关文章

  1. 【Java EE】从零开始写项目【总结】

    从零开发项目概述 最近这一直在复习数据结构和算法,也就是前面发出去的排序算法八大基础排序总结,Java实现单向链表,栈和队列就是这么简单,十道简单算法题等等... 被虐得不要不要的,即使是非常简单有时 ...

  2. 一起学习造轮子(三):从零开始写一个React-Redux

    本文是一起学习造轮子系列的第三篇,本篇我们将从零开始写一个React-Redux,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Promises/A+,Re ...

  3. 2018-10-20-C#-从零开始写-SharpDx-应用-初始化dx修改颜色

    title author date CreateTime categories C# 从零开始写 SharpDx 应用 初始化dx修改颜色 lindexi 2018-10-20 17:34:37 +0 ...

  4. C# 从零开始写 SharpDx 应用 初始化dx修改颜色

    原文:C# 从零开始写 SharpDx 应用 初始化dx修改颜色 版权声明:博客已迁移到 https://blog.lindexi.com 欢迎访问.如果当前博客图片看不到,请到 https://bl ...

  5. 深入浅出React Native 3: 从零开始写一个Hello World

    这是深入浅出React Native的第三篇文章. 1. 环境配置 2. 我的第一个应用 将index.ios.js中的代码全部删掉,为什么要删掉呢?因为我们准备从零开始写一个应用~学习技术最好的方式 ...

  6. 从零开始写redis客户端(deerlet-redis-client)之路——第一个纠结很久的问题,restore引发的血案

    引言 正如之前的一篇博文,LZ最近正在从零开始写一个redis的客户端,主要目的是为了更加深入的了解redis,当然了,LZ也希望deerlet客户端有一天能有一席之地.在写的过程当中,LZ遇到了一个 ...

  7. 从零开始写一个武侠冒险游戏-8-用GPU提升性能(3)

    从零开始写一个武侠冒险游戏-8-用GPU提升性能(3) ----解决因绘制雷达图导致的帧速下降问题 作者:FreeBlues 修订记录 2016.06.23 初稿完成. 2016.08.07 增加对 ...

  8. 从零开始写一个武侠冒险游戏-7-用GPU提升性能(2)

    从零开始写一个武侠冒险游戏-7-用GPU提升性能(2) ----把地图处理放在GPU上 作者:FreeBlues 修订记录 2016.06.21 初稿完成. 2016.08.06 增加对 XCode ...

  9. 从零开始写一个武侠冒险游戏-6-用GPU提升性能(1)

    从零开始写一个武侠冒险游戏-6-用GPU提升性能(1) ----把帧动画的实现放在GPU上 作者:FreeBlues 修订记录 2016.06.19 初稿完成. 2016.08.05 增加对 XCod ...

随机推荐

  1. JavaEE Tutorials (16) - Java消息服务概念

    16.1JMS API概述198 16.1.1什么是消息传送198 16.1.2什么是JMS API199 16.1.3何时使用JMS API199 16.1.4Java EE平台如何使用JMS AP ...

  2. nodejs中使用递归案例

    var http = require('http'); //1.正常逻辑第一步正常请求,动作进行一次的方法: function seqRequest(i,limit){ var req = http. ...

  3. Effective C++ Item 36 绝不又一次定义继承而来的 non-virtual 函数

    本文为senlie原创.转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:绝对不要又一次定义继承而来的 non-virtual 函数 --> Item 7 ...

  4. JQuery 操作input

    获取选中的值 获取一组radio被选中项的值 var item = $('input[@name=items][@checked]').val(); 获取select被选中项的文本 var item ...

  5. Deep Learning(深度学习)学习笔记整理系列之(四)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

  6. 全局通知Notification

    Notification 全局通知 关于全局通知的个人理解: 即有一个发射消息的,在整个应用中任何对象都可以接受这个消息 但是无论是哪个对象接受消息,都要在这个对象结束时移除消息 简单的说 就是给对象 ...

  7. c++ build options(important)

    The C runtime library  4 versions: Multi-threaded (/MT) Multi-threaded Debug (/MTd) Multi-threaded D ...

  8. Svn服务启动的两种方式

    一.svn服务器启动 › cmd命令行启动:vsvnserve -d –r 文档仓库路径 -d 后台执行 › -r 版本库的根目录 二.›Windows服务自动启动     利用xp.2000 以上的 ...

  9. Struts学习之文件上传

    * 单文件上传:        * 在动作类action中声明相关属性:            * 在动作类action中,要声明与页面中表单name属性同名的属性,同名的属性的类型是File类型:  ...

  10. 亲测的一款在线作图神器:ProcessOn

    本人近日发现一款作图神器:ProcessOn 它是一款在线的作图工具,完全国产,前台是用HTML5  Canvas加javascript做绘图,后台用java实现数据处理和图片生成, 整站UI基本类似 ...