目录

  • 1 项目1  电子琴设计
    • 1.1 课程概述
    • 1.2 蜂鸣器发声
    • 1.3 不同音阶发声和控制
    • 1.4 多功能电子琴
      • 1.4.1 播放一首乐曲的程序编写与仿真
      • 1.4.2 具有多功能电子琴设计与实施
      • 1.4.3 具有多功能电子琴程序编写和仿真
      • 1.4.4 具有多功能电子琴设计--直播程序讲解
  • 2 项目2  LED流水灯设计
    • 2.1 左右依次循环点亮的流水灯设计
    • 2.2 多种花样点亮的流水灯设计
    • 2.3 可调节型多功能亮灯的流水灯设计
  • 3 项目3 直流电机控制
    • 3.1 直流电机的双向转动设计
    • 3.2 转速可调的直流电机转动设计
    • 3.3 多功能直流电机双向转动设计
  • 4 项目4  步进电机控制
    • 4.1 步进电机的双向转动设计
    • 4.2 转速可调的步进电机转动设计
    • 4.3 多功能步进电机双向转动设计
  • 5 项目5 直流电机、步进电机、舵机综合设计
    • 5.1 综合设计
  • 6 项目6 广告灯设计
    • 6.1 在8*8点阵上显示一个字符
    • 6.2 在16*16点阵上显示一个汉字
    • 6.3 在16*16点阵上显示滚动汉字
  • 7 项目7 液晶显示设计
    • 7.1 在1602液晶屏上显示字符
    • 7.2 在1602液晶屏上显示自定义符号和图形
  • 8 电子万年历的制作
    • 8.1 简单万年历的制作
    • 8.2 复杂万年历的制作
    • 8.3 创新万年历的制作
  • 9 作品考核--制作18B20温控风扇
    • 9.1 任务书(拟实现的主要功能)
      • 9.1.1 单片机相关资料
      • 9.1.2 18B20相关资料
      • 9.1.3 PWM脉宽调制资料
      • 9.1.4 74H573介绍
      • 9.1.5 数码管介绍
    • 9.2 原理图、PCB图、焊接图、仿真图
    • 9.3 程序
复杂万年历的制作

1、复杂电子万年历的制作--仿真图



2、复杂电子万年历的制作--参考程序

I2C.H

/*****************************************************************

               头文件名    VIIC_C51.H

   这个头文件对应的库是VIIC_C51.LIB,库中有几个模拟I2C的函数,加入此文件 

即可使用I2C平台(主方式的软件平台), 函数是对LPC764的I2C的I/O口实

现,即其P1.3 (SDA)   , P1.2(SCL),51系列机型可以通用.           

   注意: 函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作 

一定的修改....(本例是1us机器周期,即晶振频率要小于12MHZ).

(函数的使用可参考给出的事例程序.)

*****************************************************************/

#ifdef uchar 

  #define READYDEF 1   /*宏uchar已定义*/

#else  

  #define uchar unsigned char

#endif

/*******************************************************************

                     无子地址发送字节数据函数               

功能:     从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.

           如果返回1表示操作成功,否则操作有误。

********************************************************************/

extern bit ISendByte(uchar sla,uchar c);

/*******************************************************************

                     有子地址发送多字节数据函数               

功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件

          地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。

           如果返回1表示操作成功,否则操作有误。

********************************************************************/

extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no) ;

/*******************************************************************

                    无子地址读字节数据函数               

功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地

          址sla,返回值在c.

           如果返回1表示操作成功,否则操作有误。

********************************************************************/

extern bit IRcvByte(uchar sla,uchar *c);

/*******************************************************************

                    有子地址读取多字节数据函数               

   

功能:     从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件

          地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。

           如果返回1表示操作成功,否则操作有误。

********************************************************************/

extern bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no);

#ifndef READYDEF

  #undef uchar

#endif

1602.H

#ifndef __1602_H__

#define __1602_H__

///////////////////////////////////////////////////////////

#define uchar unsigned char

#define uint unsigned int

#define dat P0 //定义LCD1602的数据口为P0口

sbit E_1602=P1^2;

sbit RW_1602=P1^1;

sbit RS_1602=P1^0;

///////////////////////////////////////////////////////////

extern void delay_1602(void);

extern void busy_1602(void);

extern void write_com_1602( uchar );

extern void wr_data_1602(uchar);

extern void write_char_1602(uchar x,uchar y,uchar dat);

extern void write_datas_1602(uchar ,uchar,uchar *, uchar );

extern void init_1602( void );

///////////////////////////////////////////////////////////

#endif

1602.C

#include<at89x52.h>

#include<intrins.h>

#include"1602.h"

//液晶模块延时函数

void delay_1602() //延时程序

{

uchar i,j;

for(i=0;i<10;i++)

for(j=0;j<22;j++); 

}

//判断液晶是不是忙碌函数

void busy_1602( )     //查询忙碌标志信号程序

{

uchar busy;

do

{

E_1602=0;

RW_1602=1;

RS_1602=0;

E_1602=1;

busy=dat;

E_1602=0;    

delay_1602();

} while(busy&0x10==1);

}

//写指令函数

void write_com_1602( uchar com )

{

busy_1602();

E_1602=0;

RW_1602=0;

RS_1602=0;

E_1602=1;

dat=com;

E_1602=0; 

}

//写数据函数

void wr_data_1602( uchar a )  //写指令到LCM程序

{

       busy_1602();

       E_1602=0;

       RW_1602=0;

       RS_1602=1;

       E_1602=1;

       dat=a;

       E_1602=0;

}

//指定位置写入一个数据,x:第几行  y,第几列  dat:数据

void write_char_1602(uchar x,uchar y,uchar dat)

{

if(x==0)

{

  write_com_1602(0x80+y);

}

else if(x==1)

{

  write_com_1602(0xc0+y);

}

wr_data_1602(dat);

}

//指定位置写入指定长度的数据,x:第几行  y,第几列  dat:数组  num:

void write_datas_1602( uchar x,uchar y,uchar *dat, uchar num )

{

  uchar i;

if(x==0)

{

  write_com_1602(0x80+y);

for(i=0;i<num;i++) //发送数据第一行

{

wr_data_1602(*(dat+i));

}

}

else if(x==1)

{

  write_com_1602(0xc0+y);

for(i=0;i<num;i++) //发送数据第一行

{

wr_data_1602(*(dat+i));

}

}

}

//1602液晶初始化函数

void init_1602( )//启动LCM程序

{

/*这里要多次激活液晶  */    

       write_com_1602(0x38);//设置显示模式

   _nop_();_nop_();

   write_com_1602(0x38);//设置显示模式 

   _nop_();_nop_();

   write_com_1602(0x38);//设置显示模式  

   _nop_();_nop_();    

       write_com_1602(0x0c);//开显示,不显示光标,不闪烁,00001100 

   write_com_1602(0x01);//显示清屏

       write_com_1602(0x06);//当读取或者写一个字符后地址指针加一    

}

I2C.C

/********************************************************************

                       VIIC_C51.C

  此程序是I2C操作平台(主方式的软件平台)的底层的C子程序,如发送数据

及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,它很方便的

与用户程序连接并扩展.....  

  

    注意:函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作 

一定的修改....(本例是1us机器周期,即晶振频率要小于12MHZ)

********************************************************************/              

#include <reg52.h>          /*头文件的包含*/

#include <intrins.h>

#define  uchar unsigned char /*宏定义*/

#define  uint  unsigned int

#define  _Nop()  _nop_()        /*定义空指令*/

/* 常,变量定义区 */

                                      /*端口位定义*/

sbit SDA=P1^7;            /*模拟I2C数据传送位*/

sbit SCL=P1^6;            /*模拟I2C时钟控制位*/

                                                 /*状态标志*/

bit ack;          /*应答标志位*/

/*******************************************************************

                     起动总线函数               

函数原型: void  Start_I2c();  

功能:       启动I2C总线,即发送I2C起始条件.

********************************************************************/

void Start_I2c()

{

  SDA=1;   /*发送起始条件的数据信号*/

  _Nop();

  SCL=1;

  _Nop();    /*起始条件建立时间大于4.7us,延时*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();    

  SDA=0;   /*发送起始信号*/

  _Nop();    /* 起始条件锁定时间大于4μs*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();       

  SCL=0;   /*钳住I2C总线,准备发送或接收数据 */

  _Nop();

  _Nop();

}

/*******************************************************************

                      结束总线函数               

函数原型: void  Stop_I2c();  

功能:       结束I2C总线,即发送I2C结束条件.

********************************************************************/

void Stop_I2c()

{

  SDA=0;  /*发送结束条件的数据信号*/

  _Nop();   /*发送结束条件的时钟信号*/

  SCL=1;  /*结束条件建立时间大于4μs*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();

  _Nop();

  SDA=1;  /*发送I2C总线结束信号*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();

}

/*******************************************************************

                 字节数据传送函数               

函数原型: void  SendByte(uchar c);

功能:  将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对

     此状态位进行操作.(不应答或非应答都使ack=0 假)     

     发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

********************************************************************/

void  SendByte(uchar c)

{

 uchar BitCnt;

 

 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/

    {

     if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/

       else  SDA=0;                

     _Nop();

     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/

      _Nop(); 

      _Nop();               /*保证时钟高电平周期大于4μs*/

      _Nop();

      _Nop();

      _Nop();         

     SCL=0; 

    }

    _Nop();

    _Nop();

    SDA=1;               /*8位发送完后释放数据线,准备接收应答位*/

    _Nop();

    _Nop();   

    SCL=1;

    _Nop();

    _Nop();

    _Nop();

    if(SDA==1)ack=0;     

       else ack=1;        /*判断是否接收到应答信号*/

    SCL=0;

    _Nop();

    _Nop();

}

/*******************************************************************

                 字节数据传送函数               

函数原型: uchar  RcvByte();

功能:  用来接收从器件传来的数据,并判断总线错误(不发应答信号),

     发完后请用应答函数。  

********************************************************************/

uchar  RcvByte()

{

  uchar retc;

  uchar BitCnt;  

  retc=0; 

  SDA=1;             /*置数据线为输入方式*/

  for(BitCnt=0;BitCnt<8;BitCnt++)

      {

        _Nop();           

        SCL=0;       /*置时钟线为低,准备接收数据位*/

        _Nop();

        _Nop();         /*时钟低电平周期大于4.7μs*/

        _Nop();

        _Nop();

        _Nop();

        SCL=1;       /*置时钟线为高使数据线上数据有效*/

        _Nop();

        _Nop();

        retc=retc<<1;

        if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */

        _Nop();

        _Nop(); 

      }

  SCL=0;    

  _Nop();

  _Nop();

  return(retc);

}

/********************************************************************

                     应答子函数

原型:  void Ack_I2c(bit a);

 

功能:主控器进行应答信号,(可以是应答或非应答信号)

********************************************************************/

void Ack_I2c(bit a)

{

  if(a==0)SDA=0;     /*在此发出应答或非应答信号 */

        else SDA=1;

  _Nop();

  _Nop();

  _Nop();      

  SCL=1;

    _Nop();

    _Nop();              /*时钟低电平周期大于4μs*/

    _Nop();

    _Nop();

    _Nop();  

 SCL=0;                /*清时钟线,钳住I2C总线以便继续接收*/

    _Nop();

    _Nop();    

}

/*******************************************************************

                    向无子地址器件发送字节数据函数               

函数原型: bit  ISendByte(uchar sla,ucahr c);  

功能:     从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.

           如果返回1表示操作成功,否则操作有误。

注意:    使用前必须已结束总线。

********************************************************************/

bit ISendByte(uchar sla,uchar c)

{

   Start_I2c();               /*启动总线*/

   SendByte(sla);            /*发送器件地址*/

     if(ack==0)return(0);

   SendByte(c);               /*发送数据*/

     if(ack==0)return(0);

  Stop_I2c();                 /*结束总线*/ 

  return(1);

}

/*******************************************************************

                    向有子地址器件发送多字节数据函数               

函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);  

功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件

          地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。

           如果返回1表示操作成功,否则操作有误。

注意:    使用前必须已结束总线。

********************************************************************/

bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no)

{

   uchar i;


   Start_I2c();               /*启动总线*/

   SendByte(sla);            /*发送器件地址*/

     if(ack==0)return(0);

   SendByte(suba);            /*发送器件子地址*/

     if(ack==0)return(0);

   for(i=0;i<no;i++)

    {   

     SendByte(*s);               /*发送数据*/

       if(ack==0)return(0);

     s++;

    } 

 Stop_I2c();                 /*结束总线*/ 

  return(1);

}

/*******************************************************************

                    向无子地址器件读字节数据函数               

函数原型: bit  IRcvByte(uchar sla,ucahr *c);  

功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地

          址sla,返回值在c.

           如果返回1表示操作成功,否则操作有误。

注意:    使用前必须已结束总线。

********************************************************************/

bit IRcvByte(uchar sla,uchar *c)

{

   Start_I2c();                /*启动总线*/

   SendByte(sla+1);           /*发送器件地址*/

     if(ack==0)return(0);

   *c=RcvByte();               /*读取数据*/

     Ack_I2c(1);               /*发送非就答位*/

  Stop_I2c();                  /*结束总线*/ 

  return(1);

}

/*******************************************************************

                    向有子地址器件读取多字节数据函数               

函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);  

功能:     从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件

          地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。

           如果返回1表示操作成功,否则操作有误。

注意:    使用前必须已结束总线。

********************************************************************/

bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)

{

   uchar i;

   Start_I2c();               /*启动总线*/

   SendByte(sla);            /*发送器件地址*/

     if(ack==0)return(0);

   SendByte(suba);            /*发送器件子地址*/

     if(ack==0)return(0);

   Start_I2c();

   SendByte(sla+1);

      if(ack==0)return(0);

   for(i=0;i<no-1;i++)

    {   

     *s=RcvByte();               /*发送数据*/

      Ack_I2c(0);                /*发送就答位*/  

     s++;

    } 

   *s=RcvByte();

    Ack_I2c(1);                 /*发送非应位*/

 Stop_I2c();                    /*结束总线*/ 

  return(1);

}

                     /*    完毕      */

TIMER.C