侧边栏壁纸
博主头像
塞塞哇 博主等级

开源创客

  • 累计撰写 38 篇文章
  • 累计创建 9 个标签
  • 累计收到 11 条评论

目 录CONTENT

文章目录

三星VFD(HNV)荧光屏模块

塞塞蛙
2024-01-16 / 0 评论 / 0 点赞 / 324 阅读 / 0 字

三星VFD荧光电子屏-显示模块

基于三星米字屏设计的VFD显示模组。

VFD显示模组具有9位显示内容,可显示数字和字母 驱动芯片是PT6315,通讯协议SPI。 DIN、CLK、RST三线组成 负压产生约为-35V,50%占空比的交流灯丝驱动,显示清晰。 外部供电需 5V供电,不可超过5V标准。 电路中请保证供电电流,防止下压降导致其他电路或单片机无法正常运行,通讯电平为3.3V。

立创开源链接地址:https://oshwhub.com/yc_chen/vfd-xian-shi-mo-kuai-san-hnv

1. 复刻说明

复刻请注意屏幕引脚尺寸超过免费打样限制。PCB板大小(125.146mmx32.131mm)

  1. 屏幕购买链接:
    https://item.taobao.com/item.htm?id=754425064614&skuId=5253614212938

  2. 这里提供一小批嘉立创的PCB空板有需要的可以另外选择:
    https://item.taobao.com/item.htm?id=754425064614&skuId=5253614212938


在线帮助手册文档:http://doc.saisaiwa.com/vfd-hnv-model/
技术交流QQ群:676436122


喜欢的可以玩一玩另一款VFD时钟:https://oshwhub.com/yc_chen/zyc-vfd-shi-zhong

2. STC8H的驱动小型开发板

在本开源EDA项目中,其中有一个Board是集成STC8H的驱动开发小板的PCB设计。
STC8的烧录代码Git仓库https://github.com/ccy-studio/CCY-HNVM-TEST

3. 驱动代码适用于单片机全平台

本驱动库代码,您可以直接在您的项目中创建对应的文件,然后直接复制过去,请注意编码格式。
之后您需要修改下对应的宏定义,即可完成全部适配

驱动库文件分别拆分成两份封装API,其中以底层通讯pt6315,另一个则可以理解成应用层操作显示内容库API。

首先根据您的平台例如 C51、Arduino系列、STM32等等 修改初始化IO和延时函数的宏定义。

例如: C51的延时采用软件延时

void delay_us(u32 us) {  //c51单片机的软件延时,这里只是实例不要复制
    unsigned char data i;

    do {
        _nop_();
        i = 5;
        while (--i)
            ;
    } while (--us);
}

Arduino系列的微秒延时

delayMicroseconds(1000)	//以微秒为单位时间,延时1000微秒,即1毫秒

STM32的微秒延时可以软件或者定时器,这里就不做多的介绍了。

后面就是操作IO的部分宏定义,如果是C51那么可以是 P31=1类似这种,Arduino的可以使用 digitalWrite(pin, value) 来操作IO引脚的电平翻转。 请根据您的平台去做特定的修改。下面的代码部分将会体现。

1. 创建文件: pt6315.h

#ifndef __PT6315__
#define __PT6315__

#define CLK_1 P_CLK = 1
#define CLK_0 P_CLK = 0
#define DIN_1 P_DIN = 1
#define DIN_0 P_DIN = 0
#define STB_1 P_STB = 1
#define STB_0 P_STB = 0

#define delay_us(x) my_delay_us(x)
#define delay_ms(x) my_delay_ms(x)

void ptSetDisplayLight(uint8_t onOff, uint8_t brightnessVal);
void setModeWirteDisplayMode(uint8_t addressMode);
void setDisplayMode(uint8_t digit);
void sendDigAndData(uint8_t dig, uint8_t* dat, size_t len);
#endif

在宏定义这里CLK_1 、CLK_0 等等 三个IO引脚的宏定义需要您根据自己的平台去编写IO的翻转,上图的示例是C51的

假如您的平台是Arduino那么需要修改代码例如:

#define CLK_1 digitalWrite(CLK,HIGH) //高电平输出
#define CLK_0 digitalWrite(CLK,LOW) //低电平输出
...
...

注意在使用前需要在main方法内一定要先初始化IO引脚,初始化IO引脚,初始化IO引脚,,例如Arduino系列操作**pinMode()**函数。

修改宏定义的两个延时函数:delay_us、delay_ms ,例如还是Arduino系列的则可以修改为

注意如果是Arduino需要引入头文件: #include <Arduino.h> 其他平台也类似。

#define delay_us(x) delayMicroseconds(x) //微秒延时
#define delay_ms(x) delay(x) //毫秒延时

在复制下面的代码前,需要先确认您修改完成了上面的宏定义的方法。

2. 创建文件: pt6315.c

#include "pt6315.h"

void writeData(uint8_t dat) {
    size_t i = 0;
    CLK_0;
    for (i = 0; i < 8; i++) {
        delay_us(10);
        if (dat & 0x01) {
            DIN_1;
        } else {
            DIN_0;
        }
        delay_us(10);
        CLK_1;
        delay_us(10);
        CLK_0;
        dat >>= 1;
    }
}

void setModeWirteDisplayMode(uint8_t addressMode) {
    uint8_t command = 0x40;
    if (addressMode) {
        command |= 0x4;
    }
    STB_1;
    delay_us(10);
    STB_0;
    delay_us(10);
    writeData(command);
    delay_us(10);
    STB_1;
}

/**
 * COMMANDS 1 显示模式设置命令
 * 0000 : 4位, 24段
 * 0001 :5位, 23段
 * 0010 : 6位数字, 22段
 * 0011 : 7位, 21段
 * 0100 : 8位, 20段
 * 0101 : 9位, 19段
 * 0110 : 10位, 18段
 * 0111 : 11位, 17段
 * 1XXX : 12位, 16段
 */
void setDisplayMode(uint8_t digit) {
    STB_1;
    delay_us(10);
    STB_0;
    delay_us(10);
    writeData(digit);
    delay_us(10);
    STB_1;
}
/**
 * 显示控制命令  COMMANDS 4
 * @param onOff 0显示关闭,1开启显示
 * @param brightnessVal 亮度占空比 0~7调整
 * 000:脉冲宽度= 1/16 0
 * 001:脉冲宽度= 2/16 1
 * 010 :脉冲宽度= 4/16 0x2
 * 011 :脉冲宽度= 10/16 3
 * 100:脉冲宽度= 11/16  4
 * 101 :脉冲宽度= 12/16 0x5
 * 110:脉冲宽度= 13/16 6
 * 111:脉冲宽度= 14/16 0x7
 */
void ptSetDisplayLight(uint8_t onOff, uint8_t brightnessVal) {
    uint8_t command = 0x80 | brightnessVal;
    if (onOff) {
        command |= 0x8;
    }
    STB_1;
    delay_us(10);
    STB_0;
    delay_us(10);
    writeData(command);
    delay_us(10);
    STB_1;
}

void sendDigAndData(uint8_t dig, const uint8_t* dat, size_t len) {
    size_t i = 0;
    STB_1;
    delay_us(10);
    STB_0;
    delay_us(10);
    writeData(0xc0 | dig);
    delay_us(10);
    for (i = 0; i < len; i++) {
        writeData(dat[i]);
    }
    delay_us(10);
    STB_1;
}

3. 创建文件:gui.h

#ifndef __VFD_GUI_
#define __VFD_GUI_

#include "pt6315.h"

// VFD位数
#define VFD_DIG_LEN 9

/**
 * 初始化
 */
void vfd_gui_init();

/**
 * 停止关闭显示
 */
void vfd_gui_stop();

/**
 * 清空VFD屏幕显示,循环刷新如果使用vfd_gui_set_text方则不需要使用它。
 */
void vfd_gui_clear();

/**
 * 显示一串文字,从0位开始。
 * (自动清空覆盖显示,方便每次不用调用clear防止闪屏出现)
 * @param colon 是否显示冒号 0|1
 * @param left_first_conlon 是否显示左边冒号 0|1
 */
void vfd_gui_set_text(const char* string,
                      const u8 colon,
                      const u8 left_first_conlon);

/**
 * 要点亮的ICON图标,可宏定义传参可参考acg动画
 */
void vfd_gui_set_icon(u32 buf);

/**
 * 设置亮度等级 1~7
 */
void vfd_gui_set_blk_level(size_t level);

/**
 * acg动画
 */
void vfd_gui_acg_update();


long map(long x, long in_min, long in_max, long out_min, long out_max);
#endif

4. 创建文件:gui.c

#include "gui.h"

u8 lightLevel = 1;  // 亮度级别
static u8 send_buf[3 * VFD_DIG_LEN] = {0};
static u8 send_buf_cache[3 * VFD_DIG_LEN] = {0};
const u32 fonts[38] = {
    0x333300,  // ASCII:0,ASCII_N:48 index:0
    0x201000,  // ASCII:1,ASCII_N:49 index:1
    0xe12100,  // ASCII:2,ASCII_N:50 index:2
    0xe13000,  // ASCII:3,ASCII_N:51 index:3
    0xe21000,  // ASCII:4,ASCII_N:52 index:4
    0xc33000,  // ASCII:5,ASCII_N:53 index:5
    0xc33100,  // ASCII:6,ASCII_N:54 index:6
    0x211000,  // ASCII:7,ASCII_N:55 index:7
    0xe33100,  // ASCII:8,ASCII_N:56 index:8
    0xe33000,  // ASCII:9,ASCII_N:57 index:9
    0x080400,  // ASCII::,ASCII_N:58 index:10
    0xe31100,  // ASCII:A,ASCII_N:65 index:11
    0xa93400,  // ASCII:B,ASCII_N:66 index:12
    0x032100,  // ASCII:C,ASCII_N:67 index:13
    0x293400,  // ASCII:D,ASCII_N:68 index:14
    0xc32100,  // ASCII:E,ASCII_N:69 index:15
    0xc30100,  // ASCII:F,ASCII_N:70 index:16
    0xc33100,  // ASCII:G,ASCII_N:71 index:17
    0xe21100,  // ASCII:H,ASCII_N:72 index:18
    0x092400,  // ASCII:I,ASCII_N:73 index:19
    0x082400,  // ASCII:J,ASCII_N:74 index:20
    0x520900,  // ASCII:K,ASCII_N:75 index:21
    0x022100,  // ASCII:L,ASCII_N:76 index:22
    0x361100,  // ASCII:M,ASCII_N:77 index:23
    0x261900,  // ASCII:N,ASCII_N:78 index:24
    0x233100,  // ASCII:O,ASCII_N:79 index:25
    0xe10100,  // ASCII:P,ASCII_N:80 index:26
    0x233900,  // ASCII:Q,ASCII_N:81 index:27
    0xe30900,  // ASCII:R,ASCII_N:82 index:28
    0xc33000,  // ASCII:S,ASCII_N:83 index:29
    0x090400,  // ASCII:T,ASCII_N:84 index:30
    0x223100,  // ASCII:U,ASCII_N:85 index:31
    0x241800,  // ASCII:V,ASCII_N:86 index:32
    0x221b00,  // ASCII:W,ASCII_N:87 index:33
    0x140a00,  // ASCII:X,ASCII_N:88 index:34
    0x140400,  // ASCII:Y,ASCII_N:89 index:35
    0x112004,  // ASCII:Z,ASCII_N:90 index:36
    0xc00000,  // ASCII:-,ASCII_N:45 index:37
};

u32 gui_get_font(char c);


void vfd_gui_init() {
    VFD_EN = 1;
   
    // VFD Setting
    setDisplayMode(6);
    setModeWirteDisplayMode(0);
    vfd_gui_set_blk_level(7);
    vfd_gui_clear();
}

void vfd_gui_stop() {
    VFD_EN = 0;
    vfd_gui_clear();
}

void vfd_gui_clear() {
    memset(send_buf, 0x00, sizeof(send_buf));
    sendDigAndData(0, send_buf, sizeof(send_buf));
}

void vfd_gui_set_icon(u32 buf) {
    uint8_t arr[3] = {0};
    memset(arr, 0x00, sizeof(arr));
    if (buf) {
        arr[0] = (buf >> 16) & 0xFF;
        arr[1] = (buf >> 8) & 0xFF;
        arr[2] = buf & 0xFF;
    }
    sendDigAndData(0x1b, arr, 3);
}

void vfd_gui_set_text(const char* string,
                      const u8 colon,
                      const u8 left_first_conlon) {
    size_t str_len = strlen(string);
    size_t index = 0, i = 0;
    size_t len = str_len > VFD_DIG_LEN ? VFD_DIG_LEN : str_len;
    memset(send_buf, 0x00, sizeof(send_buf));
    for (i = 0; i < len; i++) {
        if (string[i] && string[i] != '\0') {
            u32 buf = gui_get_font(string[i]);
            send_buf[index++] = (buf >> 16) & 0xFF;
            send_buf[index++] = (buf >> 8) & 0xFF;
            send_buf[index++] = buf & 0xFF;
        }
    }
    if (left_first_conlon) {
        send_buf[7] |= 0x40;
    }
    if (colon) {
        send_buf[13] |= 0x40;
        send_buf[19] |= 0x40;
    }
    sendDigAndData(0, send_buf, sizeof(send_buf));
}

/**
 * 亮度调节 1~7
 */
void vfd_gui_set_blk_level(size_t level) {
    if (level == lightLevel) {
        return;
    }
    lightLevel = level;
    ptSetDisplayLight(1, lightLevel);
}

long map(long x, long in_min, long in_max, long out_min, long out_max) {
    const long dividend = out_max - out_min;
    const long divisor = in_max - in_min;
    const long delta = x - in_min;
    return (delta * dividend + (divisor / 2)) / divisor + out_min;
}

u32 gui_get_font(char c) {
    if (c == ' ') {
        return 0;
    }
    if (c == '-') {
        return fonts[37];
    }
    if (c >= 48 && c <= 58) {
        return fonts[map(c, 48, 58, 0, 10)];
    } else if (c >= 65 && c <= 90) {
        return fonts[map(c, 65, 90, 11, 36)];
    } else if (c >= 97 && c <= 122) {
        return gui_get_font(c - 32);
    } else {
        return 0;
    }
}

/**
 * acg动画
 */
void vfd_gui_acg_update() {
    static u8 acf_i = 9;
    if (acf_i == 9) {
        static u32 icon = 0x040000;
        static u8 sec = 0;
        vfd_gui_set_icon(icon);
        sec++;
        if (sec == 3) {
            icon = 0x008000;
        } else if (sec < 3) {
            icon = (0x040000 >> sec);
        } else {
            icon = (0x040000 << (sec - 3));
        }
        if (sec == 4) {
            acf_i = 0;
        }
        if (sec == 7) {
            sec = 0;
            icon = 0x040000;
        }
    } else {
        u8 bi = acf_i == 0 ? 1 : (acf_i + 1) * 3 - 2;
        memcpy(send_buf_cache, send_buf, sizeof(send_buf));
        if (acf_i == 2 || acf_i == 4 || acf_i == 6) {
            send_buf_cache[bi] |= 0x80;
        } else {
            send_buf_cache[bi] |= 0xC0;
        }
        if (acf_i == 0) {
            vfd_gui_set_icon(0);
        }
        sendDigAndData(0, send_buf_cache, sizeof(send_buf_cache));
        acf_i++;
        if (acf_i == 9) {
            sendDigAndData(0, send_buf, sizeof(send_buf));
        }
    }
}

在代码中有一个宏定义:VFD_EN ,这个则是模块中EN引脚的电平翻转宏定义,这里可以根据您自己的平台做响应的修改。

例如Arduino系列的可以改为: digitalWrite(VFD_EN ,HIGH)、digitalWrite(VFD_EN ,LOW)

5. 简单使用

#include "gui.h"
void main(){
    //初始化 DIN、CLK、RST、EN引脚IO为推挽输出模式
    ...
    ... 
    vfd_gui_init(); //初始化
    vfd_gui_set_blk_level(7); //亮度调整
    while(1){
        delay_ms(500);
        vfd_gui_set_text("123456789",0,0); //设置显示内容
        vfd_gui_acg_update();//动画帧刷新,如果使用RTOS需要对数据传输pt6315上锁
    }
}
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区