51 Microcontroller for Beginners 3 - Make an Electronic Clock from Scratch

Today we use STC89C52 to make a simple microcontroller work: electronic clock. In addition to the basic travel time function, you can also manually adjust the time, set the alarm clock, and wake up from standby.

This article includes hardware and software design.

I think there are two points that electronic clocks need to consider: one is accurate timing and small error; the other is power saving, so that it can stand by for a long time under the power of mobile power.

hardware design:

First of all, we need to conceive a good system framework:

Needless to say, the basic clock circuit and reset circuit, we use eight digital tubes as the time display mode (display style: 12-00-00), in which P0 port controls its segment, P2 port controls its bit; with eight The jog button is used as keyboard input; the buzzer and LED are used as prompt sound and indicator light respectively.

Next, you can design the schematic diagram:

It can be seen that the wiring of the digital tube is more complicated, and its principle will not be discussed for the time being (refer to article 51 SCM Beginner 2-Dynamic Scanning of Digital Tube_#liufenges#的博客-CSDN Blog_Dynamic Scanning of Digital Tube ), you can see two The 1, 2, 3, 4, 5, 7, 10, and 11 of the digital tubes are connected separately, and then lead out to connect to the P0 port; the 6, 8, 9, and 12 of the two digital tubes have a total of 8 pins and P2 port connection.

It should be noted that a latch 74HC373 is added between the digital tube position control and the P2 port , and its function is to conveniently turn off the digital tube during standby. Its pin 11 is the address latch port. When it is connected to a high level, the latch is in transparent mode, and the input and output are exactly the same. Here I directly connect to VCC; pin 1 is the output latch. There is output only when the level is high, here we use P3.6 to control its output. The figure below is the 74HC373 pin diagram and its function.

In order to simplify the circuit, the buzzer and LED share an I/O port;

The data serial port of the single-chip microcomputer is led out and connected to the pin header, which is convenient for program burning.

It should be noted that in order to prevent the digital tube from burning out, a 470-ohm current-limiting resistor (not shown in the schematic diagram) should be connected in series with the P0 port .

So get the required materials:

STC89C52 chip (1 piece), 40P base (1 piece), breadboard (2 pieces), 3461BS digital tube (2 pieces), jog button (9 pieces), LED light (1 piece), 74HC373 latch chip (1 piece chip), 10K 9P exclusion (4), 470 ohm resistor (15), 12M crystal oscillator (1), 30pF ceramic capacitor (two), pin header (15 pins), led light, active buzzer One device (the difference between active and passive buzzers can be found on the Internet), one PNP transistor.

Finally we solder the components according to the schematic. The following is the finished product picture for reference

In order to make the work look simple, we adopt a dual-board design, the upper layer is the digital tube and keyboard, and the lower layer is the minimum system of the single-chip microcomputer. The two-layer motherboards are fixed with small bolts.

Since it takes a long time to customize the PCB, I use perforated boards to make circuit boards (if you are not good at electronic soldering, it is best to make PCBs), you can see that there are many flying wires, and there are more connecting wires between the two boards ( In order to prevent the solder joints from falling off due to force, you can wrap the wire between the holes). Be careful not to install the MCU on the base when soldering the base of the MCU, so as not to burn the MCU chip during welding; similarly, when soldering the crystal oscillator, it should be as fast as possible to avoid heating the crystal oscillator for a long time and damage the crystal oscillator; pay attention to alignment when inserting the MCU chip To avoid breaking or poor contact, you can use a multimeter to measure whether all the pins are connected to the base after plugging them in; how to judge the common terminal of the resistance: there will be a white dot on the leftmost or rightmost side of the resistance, and there will be a white dot. One end of the point is the common end; the jog button has four pins (one set of normally open contacts and one set of normally closed contacts), and the two pins can be connected as shown in the schematic diagram.

Commonly used keil software for MCU program development (here we take Keil uVision3 as an example):

First create a new project (click project → new → select a file address and save), then select the CPU model.

STC89C52 is fully compatible with AT89C52 (because STC is a domestic chip, there is no STC chip in keil, so we can only use other chips instead), so we can choose AT89C52 (first click Atmel, after pulling down, you can find AT89C52).

Then a query window will pop up: Copy standard 8051 Startup code to Project Folder and Add File to project? (Do you want to copy the 8051 startup code to the project folder?), click OK. If you click Cancel, it will be added automatically when creating the file.

You can see that a Target1 project file has been created , and there is a Source Group1 folder when it is pulled down. There is a STARTUP.A51 file in this folder . This is the 8051 startup code copied just now. It contains the registers of the 51 single-chip microcomputer, the allocation of I/O ports and other addresses. These are automatically generated by the software and generally do not need to be changed. .

Then add the C program file: File→new. Then a blank file of text1 will be created. Then we click Save (or Ctrl+S), select the save address (save it in an easy-to-find place, which will be used later), enter the file name, and note that the file name must be suffixed with .c to save it as a C file. If the program is written in assembly language, add the suffix .ASM.

Then right-click Source Group1, find Add Files To Group 'Source Group1' in the menu and click (this option is displayed in bold in the menu). Then add the c program file just now to the project and close the dialog box. You can see that there are more previous C files under Source Group1.

Then you can write programs.

Programming:

Define the header file of the single-chip C program #include<reg51.h>

In order to facilitate the confusion of I/O ports when writing programs later, we can define some functional pins first. For example, the buzzer, we can see from the schematic diagram that the buzzer is controlled by P3.1, so we define P3.1 as the buzzer: sbit fm=P3^1; (' sbit' is the microcontroller used to There is no such keyword in C language; the point between P3.1 should be represented by '^' in the program ), so that in the following program, if we want to use bee Buzzer, as long as fm is equal to 0 or equal to 1, the buzzer can be controlled, and there is no need to use P3^1 anymore.

Then we need to encode the digital tube. The digital tube needs to display more characters. We can use an array to define:

char codeduan[]={0xc0,0xcf,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x7f,0xbf,0xff,0x89};

(Char data type: In the microcontroller, the char data type occupies the least space, only 1 byte (octet binary), but its range is -128~127 (signed signed type), unsigned is 0~255. Therefore, if the data range of the variable is not large, char type is generally used, which can save the space of the single-chip computer) .

Then define the global variables sec, min, hour. The reason why they are defined as global variables is to make these three quantities available in all functions.

In this work, the delay function is essential, such as digital tube scanning, travel time requires a delay function (commonly used methods are timer interrupts). The calculation of the delay function can be done by Baidu. For convenience, we can directly use the STC-IPS software to automatically generate it. As long as the time required for delay is input, the software can automatically generate a delay function, which can be directly copied and pasted (minimum time for 1us). Since we need a variety of time delays, we can first write the required delay function in front to facilitate subsequent calls.

After defining the required variables, we can start writing the main function. Here we take the digital tube scanning and timing as the main program, and the digital tube scanning and timing are carried out at the same time.

Then write the time adjustment sub-function and the alarm clock sub-function. Insert the judgment condition in the main program to call the sub-function.

In order to add more tricks, a boot 'animation' motos() is also added; (see the following program for details)

It should be noted that the sub-function should be placed before the main function, otherwise it will prompt that the sub-function is not defined when compiling.

Let's talk about the keyboard. The keyboard layout and key settings are as follows.

K1 and K2 control the left and right movement of the cursor, K3 and K4 control the addition and subtraction of numbers, K5 is the confirmation key, K6 is the time adjustment (press and hold for 4 seconds to enter), K7 sets the alarm clock, and K8 is in standby mode.

I won't say much about other details, just look at the program.

The complete procedure is as follows:

/*电子时钟程序:基本电子时钟功能,能调节时间,能设置闹钟(已删减),有待机模式(已删减)*/
/*LED数码管显示器设定;
P0.0---P0.7段控线,接LED的显示段a,b,c,d,e,f,g,dp.
P2.0---P2.7位控线,从左至右

************键位设置*******************
 	            W3(+)  
  
  W1(光标左移)  W5(确认)   W2(光标右移)  	 W6(调时)      W7(闹铃)      W8 (唤醒) 
                
		        W4(-)           
**************************************/
#include<reg51.h>
#include<intrins.h>    //定义单片机的头文件
sbit fm=P3^1;          //定义单片机蜂鸣器
sbit plays=P3^6;	     //定义73HC373输出控制位
		 //    0    1    2    3    4    5    6    7    8    9    10  11   12   13   //
char codeduan[]={0xc0,0xcf,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x7f,0xbf,0xff,0x89};	   //数码管段编码
            //    0    1    2    3    4    5    6    7    8    9    dp   -    空	H   //
char codebite[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00};				   //数码管位编码
char sec=0,min=0,hour=0;
void Delay1ms()		//@12.000MHz,1ms延时函数,用于数码管动态输出
{
	unsigned char i, j;
	i = 2;j = 239;
	do
	{
		while (--j);
	} while (--i);
}
void Delay50ms()		//@12.000MHz,用于蜂鸣器提示音,30ms
{
	unsigned char i, j, k;
	i = 2;j = 95;k = 43;
	do
	{	do
		{   while (--k);
		} while (--j);
	} while (--i);
}
void adjust()			     //时间调整模式子程序
{
   int H=0,cursor=3;
   char ks,twi,temps[8],K[8];
   temps[2]=11;
   temps[5]=11;
   fm=0;Delay50ms();fm=1;  //蜂鸣器响一声提示进入时间调整模式
   while(P1!=0xef)		    //如果没有按下K8,则执行循环
      {
	 if(H<180)	    {twi=0;}  	    //进入调整模式后,光标闪烁
	 if(H>180)	    {twi=1;}  
    	 if(H==360)     {H=0;}  
       for(ks=0;ks<8;ks++)
           {
	      if(cursor==1&&twi==0)
		  {
		  temps[0]=12;temps[1]=12;
		   }
		else
		   {temps[0]=sec%10;         //求余计算秒个位
                temps[1]=sec/10;}         //求商计算秒十位
	     
	      if(cursor==2&&twi==0)
		  {
		  temps[3]=12;temps[4]=12;
		   }
		else
		   {temps[3]=min%10;         //求余计算分个位
                temps[4]=min/10;}         //求商计算分十位
		    
		if(cursor==3&&twi==0)
		  {
		  temps[6]=12;temps[7]=12;
		   }
		else				   
		   {temps[6]=hour%10;	       //求余计算时个位
		    temps[7]=hour/10;}      	 //求余计算时十位		        
	      P2=codebite[ks];	      //数码管输出选位,从第0位开始//
	      P0=codeduan[temps[ks]]; //输出段,输出要显示的数字//
	      Delay1ms();			//延时1ms,防止数码管串码
		H++;
	      P0=codeduan[12];
		}
       if(P1==0xfe)	   			  /*按下‘左’键,将光标左移 */
	         { K[1]=1;}
       if(K[1]==1&&P1!=0xfe)
		   {K[1]=0;   cursor++;}
		
	 if(P1==0xfd)			   	   /*按下‘右’键,将光标右移 */
		   { K[2]=1;}
       if(K[2]==1&&P1!=0xfd)
		   {K[2]=0;   cursor--;}
	 if(cursor<1) { cursor=3;}		  
	 if(cursor>3) { cursor=1;}
		   		
	 if(P1==0xfb)			 	  /*按下‘上’键,将数字加一 */
               { K[3]=1;}
       if(K[3]==1&&P1!=0xfb)
		   { K[3]=0;   
		     switch(cursor)
		       {
			  case 1:sec++;break;
			  case 2:min++;break;
			  case 3:hour++;break;
			  default:break;
		        }
		   }		    
	 if(P1==0xf7)			 	  /*按下‘下’键,将数字减一 */
               { K[4]=1;}
       if(K[4]==1&&P1!=0xf7)
		   { K[4]=0;   
		     switch(cursor)
		       {
			  case 1:sec--;break;
			  case 2:min--;break;
			  case 3:hour--;break;
			  default:break;
		        }
		   }
	if(sec>59) {sec=0; }			     /*对时,分,秒范围进行限制 */
	if(sec<0)  {sec=59;}
	if(min>59) {min=0; }
	if(min<0)  {min=59;}	   		   		
   	if(hour>23){hour=0; }
	if(hour<0) {hour=23;}	   		
	 }
       return;					    //如果检测到K8按下,则跳出循环,返回主函数
} 
 /*开机动画子程序*/
void motos()
{
 int mot=0;
 char m;
 char motobit[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
 char motoduan[8]={0xcf,0xa4,0xc0,0xa4,0x8e,0xc7,0xbf,0xbf}; /*编码显示“--LF2021” */
 while(mot<1800)
 {
  for(m=0;m<8;m++)
      { 
	 P2=motobit[m];	      //数码管输出选位,从第0位开始//
	 P0=motoduan[m];   //输出段,输出要显示的数字//
       Delay1ms();			//延时1ms,防止数码管串码
	 P0=codeduan[12];
	 mot++;
	 }
  }
  fm=0;Delay50ms();fm=1;Delay50ms();fm=0;Delay50ms();fm=1;
  return;
} 

 
  /*主程序,包含数码管显示以及计时*/
void main()
 {  int num=0,ks=0;
    char k,temp[8],moto=1;
    plays=0;	     /*打开锁存器74HC373使能端 */
    motos();	     /*调用开机动画 */
    temp[2]=11;
    temp[5]=11;
    while(1)
      {
       for(k=0;k<8;k++)
           {	  		     
	      temp[0]=sec%10;         //求余计算秒个位
            temp[1]=sec/10;         //求商计算秒十位
            temp[3]=min%10;         //求余计算分个位
            temp[4]=min/10;         //求商计算分十位
            temp[6]=hour%10;        //求余计算时个位
            temp[7]=hour/10;        //求商计算时十位
	      P2=codebite[k];	      //数码管输出选位,从第0位开始//
	      P0=codeduan[temp[k]];   //输出段,输出要显示的数字//
	      num++;
		Delay1ms();			//延时1ms,防止数码管串码
	      P0=codeduan[12];
		if(P1==0xdf)		//每次循环判断是否按下K1键
		   { 
		    if(num%10==0&&P1==0xdf)		//每10次循环,10ms,判断K1是否仍然按下
		       { 
		            ks++;		//如果每10次循环K1均按下,ks则自加一次
			      if(ks==300)	//如果KS记到300,表明k1已经连续按下4s,则进入时间调整模式,并将Ks清零
			          {
			           ks=0;
				     adjust();
			           } 
		        }		      //如果K1仍然按下,则将KS+1
		    }
            else{ks=0;}			//如果K1不再按下,则清零ks   
		if(num==865)		//经过与电脑时钟对比,找到最合适的值,以下为计时程序
		     {
		      sec++;
                  num=0;	      
                  if (sec==60)
                     {
                      sec=0;
                      min++;
                      if (min==60)
                           {
                            min=0;
                            hour++;
                            if (hour==24)
                               {hour=0;}
                            }
                      }			 	
	           }
	     }
      }   	
}

Program burning:

Since the single-chip microcomputer cannot directly run C language or assembly language programs, the program must be compiled into a hex file before it can be written into the single-chip microcomputer. After writing the program, if it is compiled for the first time, usually the hex file will not be automatically generated. The following settings need to be made: Click the button "Option for Target" in the figure 1, click "Output" in the pop-up window, and then check "Create HEX file". After clicking OK, click the compile button at number 4 to compile the program.

If it compiles without errors, it will display 0 errors and 0 warnings. And it prompts 'creating hex file from "#project name#"', indicating that the HEX file has been created successfully.

The space is limited, and the proteus simulation process is not shown here. You can build the circuit according to the schematic diagram and verify the program by yourself.

Here, the program is directly written into the MCU product.

We need to use the software STC-IPS , which is a program programming software specially used for STC series single-chip microcomputers. It also comes with some auxiliary functions, such as automatic generation of timer functions and the delay functions mentioned above. The figure below is its window interface.

Before burning, we need to use USB-TTL to connect the computer with the MCU. The connection method is shown in the figure below.

We need to select the corresponding MCU model first. After connecting the MCU, if it prompts "Failed to open the serial port", click "Scan", and the computer will automatically find the corresponding serial port.

Then, we click "Open Program File", select the hex file just generated, and then click "Download/Program" to download the program to the microcontroller. If there is no response after clicking download, turn off the power of the single-chip microcomputer and turn it on again, and the program can be written into the single-chip microcomputer.

In this way, the whole work is completed. The following is the finished picture after it is written into the program.

Summarize:

♦Power consumption calculation (temporarily unable to find standard 5V, 3V power supply):

Power bank power supply: voltage 5.15V, current 30~40mA, power consumption 5.15X(30~40)=154.5mW~206mW;

Three Ni-MH batteries: voltage 3.91V, current about 20mA, power consumption 3.91X20=78.2mW.

Generally speaking, the power consumption is still on the high side. After testing, the main power consumption is in the digital tube. The power consumption of the single-chip microcomputer does not exceed 10mW, so turning off the digital tube during standby can effectively reduce power consumption.

♦ Error problem: After the actual measurement of this clock, there are still visible errors.

Adjustable error: running the program takes a lot of machine time, the total time = delay function time + other program execution time. The execution time of other programs is difficult to calculate, and the time of the delay function can only be compressed through comparative debugging.

To reduce the error as much as possible, it is necessary to compare it with the standard clock (the network time of the computer or mobile phone), calculate the error, and then adjust the time of the delay function.

For example: our delay function is set to 1000ms at the beginning, after comparing with the standard time for 1 hour, I found that my clock is 1S slower, indicating that the error of my clock is 1/3600=0.0002778s=0.2778ms=277.8us (for more accuracy Calculate the error, we can improve the comparison time, the longer the time, the better the error calculation). In this way, we can reduce the time of the delay function by 278us, then the delay function should be set to 1000000-278us=999722us. For the convenience of adjustment, we can use two-level delay, the first-level delay function is in ms The unit of the secondary delay function is us, which is very convenient for debugging.

The non-adjustable error is the temperature drift of the crystal oscillator . The oscillation frequency of the crystal oscillator is made according to the environment of 25°C. If the temperature is too high or too low, the oscillation frequency will change slightly, which will affect the CPU execution speed and cause inaccurate travel time.

A more advanced method is to use the wifi module esp8266 to obtain the time from the network, and then send the time to the microcontroller, so that the problem of inaccurate travel time can be completely solved. You can also use LCD1602 or LCD12864 as a display, so that you can display more content and add more patterns (these two displays will be introduced later).

Regarding the usage of esp8266, it is a little more complicated, and I will introduce it later.

This article is for reference only, please point out if there are any deficiencies.

Guess you like

Origin blog.csdn.net/qq_55203246/article/details/114446168