|
/********************************************************************************
;* 标题: TOPAV-2008单片机开发系统演示程序 *
;* 硬件: TOPAV-2008 *
;* 文件: MA016.C *
;* 日期: 2007-5-1 *
;* 版本: 1.0 *
;* 作者: 单片机音响技术网 - zhangshaobin *
;********************************************************************************
;* 描述: *
;* PT6312VFD屏演示(频谱花式,HELLO字符显示,按键扫描) *
;* *
;********************************************************************************
;* 跳线设置: *
;* 矩阵键盘上方跳线组(短接STB,CLK,DATA) *
;* 安装好6312VFD模块(注意丝印对应且全部脚插入)VFD为真空玻璃注意爱护 *
;* 特别注意保护VFD屏左边真空抽气孔(小凸起部分不可破裂 *
;********************************************************************************
;* 【版权】 Copyright(C)单片机音响技术网All Rights Reserved *
;* 【声明】 此程序仅用于学习与参考,引用请注明版权和作者信息! *
;*******************************************************************************/
//来,一起玩转VFD屏及PT6312驱动
#include "reg51.h"
typedef bit BIT;
typedef unsigned char BYTE;
typedef unsigned int WORD;
sbit PT6312_STB = P2^3;
sbit PT6312_CLK = P2^4;
sbit PT6312_DATA = P2^5;
BYTE DISP_ARRAY[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
//BYTE code DISP_CHAR1[] = {4,192,55,118,91,58}; //TUNER
BYTE code DISP_CHAR1[] = {1,62,91,19,19,119}; //HELLO
//BYTE code DISP_CHAR1[] = {4,0,125,127,93,247}; //98.50
BYTE code DISP_KEY01[] = {0,0,119,119,119,36};
BYTE code DISP_KEY02[] = {0,0,119,119,119,107};
BYTE code DISP_KEY03[] = {0,0,119,119,119,109};
BYTE code DISP_KEY04[] = {0,0,119,119,119,60};
BYTE code DISP_KEY05[] = {0,0,119,119,119,93};
BYTE code DISP_KEY06[] = {0,0,119,119,119,95};
BYTE code DISP_KEY07[] = {0,0,119,119,119,100};
BYTE code DISP_KEY08[] = {0,0,119,119,119,127};
BYTE code DISP_KEY09[] = {0,0,119,119,119,125};
BYTE code DISP_KEY10[] = {0,0,119,119,36,119};
BYTE code DISP_KEY11[] = {0,0,119,119,36,36};
BYTE code DISP_KEY12[] = {0,0,119,119,36,107};
BIT NEW_KEY_FLAG=0;
BIT OLD_KEY_FLAG=0;
BYTE bKEY;
BYTE oldKEY;
BYTE code DISP_FREQ1[] = {1,3,7,15,31,63,127,255}; //频谱上升
BYTE code DISP_FREQ2[] = {1,2,4,8,16,32,64,128}; //频谱下降
BYTE code DISP_FREQ3[] = {128,192,224,240,248,252,254,255}; //频谱中间跳动
BYTE SEC_TIME;
BYTE DISC_RUN_TIME;
BYTE FREQ_TIME;
BYTE FREQ_SEC_TIME;
BYTE FREQ_ST_TIME;
BYTE FREQ_RANGE[4]; //手动设置的频谱,没有音频取样,假频谱... :)
BYTE KEY_BUF[3];
#define VFD_DISP_MODE 0x02 // 设置段位为 6d/16s
#define VFD_DIM_QUANTITY 0x8f //占空比14/16,显示为开
#define VFD_DATWR_MODE 0x40 //正常写入后地址加1
#define VFD_ADDSET_COMD 0xC0 //PT6312片内RAM从OOH~15H,6段使用00H~0BH共12BYTE每段16BIT两个RAM
#define VFD_SPH 0x00
#define MS20H 0xb1 //定时器0初值
#define MS20L 0xe0 //12M 20MS;45536=B1E0H 65536-45536=20000US=20MS
void Write_A_ByteTo_VFD(BYTE); //一些函数声明,如果带行参变量,编译器会忽略
void Init_vfd();
void Light_all_Write();
void Write_GID6(BYTE *);
BYTE RD_A_Bytefrom_VFD();
void KEY_Scan_Save();
BYTE Get_KEYVAL();
void KEY_Process();
void disp_Chag_disc();
void Write_GID4(BYTE *,BYTE *);
void freqrange_to_disp();
void disp_Chag_freq(); //以上函数做了申明,主程序可以写在最前面
void main()
{
TMOD = 0x11; //TMOD = 0x01,定时器0方式设置
IE = 0X82; //开总中断允许,开定时器0允许
Init_vfd(); //DISP_ARRAY数组初始化全部为0所以显示无内容,只是设置了段位,允许VFD显示
TH0 = MS20H; //定时器初值设定
TL0 = MS20L;
TR0 = 1; //开定时器0
Write_GID6(&DISP_CHAR1); //显示HELLO
while(1)
{
disp_Chag_freq(); //调用频谱条变化
disp_Chag_disc(); //调用DVD转盘旋转
KEY_Process(); //按键按下显示按键值
Light_all_Write(); //PT6312数据更新
}
}
/*************************************************************************************************/
void Init_vfd() //PT6312初始化
{
PT6312_STB = 1;
PT6312_STB = 0;
Write_A_ByteTo_VFD(VFD_DISP_MODE); //0x02 6d/16s根据显示VFD的段位设置
PT6312_STB = 1;
PT6312_STB = 0;
Write_A_ByteTo_VFD(0x8f); //占空比14/16,显示为开
PT6312_STB = 1;
Light_all_Write(); //写入所有数据到PT6312
}
void Write_A_ByteTo_VFD(BYTE vfd_data) //写一个字节数据到PT6312
{
BYTE wr_temp;
PT6312_CLK = 1;
for(wr_temp = 0;wr_temp < 8;wr_temp++)
{
PT6312_CLK = 0;
if (vfd_data & 0x01)
PT6312_DATA = 1;
else
PT6312_DATA = 0;
vfd_data >>= 1;
PT6312_CLK = 1;
}
}
void KEY_Process(void)
{
KEY_Scan_Save();
bKEY = Get_KEYVAL();
oldKEY = bKEY;
if ((bKEY == oldKEY) && (FREQ_SEC_TIME == 0))
Write_GID6(&DISP_CHAR1);
switch(bKEY)
{
case 1:
Write_GID6(&DISP_KEY01);
break;
case 2:
Write_GID6(&DISP_KEY02);
break;
case 3:
Write_GID6(&DISP_KEY03);
break;
case 4:
Write_GID6(&DISP_KEY04);
break;
case 5:
Write_GID6(&DISP_KEY05);
break;
case 6:
Write_GID6(&DISP_KEY06);
break;
case 7:
Write_GID6(&DISP_KEY07);
break;
case 8:
Write_GID6(&DISP_KEY08);
break;
case 9:
Write_GID6(&DISP_KEY09);
break;
case 10:
Write_GID6(&DISP_KEY10);
break;
case 11:
Write_GID6(&DISP_KEY11);
break;
case 12:
Write_GID6(&DISP_KEY12);
break;
// default:
// Write_GID6(&DISP_CHAR1);
// break;
}
}
BYTE Get_KEYVAL(void)
{
BYTE keyval;
if (KEY_BUF[0])
{
while (KEY_BUF[0]) //按键在KEY_BUF[0],如: 0001 0000,keyval == 5
{
keyval++;
KEY_BUF[0] >>= 1;
};
};
if (KEY_BUF[1])
{
keyval = 8;
while (KEY_BUF[1]) //按键在KEY_BUF[1],如: 0001 0000,keyval == 13
{
keyval++;
KEY_BUF[1] >>= 1;
};
};
if (KEY_BUF[2])
{
keyval = 16;
while (KEY_BUF[2]) //按键在KEY_BUF[2],如: 0000 1000,keyval == 20
{
keyval++;
KEY_BUF[2] >>= 1;
};
};
return(keyval);
}
void KEY_Scan_Save(void)
{
BYTE keybuf_number;
PT6312_STB = 0;
Write_A_ByteTo_VFD(0x76);
for (keybuf_number = 0 ;keybuf_number < 3;keybuf_number++)
{
KEY_BUF[keybuf_number] = RD_A_Bytefrom_VFD() ;
}
PT6312_STB = 1;
}
BYTE RD_A_Bytefrom_VFD(void)
{
BIT rd_temp_flag;
BYTE key_data;
BYTE rd_temp,rd_temp_keydata;
PT6312_CLK = 1;
PT6312_DATA = 1;
key_data = 0;
for(rd_temp = 0;rd_temp < 8;rd_temp++)
{
PT6312_CLK = 0;
rd_temp_flag = PT6312_DATA;
if (rd_temp_flag)
{
rd_temp_keydata = 0x80;
rd_temp_keydata >>= (7-rd_temp);
key_data |= rd_temp_keydata;
}
PT6312_CLK = 1;
}
return(key_data);
}
void Light_all_Write(void) //显示数据暂存数组的所有要显示的内容写入到PT6312
{
BYTE fill_temp;
PT6312_STB = 1;
PT6312_STB = 0;
Write_A_ByteTo_VFD(0x40); //数据写入到PT6312后其内部地址自动+1
PT6312_STB = 1;
for (fill_temp=0;fill_temp<12;fill_temp++)
{
PT6312_STB = 0;
Write_A_ByteTo_VFD(0xC0+(11-fill_temp));
Write_A_ByteTo_VFD(DISP_ARRAY[fill_temp]); //暂存显示数据的数组和PT6312内部地址一一对应
PT6312_STB = 1;
}
}
/*************************************************************************************************/
void Write_GID6(BYTE *charp)
{
BYTE char_temp;
for( char_temp = 2;char_temp < 8;char_temp++) //DISP_ARRAY数组DISP_ARRAY[2]~DISP_ARRAY[7]主显示内容更新
{
DISP_ARRAY[char_temp] = *charp;
charp++; //指针++指象实参数组下一个元素
}
}
/*************************************************************************************************/
void disp_Chag_disc() //DISC图标动画
{
DISP_ARRAY[0] = 0x50; //点亮其他一些图标"ALL","播放"
switch(DISC_RUN_TIME)
{
case 0:
{
DISP_ARRAY[1] = 0x5f; //01011111 //图标可以单独给个位变量来"与"&
break;
}
case 1:
{
DISP_ARRAY[1] = 0x6f;
break;
}
case 2:
{
DISP_ARRAY[1] = 0x77;
break;
}
case 3:
{
DISP_ARRAY[1] = 0x7b;
break;
}
case 4:
{
DISP_ARRAY[1] = 0x7d;
break;
}
case 5:
{
DISP_ARRAY[1] = 0x7e;
break;
}
}
}
/*************************************************************************************************/
void freqrange_to_disp() //显示频谱
{
switch(FREQ_TIME) //模拟的一些频谱幅度,后续根据这个幅度取DISP_FREQ1~3数组的值
//如果有动态的音频取样只需要取样值变化再取显示点亮的格数值
{
case 0:
{
FREQ_RANGE[0] = 2;
FREQ_RANGE[1] = 4;
FREQ_RANGE[2] = 1;
FREQ_RANGE[3] = 1;
break;
}
case 1:
{
FREQ_RANGE[0] = 1;
FREQ_RANGE[1] = 6;
FREQ_RANGE[2] = 1;
FREQ_RANGE[3] = 2;
break;
}
case 2:
{
FREQ_RANGE[0] = 4;
FREQ_RANGE[1] = 7;
FREQ_RANGE[2] = 3;
FREQ_RANGE[3] = 4;
break;
}
case 3:
{
FREQ_RANGE[0] = 3;
FREQ_RANGE[1] = 4;
FREQ_RANGE[2] = 5;
FREQ_RANGE[3] = 2;
break;
}
case 4:
{
FREQ_RANGE[0] = 6;
FREQ_RANGE[1] = 5;
FREQ_RANGE[2] = 7;
FREQ_RANGE[3] = 5;
break;
}
case 5:
{
FREQ_RANGE[0] = 6;
FREQ_RANGE[1] = 1;
FREQ_RANGE[2] = 3;
FREQ_RANGE[3] = 1;
break;
}
case 6:
{
FREQ_RANGE[0] = 3;
FREQ_RANGE[1] = 2;
FREQ_RANGE[2] = 1;
FREQ_RANGE[3] = 2;
break;
}
case 7:
{
FREQ_RANGE[0] = 7;
FREQ_RANGE[1] = 6;
FREQ_RANGE[2] = 4;
FREQ_RANGE[3] = 3;
break;
}
case 8:
{
FREQ_RANGE[0] = 2;
FREQ_RANGE[1] = 4;
FREQ_RANGE[2] = 5;
FREQ_RANGE[3] = 1;
break;
}
case 9: //十种变化
{
FREQ_RANGE[0] = 5;
FREQ_RANGE[1] = 7;
FREQ_RANGE[2] = 6;
FREQ_RANGE[3] = 7;
break;
}
}
}
void disp_Chag_freq()
{
freqrange_to_disp();
switch(FREQ_ST_TIME)
{
case 0:
{
Write_GID4(&DISP_FREQ1,&FREQ_RANGE);
break;
}
case 1:
{
Write_GID4(&DISP_FREQ2,&FREQ_RANGE);
break;
}
case 2:
{
Write_GID4(&DISP_FREQ3,&FREQ_RANGE);
break;
}
default:
Write_GID4(&DISP_FREQ1,&FREQ_RANGE);
}
}
void Write_GID4(BYTE *freqp,BYTE *freqrp) //两个指针的应用
{
BYTE freq_temp;
for( freq_temp = 8;freq_temp < 12;freq_temp++)
{
DISP_ARRAY[freq_temp] = freqp[*freqrp];
freqrp++;
}
}
/*************************************************************************************************/
void TR0_Service(void) interrupt 1 using 2 //TR0的定时中断函数,此函数应简单。使用寄存器组2
{
TH0 = MS20H; //重点掌握此定时方式可任意定时
TL0 = MS20L;
if(!SEC_TIME) //基准时间5X20MS = 100ms
{
DISC_RUN_TIME++;
if( DISC_RUN_TIME == 6) //DVD转盘旋转一圈需要6种状态改变,DISC_RUN_TIME变化就改变一下状态
DISC_RUN_TIME = 0;
SEC_TIME = 5;
if(!FREQ_TIME)
{
FREQ_TIME = 10; //根据FREQ_TIME值可更新10种频谱幅度每100MS变化一次
if(!FREQ_SEC_TIME)
{
FREQ_SEC_TIME = 15; //15s //15s基准
if(!FREQ_ST_TIME) //FREQ_ST_TIME赋值则可根据FREQ_ST_TIME值每15S调用更新
{
FREQ_ST_TIME = 3; //三种主显示内容和频谱模式,他们复用每判断
}
else
{
FREQ_ST_TIME--;
}
}
else
{
FREQ_SEC_TIME--;
}
}
else
{
FREQ_TIME--;
}
}
else
{
SEC_TIME--;
}
}
/*end code 2009/1/7 How to program C!*/ |
|