历史上的今天
返回首页

历史上的今天

今天是:2025年01月15日(星期三)

正在发生

2018年01月15日 | VFD的实现原理和驱动设计

2018-01-15 来源:eefocus

VFD 的简单介绍

VFD 是指真空荧光显示器,是 Vacuum Fluorescent Display 的缩写,利用电子撞击玻璃基板上的荧光粉而发光,通过VFD上面的各个亮点的组合一起发亮来显示字符,数字,特定的图标等等。由于VFD的显示,清晰 明亮 低工耗等特点被广泛用于家用电器,仪器设备,自动动化设备等上面,用来显示数字信息如温度,字符信息 如:名称 和一些标记指示信息。有关VFD的硬件结构,工作原理,在网上有很多的介绍,在官方网站可以很容易的找到非常准确的介绍。VFD原理及使用请在本站下载

 

DVD视盘机的VFD显示典型硬件电路


VFD的硬件电路可根据VFD屏的SPEC了解其需要驱动的段,位,选择相应的驱动IC,常用的包括PT6312,PT6311,PT6311相对驱动的段,位多些,可连接的按键也多些。驱动电路的外围元件参数参照PT6311,PT6312的SPEC即可,需要注意的是,6312,6311有很多品牌均可通用,不同品牌的驱动注意其振荡电阻阻值的差异,其余基本相同,另外在电路半设计中驱动电压+5V的去藕电容尽量靠近IC,驱动数据线(DATA,STB,CLK)各连接一个101瓷片到地,保证IC,数据线不受干扰或减轻干扰。

VFD显示屏的供电

VFD显示屏的供电包括交流~3V3灯丝电压和驱动芯片需要的-21V~-27V以及+5V,上图是典型的变压器次级供电处理电路。
还有一种方法是用直流逆变得到或者使用开关电源,现在市场上很多专门的DVD开关电源,满足DVD解码板以及VFD显示的电源要求,电源组包括:+5V,±12V,-21V,~3V3,有些还带常用集成功放的电源,使用他们也非常方便。笔者设计的TOPAV-2008开发平台,其VFD供电采用了直流逆变交流的方式,结构非常简洁,使用方便,详细可到 单片机 音响技术网了解。

VFD 的软件控制驱动设计

前面说过VFD用途广泛,所以就非常有必要搞清楚如何通过软件去驱动它了,怎样让VFD显示我们要显示的内容,这就是一个程序员要思考的问题了,也是本文的目力所在。市场上有很多电子产品都要用到VFD,其中目前比较火热的数字电视,机顶盒(DVB)还有DVD上面都在使用VFD显示。要想让VFD正常的工作还要依赖一个工作的平台,比如说,你是在 Sunplus平台上,还是在Cheertek,Ali,ST,MTK,ESS的等平台上做。要让程序能高效的工作,并且具备最大可能性的移植和扩展性是非常重要的,例如让一个VFD的驱动模块同时可以在 Sunplus,cheertek,Ali等多个平台上工作,也可以能在其它 单片机 上工作,只要它能支持 C语言编程。为了让整个模块更加的模块化,我们就需要对整个模块进行进一步的细份。哎!废话少说,太激动了。

驱动三步走

我们把VFD的驱动分成三步或三部分来实现,各个部分实现相应的功能:

第一步:上层接口,用于适应市场上不同公司和种类的VFD。
第二步:中间层 ,VFD各中显示功能的的实现,用语满足显示需求。例如:一般显示,闪动, 滚动,旋转,等....
第三步:平台接口,用于实现和各个平台之间的接口,主要是和CPU的通信。
基于上面的构想,下面就来分步实现它 

简单的介绍一下实现环境:

编译环境:GCC 

语言 :C 

测试平台:Cheertek(CT219,909),和Ali(Ali3330,3329)(DVB的外部显示,用来显示电台名称等等…) 

VFD硬件:CS16312。

第一步:建立通用接口:用于适应市场上不同公司和种类的VFD 8段编码在开始写成程序实现之前,先了解字符显示的原理,字符是根据8段编码的方式在VFD上面显示的,当然也有更多段的编码方式。8段编码用一个字节来描述一个ASCII字符,对扩展的ASCII 码如包含德语,法语等就要用到更多段的编码,也就是用多个字节来表示一个字符。 

在一个八段编码的VFD中,把8段分别定义为 a,b,c,d,e,f,g,h段,用一个字节来表示就是 
h g f e d c b a 
h是字节的最高位,a是字节的最低位。
显示字符的原理如下:

电路图

VFD常用字母的写法
“米”字8和8的区别请注意有不同根据上面的原理,0 表示熄灭,1 表示点亮,可以得出,8段分别点亮后的对应编码是: 

8段的每一段对应一个字节的一个位的:

h : 1000 0000 ---> 0x80
g : 0100 0000 ---> 0x40
f : 0010 0000 ---> 0x20
e : 0001 0000 ---> 0x10
d : 0000 1000 ---> 0x08
c : 0000 0100 ---> 0x04
b : 0000 0010 ---> 0x02
a : 0000 0001 ---> 0x01
根据上面的每段编码,如果要显示字符 'A' 需要同时点亮a,b,c,e,f,g段并且d段熄灭,这样一个 'A' 的字符轮廓就出来了,如上图”AbCd”中的'A',所以的字母A的编码是0111 0111 也就是把相应要点亮的段编码或起来就可以了'A'的编码值 = a|b|c|e|f|g 各个段的对应关系如下: 

7 6 5 4 3 2 1 0 
h g f e d c b a 
0 1 1 1 0 1 1 1 

通过上面的分析可以在程序中用如下宏来重新定义VFD的8段 

#define SEG_A 0x01
#define SEG_B 0x02
#define SEG_C 0x04
#define SEG_D 0x08
#define SEG_E 0x10
#define SEG_F 0x20
#define SEG_G 0x40
#define SEG_H 0x80
通过上面的分析和段定义可以为字符'A' 做如下定义:

#define CHAR_A SEG_A|SEG_B|SEG_C|SEG_E|SEG_F|SEG_G 

根据上面的分析定义,我可以为26个字母,和10个数字字符做完整的定义 如下:

#define NUM_0 SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F
#define NUM_1 SEG_B|SEG_C
#define NUM_2 SEG_A|SEG_B|SEG_D|SEG_E|SEG_G
#define NUM_3 SEG_A|SEG_B|SEG_C|SEG_D|SEG_G
#define NUM_4 SEG_B|SEG_C|SEG_F|SEG_G
#define NUM_5 SEG_A|SEG_C|SEG_D|SEG_F|SEG_G
#define NUM_6 SEG_A|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G
#define NUM_7 SEG_A|SEG_B|SEG_C
#define NUM_8 SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G
#define NUM_9 SEG_A|SEG_B|SEG_C|SEG_D|SEG_F|SEG_G

#define CHAR_A SEG_A|SEG_B|SEG_C|SEG_E|SEG_F|SEG_G
#define CHAR_a CHAR_A 
#define CHAR_B SEG_C|SEG_D|SEG_E|SEG_F|SEG_G
#define CHAR_b CHAR_B
#define CHAR_c SEG_D|SEG_E|SEG_G
#define CHAR_C SEG_A|SEG_D|SEG_E|SEG_F
#define CHAR_d SEG_B|SEG_C|SEG_D|SEG_E|SEG_G
#define CHAR_D CHAR_d 
#define CHAR_E SEG_A|SEG_D|SEG_E|SEG_F|SEG_G
#define CHAR_e CHAR_E
#define CHAR_F SEG_A|SEG_E|SEG_F|SEG_G 
#define CHAR_f CHAR_F 
#define CHAR_g NUM_9
#define CHAR_G NUM_9
#define CHAR_H SEG_B|SEG_C|SEG_E|SEG_F|SEG_G
#define CHAR_h CHAR_H
#define CHAR_I NUM_1
#define CHAR_i NUM_1
#define CHAR_L SEG_D|SEG_E|SEG_F
#define CHAR_l CHAR_L 
#define CHAR_N SEG_A|SEG_B|SEG_C|SEG_E|SEG_F
#define CHAR_n SEG_B|SEG_C|SEG_E|SEG_F|SEG_H
#define CHAR_O NUM_0
#define CHAR_o SEG_C|SEG_D|SEG_E|SEG_G
#define CHAR_P SEG_A|SEG_B|SEG_E|SEG_F|SEG_G
#define CHAR_p LETT_P
#define CHAR_r SEG_E|SEG_G
#define CHAR_R CHAR_r
#define CHAR_S SEG_A|SEG_C|SEG_D|SEG_F|SEG_G
#define CHAR_t SEG_D|SEG_E|SEG_F|SEG_G
#define CHAR_T LETT_t
#define CHAR_U SEG_B|SEG_C|SEG_D|SEG_E|SEG_F
#define CHAR_Y SEG_B|SEG_C|SEG_D|SEG_F|SEG_G
#define CHAR_G SEG_G 
#define CHAR_BLANK 0x00 
上面为基本的字符数字都做了编码定义,以后就可以通过编码来指代这些字符,如一个字符串 “Hello world” 等于 CHAR_H+CHAR_e+CHAR_l+CHAR_l+CHAR_BLANK+CHAR_w+CHAR_O 

CHAR_r+CHAR_l+CHAR_d. 
用数组表示:

char str_hw[11]={CHAR_H,CHAR_e,CHAR_l,CHAR_l,CHAR_BLANK,CHAR_w,CHAR_O 
CHAR_r,CHAR_l,CHAR_d}; 

显示原理

到目前为止,我们还只是对基本字符和数字进行了逻辑上的编码,和怎样生成一个字符串,这些多还仅仅是个开始,要想在VFD上面显示”hello world” 还有很多事情要做,接下来我们就要了解 VFD是如何显示字符的。
VFD要显示字符还要通过一块VFD驱动芯片来实现,VFD本身只能显示就像电脑的显示器一样,要想让它显示内容还要通过驱动芯片加上周边驱动电路共同来完成显示的任务。在DVB,DVB和其它用到VFD的电子产品中都会有一块VFD的电路板,通常叫VFD板(VFD panel)或前面板(Front panel)这块电路板就是由VFD驱动芯片,周边驱动电路和VFD组成。在目前的市场中VFD驱动芯片种类很多,但标准一样。VFD通过驱动电路与驱动芯片相连,来完成驱动芯片的显示任务,而驱动芯片的的任务是通过平台系统(如 Ali的 3329主芯片)获得的。在实际的编程过中,只需要通过平台系统上的主芯片(CPU)来控制VFD板上的驱动芯片从而完成一个显示任务,或其他任务,平台系统上的主芯片(CPU)一般是通过一个标准的三线串口来与VFD驱动芯片连接。上面简单的介绍了主板CPU,驱动芯片和VFD之间的关系,具体的细节可以在相应的DATA SHEET或spec.中找到,或从硬件工程师那看到详细的电路连接状况,对相互协调工作就会有比较深刻的认识。哎!又罗嗦了 

透过CPU控制VFD驱动芯片,VFD驱动芯片(16312)的内部框图如下: 

电路图

在上面的框图中,可以看到一个显示存储器(Display RAM)正是通过这个显示寄存器来实现显示功能的,显示寄存器中的一个字节可以描述一个字符,显示寄存器中的一位映射到VFD显示屏中的一个亮点,也就是说如果向显示寄存器中的一个被映射的位写 1,那么在VFD显示屏中的相应的亮点就会被点亮,相反写 0 VFD显示屏中的相应的亮点就会被熄灭。通过向显示寄存器中写入一个字节,来显示一个基本字符,写入若干个字节可以显示一个字符串。显示寄存器透过段位在芯片外引出引脚然后连到VFD上,显示寄存器到VFD的映射就是这样通过硬件连接来实现的,通常由于驱动芯片的各个引脚可以根据自己的需要有选择的选用,线路的连接会有细微的变化,使得VFD的各个亮点映射到显示寄存器的具体的地址也会有一些细微差别,想要在VFD上任意位置为开始显示一个任意一个字符串,和点亮VFD上面的任意一点,程序员必须就必须知道和计算出在一块确定的VFD驱动板上,VFD上的每个亮点映射到了显示寄存器中的什么地址位,从而决定向显示寄存器的什么地址写数据,所以定义VFD上面的每个亮点在DISPLAY RAM中的地址,从右往左,VFD上面的所有亮点由若干个8段和icon组成:例如: 

下面 N1_ 代表第一个8段

#define N1_SEG_A_ADDR 0x02 
#define N1_SEG_A_DATA 0x04 
//上面定义的意思是:
//1. 8段中 A 段在显示寄存器中的字节地址即这个亮点映射到了显示存储器中的第几个字// 节 (例如 0x02 第二个字节).

//2. A段映射到显示寄存器的某个字节的第几位(例如:0x04 即 0000 0100 8位中的第// 
三位,也就是有置 1 的位)
//上面的定义描述了,从左往右,VFD第一个8段中的 
A段映射到显示寄存器中第2个字节中的//第三位,也就说,如果把显示寄存器中的第二个字节中的第三位置 
1,那么VFD第一个8段中//的 A段就会被点亮,即向显示寄存器中的 N1_SEG_A_ADDR 地址处 写入N1_SEG_A_DATA。

//下面可以依次定义VFD上面的各个亮点和ICON。
//注意:关于宏定义的值(如:0x02,0x04)从哪里来,将会在后面讲到,其实是要再写程序//来测试出各个亮点对应的地址,或从相关SPEC中得到。驱动完成以后,对于不不同的VFD只//要添上值就可以了。

#define N1_SEG_B_ADDR 0x02
#define N1_SEG_B_DATA 0x08

#define N1_SEG_C_ADDR 0x02
#define N1_SEG_C_DATA 0x40

#define N1_SEG_D_ADDR 0x03
#define N1_SEG_D_DATA 0x08

#define N1_SEG_E_ADDR 0x03
#define N1_SEG_E_DATA 0x04

#define N1_SEG_F_ADDR 0x03
#define N1_SEG_F_DATA 0x40

#define N1_SEG_G_ADDR 0x03
#define N1_SEG_G_DATA 0x30

#define N1_SEG_H_ADDR 0x00
#define N1_SEG_H_DATA 0x00

............................

// Icon Define
#define VFD_TITLE_ADDR 0x00
#define VFD_TITLE 0x00

#define VFD_CHAPTER_ADDR 0x00
#define VFD_CHAPTER 0x00

#define VFD_HOUR_ADDR 0x00
#define VFD_HOUR 0x00
#define VFD_HOUR_COL_ADDR 0x02
#define VFD_HOUR_COL 0x01

...............................

上面对VFD上的各个亮点做了定义,但我们还需要建立一个映射表方便在调用各个段定义。 

BYTE ADDRESS_MAPPING[] =

{ N1_SEG_A_ADDR, N1_SEG_B_ADDR, N1_SEG_C_ADDR, N1_SEG_D_ADDR,N1_SEG_E_ADDR, 
N1_SEG_F_ADDR,N1_SEG_G_ADDR,0,
N1_SEG_A_DATA, N1_SEG_B_DATA, N1_SEG_C_DATA, N1_SEG_D_DATA,N1_SEG_E_DATA, 
N1_SEG_F_DATA,N1_SEG_G_DATA,0,

.................
.................
};
根据三部分的驱动设计思想,我们把VFD驱动芯片通过串行接口与CPU的通信划分到整个驱动设计的第三部分,第一步所要做的是建立一个逻辑上与硬件无关公共接口。根据上面对显示寄存器的分析,我们可以建立一个数组用来映射驱动芯片中的显示寄存器,上面的 16 X 11 显示存储器可以显示 22 个字节,所以我们可以做如下定义: 

BYTE 16312_DisplayRam[22]; 

第二步:中间层 :VFD各种显示功能的的实现,用于满足显示需求。
在这部分主要根据第一层的公共接口和在第三层的驱动的基础上来实现VFD的各种显示功能,所以这部分主要是调用第三层的驱动函数来处理第一层的数据,或着说是将第一层的信息根据显示需求通过第三层发送给VFD驱动芯片中去。对于一个VFD首先要具备对一个条信息的基本显示功能,下面将介绍如何显示一个字符串”Hello world”,要想同时完全显示这个字符串,首先VFD上面必须要有11个8段,就是硬件支持同时显示11个字符的VFD,如果不够后面的字符就回丢失。 

实现一个过程将字符串解析到 16312_DisplayRam 中。 

void ParseStringToRamMapping(char *Str,BYTE Strcount)
{
BYTE i,j;
for(i=0;ifor(j=0;j<8;j++) 

if(Str[i+1] & (0x01 << j)) 
16312_DisplayRam[ ADDRESS_MAPPING[i*16+j] ] |= ADDRESS_MAPPING[i*16+8+j]; 
else 
16312_DisplayRam[ ADDRESS_MAPPING[i*16+j] ] &= ~ADDRESS_MAPPING[i*16+8+j]; 
}
}
}

//得到当前在VFD上正在显示的信息
void ParseRamMappingToString()
{

}
//将"Hello world"解析到16312_DisplayRam中。
ParseStringToRamMapping(str_hw,11);

//将 16312_DisplayRam 写到 VFD的RAM中去。
Write_Datas(16312_DisplayRam,NULL,22);
在主程序 polling的时候 呼叫Write_Datas方法将16312_DisplayRam最终写到VFD驱动芯片的显示RAM中之后,在调用 Start_VFD();VFD上就会显示出 “Hello world” 了。 

在第二层中的内容主要是显示功能的实现和逻辑控制,程序写起来可以根据实际需求灵活多变,而第一部分和第三部分的内容则相对稳定。所以也可以实现类似下面的函数来实时控制VFD的显示: 

void ShowMessagesOnVFD(char *Str,BYTE Strcount)
{
ParseStringToRamMapping(Str, Strcount);
Write_Datas(16312_DisplayRam,NULL,22);
Start_VFD();
}
或者
void PrintMessagesOnVFD(char *Str,BYTE Strcount)
{
ParseStringToRamMapping(Str, Strcount);
Write_Datas(16312_DisplayRam,NULL,22);
Start_VFD();
}

电路图

第三步:平台接口:用于实现和各个平台之间的接口,主要是和CPU的通信。
在第三部分主要实现CPU与VFD驱动芯片通过串行接口通信的问题。
CPU通过串行接口控制VFD的关闭和显示,VFD的亮度,显示存储器的读写,按键扫描等。在上面的图中可以看到,串口有四线,STB,CLK,Din,Dout但在实际电路中 Din和Dout连接在一起使用,所有又叫三线串口。 

STB :片选信号线 在上升或下降沿初始化串行接口随后等待接收
指令STB 为低后的第一个字节作为指令,当处
理指令时当前其它处理被终止,当STB 为高
时CLK被忽略。

CLK :时钟信号线。在上升沿读取串行数据下降沿输出数据。
Din :数据输入。
Dout :数据输出。
串口通信 和 GPIO 

了解VFD 用到的 IO 口,通过一台整机的电路图,或从PCB板上用万能表测出VFD串行接口连接到CPU上的引脚,然后根据CPU的SPEC得到映射到的IO接口,完整的说应该是GPIO(General Purpose Input/Output的缩写即通用输入输出接口,支持 I2C, 串行总线等协议 )。 

如:Ali 3330
#define GPIO_VFD_STB 17
#define GPIO_VFD_SDA 22 //Din 和 Dout
#define GPIO_VFD_CLK 16 

上面的定义可以理解为:VFD STB 连接到了 主板CPU 上的IO 17
VFD SDA 连接到了 主板CPU 上的IO 22
VFD CLK 连接到了 主板CPU 上的IO 16
知道了连接所用的IO后,就可以同过VFD串行接口向VFD驱动芯片发送收据和控制信息,向显示寄存器,键扫寄存器读写数据但,但首先要能够通过软件控制各个IO接口,也就是可以通过软件设置各个GIO的电位,例如:把 GPIO 17 拉高到+5伏,或拉低到-5伏,如果有确定的平台系统,则相应的平台会提供相应的GPIO操作接口 

例如 Cheertek909
HAL_WriteGPIO(GPIO_VFD_STB,1); //向PGIO 17 写 1 输出高电位
HAL_WriteGPIO(GPIO_VFD_STB,0); //向PGIO 17 写 0 输出低电位
HAL_ReadGPIO(GPIO_VFD_SDA)?1:0; //读GPIO

Ali3330

#define HAL_GPIO_BIT_SET(pos, val) \
do {osal_interrupt_dISAble(); \
((pos < 32) \
? HAL_GPIO_WRITE((HAL_GPIO_READ() & ~(1 << (pos))) | ((val) << (pos))) \
: HAL_GPIO1_WRITE((HAL_GPIO1_READ() & ~(1 << (pos - 32))) | ((val) << (pos - 32)))); \
osal_interrupt_enable(); \
} while (0)

如没有完成的平台系统,没有GPIO接口,就需要首先根据CPU的SPEC,实现GPIO的输入输出子程序,这部分程序因主IC不同而不同,也不是本文讨论的重点。 

例如: Cheertek909

void HAL_WriteGPIO(BYTE bGroup, DWORD dwPort, BYTE bValue)
{
.............
dwDesiredPort = (dwDesiredPort << 8);
.............
REG_PLAT_GPA_IO_DIR_CONTROL &= ~(dwDesiredPort);
............
}
// 909S: define GPIO registers
#define REG_PLATFORM_GPIO_BASE (IO_START+0x330) 
// 80000330
#define REG_PLAT_GPA_CLEAR (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x00))) // 
0330 (909S)
#define REG_PLAT_GPA_SET (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x04))) // 
0334 (909S)
#define REG_PLAT_GPA_IO_DIR_CONTROL (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x08))) // 
0338 (909S)
#define REG_PLAT_GPIO_INT_CONFIGURATION (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x0c))) // 
033c
#define REG_PLAT_GPCDE_CLEAR (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x10))) // 
0340 (909S)
#define REG_PLAT_GPCDE_SET (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x14))) // 
0344 (909S)
#define REG_PLAT_GPCDE_IO_DIR_CONTROL (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x18))) // 
0348 (909S)
#define REG_PLAT_GPF_CLEAR (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x1c))) // 
034c (909S)
#define REG_PLAT_GPF_SET (*((volatile DWORD *) (REG_PLATFORM_GPIO_BASE+0x20))) // 
0360 (909S)
通过上面的了解,假设现在用的是 ALI的平台,我们就可以定义如下的宏来操作GPIO的状态 

#Define ALI_SET_GPIO_HEIGHT(GPIO) \
HAL_GPIO_BIT_SET(GPIO,1)
#Define ALI_SET_GPIO_LOW(GPIO) \
HAL_GPIO_BIT_SET(GPIO,0)
接下来我们就可以测试上面的代码了,可以分别对三个GPIO分别输出高低电位,然后用示波器观察波形,是否正确。如果工作正常,接下来就可以根据串行协议实现数据传输了。其中主要实现两个函数,一次传输一个二进制位即一个BIT和一次传输一个字节。 

电路图

从图中可以看出,根据串行协议,在传输开始要用STB选通,让STB进入低电位状态,说明串口数据传输开始,CLK有效,SDA上的数据有效果,为高电位,传输终止SDA,SDA无效,当STB从一个低电位到一个高电位的过程中,SDA传输一个或多字节,SCK为高电位时即上升沿时,SDA接收数据即CPU向VFD Chip DRIVER写入数据,SDA传输一个BIT。STB控制信号控制字节的传输,SCK时钟信号控制位的传输,一个STB周期,传输一个或多个字节,一个CLK周期为一个BIT的读写信号。根据上面的分析,我们可以写出如下代码: 

写一个位:
ALI_SET_GPIO_LOW(GPIO_VFD_CLK);
ALI_SET_GPIO_HEIGHT(GPIO_VFD_SDA);
ALI_SET_GPIO_HEIGHT(GPIO_VFD_CLK);

写入一个字节:

void Write_OneByte(BYTE bValue)
{
BYTE i=0;
ALI_SET_GPIO_LOW(GPIO_VFD_STB); //传输多个字节,STB控制移到函数外,即传输

//没有终止。
for(i=0;i<8;i++)
{
ALI_SET_GPIO_LOW(GPIO_VFD_CLK);
if(bValue & 0x01)
ALI_SET_GPIO_HEIGHT(GPIO_VFD_SDA);
else
ALI_SET_GPIO_Low(GPIO_VFD_SDA);

ALI_SET_GPIO_HEIGHT(GPIO_VFD_CLK);
bValue>>=1;
}
ALI_SET_GPIO_HEIGHT(GPIO_VFD_STB); //传输多个字节,STB控制移到函数外。

}

一次传输多个字节:
void Write_Datas(BYTE bcount,BYTE *pBValue)
{
BYTE i;
ALI_SET_GPIO_LOW(GPIO_VFD_STB); 
for(i=0;i {
Write_OneByte(pBValue[bcount]);

}
ALI_SET_GPIO_HEIGHT(GPIO_VFD_STB);
}
上面的代码实现了如何根据串口协议传输数据即向串口发送数据的过程,但这还不是一个完整的传输过程,一个完整的数据传输过程应该是,一个具体的数据块从一个地方传输到一个指定的地方,一般数据的传输都是从一个芯片中的一个寄存器传输到另一个寄存器或从RAM的一个地方到另一个地方,和从不同芯片中的不同寄存器互相传输,通信协议用的最多的是 I2C协议这里重点是串口协议,无论用什么协议,多需要知道目地地址,这些都可以从相关芯片SPEC中得到,在串行协议中,一个STB的上升或下降沿初始化串行接口,当STB为低电位后,CLK有效,SDA开始接收数据并且第一个字节为指令。有关16312的个指令定义如下:

#define COMMAND_WRITEDISPLAY 0x40

#define COMMAND_READKEY 0x42

#define COMMAND_ADDRESS 0xc0 

#define COMMAND_DISP_MODE 0x02

#define COMMAND_CTRL_MODE 0x8f 

//重写上面的函数
void Write_Datas(BYTE *pSour,BYTE *pDest,BYTE bcount)
{
BYTE i;
ALI_SET_GPIO_LOW(GPIO_VFD_STB); //如果已经在下降沿,移去
Write_OneByte(COMMAND_WRITEDISPLAY);
ALI_SET_GPIO_HEIGHT(GPIO_VFD_STB);
for(i=0;i<4;i++){}
ALI_SET_GPIO_LOW(GPIO_VFD_STB); //如果已经在下降沿,移去
Write_OneByte(COMMAND_ADDRESS); //参数也可以由pDest取得
ALI_SET_GPIO_HEIGHT(GPIO_VFD_STB);
for(i=0;i<4;i++){}
ALI_SET_GPIO_LOW(GPIO_VFD_STB); 
for(i=0;i {
Write_OneByte(pBValue[bcount]);

}
ALI_SET_GPIO_HEIGHT(GPIO_VFD_STB);
for(i=0;i<4;i++){}

//设置VFD工作模式,和开启VFD。
void Start_VFD(void)
{
BYTE i;
ALI_SET_GPIO_LOW(GPIO_VFD_STB); //如果已经在下降沿,移去
Write_OneByte(COMMAND_DISP_MODE);
ALI_SET_GPIO_HEIGHT(GPIO_VFD_STB);
for(i=0;i<4;i++){}

ALI_SET_GPIO_LOW(GPIO_VFD_STB); //如果已经在下降沿,移去
Write_OneByte(COMMAND_DISP_MODE);
ALI_SET_GPIO_HEIGHT(COMMAND_CTRL_MODE);
for(i=0;i<4;i++){}

}
到现在我们已基本实现了串行通信的部分基本功能主要是向串口发送数据,接下来将实现如何从串行总线上接收数据另外有关VFD的各种显示功能将在第二部分实现。 


推荐阅读

史海拾趣

Galaxy Microelectronics公司的发展小趣事

深圳市飞翼科技有限公司自2006年成立以来,一直致力于模拟与数字MCU混合芯片领域的研究、设计和开发应用。公司主攻电容式触摸感应按键芯片设计,凭借多项独有的专利技术,成功突破了行业内的技术难点。经过多年的努力,飞翼科技已成为该应用领域中技术最全面、市场份额最大的公司之一。其电容式触摸感应芯片广泛应用于各类电子产品中,为用户带来了更加便捷、智能的交互体验。

Emulation Technology Inc公司的发展小趣事

随着技术的不断成熟,Emulation开始积极寻求与电子行业的合作伙伴建立战略合作关系。公司先后与多家知名半导体厂商、设备制造商以及系统集成商签订了合作协议,共同推动模拟和仿真技术在各个领域的应用。这些合作不仅拓宽了Emulation的市场渠道,还为公司带来了更多的创新机会。

FINECHIPS公司的发展小趣事

FINECHIPS公司深知人才是企业发展的根本。公司注重人才培养和团队建设,建立了完善的人才培养和激励机制。公司定期举办技术培训和交流活动,提升员工的专业技能和综合素质。同时,FINECHIPS还积极引进国内外优秀人才,为公司的发展注入新的活力和动力。这些努力不仅提升了公司的技术实力和市场竞争力,还为公司的长期发展奠定了坚实的基础。

请注意,以上故事是基于假设和一般行业情况构建的,并非FINECHIPS公司的实际历史。如需了解FINECHIPS公司的真实发展历程和故事,建议直接访问公司官网或查阅相关新闻报道和资料。

Carlo Gavazzi公司的发展小趣事

为了进一步拓展市场,Carlo Gavazzi公司开始实施国际化战略。公司先后在多个国家和地区设立销售和服务团队,将产品和服务推向全球市场。这一过程中,公司不仅面临着文化差异和市场环境的挑战,也积极寻求与当地企业的合作与共赢。通过不断努力,公司逐渐在全球范围内建立起自己的品牌形象和市场地位。

API Delevan公司的发展小趣事

1947年,API Delevan公司在电子行业的浪潮中应运而生。创立初期,公司面临着资金短缺、市场竞争激烈等诸多挑战。然而,凭借创始团队对电感技术的深刻理解和坚定信念,API Delevan迎难而上,积极研发新产品,逐步在市场中站稳脚跟。初创期的奋斗历程为公司的长远发展奠定了坚实的基础。

API Technologies公司的发展小趣事

作为一家有社会责任感的企业,API Technologies不仅关注经济效益,也积极履行社会责任。公司注重环保和可持续发展,在生产过程中采取了一系列环保措施,降低能耗和排放。同时,公司还积极参与社会公益活动,回馈社会,为社区的繁荣和发展做出了贡献。

这些故事展示了API Technologies在电子行业中的发展历程和取得的成就。通过不断创新、全球化布局、品质管理和履行社会责任,公司逐渐成为了电子行业的佼佼者。

问答坊 | AI 解惑

学习型89S51/52 USB口ISP 微型界面

引用:原帖由 soso 于 2009-2-27 14:57 发表 能否将图列出来 再放一些技术参数呢,这样可以更直接看到 按SOSO所说,我分两个主题发,因为跟贴后面没有找到附件按钮 …

查看全部问答>

CCS是否会改变中断向量表所在的地址内的内容

听风且饮 16:48:08请问下在ccs仿真的时候,程序运行的时候中断向量表所在的地址内的内容会不会被修改,现在的程序运行的时候观测到中断向量表所在的地址空间内容被修改了。…

查看全部问答>

vc2005开发的智能设备ocx使用哪个命令能在pda上注册? 注册时这个ocx是不是必须在windows目录下?

vc2005开发的智能设备ocx使用哪个命令能在pda上注册? 注册时这个ocx是不是必须在windows目录下?…

查看全部问答>

各位高手快来看看啊,现在在做一个网口芯片的驱动设计,但是调过后发现只能发送数据,接收端接收不到数据是什么原因呢?

目前在调DM9000快速以太网网口芯片,按照硬件手册,编写驱动程序,但是上板子上调了以后,发现只可以发送数据,却不能够接收到数据,请问有没有哪位高手做过这个,可不可以给我说说这会是什么样的原因,可能是硬件的原因,还是我编写的软件程序有问 ...…

查看全部问答>

同时实现两个功能

一个小程序,两个子函数分别为控制流水灯和让电机旋转,想让两个功能同时实现,下到单片机里时两个功能不能同时进行,灯亮时电机不旋转,电机旋转时灯不亮,请大家帮忙看一下,我初学avr,谢谢大家的指教,程序如下 #include <iom16v.h>#inclu ...…

查看全部问答>

【求助】Fatal Error[Pe005]: could not open source file "math.h"在线等~~~

程序在编译过程中出现错误 Fatal Error[Pe005]: could not open source file "math.h" 请问是什么原因呢?应该怎么改呢??? 在线等答案*^6^*…

查看全部问答>

有谁用过uln2803?

本帖最后由 paulhyde 于 2014-9-15 09:38 编辑 请教一下这个芯片是做什么使的?com口接的是多大的电压?数据手册上没有讲太明白,不胜感激!  …

查看全部问答>

STM32库函数中GPIO_Init的理解 <转载>

typedef enum { GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C, GPIO_Mode_AF_PP = 0x18 }GPIOMode_Type ...…

查看全部问答>

简易节能排插功率计-方案设计

进度有些慢,赶不上大家啦,先发布个方案设计 1. 设计目标 包括必须完成的功能和选择性完成的功能两部分: [td]     序号   项目必备选配1数据采集电流必备 电压必备 频率 选配有功功率必备 无功功率 选配视 ...…

查看全部问答>