Pointer electronic clock and perpetual calendar designed based on STM32

1. Project introduction

This is a small project of pointer electronic clock + perpetual calendar designed based on STM32. It uses a 3.5-inch LCD screen to display the clock, calendar, temperature and weather. It supports the touch screen to adjust the setting time, set the alarm clock, view the calendar, etc. The main technical point of the overall project is the graphic drawing of LCD screen. For example: clock drawing, minute hand, second hand, dial, calendar drawing, etc.

The time of the clock directly adopts the RTC clock of STM32 itself, and the indoor room temperature data is obtained by DS18B20 temperature sensor. The specific model of STM32 chip is STM32F103ZET6. As long as it is the development board of STM32F1 series, the code can be universal.

The LCD display adopts the 3.5-inch TFT display of punctual atom, supports 8080 timing, and has its own touch screen function. The touch screen is a resistance screen, the driver chip is XPT2046, SPI interface, and communication is very convenient.

STM32F103ZET6 has FSMC function and can output 8080 timing. In this project, FSMC control is used to drive LCD screen, with high efficiency.

The main interface is as follows:

Project source code download address: https://download.csdn.net/download/xiaolong1126626497/63897554

Project video presentation address:

Pointer electronic clock and calendar based on STM32

2. Project function introduction

Each sub function page is explained in detail below.

2.1 real time clock page

Display the dial, minute hand, hour hand, second hand, scale and change the clock time box above the LCD screen, realize the movement of minute hand, hour hand and second hand, and synchronously display the digital clock below the real-time clock.

Use the touch screen function to realize the clock setting function, click "+" "-" to the clock setting box, and the clock setting interface will pop up to start setting the clock and date; Click "+" "-" to set the alarm clock box, and the alarm clock setting interface will pop up to start setting the alarm clock.

2.2 calendar page

The date, week, weather and real-time temperature are displayed in the middle of the LCD screen, the calendar is displayed below the LCD screen, the Yellow calendar is displayed on the left and right sides, and today's date is highlighted on the calendar.

3. Explanation of main procedures for project realization

3.1 flow chart

3.2 ds18b2.c code

The main codes of DS18B20 temperature sensor are listed below

#include "ds18b20.h"
#include "delay.h"  
​
//Reset DS18B20
void DS18B20_Rst(void)     
{                 
    DS18B20_IO_OUT();   //SET PG11 OUTPUT
    DS18B20_DQ_OUT=0;   //Pull down DQ
    DelayUs(750);       //Pull down 750us
    DS18B20_DQ_OUT=1;   //DQ=1 
    DelayUs(15);        //15US
}
//Waiting for a response from DS18B20
//Return 1: the existence of DS18B20 is not detected
//Return 0: exists
u8 DS18B20_Check(void)     
{   
    u8 retry=0;
    DS18B20_IO_IN();    //SET PG11 INPUT     
    while (DS18B20_DQ_IN&&retry<200)
    {
        retry++;
        DelayUs(1);
    };   
    if(retry>=200)return 1;
    else retry=0;
    while (!DS18B20_DQ_IN&&retry<240)
    {
        retry++;
        DelayUs(1);
    };
    if(retry>=240)return 1;     
    return 0;
}
//Read a bit from DS18B20
//Return value: 1 / 0
u8 DS18B20_Read_Bit(void)    
{
    u8 data;
    DS18B20_IO_OUT();   //SET PG11 OUTPUT
    DS18B20_DQ_OUT=0; 
    DelayUs(2);
    DS18B20_DQ_OUT=1; 
    DS18B20_IO_IN();    //SET PG11 INPUT
    DelayUs(12);
    if(DS18B20_DQ_IN)data=1;
    else data=0;     
    DelayUs(50);           
    return data;
}
//Read a byte from DS18B20
//Return value: read data
u8 DS18B20_Read_Byte(void)     
{        
    u8 i,j,dat;
    dat=0;
    for (i=1;i<=8;i++) 
    {
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }                           
    return dat;
}
//Write a byte to DS18B20
//dat: bytes to write
void DS18B20_Write_Byte(u8 dat)     
 {             
    u8 j;
    u8 testb;
    DS18B20_IO_OUT();   //SET PG11 OUTPUT;
    for (j=1;j<=8;j++) 
    {
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) 
        {
            DS18B20_DQ_OUT=0;   // Write 1
            DelayUs(2);                            
            DS18B20_DQ_OUT=1;
            DelayUs(60);             
        }
        else 
        {
            DS18B20_DQ_OUT=0;   // Write 0
            DelayUs(60);             
            DS18B20_DQ_OUT=1;
            DelayUs(2);                          
        }
    }
}
//Start temperature conversion
void DS18B20_Start(void) 
{                                          
    DS18B20_Rst();     
    DS18B20_Check();     
    DS18B20_Write_Byte(0xcc);   // skip rom
    DS18B20_Write_Byte(0x44);   // convert
} 
//Initialize the IO port DQ of DS18B20 and detect the existence of DS at the same time
//Return 1: does not exist
//Return 0: exists         
u8 DS18B20_Init(void)
{
    RCC->APB2ENR|=1<<8;         //Enable PORTG port clock 
    GPIOG->CRH&=0XFFFF0FFF;     //PORTG.11 push pull output
    GPIOG->CRH|=0X00003000;
    GPIOG->ODR|=1<<11;          //Output 1
    DS18B20_Rst();
    return DS18B20_Check();
}  
//Get the temperature value from ds18b20
//Accuracy: 0.1C
//Return value: temperature value (- 550 ~ 1250) 
short DS18B20_Get_Temp(void)
{
    u8 temp;
    u8 TL,TH;
    short tem;
    DS18B20_Start ();           // ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();     
    DS18B20_Write_Byte(0xcc);   // skip rom
    DS18B20_Write_Byte(0xbe);   // convert      
    TL=DS18B20_Read_Byte();     // LSB   
    TH=DS18B20_Read_Byte();     // MSB  
              
    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
        temp=0;                 //The temperature is negative  
    }else temp=1;               //The temperature is positive        
    tem=TH;                     //Get the top eight
    tem<<=8;    
    tem+=TL;                    //Get the bottom eight
    tem=(float)tem*0.625;       //transformation     
    if(temp)return tem;         //Return temperature value
    else return -tem;    
}
3.3 lcd Screen graphics rendering core algorithm
 The functions of the whole project are LCD On the display screen, you need to draw line segments, circles, rectangles, angle line segments, Chinese, numbers, etc. the core codes of this part are listed below.

/*
Function function: draw horizontal line
 Function parameters: x,y: coordinates
        length:length
*/
void LcdDrawThwartLine(u16 x,u16 y,u16 length,u16 color)
{
    u16 i;
    for(i=0;i<length;i++)
    {
        LcdDrawPoint(x+i,y,color);
    }
}
/*
Function: draw a vertical line
 Function parameters: x,y: coordinates
         length:length
*/
void LcdDrawVerticalLine(u16 x,u16 y,u16 length,u16 color)
{
    u16 i;
    for(i=0;i<length;i++)
    {
        LcdDrawPoint3(x,y+i,color);
    }
}
​
/*
Function function: draw rectangle
 Function parameters: x,y: coordinates
         length:long
                 width:wide
*/
void LcdDrawRectangle(u16 x,u16 y,u16 length,u16 width,u16 color)
{
    LcdDrawThwartLine(x,y,length,color);
    LcdDrawVerticalLine(x,y,width,color);
    LcdDrawThwartLine(x,y+width,length,color);
    LcdDrawVerticalLine(x+length,y,width,color);
}
​
//Draw a line at two points
//x1,y1: starting point coordinates
//x2,y2: end coordinates  
void LcdDrawLine(u16 x1, u16 y1, u16 x2, u16 y2,u16 color)
{
    u16 t; 
    int xerr=0,yerr=0,delta_x,delta_y,distance; 
    int incx,incy,uRow,uCol; 
    delta_x=x2-x1; //Calculate coordinate increment 
    delta_y=y2-y1; 
    uRow=x1; 
    uCol=y1; 
    if(delta_x>0)incx=1; //Set single step direction 
    else if(delta_x==0)incx=0;//Vertical line 
    else {incx=-1;delta_x=-delta_x;} 
    if(delta_y>0)incy=1; 
    else if(delta_y==0)incy=0;//level 
    else{incy=-1;delta_y=-delta_y;} 
    if( delta_x>delta_y)distance=delta_x; //Select basic incremental axis 
    else distance=delta_y; 
    for(t=0;t<=distance+1;t++ )//Draw line output 
    {  
        LcdDrawPoint(uRow,uCol,color);//Draw point 
        xerr+=delta_x ; 
        yerr+=delta_y ; 
        if(xerr>distance) 
        { 
            xerr-=distance; 
            uRow+=incx; 
        } 
        if(yerr>distance) 
        { 
            yerr-=distance; 
            uCol+=incy; 
        } 
    }  
} 
​
​
//Draw a circle of the specified size at the specified position
//(x,y): center point
//r: radius
void LcdDraw_Circle(u16 x0,u16 y0,u8 r,u16 color)
{
    int a,b;
    int di;
    a=0;b=r;      
    di=3-(r<<1);             //Mark for judging the position of the next point
    while(a<=b)
    {
        LcdDrawPoint(x0+a,y0-b,color);             //5
        LcdDrawPoint(x0+b,y0-a,color);             //0           
        LcdDrawPoint(x0+b,y0+a,color);             //4               
        LcdDrawPoint(x0+a,y0+b,color);             //6 
        LcdDrawPoint(x0-a,y0+b,color);             //1       
        LcdDrawPoint(x0-b,y0+a,color);             
        LcdDrawPoint(x0-a,y0-b,color);             //2             
        LcdDrawPoint(x0-b,y0-a,color);             //7               
        a++;
        //Draw a circle using Bresenham algorithm     
        if(di<0)di +=4*a+6;   
        else
        {
            di+=10+4*(a-b);   
            b--;
        }                           
    }
} 
​
/*
Function: draw a straight line from any angle 
Parameters:
                    w  : Start with the center of the circle and don't draw the length
                    len:radius
                    c  :colour
                    x,y:coordinate
 Actual length = len-w
*/
​
void LcdDrawAngleLine(u32 x,u32 y,float du,u32 len,u32 w,u16 c)
{
  int i;
    int x0,y0;
    float k=du*(3.1415926535/180);  
    for(i=len-w;i<len;i++)
    {
      x0=cos(k)*i;
        y0=sin(k)*i;
        LcdDrawPoint(x+x0,y+y0,c);
    }   
}
​
​
/*
Function function: rectangle color filling
 Parameters: (sx,sy),(ex,ey): rectangular diagonal coordinates
                    color:Color to fill
*/
void LcdFill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{          
    u16 i,j;
    u16 xlen=0;
    xlen=ex-sx+1;    
    for(i=sy;i<=ey;i++)
    {
        LcdSetCursor(sx,i);                     //Set cursor position 
        LcdWriteReg(0X2C);        //Start writing GRAM
        for(j=0;j<xlen;j++)LcdWriteData(color);     
    }    
} 
​
​
/*
Function: draw lines at any angle
x0,y0:Starting point coordinates
a: angle
c: colour
n: length
*/
void LcdDrawAngleLine2(u32 x0,u32 y0,double a,u16 n,u16 c,u16 mode)
{
    u32 x,y;
    u32 i;
    double p=a*3.1415926535/180;
    for(i=0;i<=n;i++)  //n is the length
    {
            x=i*cos(p)+x0;
            y=i*sin(p)+y0;
        if(mode==1)LcdDrawPoint(x,y,c); //Draw point
        else if(mode==2) LcdDrawPoint2(x,y,c);  //Draw point
        else LcdDrawPoint3(x,y,c);  //Draw point
    }
}
/*
Function function: draw points (BOLD)
Function parameters: x,y: coordinates
*/
void LcdDrawPoint2(u16 x,u16 y,u16 color)
{
    LcdSetCursor(x,y);        //Set cursor position 
    LcdWriteReg(0X2C);        //Start writing GRAM
    LcdWriteData(color);    //Write data
    LcdWriteData(color);    //Write data
    LcdWriteData(color);    //Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
}
/*
Function function: draw points (thinning)
Function parameters: x,y: coordinates
*/
void LcdDrawPoint3(u16 x,u16 y,u16 color)
{
    LcdSetCursor(x,y);        //Set cursor position 
    LcdWriteReg(0X2C);        //Start writing GRAM
    LcdWriteData(color);    //Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
//  LcdWriteData(color);    // Write data
}
​
/*
Function function: draw lines from any angle, standard bold
void LcdDrawAngleLine2(u32 x0,u32 y0,double a,u32 n,u32 c,u32 mode)
*/
​
void Lcdline_add(u32 x,u32 y,double a,u16 n,u16 c, u8 add )
{
    u8 i;
    for(i=1;i<add;i++)
    {
        x-=i;
        y-=i;
        LcdDrawAngleLine2(x,y,a,n,c,1);
    }
    for(i=1;i<add;i++)
    {
        x+=i;
        y+=i;
        LcdDrawAngleLine2(x,y,a,n,c,1);
    }
}

Added by moise on Mon, 10 Jan 2022 11:50:56 +0200