C51单片机学习笔记–DS1302时钟芯片&&蜂鸣器&&I2C总线&&AT24C02存储器

文章目录

  • 一、DS1302时钟芯片介绍
  • 二、DS1302时钟芯片相关寄存器和数据传输
  • 三、DS1302时钟芯片实验
  • 四、蜂鸣器工作原理
  • 五、I2C总线和时序结构介绍
  • 六、AT24C02存储模块介绍
  • 七、电子琴实验——综合之前所学的模块

一、DS1302时钟芯片介绍


DS1302时钟芯片是具有涓细电流充电能力的低功耗实时时钟芯片。实时时钟计算年、月、日、时、分、秒、星期,直到 2100 年,并有闰年调节功能。DS1302芯片包含一个用于存储实时时钟/日历的 31 字节的静态 RAM,可通过简单的串行接口与微处理器通讯,将当前的是时钟存于RAM。相较于定时器,时钟芯片的精度更高,运行更稳定且DS1302芯片对于少于 31 天的月份月末会自动调整,并会自动对闰年进行校正。

DS1302时钟芯片由VCC和GND端供电,晶振通过内部电路处理后向时钟芯片提供一个稳定的脉冲,时钟芯片利用该脉冲来计时。CE引脚作用是输出使能电平来控制数据输入输出和串行时钟,IO引脚则用来传输数据,写程序时的数据传输过程类似74HC595移位寄存器,串行时钟(SCLK)也是通过高低电平来控制数据传输。


DS1302工作时为了对任何数据传送进行初始化,需要将复位脚(RST)置为高电平且将8位地址和命令符分别装入移位寄存器。数据在时钟(SCLK)的上升沿开始串行输入,前8位指定访问地址,命令符装入移位寄存器后,在之后的时钟周期,写操作时输入数据,读操作时输出数据。

二、DS1302时钟芯片相关寄存器和数据传输

上面讲到,通过控制DS1302相关寄存器,我们就可以让CPU和时钟芯片数据传输,从而获取时钟时间状态以及控制时钟的初始值。

从上述图中可以看出,通过控制寄存器IO引脚传输数据时要同时输入命令字和数据,其中读写命令字分别有9个,分别对应时钟芯片不同的计时单位,所以通过相应的命令字和初始值我们就可以初始化时钟的某个计时单位。


通过上述数据传输原理图,我们要先给CE引脚赋高电平来打开数据传输读写口,然后通过给SCLK串行时钟引脚间隔赋高低电平来完成单字节写入,原理类似移位寄存器,在高电平时将二进制数一位一位挪入,最后给CE引脚赋低电平来关闭数据传输读写口,读出的过程也类似。

三、DS1302时钟芯片实验

按照上述原理,我们先给DS1302时钟芯片数据传输过程进行封装,然后在主函数里面调用读和写的子函数来实现时钟的初始化。

这里我们也会用到LCD1602液晶屏作为时钟的显示模块,所以记得在主函数之前include一下LCD1602的模块。

# include <REGX52.H>sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;void DS1302_Init()
{DS1302_CE=0;DS1302_SCLK=0;
}void DS1302_Write(unsigned char Command, Data)//定义一个写入函数
{unsigned int i=0;DS1302_CE=1;for (i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}for (i=0;i<8;i++){DS1302_IO=Data&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}DS1302_CE=0;}unsigned char DS1302_Read(unsigned char Command)//定义一个读出函数
{unsigned int i=0,Data=0x00;Command|=0x01;DS1302_CE=1;for (i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=0;DS1302_SCLK=1;}for (i=0;i<8;i++){DS1302_SCLK=1;DS1302_SCLK=0;if (DS1302_IO){Data|=(0x01<<i);}}DS1302_CE=0;DS1302_IO=0;return Data;
}

这个是封装好的DS1302模块,开始前先进行三个数据传输引脚的位声明。

# include <REGX52.H>
# include "LCD1602.h"
# include "DS1302.h"
# include "delay.h"void main()
{unsigned char Second=0,Minute=0,Hour=0,Date=0,Month=0;LCD_Init();DS1302_Init();LCD_ShowString(1,1,"Timer:    Date:");LCD_ShowString(2,1,"  :  :      .");DS1302_Write(0x8E,0x00);DS1302_Write(0x80,50/10*16+50%10);DS1302_Write(0x82,4/10*16+4%10);DS1302_Write(0x84,10/10*16+10%10);DS1302_Write(0x86,13/10*16+13%10);DS1302_Write(0x88,11/10*16+11%10);DS1302_Write(0x8E,0x80);while(1){Second=DS1302_Read(0x81)/16*10+DS1302_Read(0x81)%16;Minute=DS1302_Read(0x83)/16*10+DS1302_Read(0x83)%16;Hour=DS1302_Read(0x85)/16*10+DS1302_Read(0x85)%16;Date=DS1302_Read(0x87)/16*10+DS1302_Read(0x87)%16;Month=DS1302_Read(0x89)/16*10+DS1302_Read(0x89)%16;LCD_ShowNum(2,7,Second,2);LCD_ShowNum(2,4,Minute,2);LCD_ShowNum(2,1,Hour,2);LCD_ShowNum(2,11,Month,2);LCD_ShowNum(2,14,Date,2);}
}

主函数里面除了调用时钟读写模块,还要进行BCD转码,否则会出错。

四、蜂鸣器工作原理


蜂鸣器分为有源蜂鸣器和无源蜂鸣器。
这里的“源”不是指电源。而是指震荡源。 也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫。 而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫,必须用2K~5K的方波去驱动它。

通过改变引脚输出的频率,就可以调整蜂鸣器的音调,产生各种不同的声音;同时改变输出电平的高低电平占空比,则可以控制蜂鸣器的声音大小。


上面的截图显示了从低音,中音到高音的每个音符对应的频率,其中包括7个基本音符的升调,通过频率我们可以计算出对应的周期,对周期取整后就可以近似得到蜂鸣器发出该声调所需要的高低电平时间。

我们可以利用之前学过的中断定时器原理,通过设定定时器的重装载值来控制中断系统在一个设定的时间后产生一个中断,此时翻转蜂鸣器就可以发出声音了。

五、I2C总线和时序结构介绍


I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行通信总线,是微电子通信控制领域广泛采用的一种总线标准。I2C总线可以将单片机与其他具有I2C总线通信接口的外围设备连接起来,通过串行数据(SDA)线和串行时钟(SCL)线与连接到该双线的器件传递信息。每个I2C器件都有一个唯一的识别地址(I2C总线支持7位和10位地址),而且可以作为一个发送器或接收器。I2C器件在执行数据传输时也可以看作是主机或从机,主机是初始化总线数据传输并产生允许传输时钟信号的器件,此时任何被寻址的其他I2C器件都被认为是从机。

下面讲讲I2C总线的6种时序结构,用于主机和从机的数据传输。

根据上述原理图,写程序时我们要建立六个子函数模块,开始传输数据时SCL和SDA都应该处于高电平,先拉低SDA电平再拉低SCL电平,在传输或者接收数据时要拉高并保持SCL高电平然后读取放到SDA上的数据,结束传输数据就和开始时相反,还要设置应答模块在主机和从机间建立应答通讯。

六、AT24C02存储模块介绍


AT24C02是一种掉电数据不丢失的储存器,通过I2C总线的通讯协议来给存储器写入数据,但AT24C02内部储存空间只有256字节,每个字节可以存入8位二进制数,所以每个字节所存的最大整数为255,存储和读取时通过地址来找数据,类似C语言里面的指针。

从上述原理图可以看出,AT24C02分别有8个引脚,其中A2、 A1、 A0这三个引脚用于器件地址的输入,SDA是双向串行数据传输引脚,SCL则是串行时钟输入引脚,数据上升沿写入下降沿读出,WP是写保护引脚,专门为数据提供保护,VCC和GND则是电源正负极。

结合I2C总线是时序结构和数据帧以及上述原理,我们只需要将AT24C02封装成一个包含读写函数的模块即可,读写模块分别遵照数据读写时发送地址和应答,再发送数据和应答的基本原理并调用之前的I2C模块函数。

七、电子琴实验——综合之前所学的模块

细心的小伙伴肯定会发现缺了关于蜂鸣器的实验,别着急这不来了!

之前学到蜂鸣器时我的脑子里就蹦出来一个神奇的想法,可不可以做一个类似电子琴的玩意呢?谁知这个想法直接将我带上了一段奇妙的创造之旅!

温馨提示:下面信息量可能有点爆炸!!

做电子琴首先要有输入模块,于是我想利用矩阵按键和独立按键来模拟电子琴的键盘,因为矩阵键盘只有16个键,对于36个从低中高还有声调的音符显然不够,于是我就想用独立按键的前三位来控制低中高三中音调,用矩阵按键前12个按键来控制音符,想法很美好但我实践的时候却发现之前写独立按键模块时的代码是利用delay延迟和while循环来给按键消抖并实验放手返回值,但如果同时按下独立按键和矩阵键盘就会发现程序卡死在while循环里导致读出的矩阵按键值可能是上一次的值,所以我思考了一下决定用定时器中断来解决这个问题,通过中断触发来定时比较独立按键的返回值来确定按键是否放开,这样就不会让程序卡死在while循环里了!

#include <REGX52.H>/*** @brief  定时器0初始化,1毫秒@12.000MHz* @param  无* @retval 无*/
void Timer0Init(void)
{TMOD &= 0xF0;      //设置定时器模式TMOD |= 0x01;      //设置定时器模式TL0 = 0x18;        //设置定时初值TH0 = 0xFC;     //设置定时初值TF0 = 0;        //清除TF0标志TR0 = 1;       //定时器0开始计时ET0=1;EA=1;PT0=0;
}/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18;        //设置定时初值TH0 = 0xFC;     //设置定时初值T0Count++;if(T0Count>=1000){T0Count=0;}
}
*/
#include <REGX52.H>
#include "Delay.h"unsigned char Key_KeyNumber;unsigned char Key(void)
{unsigned char Temp=0;Temp=Key_KeyNumber;Key_KeyNumber=0;return Temp;
}unsigned char Key_GetState()
{unsigned char KeyNumber=0;if(P3_1==0){KeyNumber=1;}if(P3_0==0){KeyNumber=2;}if(P3_2==0){KeyNumber=3;}if(P3_3==0){KeyNumber=4;}return KeyNumber;
}void Key_Loop(void)
{static unsigned char NowState,LastState;LastState=NowState;               //按键状态更新NowState=Key_GetState();        //获取当前按键状态//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测if(LastState==1 && NowState==0){Key_KeyNumber=1;}if(LastState==2 && NowState==0){Key_KeyNumber=2;}if(LastState==3 && NowState==0){Key_KeyNumber=3;}if(LastState==4 && NowState==0){Key_KeyNumber=4;}
}

这个是优化后的独立按键模块,只要在主函数的中断函数内调用Key_Loop子函数就可以定时比较来确定按键状态了。

# include <REGX52.H>
# include "delay.h"int  Matrix()
{int number;P1=0xFF;P1_3=0;if(P1_7==0){delay(20);while(P1_7==0);delay(20);number=1;}if(P1_6==0){delay(20);while(P1_6==0);delay(20);number=5;}if(P1_5==0){delay(20);while(P1_5==0);delay(20);number=9;}if(P1_4==0){delay(20);while(P1_4==0);delay(20);number=13;}P1=0xFF;P1_2=0;if(P1_7==0){delay(20);while(P1_7==0);delay(20);number=2;}if(P1_6==0){delay(20);while(P1_6==0);delay(20);number=6;}if(P1_5==0){delay(20);while(P1_5==0);delay(20);number=10;}if(P1_4==0){delay(20);while(P1_4==0);delay(20);number=14;}P1=0xFF;P1_1=0;if(P1_7==0){delay(20);while(P1_7==0);delay(20);number=3;}if(P1_6==0){delay(20);while(P1_6==0);delay(20);number=7;}if(P1_5==0){delay(20);while(P1_5==0);delay(20);number=11;}if(P1_4==0){delay(20);while(P1_4==0);delay(20);number=15;}P1=0xFF;P1_0=0;if(P1_7==0){delay(20);while(P1_7==0);delay(20);number=4;}if(P1_6==0){delay(20);while(P1_6==0);delay(20);number=8;}if(P1_5==0){delay(20);while(P1_5==0);delay(20);number=12;}if(P1_4==0){delay(20);while(P1_4==0);delay(20);number=16;}return number;
}

这里附上矩阵按键模块,我这里没有优化不过不影响最后的效果,想要优化的小伙伴可以参照独立按键的思路来操作。

解决好键盘模拟后还要解决数据读写问题,刚开始我打算在主函数里面定义一个音符索引和节拍索引数组直接将按键值写入数组,但我发现如果将索引写入数组是不够用的,所以我想结合I2C总线和AT24C02存储器将音符索引和节拍索引数组写入其中到播放时再读出,这样就可以扩容了。

# include <REGX52.H>sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;void I2C_Start()
{I2C_SDA=1;I2C_SCL=1;I2C_SDA=0;I2C_SCL=0;}void I2C_Stop()
{I2C_SDA=0;I2C_SCL=1;I2C_SDA=1;
}void I2C_SendData(unsigned char Data)
{ unsigned char i;for(i=0;i<8;i++){I2C_SDA=Data&(0x80>>i);I2C_SCL=1;I2C_SCL=0;}
}unsigned char I2C_ReceiveData()
{unsigned char i,Data=0x00;I2C_SDA=1;for(i=0;i<8;i++){I2C_SCL=1;if(I2C_SDA){Data|=(0x80>>i);}I2C_SCL=0;}return Data;
}void I2C_SendAck(unsigned char Ack)
{I2C_SDA=Ack;I2C_SCL=1;I2C_SCL=0;
}unsigned char I2C_ReceiveAck()
{unsigned char Ack;I2C_SDA=1;I2C_SCL=1;Ack=I2C_SDA;I2C_SCL=0;return Ack;
}

这个是I2C总线模块,里面定义了6个子函数供其他模块调用来完成数据传输。

# include <REGX52.H>
# include "I2C.h"#define AT24C02_ADDRESS     0xA0void AT24C02_Write(unsigned char DataAddress,Data)
{I2C_Start();I2C_SendData(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendData(DataAddress);I2C_ReceiveAck();I2C_SendData(Data);I2C_ReceiveAck();I2C_Stop();
}unsigned char AT24C02_Read(unsigned char DataAddress)
{unsigned char Data;I2C_Start();I2C_SendData(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendData(DataAddress);I2C_ReceiveAck();I2C_Start();I2C_SendData(AT24C02_ADDRESS|0x01);I2C_ReceiveAck();Data=I2C_ReceiveData();I2C_SendAck(1);I2C_Stop();return Data;
}

AT24C02模块就相对简洁了,只需要调用I2C总线模块子函数匹配传收的数据帧原理即可传输数据。

搞定完音符和节拍读写后我好像利用LCD液晶屏来显示写入的音符note和写入的节拍beat,废话不多说,直接上主函数。

# include <REGX52.H>
# include "delay.h"
# include "Timer0.h"
# include "AT24C02.h"
# include "LCD1602.h"
# include "Key.h"
# include "Matrix.h"sbit Buzzer=P2^5;#define SPEED  500#define P 0
#define L1  1
#define L1_ 2
#define L2  3
#define L2_ 4
#define L3  5
#define L4  6
#define L4_ 7
#define L5  8
#define L5_ 9
#define L6  10
#define L6_ 11
#define L7  12
#define M1  13
#define M1_ 14
#define M2  15
#define M2_ 16
#define M3  17
#define M4  18
#define M4_ 19
#define M5  20
#define M5_ 21
#define M6  22
#define M6_ 23
#define M7  24
#define H1  25
#define H1_ 26
#define H2  27
#define H2_ 28
#define H3  29
#define H4  30
#define H4_ 31
#define H5  32
#define H5_ 33
#define H6  34
#define H6_ 35
#define H7  36unsigned int code Frequency[]={0,63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,
};unsigned char Musickey,Frequencykey,KeyNum,Data,i=0,j=0,count=0,M_count=0,Button,a;void main()
{ LCD_Init();Timer0Init();while(1){Button=Key();KeyNum=Matrix();if(Button==4&&count==0){count=1;AT24C02_Write(i+1,0);}else if(Button==4&&count==1){count=0;}if(count==0){ if(i%2==0){M_count=1;}else {M_count=0;}if(Button==1){KeyNum=Matrix();Data=KeyNum;AT24C02_Write(i,Data);delay(5);Data=AT24C02_Read(i);delay(5);i++;if (M_count==1){if (KeyNum==1||KeyNum==3){LCD_ShowString(2,1,"Note: L  ");a=(i+1)/2;LCD_ShowNum(2,8,(KeyNum+1)/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==2||KeyNum==4){a=(i+1)/2;LCD_ShowString(2,1,"Note: L _");LCD_ShowNum(2,8,KeyNum/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==5||KeyNum==6){a=(i+1)/2;LCD_ShowString(2,1,"Note: L _");LCD_ShowNum(2,8,KeyNum-2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==8||KeyNum==10||KeyNum==12){a=(i+1)/2;LCD_ShowString(2,1,"Note: L  ");LCD_ShowNum(2,8,(KeyNum+2)/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==7||KeyNum==9||KeyNum==11){a=(i+1)/2;LCD_ShowString(2,1,"Note: L _");LCD_ShowNum(2,8,(KeyNum+1)/2,1);LCD_ShowNum(2,11,a,2);}}else if(M_count==0){LCD_ShowString(1,1,"Beat:");LCD_ShowNum(1,7,Data,2);LCD_ShowNum(1,11,i/2,2);}Data=0;}if(Button==2){KeyNum=Matrix();Data=12*M_count+KeyNum;AT24C02_Write(i,Data);delay(5);Data=AT24C02_Read(i);delay(5);i++;if (M_count==1){if (KeyNum==1||KeyNum==3){a=(i+1)/2;LCD_ShowString(2,1,"Note: M  ");LCD_ShowNum(2,8,(KeyNum+1)/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==2||KeyNum==4){a=(i+1)/2;LCD_ShowString(2,1,"Note: M _");LCD_ShowNum(2,8,KeyNum/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==5||KeyNum==6){a=(i+1)/2;LCD_ShowString(2,1,"Note: M _");LCD_ShowNum(2,8,KeyNum-2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==8||KeyNum==10||KeyNum==12){a=(i+1)/2;LCD_ShowString(2,1,"Note: M  ");LCD_ShowNum(2,8,(KeyNum+2)/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==7||KeyNum==9||KeyNum==11){a=(i+1)/2;LCD_ShowString(2,1,"Note: M _");LCD_ShowNum(2,8,(KeyNum+1)/2,1);LCD_ShowNum(2,11,a,2);}}else if(M_count==0){LCD_ShowString(1,1,"Beat:");LCD_ShowNum(1,7,Data,2);LCD_ShowNum(1,11,i/2,2);}Data=0;}if(Button==3){KeyNum=Matrix();Data=24*M_count+KeyNum;AT24C02_Write(i,Data);delay(5);Data=AT24C02_Read(i);delay(5);i++;if (M_count==1){if (KeyNum==1||KeyNum==3){a=(i+1)/2;LCD_ShowString(2,1,"Note: H  ");LCD_ShowNum(2,8,(KeyNum+1)/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==2||KeyNum==4){a=(i+1)/2;LCD_ShowString(2,1,"Note: H _");LCD_ShowNum(2,8,KeyNum/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==5||KeyNum==6){a=(i+1)/2;LCD_ShowString(2,1,"Note: H _");LCD_ShowNum(2,8,KeyNum-2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==8||KeyNum==10||KeyNum==12){a=(i+1)/2;LCD_ShowString(2,1,"Note: H  ");LCD_ShowNum(2,8,(KeyNum+2)/2,1);LCD_ShowNum(2,11,a,2);}else if(KeyNum==7||KeyNum==9||KeyNum==11){a=(i+1)/2;LCD_ShowString(2,1,"Note: H _");LCD_ShowNum(2,8,(KeyNum+1)/2,1);LCD_ShowNum(2,11,a,2);}}else if(M_count==0){LCD_ShowString(1,1,"Beat:");LCD_ShowNum(1,7,Data,2);LCD_ShowNum(1,11,i/2,2);}Data=0;}}if (count==1){ for (j=0;j<=i+1;j++){Frequencykey=AT24C02_Read(j);j++;Musickey=AT24C02_Read(j);delay(SPEED/4*Musickey);TR0 = 0;delay(10);TR0 = 1;if(Frequencykey==0){TR0=0;}}}}
}
void Timer0_Routine() interrupt 1
{static unsigned int T0Count1;if(count==0){TL0 = 0x18;        //设置定时初值TH0 = 0xFC;     //设置定时初值T0Count1++;if(T0Count1>=20){T0Count1=0;Key_Loop(); //20ms调用一次按键驱动函数}}else if(Frequency[Frequencykey]&&count==1){TL0 = Frequency[Frequencykey]%256;      //设置定时初值TH0 = Frequency[Frequencykey]/256;        //设置定时初值Buzzer=!Buzzer;}
}

主函数中一共有几大块进行说明:

1.要建立一个音符索引数组,数组中存放了定时器的重装载值来控制中断输出,其中音符L1表示低音DO,音符L1_表示低音升DO,音符M1则表示中音DO,音符H1则表示高音DO;

2.主函数有读写和播放两个主要模块,通过独立按键第四位来进行按键切换;

3.节拍索引我直接读取矩阵键盘的值来确定,正常一小节16拍,所以就算一小节只有一个音符也够用,至于音符演奏时间的计算就定义一个初始的SPEED,通过节拍四则运算确定每个音符的播放时长;

4.LCD液晶屏显示模块也需要通过复杂的逻辑判断来实现既有字母又有数字的混合显示,而且升调比原调多了一个“_”,所以如果想用指针数组实现也相当麻烦;

5.定时器中断函数需要服务于蜂鸣器和独立按键扫描两个模块,为了避免独立按键扫描时蜂鸣器乱叫,我给读写模块和播放模块通过if判断来执行不同的中断。

在做这个模拟电子琴的实验中我也遇到了很多问题,经过不断调试也取得了一些效果,但仍有一些不完善的地方,有兴趣的小伙伴可以一起玩一下并加以改善。

C51单片机——电子琴实验

【C51单片机学习笔记--DS1302时钟芯片蜂鸣器I2C总线AT24C02存储器】相关推荐

  1. C51单片机学习笔记(一)——搭建开发环境及烧写工具

    C51单片机学习笔记(一)--搭建开发环境及烧写工具 文章目录 C51单片机学习笔记(一)--搭建开发环境及烧写工具 1.搭建软件开发环境及使用(Keil uVision) 2.将程序下载到单片机(烧 ...

  2. C51单片机学习笔记之定时器

    简介 "定时器/计数器"说的是一个东西,因为它既能计时也能计数.是存在于单片机内部的一个独立的硬件部分,依赖晶振产生固定的时间间隔,产生了一定量的固定时间间隔后会引发定时器中断从而 ...

  3. c51单片机学习笔记-LED流水灯实验

    目的:实现 LED 流水灯,只需循环让 D1-D8 指示灯逐个点亮. 方法:点亮 D1 且把 D2-D8 熄灭,延时一段时间后再点亮 D2 且把 D1. D3-D8 熄灭,延时一段时间后再点亮 D3 ...

  4. 【C51单片机学习笔记----DS18B20温度传感器LCD1602液晶屏直流电机调速与呼吸灯AD模数转换红外外部中断】

    文章目录 一.DS18B20温度传感器 1.DS18B20温度传感器连接原理图 2.DS18B20温度传感器单总线通信时序 3.DS18B20温度传感器代码模块 二.LCD1602液晶屏 1.LCD1 ...

  5. 单片机学习笔记 —— 可变调的蜂鸣器

    一.乐理基础 相关名词: 音名:do re mi fa so la xi 唱名:C D E F G A B,此外还有#C #D #E-表示升一个调 半音:C和#C的频率比值为1:2,它们之间相差12个 ...

  6. 51单片机学习笔记【七】——蜂鸣器和继电器

    一.蜂鸣器 1.蜂鸣器基础 蜂鸣器按驱动方式分为有源蜂鸣器和无源蜂鸣器,有源蜂鸣器内部带振荡器,接入一个低电平便会响:无源蜂鸣器不带振荡器,让它响要接500HZ~4.5KHZ之间的脉冲信号来驱动才会响 ...

  7. C51单片机学习笔记之串口通信

    简介 串口通信就是单片机和pc之间的一种通信方式. 通信方式:并行,串行,同步,异步(最常用的) 传输方向:单工,半双工(不同时间),全双工 基本结构 ​ 相关寄存器 SCON串口控制寄存器(主要用方 ...

  8. C51单片机学习笔记之矩阵键盘

    简介 矩阵键盘一般为4×4或4×3的.矩阵键盘的判断方式分按行扫描和按列扫描. 简单说就是给全体一个高电平,然后给一个按键的一端附上低电平,再判断另一端是否为低电平. 原理图 代码部分 #includ ...

  9. 单片机课程设计——《基于AT89S52单片机和DS1302时钟芯片的电子时钟(可蓝牙校准)》...

    引言 本设计以AT89S52单片机为控制核心,时钟芯片DS1302提供时钟源,配合LCD1602液晶显示模块,组成基本硬件系统,同时利用HC-05嵌入式蓝牙串口通讯模块,可在手机端进行日期.时间的校准 ...

最新文章

  1. delphi创建和读取xml(xml简单操作举例)
  2. 3.7 测试时的 BatchNorm-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  3. python2 与 python3 语法区别--转
  4. C#设计模式——生成器模式(Builder Pattern)
  5. linux平台安装React Native遇到的坑
  6. 使用kibana客户端工具操作ElasticSearch(增删改查一)
  7. 1000道Python题库系列分享八(29道)
  8. python 序列类型函数_序列类型可用的内置函数
  9. 巴菲特对合伙人提过3个要求
  10. Spring管理hibernate的事务的方法
  11. 苹果Mac定制化App开发神器:FileMaker Pro
  12. PHP可以通过什么组件上传大文件
  13. PHP-dede学习:common.ini.php文件
  14. 英语知识点整理day02
  15. webrt分析六(nack)
  16. 用matlab求解二元二次方程组的方法
  17. django tests 小结
  18. java oa系统二次开发_浅谈OA系统的二次开发
  19. cadence软件打开报错“计算机中丢失cdsCommon.dll”的解决办法
  20. Python win32com 操作word 插入回车符,换行符

热门文章

  1. 天才如周杰伦与周星驰也难逃孤独
  2. 很好看的后台管理界面
  3. 计算机考试文字颜色不对,2017年计算机一级考试WPS2007:让公式中的文字变个颜色...
  4. wma和mp3哪个音质好 如何将wma转换成mp3
  5. 行业研究报告:合束器市场现状及未来发展趋势
  6. cocos2dx中的定时器
  7. [附源码]SSM计算机毕业设计电子病历信息管理系统JAVA
  8. 海蜘蛛路由免费版也可以看流量
  9. 20万+字,熬夜整理了一份程序员不可或缺的软技能高分原创电子书送给你
  10. 有源医疗器械注册送检介绍(EMC部分)