kerecs 发表于 2016-9-2 15:51:26

[51]童年回忆,咬手鲨鱼改装闹钟

1.概要:
还记得小时候玩的咬手鲨鱼吗?数十颗牙齿随机按下,鲨鱼嘴巴就会咬下。现在来试着把它改成闹钟吧!


2.最后成品图:
使用方法:闹钟响起,必须按下那颗会使嘴巴闭合的牙齿才能关闭闹钟(每次随机)。也就是说,早上起床会被鲨鱼咬到痛醒,或者你也能闪躲不被咬到,如果足够清醒的话。


3.教程:
(1)材料:咬手鲨鱼+51单片机+DS3231+ TM1637驱动数码管
(2)程序:(看程序注释应该知道怎么接线)

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int

#define DS3231_WriteAddress 0xD0
#define DS3231_ReadAddress0xD1   
#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;    //蜂鸣器
bitack;          //应答标志位

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;
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);
    if(dpFlag)
      TM1637_writeData(0xc1, SEGDataDp); //带数点
    else
      TM1637_writeData(0xc1, SEGData);//不带数点
    TM1637_writeData(0xc2, SEGData);
    TM1637_writeData(0xc3, SEGData);
    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 - '0') * 10 + (Recive_table - '0');
                                                                if(Recive_table == 'h')               
                                                                                ModifyHour(num);
                                                                else if(Recive_table == 'm')
                                                                                ModifyMinute(num);
                                                }
                                                else if(i == 2)//获取时钟时间并发给手机
                                                                flag = 1;
                                                else if(i == 5)
                                                {
                                                                alarmHour = (Recive_table - '0') * 10 + (Recive_table - '0');
                                                                alarmMin = (Recive_table - '0') * 10 + (Recive_table - '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);
                                }
                               
    }
}

(3)塞进去,大功告成

PINKWALKMAN 发表于 2016-9-2 21:56:51

好久没见51程序了,都怪Arduino。哈哈……还是那么亲切。
程序写不错。

P.919HY 发表于 2016-11-1 20:47:47

能做出来不容易啊
页: [1]
查看完整版本: [51]童年回忆,咬手鲨鱼改装闹钟