大学
单片机实验报告
题 目 : 流水灯设计
姓 名 : XX
学 号 :
学 院 : 计算机与信息技术学院
专 业 : 软件工程
指导教师 :
20##年6 月 3 日
灯 舞
设计思路:
程序开始运行,音乐开始播放,播放完成后,小灯开始跳舞。按下key1 键,屏幕(LCD)显示数字1,表示第一式。红、黄、绿灯依次出来亮相,灯光按红灯点亮再熄灭、黄灯点亮再熄灭、绿灯点亮再熄灭的方式循环两次。按下key2 键,屏幕显示数字2,表示第二式。各灯光就位,灯光依次按北、东、南、西四个方向点亮再同时熄灭,循环两次。按下Key3 键,屏幕显示数字3,表示第三式,小灯以对角线方式,从LED1开始按顺时针方向依次全部点亮,再按此方式熄灭,循环两次。按下Key4键,屏幕显示数字4,表示第四式。将所有的灯划为4部分:东北方向、东南方向、西南方向和西北方向的四个部分。小灯依次按东北、东南、西南、西北方向点亮,再按此方向熄灭,循环两次。按下Key5键,屏幕显示数字5,表示第五式。把中间的LED灯LEDSEC看做领舞,由其带领每个灯点亮,从LED1开始按顺时针方式点亮,全部点亮后熄灭,循环两次。按下Key6键,屏幕显示数字6,表示第六式。将所有的小灯像打开扇子一样点亮,从中间开始,全部点亮后熄灭,循环两次。
流程图:
程序清单:
//onchip.asm文件:
OPT_SET CSEG AT 80H
OPTION: DB 2EH
DB 00H
DB 00H
DB 00H
DB 03H
END
-----------------------------------------------------------------------------------------------
//music.h文件:
#ifndef _MUSIC_H_
#define _MUSIC_H_
#pragma sfr
#pragma EI //声明开中断
#pragma DI //声明关中断
void TimerInit(void);
void INTTM000(void);
__interrupt void MD_INTTM000();
void flat(int n,int m);
void stop(void);
void song(void);
#endif
------------------------------------------------------------------------------------------------------
//主程序文件:
#pragma sfr //使用特殊功能寄存器
#pragma NOP //使用空操作功能
#pragma ACCESS //使用存储器读写功能
#pragma DI //使用关中断功能
#pragma EI //使用开中断功能
#pragma interrupt INTKR OnKeyPress //使用按键中断功能
#pragma interrupt INTTM000 MD_INTTM000 // Interrupt
#include "music.h"
signed int Num = 0;
unsigned int freq_b[] = {524, 587, 660, 698, 784, 880, 988};
unsigned int regSet_b[]= {3816, 3406, 3030, 2864, 2550, 2272, 2022};
unsigned char gCurrentScheme = 1; //定义当前小灯闪亮模式
unsigned char gFlag = 1; //有按键按下时设置标志gFlag为0, //否则为1
/*--------------长延时函数-------------*/
void Delay()
{
unsigned char i,j;
for(i = 0 ; i < 200 ; i++)
{
for(j = 0;j < 100 ; j++)
{
}
}
}
/*--------------短延时函数------------*/
void Delay1()
{
unsigned char i,j;
for(i = 0 ; i < 200 ; i++)
{
for(j = 0;j < 50 ; j++)
{
}
}
}
/*----------按键中断初始化函数--------*/
void InitKey_INTKR(void)
{
PM4 = 0x3F; //端口4的位5~位0为输入端口 PU4 = 0x3F; //设置端口4的位5~位0 使用内 //部上拉电阻
KRM = 0x3F; //设置每个按键按下都会产生按 //键中断信号
KRMK = 0; //按键中断屏蔽标志设置为允许按
//键中断
}
/*------------初始化LED灯------------*/
void InitLed()
{
PM13 = 0xF0; //端口13的低4位为输出模式
PM14 = 0xF0; //端口14的低4位为输出模式
PM15 = 0XF0; //端口15的低4位为输出模式
PM3.4 = 0; //端口P34为输出模式
}
/*-------按键中断服务函数------------*/
void OnKeyPress(void)
{
DI(); //关中断
gFlag = 0; //设置有按键按下标志
switch(P4 & 0x3F) //检测P4端口的位5~位0的值
{
case 0x3E: //按下Key1键
gCurrentScheme = 1; //选择1号LED灯闪亮模式
break;
case 0x3D: //按下Key2键
gCurrentScheme = 2; //选择2号LED灯闪亮模式
break;
case 0x3B: //按下Key3键
gCurrentScheme = 3; //选择3号LED闪亮模式
break;
case 0x37: //按下Key4键
gCurrentScheme = 4; //选择4号LED闪亮模式
break;
case 0x2F: //按下key5键
gCurrentScheme = 5; //选择5号LED闪亮模式
break;
case 0x1F: //按下key6键
gCurrentScheme = 6; //选择6号LED闪亮模式
break;
default: //其他情况不做选择
break;
}
EI(); //开中断
} //中断返回
/*------------灯全熄灭函数-------------*/
void LightOff()
{
P13 = 0; //端口13的低四位输出为0
P14 = 0; //端口14的低四位输出为0
P15 = 0; //端口15的低四位输出为0
}
/*------------小灯闪亮模式1------------*/
void Modle1(void)
{
unsigned char w;
pokeb(0xFA40,0x00); //LCD显示1
pokeb(0xFA41,0x06);
for(w = 0 ; w < 2 && gFlag; w++) //无按键中断时循环2次
{
P3.4 = 1; //点亮红灯
P13.0 = 1;
P13.3 = 1;
P14.2 = 1;
P15.1 = 1;
Delay(); //延时
P3.4 = 0; //熄灭红灯
P13.0 = 0;
P13.3 = 0;
P14.2 = 0;
P15.1 = 0;
Delay(); //延时
P13.1 = 1; //点亮黄灯
P14.0 = 1;
P14.3 = 1;
P15.2 = 1;
Delay(); //延时
P13.1 = 0; //熄灭黄灯
P14.0 = 0;
P14.3 = 0;
P15.2 = 0;
Delay(); //延时
P13.2 = 1; //点亮绿灯
P14.1 = 1;
P15.0 = 1;
P15.3 = 1;
Delay(); //延时
P13.2 = 0; //熄灭绿灯
P14.1 = 0;
P15.0 = 0;
P15.3 = 0;
Delay(); //延时
}
}
/*------------小灯闪亮模式2------------*/
void Modle2(void)
{
unsigned char w;
pokeb(0xFA40,0x0e); //LCD显示2
pokeb(0xFA41,0x03);
for(w = 0;w < 2 && gFlag; w++) //没有中断时循环两次
{
P13.0 = 1; //北边三个灯亮
P13.1 = 1;
P13.2 = 1;
Delay(); //延时
P13.3 = 1; //东边三个灯亮
P14.0 = 1;
P14.1 = 1;
Delay(); //延时
P14.2 = 1; //南边三个灯亮
P14.3 = 1;
P15.0 = 1;
Delay(); //延时
P15.1 = 1; //西边三个灯亮
P15.2 = 1;
P15.3 = 1;
Delay(); //延时
LightOff(); //12个灯熄灭
Delay(); //延时
}
}
/*-------------小灯闪亮模式3------------*/
void Modle3(void) //从以LED1为对角线的灯开始顺
//时针以对角线方式亮
{ //再依次对角线方式灭,循环两次
unsigned char w;
pokeb(0xFA40,0x0a); //LCD显示3
pokeb(0xFA41,0x07);
for(w = 0;w < 2 && gFlag ; w++) //没有中断时循环2次
{
P13.0 = 1; //LED1 、LEDSEC、LED7亮
P3.4 = 1;
P14.2 = 1;
Delay(); //延时
P13.1 = 1; //LED2、LED8亮
P14.3 =1;
Delay(); //延时
P13.2 = 1; //LED3、LED9亮
P15.0 = 1;
Delay(); //延时
P13.3 = 1; //LED4、LED10亮
P15.1 = 1;
Delay(); //延时
P14.0 = 1; // LED5、LED11亮
P15.2 = 1;
Delay(); //延时
P14.1 =1; // LED6、LED12亮
P15.3 = 1;
Delay(); //延时
P13.0 = 0; //LED1 、LEDSEC、LED7灭
P3.4 = 0;
P14.2 = 0;
Delay(); //延时
P13.1 = 0; //LED2、LED8灭
P14.3 =0;
Delay(); //延时
P13.2 = 0; //LED3、LED9灭
P15.0 = 0;
Delay(); //延时
P13.3 = 0; //LED4、LED10灭
P15.1 = 0;
Delay(); //延时
P14.0 = 0; // LED5、LED11灭
P15.2 = 0;
Delay(); //延时
P14.1 = 0; // LED6、LED12灭
P15.3 = 0;
Delay(); //延时
}
}
/*-------------小灯闪亮模式4---------*/ //小灯按东北、东南、西南、西北 //方向依次亮
void Modle4(void) //再按此方式灭,循环两次
{
unsigned char w;
pokeb(0xFA40,0x03); //LCD显示4
pokeb(0xFA41,0x06);
for(w = 0 ; w < 2 && gFlag; w++)
{
P13.1 = 1; //东北方向3个小灯亮
P13.2 = 1;
P13.3 = 1;
Delay(); //延时
P14.0 = 1; //东南方向3个小灯亮
P14.1 = 1;
P14.2 = 1;
Delay(); //延时
P14.3 = 1; //西南方向3个小灯亮
P15.0 = 1;
P15.1 = 1;
Delay(); //延时
P15.2 = 1; //西北方向3个小灯亮
P15.3 = 1;
P13.0 = 1;
Delay(); //延时
P3.4 = 1; //LEDSEC灯亮
Delay(); //延时
LightOff(); //所有灯全灭
P3.4 = 0;
}
}
/*------------小灯闪亮模式5-----------*/
void Modle5(void) //由LEDSEC灯带动,每次带动一 //个灯亮,
{ //从LED1开始,顺时针亮循环两次
unsigned char w;
pokeb(0xFA40,0x0b); //LCD显示5
pokeb(0xFA41,0x05);
for(w = 0 ; w < 2 && gFlag ; w++ )
{
P3.4 = 1; // LED1亮
P13.0 = 1;
Delay1();
Delay1();
P3.4 = 1; //LED2亮
P13.1 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED3亮
P13.2 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED4亮
P13.3 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED5亮
P14.0 = 1;
Delay1();
Delay1();
P3.4 = 1; //LED6亮
P14.1 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED7亮
P14.2 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED8亮
P14.3 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED9亮
P15.0 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED10亮
P15.1 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED11亮
P15.2 = 1;
Delay1();
Delay1();
P3.4 = 1; // LED12亮
P15.3 = 1;
Delay1();
Delay1();
}
}
/*-------------小灯闪亮模式6----------*/
void Modle6(void) //由中间开始像打开扇子一样
//依次亮灯,循环两次
{
unsigned char w ;
pokeb(0xFA40,0x0f); //LCD显示6
pokeb(0xFA41,0x05);
for(w = 0 ; w < 2 && gFlag ; w++)
{
P13.1 = 1; //中间三个灯亮
P3.4 = 1;
P14.3 = 1;
Delay(); //延时
P13. 0 = 1; //上方两个灯亮
P13.2 = 1;
Delay(); //延时
P15.3 = 1; //东西方向上上方两个灯亮
P13.3 = 1;
Delay(); //延时
P15.2 = 1; //东西方向上中间两个灯亮
P14.0 = 1;
Delay(); //延时
P15.1 = 1; //东西方向上下方两个灯亮
P14.1 = 1;
Delay(); //延时
P15.0 = 1; //下方两个灯亮
P14.2 = 1;
Delay(); //延时
LightOff(); //灯全灭
P3.4 = 0;
}
}
/*-----------song------------ */
void TimerInit(void)
{
PRM00 = 0x01; //计时时钟频率=fprs/2 = 4 MHz
CRC00 = 0x00; //CR000作为比较寄存器
TOC00 = 0x03; //方波输出
CR000 = 0x11C1; //M=62002
PM3.4 = 0; //计时器初始化
P3.4 = 0;
PM3.3 = 0; //蜂鸣器初始化
}
void INTTM000(void)
{
TMMK000 = 0; //禁止屏蔽
TMPR000 = 0x1; //低优先级
}
__interrupt void MD_INTTM000() //定时中断
{
Num -=1;
P3.3 = !P3.3;
}
//n区别音高,m控制音长,四分之一拍的m倍
void flat(int n,int m)
{
Num = m*freq_b[n]/2; //控制时长,四分之一拍;
TMC00 &= 0b11110011;
CR000 = regSet_b[n];
TMC00 |= 0b00001100;
while(Num>0){;}
//TMC00 &= 0b11110011;
}
void stop(void) //音乐停止函数
{
PM3.3 = 1;
TMC00 &= 0b11110011;
}
void song() //音乐《小星星》
{
unsigned int M=0;
DI();
INTTM000();
TimerInit();
EI();
flat(1,1);flat(1,1);flat(5,1);flat(5,1);flat(6,1);
flat(6,1);flat(5,2);
flat(4,1);flat(4,1);flat(3,1);flat(3,1);flat(2,1);
flat(2,1);flat(1,2);
flat(5,1);flat(5,1);flat(4,1);flat(4,1);flat(3,1);
flat(3,1);flat(2,2);
flat(5,1);flat(5,1);flat(4,1);flat(4,1);flat(3,1);
flat(3,1);flat(2,2);
stop(); //音乐停
}
/*--------------主函数-------------*/
void main()
{
PF2 = 0x00; //设置seg0 到seg19引脚所对应的端 PFALL = 0X0F; //口为SEG信号输出口
LCDC0 = 0X34; //设置LCD原时钟和LCD时钟频率
LCDMD = 0X30; //设置LCD电压为3/5电源电压
LCDM =0XC0; //输出SEG和COM波形,4分时1/3
//偏压模式
InitKey_INTKR(); //初始化按键
LightOff(); //灯全熄灭
InitLed(); //初始化LED灯
EI(); //开中断
while(1)
{
switch(gCurrentScheme) //判断当前显示模式
{
case 1:
gFlag = 1; //清有按键按下标志
Modle1(); //运行模式1
gCurrentScheme = 0; //清除当前模式
break;
case 2:
gFlag = 1; //清有按键按下标志
Modle2(); //运行模式2
gCurrentScheme = 0; //清除当前模式
break;
case 3:
gFlag = 1; //清有按键按下标志
Modle3(); //运行模式3
gCurrentScheme = 0; //清除当前模式
break;
case 4:
gFlag = 1; //清有按键按下标志
Modle4(); //运行模式4
gCurrentScheme = 0; //清除当前模式
break;
case 5:
gFlag = 1; //清有按键按下标志
Modle5(); //运行模式5
gCurrentScheme = 0; //清除当前模式
break;
case 6:
gFlag = 1; //清有按键按下标志
Modle6(); //运行模式6
gCurrentScheme = 0; //清除当前模式
break;
default:
break;
}
}
}