村网通总站 姬家寨村 455496.nync.com 欢迎您!
《姬家寨牌汉字点阵音乐频谱显示系统》
硬件设计:姬学瑞;软件编程:姬学瑞;版权所有,侵权必究!
中国新乡市姬家寨村电子科技研究所研制!
一main.c
#include "STC12C5A.h"
#include <intrins.h>
#include <math.h>
#include "DS1302.h"
#include "Led.h"
#define uchar unsigned char
#define uint unsigned int
#define BinToHex(n) (((n>>21)&0x80)|((n>>18)&0x40)|((n>>15)&0x20)|((n>>12)&0x10)|((n>>9)& 0x08)|((n>>6)&0x04)|((n>>3)&0x02)|((n)&0x01))
#define B(n) BinToHex(0x##n##l) // 8位2进制宏
uchar code ColScan_2[16] = {0x17,0x13,0x15,0x11,0x16,0x12,0x14,0x10,
0x27,0x23,0x25,0x21,0x26,0x22,0x24,0x20}; // 74hc138 进行列扫描
float code iw[64]=
{
1.000,0,0.9952,-0.0980,0.9808,-0.1951,0.9569,-0.2903,0.9239,-0.3827,0.8819,-0.4714,0.8315,-0.5556,
0.7730,-0.6344,0.7071,-0.7071,0.6344,-0.7730,0.5556,-0.8315,0.4714,-0.8819,0.3827,-0.9239,0.2903,-0.9569,
0.1951,-0.9808,0.0980,-0.9952,0.0,-1.0000,-0.0980,-0.9952,-0.1951,-0.9808,-0.2903,0.9569,-0.3827,-0.9239,
-0.4714,-0.8819,-0.5556,-0.8315,-0.6344,-0.7730,-0.7071,-0.7071,-0.7730,-0.6344,-0.8315,-0.5556,-0.8819,-0.4714,
-0.9239,-0.3827,-0.9569,-0.2903,-0.9808,-0.1951,-0.9952,-0.0980
};
uint data LEDBuf[16];
uint idata refreshflag[16];
uchar fft_sign = 0; // 进行fft变换标志位
struct compx
{
float real;
float imag;
};
struct compx dd[65]; // FFT数据
data struct compx temp;
void delay500ms(void)
{
unsigned char a,b,c,n;
for(c=218;c>0;c--)
for(b=79;b>0;b--)
for(a=238;a>0;a--);
for(n=4;n>0;n--);
}
void Delay(uint n)
{
uint x;
while (n--)
{
x = 5000;
while (x--);
}
}
void GPIO_Init() // GPIO口的初始化
{
P1M1 = B(00000011);
P1M0 = B(00000000);
P1 = B(00000011);
P1ASF = B(00000011);
}
void Interrupt_Init(void) // 单片机中断初始化
{
TMOD = 0x01; // 高4位控制T/C1
EA = 1; // 开总中断
TH0 = 0x00; // 16位计数寄存器T1高8位
TL0 = 0x00; // 16位计数寄存器T1低8位
ET0 = 1; // T/C1中断开
TR0 = 1; // T/C1启动
}
void ADC_Init() // 集成ADC的初始化(官方函数)
{
ADC_RES = 0; //Clear previous result
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
Delay(2); //ADC power-on and delay
}
uchar GetADCResult(uchar ch) // 进行AD转换(官方函数)
{
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
_nop_(); //Must wait before inquiry
_nop_();
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag
ADC_CONTR &= ~ADC_FLAG; //Close ADC
return ADC_RES; //Return ADC result
}
void ee(struct compx b1,uchar b2) //复数乘法
{
temp.real=b1.real*iw[2*b2]-b1.imag*iw[2*b2+1];
temp.imag=b1.real*iw[2*b2+1]+b1.imag*iw[2*b2];
}
uint mypow(uchar nbottom,uchar ntop) //乘方函数
{
uint result=1;
uchar t;
for(t=0;t<ntop;t++)result*=nbottom;
return result;
}
void fft(struct compx *xin,uchar data N) //快速傅立叶变换
{
uchar data fftnum,i,j,k,l,m,n,disbuff,dispos,dissec;
data struct compx t;
fftnum=N; //傅立叶变换点数
for(m=1;(fftnum=fftnum/2)!=1;m++);//求得M的值
for(k=0;k<=N-1;k++) //码位倒置
{
n=k;
j=0;
for(i=m;i>0;i--) //倒置
{
j=j+((n%2)<<(i-1));
n=n/2;
}
if(k<j){t=xin[1+j];xin[1+j]=xin[1+k];xin[1+k]=t;}//交换数据
}
for(l=1;l<=m;l++) //FFT运算
{
disbuff=mypow(2,l); //求得碟间距离
dispos=disbuff/2; //求得碟形两点之间的距离
for(j=1;j<=dispos;j++)
for(i=j;i<N;i=i+disbuff) //遍历M级所有的碟形
{
dissec=i+dispos; //求得第二点的位置
ee(xin[dissec],(uint)(j-1)*(uint)N/disbuff);//复数乘法
t=temp;
xin[dissec].real=xin[i].real-t.real;
xin[dissec].imag=xin[i].imag-t.imag;
xin[i].real=xin[i].real+t.real;
xin[i].imag=xin[i].imag+t.imag;
}
}
}
void processfft(uchar num)
{
uchar pt;
uint tmp;
for(pt=1;pt<65;pt++)
{
dd[pt].imag=0; //清零虚部
}
fft(dd,64); //对当前数据进行傅立叶变换
for(pt=1;pt<33;pt++)
{
dd[pt].real=sqrt(dd[pt].real*dd[pt].real+dd[pt].imag*dd[pt].imag);//取均方根
}
switch(num)
{ // 选择显示模式
case 1: {
for(pt=0;pt<16;pt++) // style 1
{
LEDBuf[pt]=0xffff;
tmp = dd[(pt+1)*2].real;
tmp = (tmp/16)+1;
LEDBuf[pt]<<=tmp;
LEDBuf[pt]=~(LEDBuf[pt]);
}
break;
}
case 2: {
for(pt=0;pt<16;pt++) // style 2
{
if(refreshflag[pt]<(dd[pt].real/16)+1)
{
LEDBuf[pt]=0xffff;
tmp = dd[(pt+1)*2].real;
tmp = (tmp/16)+1;
refreshflag[pt] = tmp;
LEDBuf[pt]<<=tmp;
}
else
{
if(refreshflag[pt]>1)
{
refreshflag[pt]--;
}
LEDBuf[pt]=0xffff;
tmp = refreshflag[pt];
LEDBuf[pt]<<=tmp;
}
LEDBuf[pt]=~(LEDBuf[pt]);
}
break;
}
case 3: { // style 3
for(pt=0;pt<16;pt++)
{
LEDBuf[pt]=0xffff;
tmp = dd[(pt+1)*2].real;
tmp = (tmp/16)+1;
if(refreshflag[pt]<tmp)
{
refreshflag[pt] = tmp;
}
else
{
if(refreshflag[pt]>1)
{
refreshflag[pt]--;
}
tmp = refreshflag[pt];
}
LEDBuf[pt]&=(0x0001<<(tmp-1));
}
break;
}
case 4: { // style 4
for(pt=0;pt<16;pt++)
{
LEDBuf[pt]=0xffff;
tmp = dd[(pt+1)*2].real;
tmp = (tmp/16)+1;
LEDBuf[pt]<<=tmp;
LEDBuf[pt]=~(LEDBuf[pt]);
if(refreshflag[pt]<tmp)
{
refreshflag[pt] = tmp;
}
else
{
if(refreshflag[pt]>1)
{
refreshflag[pt]--;
}
tmp = refreshflag[pt];
}
LEDBuf[pt]|=(0x0001<<(tmp-1));
}
}
}
}
void main()
{
uchar i,num=1;
uint n;
GPIO_Init(); // io口初始化
ADC_Init(); // 集成adc初始化
DS1302Init(); // 初始化1302
MyLove(); // 开机动画
while(GetADCResult(0)+GetADCResult(1)==0) // 没有插入耳机时
{
DisplayTime(); // 显示时间
TimeSetting(); // 时间设定
}
for(i=0;i<16;i++) // 清空数据缓存
{
refreshflag[i] = 0x0000;
}
Interrupt_Init();
while(1)
{
if(fft_sign == 1) // 读取频率为20Hz
{
fft_sign = 0;
for(i=0;i<65;i++)
{
dd[i].real=(GetADCResult(0)+GetADCResult(1))<<2; // 读取ad结果并放大4倍;
}
processfft(num); // 傅立叶变化及处理
}
for(i=0;i<16;i++)
{ // 显示
LineInput(0x0000);
P2 = ColScan_2[i];
LineInput(LEDBuf[i]);
n = 512;
while(n--);
LineInput(0x0000);
}
if(ACT_Key == 0) // 动作检测,切换效果
{
num++;
if(num>4)
{
num = 1;
}
delay500ms();
}
}
}
void Timer0() interrupt 1 //20hz
{
TL0 = 0x3c;
TH0 = 0xb0;
fft_sign = 1;
}
二DS1302.c
/******************1302读写指令***************************/
#include"DS1302.h"
void delay10us(void) //误差 -0.030303030303us
{
unsigned char a,b;
for(b=23;b>0;b--)
for(a=2;a>0;a--);
_nop_(); //if Keil,require use intrins.h
}
void DS1302Write(uchar addr,dat) //地址、数据发送子程序
{
uchar i,temp;
CE = 0; //CE引脚为低,数据传送中止
SCLK = 0; //清零时钟总线
CE = 1; //CE引脚为高,逻辑控制有效
for(i=8;i>0;i--) //发送地址
{
SCLK = 0;
temp = addr;
DIO = (bit)(temp&0x01);
addr>>= 1;
delay10us();
SCLK = 1;
}
for (i=8;i>0;i--) //发送数据
{
SCLK = 0;
temp = dat;
DIO = (bit)(temp&0x01);
dat>>= 1;
delay10us();
SCLK = 1;
}
CE = 0;
}
uchar DS1302Read(uchar addr) //数据读取子程序
{
uchar i,temp;
CE = 0;
SCLK = 0;
CE = 1;
for(i=8;i>0;i--) //发送地址
{
SCLK =0;
temp =addr;
DIO =(bit)(temp&0x01);
addr>>= 1;
delay10us();
SCLK = 1;
}
for(i=8;i>0;i--) //读取数据
{
ACC_7 = DIO;
SCLK = 1;
ACC>>= 1;
delay10us();
SCLK =0;
}
CE = 0;
return(ACC);
}
void DS1302Init(void)
{
DS1302Write(0x8e,0x00); //写保护关
DS1302Write(0x80,DS1302Read(0x81)&0x7f); //启动1302
// DS1302Write(0x82,0x52); //初始分钟值
// DS1302Write(0x84,0x10); //初始小时模式 初始时间
// DS1302Write(0x86,0x04); //初始天数
// DS1302Write(0x88,0x03); //初始月数
// DS1302Write(0x8c,0x13); //初始年数
// DS1302Write(0x8a,0x01); //初始星期
DS1302Write(0x8e,0xff); //开写保护
}
三led.c
#include "Led.h"
uint code ILoveWenWen[15][16] = {
{0x0810,0x0c10,0x2b20,0x18c0,0x08c0,0x0f20,0x0810,0x0810,
0x0408,0x0608,0x1598,0x0c60,0x0460,0x0790,0x0408,0x0408}, // 显示 1
{0x4002,0x7ffe,0x4002,0x1fc0,0x2020,0x2010,0x1008,0x0804,
0x1008,0x2010,0x2020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 显示 I Love You 2
{0x4002,0x7ffe,0x4002,0x1fc0,0x3020,0x2010,0x1008,0x0804,
0x1008,0x2010,0x2020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 3
{0x4002,0x7ffe,0x4002,0x1fc0,0x3820,0x3010,0x1008,0x0804,
0x1008,0x2010,0x2020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 4
{0x4002,0x7ffe,0x4002,0x1fc0,0x3c20,0x3810,0x1008,0x0804,
0x1008,0x2010,0x2020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 5
{0x4002,0x7ffe,0x4002,0x1fc0,0x3e20,0x3c10,0x1808,0x0804,
0x1008,0x2010,0x2020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 6
{0x4002,0x7ffe,0x4002,0x1fc0,0x3f20,0x3e10,0x1c08,0x0804,
0x1008,0x2010,0x2020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 7
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fa0,0x3f10,0x1e08,0x0c04,
0x1808,0x3010,0x2020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 8
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fe0,0x3f90,0x1f08,0x0e04,
0x1c08,0x3810,0x3020,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 9
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fe0,0x3fd0,0x1f88,0x0f04,
0x1e08,0x3c10,0x3820,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 10
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fe0,0x3ff0,0x1fc8,0x0f84,
0x1f08,0x3e10,0x3c20,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 11
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fe0,0x3ff0,0x1fe8,0x0fc4,
0x1f88,0x3f10,0x3e20,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 12
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fe0,0x3ff0,0x1ff8,0x0fe4,
0x1fc8,0x3f90,0x3f20,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 13
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fe0,0x3ff0,0x1ff8,0x0ff4,
0x1fe8,0x3fd0,0x3fa0,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 14
{0x4002,0x7ffe,0x4002,0x1fc0,0x3fe0,0x3ff0,0x1ff8,0x0ffc,
0x1ff8,0x3ff0,0x3fe0,0x1fc0,0x7ffc,0x0002,0x0002,0x7ffc}, // 15
};
uint code Dis_num[10][3] = {
{0x3ffc,0x300c,0x3ffc}, // 0
{0x0000,0x0000,0x3ffc}, // 1
{0x31fc,0x318c,0x3f8c}, // 2
{0x318c,0x318c,0x3ffc}, // 3
{0x3f80,0x0180,0x3ffc}, // 4
{0x3f8c,0x318c,0x31fc}, // 5
{0x3ffc,0x318c,0x31fc}, // 6
{0x3000,0x3000,0x3ffc}, // 7
{0x3ffc,0x318c,0x3ffc}, // 8
{0x3f8c,0x318c,0x3ffc} // 9
};
uchar code ColScan[16] = {0x17,0x13,0x15,0x11,0x16,0x12,0x14,0x10,
0x27,0x23,0x25,0x21,0x26,0x22,0x24,0x20}; // 74hc138 进行列扫描
void delay10ms(void)
{
unsigned char a,b,c;
for(c=199;c>0;c--)
for(b=120;b>0;b--)
for(a=1;a>0;a--);
}
void LineInput(uint dat) // 单列数据显示
{
uchar n;
_RCLK = 0;
for(n=0;n<16;n++)
{
_SRCLK = 0;
_SER = (dat>>n)&0x01;
_SRCLK = 1;
}
_RCLK = 1;
}
void DisplayTime(void)
{
uchar m,n,i,a,b;
static uchar breathe = 255;
static uchar sign = 0;
n = 0;
a = DS1302Read(0x85)&0x0f; // 读取小时的个位
b = (DS1302Read(0x85)&0x70)>>4; // 读取小时的十位
for(i=0;i<3;i++) // 显示小时的十位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[b][i]);
n++;
m = light;
while(m--); // 亮度调节
LineInput(0x0000);
}
n++; // 空一行
for(i=0;i<3;i++) // 显示小时的个位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[a][i]);
n++;
m = light;
while(m--);
LineInput(0x0000);
}
for(i=0;i<2;i++) // 显示分割符 呼吸效果
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(0x0660);
n++;
if(sign == 0) // 渐渐变暗
{
breathe--;
if(breathe == 0)
{
sign = 1;
}
}
else
{
breathe++;
if(breathe == 255)
{
sign = 0;
}
}
m = breathe;
while(m--);
LineInput(0x0000);
}
a = DS1302Read(0x83)&0x0f; // 读取分钟个位
b = (DS1302Read(0x83)&0x70)>>4; // 读取分钟十位
for(i=0;i<3;i++) // 显示分钟十位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[b][i]);
n++;
m = light;
while(m--);
LineInput(0x0000);
}
n++; // 空一行
for(i=0;i<3;i++) // 显示分钟个位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[a][i]);
n++;
m = light;
while(m--);
LineInput(0x0000);
}
}
void TimeSetting(void)
{
uchar m,n,i,a,b,x;
if(Key_1==0) // 按键进入时间设定
{
delay10ms();
delay10ms();
if(Key_1==0) // 确定按下按键
{
while(Key_1==0); // 松手检测
a = DS1302Read(0x85)&0x0f; // 读取小时的个位
b = (DS1302Read(0x85)&0x70)>>4; // 读取小时的十位
x = 10*b+a; // 化成十进制数
while(Key_1==1) // 首先设定小时
{
n = 0;
for(i=0;i<3;i++) // 显示小时的十位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[b][i]);
n++;
m = light;
while(m--); // 亮度调节
LineInput(0x0000);
}
n++; // 空一行
for(i=0;i<3;i++) // 显示小时的个位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[a][i]);
n++;
m = light;
while(m--);
LineInput(0x0000);
}
if(Key_2==0) // 按下另外一键使小时加一
{
delay10ms();
delay10ms();
if(Key_2==0)
{
while(Key_2==0);
x++;
if(x>23) // 小时的最大值为23
{
x = 0;
}
a = x%10;
b = x/10;
}
}
}
delay10ms();
delay10ms();
while(Key_1==0); // 松手检测
x = a+(b<<4);
DS1302Write(0x8e,0x00); // 写保护关
DS1302Write(0x84,x); // 保存更改
DS1302Write(0x8e,0xff); // 开写保护
a = DS1302Read(0x83)&0x0f; // 读取分钟的个位
b = (DS1302Read(0x83)&0x70)>>4; // 读取分钟的十位
x = 10*b+a; // 化成十进制数
while(Key_1==1) // 然后设定分钟
{
n = 9;
for(i=0;i<3;i++) // 显示分钟的十位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[b][i]);
n++;
m = light;
while(m--); // 亮度调节
LineInput(0x0000);
}
n++; // 空一行
for(i=0;i<3;i++) // 显示分钟的个位
{
LineInput(0x0000);
P2 = ColScan[n];
LineInput(Dis_num[a][i]);
n++;
m = light;
while(m--);
LineInput(0x0000);
}
if(Key_2==0) // 按下另外一键使分钟加一
{
delay10ms();
delay10ms();
if(Key_2==0)
{
while(Key_2==0);
x++;
if(x>59) // 分钟的最大值为23
{
x = 0;
}
a = x%10;
b = x/10;
}
}
}
delay10ms();
delay10ms();
while(Key_1==0); // 松手检测
x = a+(b<<4);
DS1302Write(0x8e,0x00); // 写保护关
DS1302Write(0x82,x); // 保存更改
DS1302Write(0x8e,0xff); // 开写保护
}
}
}
void MyLove(void)
{
uchar m,i;
int n;
for(n=0;n<=256;n++)
{
for(i=0;i<16;i++)
{
LineInput(0x0000);
P2 = ColScan[i];
if(i <= n>>4)
{
LineInput(ILoveWenWen[0][i]|0x8000);
}
else
{
LineInput(ILoveWenWen[0][i]);
}
m = light;
while(m--);
LineInput(0x0000);
}
}
for(n=256;n>=0;n--)
{
for(i=0;i<16;i++)
{
LineInput(0x0000);
P2 = ColScan[i];
if(i >= n>>4)
{
LineInput(ILoveWenWen[0][i]|0x8001);
}
else
{
LineInput(ILoveWenWen[0][i]|0x8000);
}
m = light;
while(m--);
LineInput(0x0000);
}
}
for(n=0;n<=1024;n++)
{
for(i=0;i<16;i++)
{
LineInput(0x0000);
P2 = ColScan[i];
if((n>>6)>=13)
{
LineInput(ILoveWenWen[14][i]);
}
else
{
LineInput(ILoveWenWen[(n>>6)+1][i]);
}
m = light;
while(m--);
LineInput(0x0000);
}
}
}