1.概要:
还记得小时候玩的咬手鲨鱼吗?数十颗牙齿随机按下,鲨鱼嘴巴就会咬下。现在来试着把它改成闹钟吧!
2.最后成品图:
使用方法:闹钟响起,必须按下那颗会使嘴巴闭合的牙齿才能关闭闹钟(每次随机)。也就是说,早上起床会被鲨鱼咬到痛醒,或者你也能闪躲不被咬到,如果足够清醒的话。
3.教程:
(1)材料:咬手鲨鱼+51单片机+DS3231+ TM1637驱动数码管
(2)程序:(看程序注释应该知道怎么接线)
4.STC89C52RC程序:
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define DS3231_WriteAddress 0xD0
#define DS3231_ReadAddress 0xD1
#define DS3231_SECOND 0x00
#define DS3231_MINUTE 0x01
#define DS3231_HOUR 0x02
#define DS3231_WEEK 0x03
#define DS3231_DAY 0x04
#define DS3231_MONTH 0x05
#define DS3231_YEAR 0x06
unsigned char dpFlag = 0; //dp标志位
unsigned char code SEGData[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//1-9,不带数点
unsigned char code SEGDataDp[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; //1-9,带数点
unsigned int countTime = 0;
unsigned char time, sec;
uchar alarmHour = 24, alarmMin = 60, alarmHour2 = 24, alarmMin2 = 60;
sbit CLK = P0^0; //数码管时钟
sbit DIO = P0^1; //数码管数据
sbit SDA = P0^2; //模拟I2C数据传送位SDA
sbit SCL = P0^3; //模拟I2C时钟控制位SCL
sbit we1 = P1^0; //时,十位
sbit we2 = P1^1; //时,个位
sbit we3 = P1^2; //分,十位
sbit we4 = P1^3; //分,个位
sbit we5 = P1^4; //秒,十位
sbit we6 = P1^5; //秒,个位
sbit closeBeep = P2^6; //??
sbit beep = P2^7; //蜂鸣器
bit ack; //应答标志位
struct {
char shi;
char ge;
} Hour;
struct {
char shi;
char ge;
} Minute;
uchar flag = 0;
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar Recive_table[3];
static uchar i = 0;
uchar num = 0;
void TM1637_start();
void TM1637_stop();
void TM1637_write1Bit(unsigned char mBit);
void TM1637_write1Byte(unsigned char mByte);
void TM1637_writeCammand(unsigned char mData);
void TM1637_writeData(unsigned char addr, unsigned char mData);
void time_set(char hour, char min);
void time_display();
void timer0_init();
void delay_140us();
void delayus(uint us);
uchar BCD2HEX(uchar val) //BCD码转换为Byte
{
uchar temp;
temp=val&0x0f;
val>>=4;
val&=0x0f;
val*=10;
temp+=val;
return temp;
}
uchar HEX2BCD(uchar val) //B码转换为BCD码
{
return (((val%100)/10)<<4)|(val%10);
}
void delayus(uint us)
{
while (us--);
}
void Start_I2C()
{
SDA=1; //???????????
delayus(1);
SCL=1;
delayus(5); //??????????4.7us,??
SDA=0; //??????
delayus(5); // ??????????4祍
SCL=0; //??I2C??,?????????
delayus(2);
}
void Stop_I2C()
{
SDA=0; //???????????
delayus(1); //???????????
SCL=1; //??????????4us
delayus(5);
SDA=1; //??I2C??????
delayus(4);
}
void SendByte(uchar c)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) //?????????8?
{
if((c<<BitCnt)&0x80)
SDA=1; //?????
else
SDA=0;
delayus(1);
SCL=1; //??????,????????????
delayus(5); //???????????4祍
SCL=0;
}
delayus(2);
SDA=1; //8??????????,???????
delayus(2);
SCL=1;
delayus(3);
if(SDA==1)
ack=0;
else
ack=1; //???????????
SCL=0;
delayus(2);
}
uchar RcvByte()
{
uchar retc;
uchar BitCnt;
retc = 0;
SDA = 1; //?????????
for(BitCnt = 0;BitCnt < 8;BitCnt++)
{
delayus(1);
SCL = 0; //??????,???????
delayus(5); //?????????4.7祍
SCL = 1; //???????????????
delayus(3);
retc = retc << 1;
if(SDA == 1)
retc = retc + 1; //????,????????retc?
delayus(2);
}
SCL = 0;
delayus(2);
return(retc);
}
void Ack_I2C(bit a)
{
if(a == 0)
SDA = 0; //????????????
else
SDA = 1;
delayus(3);
SCL = 1;
delayus(5); //?????????4祍
SCL = 0; //????,??I2C????????
delayus(2);
}
uchar write_byte(uchar addr, uchar write_data)
{
Start_I2C();
SendByte(DS3231_WriteAddress);
if (ack == 0)
return 0;
SendByte(addr);
if (ack == 0)
return 0;
SendByte(write_data);
if (ack == 0)
return 0;
Stop_I2C();
delayus(10);
return 1;
}
uchar read_current()
{
uchar read_data;
Start_I2C();
SendByte(DS3231_ReadAddress);
if(ack == 0)
return(0);
read_data = RcvByte();
Ack_I2C(1);
Stop_I2C();
return read_data;
}
uchar read_random(uchar random_addr)
{
Start_I2C();
SendByte(DS3231_WriteAddress);
if(ack == 0)
return(0);
SendByte(random_addr);
if(ack == 0)
return(0);
return(read_current());
}
/********************************************************************
* 名称 : void init()
* 功能 : 程序初始化
* 输入 : void
* 输出 : 无
**************************************************************/
void init()
{
TMOD = 0X21; //用定时器设置串口波特率 9600
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
TR0 = 1;
ET0 = 1;
EA = 1;
//for bluetooth
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
REN = 1; //串口初始化
SM0 = 0;
SM1 = 1;
EA = 1; //开启总中断
ES = 1;
}
/********************************************************************
* 名称 : void time_display()
* 功能 : 显示时间
* 输入 : void
* 输出 : 无
**************************************************************/
void TimeDisplay(uchar Dhour,uchar Dmin)
{
Hour.shi = Dhour / 10; //时,十位
Hour.ge = Dhour % 10; //时,个位
Minute.shi = Dmin / 10; //分,十位
Minute.ge = Dmin % 10; //分,个位
TM1637_writeCammand(0x44);
TM1637_writeData(0xc0, SEGData[Hour.shi]);
if(dpFlag)
TM1637_writeData(0xc1, SEGDataDp[Hour.ge]); //带数点
else
TM1637_writeData(0xc1, SEGData[Hour.ge]); //不带数点
TM1637_writeData(0xc2, SEGData[Minute.shi]);
TM1637_writeData(0xc3, SEGData[Minute.ge]);
TM1637_writeCammand(0x8a);
}
/********************************************************************
* 名称 : void computer_and_display_time()
* 功能 : 显示时间
* 输入 : void
* 输出 : 无
**************************************************************/
void compute_and_display_time()
{
//计算时间
uchar Htemp1, Htemp2, Mtemp1, Mtemp2;// Stemp1, Stemp2;
Htemp1 = read_random(DS3231_HOUR); //获取时
Htemp1&=0x3f;
Htemp2 = BCD2HEX(Htemp1);
Mtemp1 = read_random(DS3231_MINUTE); //获取分
Mtemp2 = BCD2HEX(Mtemp1);
if(alarmHour == Htemp2 && alarmMin == Mtemp2)
{
if(closeBeep == 0)
{
if(beep == 1)
beep = 0;
else
beep = 1;
}
else
{
beep = 0;
}
}
else
closeBeep = 0;
//显示时间
TimeDisplay(Htemp2, Mtemp2);
}
/********************************************************************
* 名称 : void TM1637_start()
* 功能 : start信号
* 输入 : void
* 输出 : 无
**************************************************************/
void TM1637_start()
{
CLK = 1;
DIO = 1;
delay_140us();
DIO = 0;
delay_140us();
CLK = 0;
delay_140us();
}
/********************************************************************
* 名称 : void TM1637_stop()
* 功能 : stop信号
* 输入 : void
* 输出 : 无
**************************************************************/
void TM1637_stop()
{
CLK = 0;
delay_140us();
DIO = 0;
delay_140us();
CLK = 1;
delay_140us();
DIO = 1;
delay_140us();
}
/********************************************************************
* 名称 : void TM1637_write1Bit(unsigned char mBit)
* 功能 : 写入1bit
* 输入 : unsigned char mBit
* 输出 : 无
**************************************************************/
void TM1637_write1Bit(unsigned char mBit)
{
CLK = 0;
delay_140us();
if(mBit)
DIO = 1;
else
DIO = 0;
delay_140us();
CLK = 1;
delay_140us();
}
/********************************************************************
* 名称 : void TM1637_write1Byte(unsigned char mByte)
* 功能 : 写入1bit数据
* 输入 : unsigned char mByte
* 输出 : 无
**************************************************************/
void TM1637_write1Byte(unsigned char mByte)
{
char loop = 0;
for(loop = 0; loop < 8; loop++)
{
TM1637_write1Bit((mByte>>loop)&0x01); //取得最低位
}
CLK = 0;
delay_140us();
DIO = 1;
delay_140us();
CLK = 1;
delay_140us();
while(DIO == 1); //获得应答位
}
/********************************************************************
* 名称 : void TM1637_writeCammand(unsigned char mData)
* 功能 : 写入1byte指令
* 输入 : unsigned char mData
* 输出 : 无
**************************************************************/
void TM1637_writeCammand(unsigned char mData)
{
TM1637_start();
TM1637_write1Byte(mData); //指令数据
TM1637_stop();
}
/********************************************************************
* 名称 : void TM1637_writeData(unsigned char addr, unsigned char mData)
* 功能 : 固定地址写入1byte数据
* 输入 : unsigned char addr, unsigned char mData
* 输出 : 无
**************************************************************/
void TM1637_writeData(unsigned char addr, unsigned char mData)
{
TM1637_start();
TM1637_write1Byte(addr); //地址
TM1637_write1Byte(mData); //数据
TM1637_stop();
}
/********************************************************************
* 名称 : void timer0_isr()
* 功能 : 定时50ms(实际运行时由于指令运行的延时,会大于50ms)
* 输入 : void
* 输出 : 无
**************************************************************/
void timer0_isr() interrupt 1
{
TH0 = (65536 - 50000) / 256; //5 ????
TL0 = (65536 - 50000) % 256;
countTime ++;
}
/********************************************************************
* 名称 : delay_140us()
* 功能 : 延时
* 输入 : void
* 输出 : 无
**************************************************************/
void delay_140us()
{
int i;
for(i = 0; i < 20; i++)
_nop_();
}
/********************************************************************
* 名称 : void ModifyTime(uchar hou,uchar min,uchar sec)
* 功能 : 修改时间(全)
* 输入 : void
* 输出 : 无
**************************************************************/
void ModifyTime(uchar hou, uchar min,uchar sec)
{
uchar temp = 0;
temp = HEX2BCD(hou);
write_byte(DS3231_HOUR, temp); //设置时
temp = HEX2BCD(min);
write_byte(DS3231_MINUTE, temp); //设置分
temp = HEX2BCD(sec);
write_byte(DS3231_SECOND, temp); //设置秒
}
/********************************************************************
* 名称 : void ModifyTime(uchar hou,uchar min,uchar sec)
* 功能 : 修改时间(时)
* 输入 : void
* 输出 : 无
**************************************************************/
void ModifyHour(hour)
{
uchar temp = HEX2BCD(hour);
write_byte(DS3231_HOUR, temp); //设置时
}
/********************************************************************
* 名称 : void Modifymin(minute)
* 功能 : 修改时间(分)
* 输入 : void
* 输出 : 无
**************************************************************/
void ModifyMinute(minute)
{
uchar temp = HEX2BCD(minute);
write_byte(DS3231_MINUTE, temp); //设置分
}
/********************************************************************
* 名称 : void ModifyTime(uchar hou,uchar min,uchar sec)
* 功能 : 修改时间(秒)
* 输入 : void
* 输出 : 无
**************************************************************/
void ModifySecond(second)
{
uchar temp = HEX2BCD(second);
write_byte(DS3231_SECOND, temp); //设置秒
}
/********************************************************************
* 名称 : void receiveData() interrupt 4
* 功能 : 接收蓝牙数据
* 输入 : void
* 输出 : 无
**************************************************************/
void receiveData() interrupt 4
{
if(RI == 1)
{
RI = 0;
Recive_table = SBUF;
if(Recive_table == '\n')
{
if(i == 4)//调整时间
{
num = (Recive_table[1] - '0') * 10 + (Recive_table[2] - '0');
if(Recive_table[0] == 'h')
ModifyHour(num);
else if(Recive_table[0] == 'm')
ModifyMinute(num);
}
else if(i == 2)//获取时钟时间并发给手机
flag = 1;
else if(i == 5)
{
alarmHour = (Recive_table[0] - '0') * 10 + (Recive_table[1] - '0');
alarmMin = (Recive_table[2] - '0') * 10 + (Recive_table[3] - '0');
flag = 2;
}
i = 0;
}
else
i++;
}
else
TI = 0;
}
/***********************************************************
*****
***** 主函数
*****
***********************************************************/
void main()
{
init();
// bluetoothVcc = 1;
// bluetoothGnd = 0;
beep = 0;
closeBeep = 0;
while(1)
{
//计算+显示时间
compute_and_display_time();
if(countTime <= 10) //第一微秒:不带数点
{
dpFlag = 0;
}
else if(countTime <= 20) //第二微秒:带数点
{
dpFlag = 1;
}
else //重置计数器
{
countTime = 0;
}
//蓝牙操作
if(flag == 1) //反馈回当前时间
{
uchar Htemp1, Htemp2, Mtemp1, Mtemp2;
Htemp1 = read_random(DS3231_HOUR); //获取时
Htemp1&=0x3f;
Htemp2 = BCD2HEX(Htemp1);
Mtemp1 = read_random(DS3231_MINUTE); //获取分
Mtemp2 = BCD2HEX(Mtemp1);
//发送时
ES = 0;
SBUF = Htemp2;
while(!TI);
TI = 0;
ES = 1;
//发送分
ES = 0;
SBUF = Mtemp2;
while(!TI);
TI = 0;
ES = 1;
flag = 0;
}
else if(flag == 2)//设置闹钟
{
dpFlag = 1;
TimeDisplay(alarmHour, alarmMin);
ES = 0;
SBUF = 1; //单片机的数据发送到计算机,表示闹钟设置成功
while(!TI);
TI = 0;
ES = 1;
flag = 0;
delayus(100000);
}
}
}
5.塞进去,大功告成:
PS:最后做好后送人了,听反馈似乎代码还有点小问题,所以你可以再自己改改。