信号发生器设计报告
电子琴程序
2009-08-30 13:47:34| 分类: 默认分类
| 标签: |举报 |字号大中小 订阅
电子琴程序发送部分:
/*
本程序是用AD9851的DDS模块做的电子琴,
电子琴的音符完整,共21个按键,分别是低1--7,中1--7,高1--7。本程序为双机通信的发送部分,可以显示频率
*/
#include <REG51.H> //
单片机内部专用寄存器定义
/**************************************/
sbit K1= P1^0 //
键K1输入引脚定义
sbit K2= P1^1 // 键K2输入引脚定义
sbit K3= P1^2 //
键K3输入引脚定义
sbit K4= P1^3 // 键K4输入引脚定义
sbit K5= P1^4 //
键K5输入引脚定义
sbit K6= P1^5 // 键K6输入引脚定义
sbit K7= P1^6 //
键K7输入引脚定义
sbit K8= P1^7 //
键K15输入引脚定义
/**************************************/
sbit K9= P2^0 //
键K8输入引脚定义
sbit K10= P2^1 // 键K9输入引脚定义
sbit K11= P2^2 //
键K10输入引脚定义
sbit K12= P2^3 // 键K11输入引脚定义
sbit K13= P2^4 //
键K12输入引脚定义
sbit K14= P2^5 // 键K13输入引脚定义
sbit K15= P2^6 //
键K14输入引脚定义
sbit K16= P2^7 //
键K16输入引脚定义
/**************************************/
sbit K17= P3^2 //
键K17输入引脚定义
sbit K18= P3^3 // 键K18输入引脚定义
sbit K19= P3^4 //
键K19输入引脚定义
sbit K20= P3^5 // 键K20输入引脚定义
sbit K21= P3^7 // 键K21输入引脚定义
/******************延时程序********************/
void delay(unsigned int
k)
{
unsigned int i,j
for(i=0i<ki++){
for(j=0j<121j++)
{}}
}
/*****************串口初始化程序*****************/
void
init
(void)
{
TMOD=0x20
TH1=0xfd
TL1=0xfd
SCON=0x50
TR1=1
}
/*****************串口发送程序*****************/
void chuan(shu)
{
SBUF=shu
TI=0
}
/******************主程序********************/
void main(void)
{
init()
while(1)
{
if(K1==0) chuan(1)
else if(K2==0)
chuan(2)
else if(K3==0) chuan(3)
else if(K4==0) chuan(4)
else
if(K5==0) chuan(5)
else if(K6==0) chuan(6)
else if(K7==0)
chuan(7)
else if(K8==0) chuan(8)
else if(K9==0) chuan(9)
else
if(K10==0) chuan(10)
else if(K11==0) chuan(11)
else if(K12==0)
chuan(12)
else if(K13==0) chuan(13)
else if(K13==0)
chuan(13)
else if(K14==0) chuan(14)
else if(K15==0)
chuan(15)
else if(K16==0) chuan(16)
else if(K17==0)
chuan(17)
else if(K18==0) chuan(18)
else if(K19==0)
chuan(19)
else if(K20==0) chuan(20)
else if(K21==0)
chuan(21)
elsechuan(0)
}
}
电子琴接收部分:
/*
本程序是用AD9851的DDS模块做的电子琴,
电子琴的音符完整,共21个音符,分别是低1--7,中1--7,高1--7。本程序为双机通信的接受部分。有直接演奏方式,录音演奏方式,录音后放音方式
,可以显示频率 */
#include <STC12C5410AD.H>
#include<intrins.h>
#include <stdio.h> /* prototype
declarations for I/O functions */
#define uchar unsigned char
#define uint unsigned int
sbit
E_CLK =P2^6//clock input 同步时钟输入端
sbit RW_SID
=P2^5//data input/output 串行数据输入、输出端
sbit RS_DI
=P2^4 // 4号脚 jichunqiinput
sbit DataIn_AD9851=P2^3
//控制子串传送位
sbit DDS_CLK=P2^2//接外部晶振时钟 这里为30M
sbit
DDS_FQUD=P2^1 //更新发送频率
sbit RST_AD9851= P2^0//复位
unsigned char Control_AD9851 = 0x01// Phase0 ,power on mode and 6 REFCLK
Multiplier enable
/* T0_int 定时 时间常数 5ms=5000=1388H->EC78H f=12MH */
#define
time_5ms_H 0xC2 /* 定时时间为1/64s */
#define time_5ms_L 0xF7
charshu, bb
unsigned char p=0
unsigned char
point=0
unsigned char recode_n=0
unsigned char xdata
array[50]={0}
unsigned int xdata arrayt[50]={0}
float const
ton[]={0.00,261.63,293.67,329.63,349.23,391.99,440.00,494.00,
523.25,587.33,659.25,698.46,783.99,880.00,987.76,
1046.50,1174.66,1381.51,1396.92,1567.98,1760.00,1975.52}
unsigned int ttt,
nnn
unsigned char mode=0
sbit KEY_rec =P3^5
sbit KEY_play=P3^7
/*************************延时程序***************************/
void
delay(uint k)
{
uint i,j
for(i=0i<ki++)
{for(j=0j<121j++)
{}}
}
/*************************串行发送一字节数据***************************/
void SendByte(unsigned char dat)
{
unsigned
char i
RS_DI=1
for(i=0i<8i++)
{
E_CLK=0
if(dat&0x80)RW_SID=1
else RW_SID=0
E_CLK=1
dat=dat<<1
}
}
/*************************写控制命令***************************/
void
SendCMD(unsigned char dat)
{
SendByte(0xF8)//11111,00,0
RW=0,RS=0 同步标志
SendByte(dat&0xF0)//高四位
SendByte((dat&0x0F)<<4)//低四位
}
/************************写显示数据或单字节字符 ****************************/
void SendDat(unsigned char dat)
{
SendByte(0xFA)//11111,01,0 RW=0,RS=1
SendByte(dat&0xF0)//高四位
SendByte((dat&0x0F)<<4)//低四位
}
/************************显示字符串****************************/
void
hzkdis(unsigned char code *s)
{ while(*s>0)
{
SendDat(*s)
s++
delay(5)
}
}
/************************显示数据子程序****************************/
void
Display(unsigned char x_add,unsigned long date,unsigned char dot)
{
unsigned char date0,date1,date2,date3,date4,date5//
date5=(date%1000000)/100000
date4=(date%100000)/10000
date3=(date%10000)/1000
date2=(date%1000)/100
date1=(date%100)/10
date0=date%10
SendCMD(x_add)
if(dot==0x02) //100---9999.99
{
SendDat(0x30+date5)
SendDat(0x30+date4)
SendDat(0x30+date3)
SendDat(0x30+date2)
SendDat(0x2e)
SendDat(0x30+date1)
SendDat(0x30+date0)
SendDat(0x48)
SendDat(0x7a)
}
}
/*************************设置AD9851频率***************************/
void
SentFreq(unsigned long int freq)
{
unsigned char i=0
unsigned int
temp
DDS_FQUD=0
for(i=0i<32i++) //串口数据
输入频率控制字
{
DDS_CLK =
0
temp=((freq>>i)&1)
DataIn_AD9851 = temp
DDS_CLK =
1
}
for(i=0i<8i++)//phase-b4 ph-b3 ph-b2 ph-b1 ph-b0 Power-down
Logic0* 6*REFCLK Multiplier_En
{
DDS_CLK = 0
temp=((Control_AD9851>>i)&1)
DataIn_AD9851 = temp
DDS_CLK = 1
}
DDS_CLK = 0
DDS_FQUD = 1
DDS_FQUD =
0
}
/**************************换算频率,并输出***********************/
void
Set_Freq(float Freqency)
{unsigned long int freq_temp
freq_temp=
(unsigned long int)(23.861*Freqency)// SYSCLK = 180 MHz
2^32/180000000=23.861
SentFreq(freq_temp)
}
/*************************T0作定时器,T1作波特率发生器,初始化*************************/
void
init (void)
{
TMOD= 0x01 /* 0001$0001 T1 &T0 are 16bit
timers */
TH0 = time_5ms_H/* T0 timer 5ms */
TL0 =
time_5ms_L
/* TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 */
TCON= 0x10 /* 0 0 0 1 0 0 0 0 */
/*start T0xint1 xint0 */
IE= 0x82/* 1000 0010,
EA=ET0=1,
*/
TMOD=0x20
TH1=0xfd
TL1=0xfd
TR1=1
SCON=0x50
ES=1
EA=1
}
/*************************设置AD9851初始化*************************/
void
AD9851Init(void) //DDS初始化函数,包括DDS复位和初始化为串行发送
{
DDS_CLK=0
DDS_FQUD=0
RST_AD9851=0
RST_AD9851=1//复位AD9851
RST_AD9851=1
RST_AD9851=1
RST_AD9851=0
DDS_CLK=1
DDS_CLK=0
DDS_FQUD=1
DDS_FQUD=0
}
/**************************初始化LCM
**************************/
void initlcm(void)
{
delay(100)
SendCMD(0x30)//功能设置,一次送8位数据,基本指令集
SendCMD(0x0C)//0000,1100 整体显示,游标off,游标位置off
SendCMD(0x14)
SendCMD(0x01)//0000,0001 清DDRAM 即清屏
SendCMD(0x02)//0000,0010 DDRAM地址归位
SendCMD(0x80)//1000,0000
设定DDRAM 7位地址000,0000到地址计数器AC
//SendCMD(0xb8|page)翻页
}
/**********************主程序******************************/
void
main(void)
{
uchar t
init()
AD9851Init()
initlcm()//12864初始化程序
shu=0
bb=255
while(1)
{
switch(mode)
{
case 0: //
演奏方式
SendCMD(0x80)//第一行(如果是地址是:80H,即LCD的第一行的第一个位置显示)
hzkdis("
音乐播放频率:")
if (shu!=bb)
{
Set_Freq(ton[shu])
Display(0x93,(unsigned
long)100*ton[shu],0x02)
bb=shu
}
if
(KEY_rec==0)
{
mode=1
point=0
recode_n=0
shu=0
bb=255
nnn=0
}
else if (KEY_play==0)
{
mode=2
p=1
}
break
case
1: // 录音方式
// SendCMD(0x01)//0000,0001 清DDRAM 即清屏
//
delay(10)
SendCMD(0x80)//第一行(如果是地址是:80H,即LCD的第一行的第一个位置显示)
hzkdis("
音乐录制频率:")
if (shu!=bb)
{
arrayt[point]=nnn // 记录上一音阶时间
Set_Freq(ton[shu])
Display(0x93,(unsigned long)100*ton[shu],0x02)
nnn=0
bb=shu
recode_n++
}
if ((recode_n>=50) || (KEY_play==0))
//停止录音
{
Set_Freq(0.0)
p=0
mode=0
shu=0
bb=20
}
break
case 2: //
放音方式
SendCMD(0x80)//第一行(如果是地址是:80H,即LCD的第一行的第一个位置显示)
hzkdis("
音乐重播频率:")
for(t=0t<recode_nt++)
{
Set_Freq(ton[array[p]])
Display(0x93,(unsigned
long)*ton[array[p]],0x02)
ttt=arrayt[p]
while
(ttt)
delay(100)
p++
}
if
(p>recode_n)
{
Set_Freq(0.0)
p=0
mode=0
shu=0
bb=20
}
break
}
}
}
//*==================================*/
/* 串口中断接收
*/
/*==================================*/
void s_receive() interrupt 4
//串行中断
{
if(RI==1) //接收中断标志位
{
RI=0//中断标志清零
shu=SBUF //RXData赋值
}
else
TI=0
}
1,数据管显示就没什么了,找几个简单的数码管驱动程序改改就可以了,一般都是先选中数码管,然后设置值,就可以显示了,不过需要注意刷新,10ms刷新一个应该就可以了,刷新频率比较低的话会闪闪的,这个你应该明白。2,蜂鸣器发do音,这个硬件实现我就不知道了,也许有硬件可以 编码控制自动生成对应频率的值。我想如果通过软件实现的话,不妨考虑一下定时器。假设do音是1000Hz的频率(没有查,不清楚,假设的),那么你可以控制定时器的触发频率为1000hz,触发一次,对应的输出到蜂鸣器的口的电平跳变一下,如果定时器的频率为1000hz的话,那么应该有500hz的频率,一个周期需要一高一低嘛!中断读取按键信号,分析按键,然后设定定时器的频率,启动定时器,设置一个响的时间,然后到时间关闭定时器,这样你按下k1就会发出一声do的声音,然后停了。
3,按键读取程序,中断或者查询方式,自己选择吧,别忘了延迟5ms左右再次读取按键,这个是消抖的。
4,建议模块化编程,先搞定按键的,然后搞定数码管的,然后搞定定时器的,然后再考虑如何把它们组合起来。好了不说了,说得有点多了,再说会我都回到大学时代了,哈哈。总之自己一点一点的做,应该不难,51熟练,c语言熟练,板子焊接的结构比较清晰的话,很快就可以搞定的。
5,还是建议你自己写一份各个模块的驱动的代码,例如按键的,数码管的,led的,温度传感器的,光敏的,蜂鸣器的,遥控器的,定时器的,中断的,等等等等模块(可以借鉴别人写的,自己一定要会),然后需要的时候,copy过来,改改就行,快而且bug少。建议keil c语言编程,用汇编编码太耗时了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)