/****************************************************************************** 延时框架
/*****************************************************************************/
void delay(unsigned int a) //延时函数延时a ms
{
unsigned int x,y;
for(x=a;x>0;x--)
{
for(y=120;y>0;y--);
}
}
/****************************************************************************** 音乐框架
/*****************************************************************************/ #include
unsigned char backTL0; //让计时器保存之前的大小,中断之后继续
unsigned char backTH0;
//中高低音的计时器开始数值
unsigned int low[]={0xf88c,0xf95b,0xfa15,0xfa67,0xfb04,0xfb90,0xfc0c};
unsigned int mid[]={0xfc44,0xfcac,0xfd09,0xfd34,0xfd82,0xfdc8,0xfe06};
unsigned int high[]={0xfe22,0xfe56,0xfe85,0xfe9a,0xfec1,0xfee4,0xff03};
//unsigned int music[]={0xf88c,0xf95b,0xfa15,0xfa67,0xfb04,0xfb90,0xfc0c,0xfc44,0xfcac,0xfd09,0xfd34,0xfd82, 0xfdc8,0xfe06,0xfe22,0xfe56,0xfe85,0xfe9a,0xfec1,0xfee4,0xff03};
sbit P15=P1^5; //音乐输出端口为P1.5 可设其他端口
void inter() interrupt 1 using 1 //计时器中断
{
P15=~P15;
TL0=backTL0;
TH0=backTH0;
}
void settimer() //中断允许
{
TMOD=0x01; //设置模式详情看STC资料书
EA=1; //总中断允许
ET0=1;
TR0=1;
}
void delay89ms(unsigned int a) //延时函数89ms是一个四分音符的长度(一分钟80拍){
unsigned int x,y,f;
f=a*93;
for(x=f;x>0;x--)
{
for(y=120;y>0;y--);
}
}
void play(int a,int de,int cl)
//低中高音播放子函数a是放第几个音,第一个音(do)为0,re为1,以此类推xi是6 //de是延时长度,一个四分音符为5,cl为1 2 3分别为低中高音
{
a=a-1;
switch(cl){
case(1):
TL0=(unsigned char)music[a];
TH0=(unsigned char)(music[a]>>8);
break;
case(2):
TL0=(unsigned char)music[a+7];
TH0=(unsigned char)(music[a+7]>>8);
break;
case(3):
TL0=(unsigned char)music[a+14];
TH0=(unsigned char)(music[a+14]>>8);
break;
}
backT0L=TL0;
backT0H=TH0;
delay89ms(de);
}void main()
{
settimer();
while(1)
{
}
}
/****************************************************************************** 按键框架(独立按键)
/*****************************************************************************/ sbit K1=P3^0; //RxD
//sbit K2=P3^1; //TxD
//sbit K3=P3^2; //INT0
//sbit K4=P3^3; //INT1
unsigned int i; //用于按键延时计数
if(K1==0) //检测按键K1是否按下
{
Delay10ms(); //消除抖动
if(K1==0) //再次检测按键是否按下
{/* 这里写需要执行的动作*/}
while((i<50)&&(K1==0)) //检测按键松手检测,如果不松手超过延时也会自动结束等待
{
Delay10ms();//等待10ms
i++;
}
i=0;
}
/****************************************************************************** 数码管框架(88888888)
/*****************************************************************************/ sbit LSA=P2^2; //片选信号
sbit LSB=P2^3;
sbit LSC=P2^4;
//P2^2 3 4 组成3位位选信号 4 3 2 3个为000时启动从左至右第一个数码管
//001为第二个以此类推111激活最左边的
//另外一种方法是用P2=i<<2;来实现激活从左至右第i个管子
//如果P2=2,也就是P2=00000010,我们想激活第2个管子,左移2位后,000 010 00
//P2^4 3 2 就是010,也就是第二个的片选信号
unsigned char code DIG_CODE[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示0~9的值
//unsigned char code DIG_CODE[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
P0=DIG_CODE[/* 0-9 */] //显示数字
//如果要动态显示也就是多个数码管,交替显示,可以利用人的视觉暂停作用使人看到多个数码管同时显示的效果
//同样静态就是一个数码管长开即可
/****************************************************************************** 键盘矩阵框架
/*****************************************************************************/ unsigned int KeyValue;//0-15,表示第几个按键按下,数值可以自己替换
void KeyDown(void)
{
char a;
P1=0x0f;
if(P1!=0x0f)
{
Delay10ms(); //去抖动
if(P1!=0x0f)
{
//测试列
P1=0X0F;
switch(P1)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=3;break;
//default: K eyValue=17; //检测出错回复17意思是把数码管全灭掉。
}
//测试行
P1=0XF0;
switch(P1)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+4;break;
case(0Xd0): KeyValue=KeyValue+8;break;
case(0Xe0): KeyValue=KeyValue+12;break;
//default: K eyValue=17;
}
while((a<50)&&(P1!=0xf0)) //检测按键松手检测
{
Delay10ms();
a++;
}
a=0;
}
}
}
//行线和列线是通过某个按键的按下和抬起实现联通和断开的并且导线两端上的信号是经过“与”的关系再体现到导线上的
/****************************************************************************** lcd液晶显示框架(型号LCD1602)
/*****************************************************************************/ //lcd头文件lcd.h
#ifndef __LCD_H_
#define __LCD_H_
/********************************************************************
当使用的是4位数据传输的时候定义,使用8位取消这个定义
********************************************************************/
#define LCD1602_4PINS
#include
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
/**********************************
函数声明
**********************************/
void Lcd1602_Delay1ms(uint c);//在51单片机12MHZ时钟下的延时函数误差0us void LcdWriteCom(uchar com);//LCD1602写入8位命令子函数
void LcdWriteData(uchar dat);//LCD1602写入8位数据子函数
void LcdInit();//LCD1602初始化子程序
#endif
//lcd头文件实现lcd.c
#include"lcd.h"
/****************************************************************
* 函数名: Lcd1602_Delay1ms
* 函数功能: 延时函数,延时1ms
* 输入: c
* 输出: 无
* 说名: 该函数是在12MHZ晶振下,12分频单片机的延时。
*****************************************************************/ void Lcd1602_Delay1ms(uint c) //误差0us
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/****************************************************************
* 函数名: LcdWriteCom
* 函数功能: 向LCD写入一个字节的命令
* 输入: com
* 输出: 无
*****************************************************************/ #ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待数据稳定
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //选择写入命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
// Lcd1602_Delay1ms(1);
LCD1602_DATAPINS = com << 4; //发送低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/****************************************************************
* 函数名: LcdWriteData
* 函数功能: 向LCD写入一个字节的数据
* 输入: dat
* 输出: 无
****************************************************************/
#ifndef LCD1602_4PINS
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //写入数据
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择写入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //写入低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/********************************************************************
* 函数名: LcdInit()
* 函数功能: 初始化LCD屏
********************************************************************/
#ifndef LCD1602_4PINS
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //开显示
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
#else
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x32); //将8位总线转为4位总线
LcdWriteCom(0x28); //在四位线下的初始化
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
#endif
//使用lcd时
#include"lcd.h"
unsigned char PuZh[]=" Pechin Science "; //定义传送字符串
unsigned char i;
LcdInit();//初始化
for(i=0;i<16;i++)
{
LcdWriteData(PuZh[i]); //循环输入字符,一次一个
}
/*LCD1602 对写进去的数据字节呢是以ASCII 码识别的。另外这里只是一个框架,若要熟练运用液晶屏,需要自己学习他的引脚,时序等等*/
/****************************************************************************** 时钟芯片ds1302框架
/*****************************************************************************/ //ds1302.h
#ifndef __DS1302_H_
#define __DS1302_H_
//---包含头文件---//
#include
#include
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;
//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();
//---加入全局变量--//
extern uchar TIME[7]; //加入全局变量
#endif
//ds1302.c
#include"ds1302.h"
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0, 0, 0x12, 0x01, 0x01, 0x02, 0x13};
/****************************************************************************** * 函数名: Ds1302Write
* 函数功能: 向DS1302命令(地址+数据)
* 输入: addr,dat
* 输出: 无
******************************************************************************/ void Ds1302Write(uchar addr, uchar dat)
{
uchar n;
RST = 0;
_nop_();//延时一个机器周期
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for (n=0; n<8; n++)//开始传送八位地址命令
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++)//写入8位数据
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;//传送数据结束
_nop_();
}
/****************************************************************************** * 函数名: Ds1302Read
* 函数功能: 读取一个地址的数据
* 输入: addr
* 输出: dat
******************************************************************************/
uchar Ds1302Read(uchar addr)
{
uchar n,dat,dat1;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1;//然后将RST(CE)置高电平。
_nop_();
for(n=0; n<8; n++)//开始传送八位地址命令
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
_nop_();
for(n=0; n<8; n++)//读取8位数据
{
dat1 = DSIO;//从最低位开始接收
dat = (dat>>1) | (dat1<<7);
SCLK = 1;
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
RST = 0;
_nop_(); //以下为DS1302复位的稳定时间,必须的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
/****************************************************************************** * 函数名: Ds1302Init
* 函数功能: 初始化DS1302.
* 输入: 无
* 输出: 无
******************************************************************************/ void Ds1302Init()
{
uchar n;
Ds1302Write(0x8E,0X00); //禁止写保护,就是关闭写保护功能
for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
{
Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
}
Ds1302Write(0x8E,0x80); //打开写保护功能
}
/****************************************************************************** * 函数名: Ds1302ReadTime
* 函数功能: 读取时钟信息
******************************************************************************/ void Ds1302ReadTime()
{
uchar n;
for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
{
TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
}
}
//主文件mian
#include"lcd.h"
#include"ds1302.h"
unsigned char SetState,SetPlace;
void LcdDisplay() //显示函数,com指令需要了解lcd后才能理解这里的指令是设
//置年月日时分秒周显示的位置的
{
LcdWriteCom(0x80+0X40);
LcdWriteData('0'+TIME[2]/16); //时
LcdWriteData('0'+(TIME[2]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[1]/16); //分
LcdWriteData('0'+(TIME[1]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[0]/16); //秒
LcdWriteData('0'+(TIME[0]&0x0f));
LcdWriteCom(0x80);
LcdWriteData('2');
LcdWriteData('0');
LcdWriteData('0'+TIME[6]/16); //年
LcdWriteData('0'+(TIME[6]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[4]/16); //月
LcdWriteData('0'+(TIME[4]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[3]/16); //日
LcdWriteData('0'+(TIME[3]&0x0f));
LcdWriteCom(0x8D);
LcdWriteData('0'+(TIME[5]&0x07)); //星期
}
void Int0Configuration()//外部中断设置
{
//设置INT0
IT0=1;//跳变沿出发方式(下降沿)
EX0=1;//打开INT0的中断允许。
EA=1;//打开总中断
}
void Int0() interrupt 0 //外部中断,这里是k3按键按下后中断
{
Delay10ms();
if(K3==0)
{
SetState=~SetState; //状态设置取反
SetPlace=0; //设置位置归位
Ds1302Init();
}
}
void main()
{
unsigned char i;
Int0Configuration();//中断配置好
LcdInit();//lcd初始化
Ds1302Init();//1302初始化
while(1)
{
if(SetState==0) //时钟状态,为1时是设置状态,0为读取状态
{
Ds1302ReadTime(); //读取时钟信息
}
else
{
if(K1==0) //检测按键K1是否按下
{
Delay10ms(); //消除抖动
if(K1==0)
{
SetPlace++; //设置位置0-6分别为秒、分、时、日、月、周几、年
if(SetPlace>=7)
SetPlace=0;
}
while((i<50)&&(K1==0)) //检测按键是否松开
{
Delay10ms();
i++;
}
i=0;
}
if(K2==0) //检测按键K2是否按下
{
Delay10ms(); //消除抖动
if(K2==0)
{
TIME[SetPlace]++;
if((TIME[SetPlace]&0x0f)>9) //换成BCD码。
{
TIME[SetPlace]=TIME[SetPlace]+6;
}
if((TIME[SetPlace]>=0x60)&&(SetPlace<2))//分秒只能到59
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x24)&&(SetPlace==2))//小时只能到23
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x32)&&(SetPlace==3))//日只能到31
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x13)&&(SetPlace==4))//月只能到12
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x7)&&(SetPlace==5))//周只能到7
{
TIME[SetPlace]=1;
}
}
while((i<50)&&(K2==0)) //检测按键是否松开
{
Delay10ms();
i++;
}
i=0;
}
}
LcdDisplay();
}
}
/****************************************************************************** 电机框架
/*****************************************************************************/ unsigned char code FFW[8]={0xf1,0xf3,0xf2,0xf6,0xf4,0xfc,0xf8,0xf9}; //反转顺序void Motor()//电机的io端口是P1
{
unsigned char i;
for(i=0;i<8;i++)
{
GPIO_MOTOR = FFW[i]&0x1f; //取数据
Delay(30); //调节转速
}
}
void main(void)
{
while(1)
{
Motor();
}
}
/****************************************************************************** LED点阵框架
/*****************************************************************************/ #include
#include
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
void Hc595SendByte(unsigned char dat)//这是74hc595子函数,控制列的暗亮
{
unsigned char a;
SRCLK=0; //3.6
RCLK=0; //3.5
for(a=0;a<8;a++)
{
SER=dat>>7;
dat<<=1;
SRCLK=1;
_nop_();
_nop_();
SRCLK=0;
}
RCLK=1;
_nop_();
_nop_();
RCLK=0;
}
void main()
{
while(1)
{
P0=0X/*XX*/;//xx表示点阵行的显示 p0控制行,595列的显示
Hc595SendByte(0xXX);//列的显示
Hc595SendByte(0);//列每次显示完需要消隐,防止有灯闪烁
}
}
//要显示8X8的一个点阵图案,可以每次显示一行或一列,然后迅速切换下一行便可以显示图案。
//P0的 1表示暗,0表示亮,如00011000则为亮亮亮暗暗亮亮亮
//595 1表示亮,0表示暗
//protues仿真中所有p0与595的取值与实际是相反的,即是仿真要取非
//P0是位选信号(哪一列) 595是段码(这一列亮哪些)
/****************************************************************************** 中断框架
/*****************************************************************************/ /*原理*/
/************************************************************************** STC90C51RC/RD+系列单片机提供了8个中断请求源,它们分别是:外部中断O(INTO),定时器。中断、外部中断1(INT1)、定时器1中断、定时器2中断、串口(UART)中断、外部中断2(INT2)、外部中断3(INT3)。所有的中断都具有4个中断优先级。用户可以用关总中断允许位(EA/IE.7)或相应中断的允许位来屏蔽所有的中断请求,也可以用打开相应的中断允许位来使CPU响应相应的中断申请;、每二个中断源可以用软件独立地控制为开中断或关中断状态;每一个中断的优先级别均可用软件设置。高优先级的中断请求可以打断低优先级的中断,反之,低优先级的中断请求不可以打断高优先级及同优先级的中断。当两个相同优先级的中断同时产生时,将由查询次序来决定系统先响应哪个中断。STC90C51RC/RD+系列单片机的各个中断查询次序表如下图所示。
通过设置新增加的特殊功能寄存器IPH中的相应位,可将中断优先级设为四级,如果只设置IP或XICON,那么中断优先级就只有两级,与传统8051单片机两级中断优先级完全兼容。
如果使用C语言编程,,中断查询次序号就是中断号,例如:
void Into_Routine(void) interrupt 0;
void TimerO_Rountine(void) interrupt 1;
void Intl_Routine(void) interrupt 2;
void Timer1_Rountine(void) interrupt 3;
void UART_Routine(void) interrupt 4;
void Timer2_Routine(void) interrupt 5;
void Int2_Routine(void) interrupt 6;
void Int3_Routine(void) interrupt 7;
中断触发表如下图所示
******************************************************************************/ void TimerConfiguration()//定时器初始化
{
TMOD=0X02;//选择为定时器0模式,工作方式2,仅用TRX打开启动。
TH0=0X9C; //给定时器赋初值,定时100us
TL0=0X9C;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
void Timer() interrupt 1//当定时器中断时所采取的动作
{
DigDisplay();
}
/****************************************************************************** 状态机框架
/*****************************************************************************/ //Keyboard.h
#ifndef __Key_State_H__
#define __Key_State_H__
unsigned char read_key(void);
#endif
//keyboard.c
#include
sbit key_sr1 = P1^6; // 按键输入口
#define key_state_0 0 //按键的初始状态
#define key_state_1 1 //按键按下的状态
#define key_state_2 2 //按键释放的状态
/****************************************************************************** 函数名称:按键扫描程序
功能:检测按键,并返回按键值
返回值:key_press
时间:2014-12-14
备注:
******************************************************************************/ unsigned char read_key(void)
{
static char key_state = 0; //按键的状态
unsigned char key_press; //按键是否被按下
unsigned char key_return = 0; //按键返回值
key_press = key_sr1; // 读按键I/O电平
switch (key_state)
{
case key_state_0: // 按键初始态
if (!key_press)
{
key_state = key_state_1;// 键被按下,状态转换到键确认态}
break;
case key_state_1: // 按键确认态
if (!key_press)
{
key_return = 1; // 按键仍按下,按键确认输出为“1”
key_state = key_state_2;// 状态转换到键释放态
}
else
{
key_state = key_state_0; // 按键已抬起,转换到按键初始态}
break;
case key_state_2:
if (key_press)
{
key_state = key_state_0;//按键已释放,转换到按键初始态}
break;
}
return key_return; //返回按键值
}