前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于STM32设计的指针式电子钟与日历

基于STM32设计的指针式电子钟与日历

原创
作者头像
DS小龙哥
发布2022-01-06 14:15:17
1.4K0
发布2022-01-06 14:15:17
举报

1. 项目简介

这是基于STM32设计的一个指针式电子钟+万年历小项目,采用3.5寸的LCD屏显示时钟,日历、温度、天气,支持触摸屏调整设置时间,设置闹钟,查看日历等等。整体项目主要是技术点就是LCD屏的图形绘制。比如: 时钟的时针绘制、分针、秒针、表盘、日历绘制等等。

时钟的时间是直接采用STM32本身的RTC时钟,室内的室温数据采用DS18B20温度传感器获取,STM32芯片的具体型号是STM32F103ZET6,只要是STM32F1系列的开发板,代码都是可以通用的。

LCD显示屏采用的正点原子的3.5寸TFT显示屏,支持8080时序,自带触摸屏功能,触摸屏是电阻屏,驱动芯片是XPT2046,SPI接口,通信非常方便。

STM32F103ZET6带有FSMC功能,可以输出8080时序,本项目里驱动LCD屏就采用FSMC控制的,效率比较高。

主界面如下:

image-20211231110615969
image-20211231110615969

项目源码下载地址: https://download.csdn.net/download/xiaolong1126626497/63897554

项目视频演示地址: https://live.csdn.net/v/182594

2. 项目功能介绍

下面对每个子功能页面做详细讲解。

2.1 实时时钟页面

在LCD屏上方显示表盘、分针、时针、 秒针、刻度、更改时钟时间方块,并实现分针、时针、秒针的移动,在实时时钟下方同步显示数字时钟。

image-20211231112132730
image-20211231112132730

运用触摸屏功能实现时钟设置功能,点击“+” “-”至设置时钟方块,跳出设置时钟界面,即可开始设置时钟与日期;点击“+”“-”至设置闹钟方块,跳出设置闹钟界面,即可开始设置闹钟。

image-20211231112305798
image-20211231112305798

2.2 日历页面

在LCD屏中部显示日期、星期、天气、实时温度,在LCD屏下方显示日历、左右两边显示黄历,并在日历上重点突出今天的日期。

image-20211231112355785
image-20211231112355785

3. 项目实现主要程序讲解

3.1 流程图

image-20211231112512719
image-20211231112512719

3.2 ds18b2.c 代码

下面列出DS18B20温度传感器主要代码.

代码语言:txt
复制
#include "ds18b20.h"
#include "delay.h"	

//复位DS18B20
void DS18B20_Rst(void)	   
{                 
	DS18B20_IO_OUT(); 	//SET PG11 OUTPUT
    DS18B20_DQ_OUT=0; 	//拉低DQ
    DelayUs(750);    	//拉低750us
    DS18B20_DQ_OUT=1; 	//DQ=1 
	DelayUs(15);     	//15US
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
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;
}
//从DS18B20读取一个位
//返回值: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;
}
//从DS18B20读取一个字节
//返回值:读到的数据
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;
}
//写一个字节到DS18B20
//dat:要写入的字节
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);                          
        }
    }
}
//开始温度转换
void DS18B20_Start(void) 
{   						               
    DS18B20_Rst();	   
	DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0x44);	// convert
} 
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在    	 
u8 DS18B20_Init(void)
{
	RCC->APB2ENR|=1<<8;   	 	//使能PORTG口时钟 
	GPIOG->CRH&=0XFFFF0FFF;		//PORTG.11 推挽输出
	GPIOG->CRH|=0X00003000;
	GPIOG->ODR|=1<<11;      	//输出1
	DS18B20_Rst();
	return DS18B20_Check();
}  
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-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;					//温度为负  
    }else temp=1;				//温度为正	  	  
    tem=TH; 					//获得高八位
    tem<<=8;    
    tem+=TL;					//获得底八位
    tem=(float)tem*0.625;		//转换     
	if(temp)return tem; 		//返回温度值
	else return -tem;    
}

3.3 lcd屏图形绘制核心算法

整个项目的功能都是在LCD显示屏上,需要绘制线段、绘制圆、绘制矩形、绘制角度线段、绘制中文、绘制数字等等,下面列出这部分的核心代码。

代码语言:txt
复制
/*
函数功能:画横直线
函数形参:x,y:坐标
        length:长度
*/
void LcdDrawThwartLine(u16 x,u16 y,u16 length,u16 color)
{
	u16 i;
	for(i=0;i<length;i++)
	{
		LcdDrawPoint(x+i,y,color);
	}
}
/*
函数功能:画竖直线
函数形参:x,y:坐标
         length:长度
*/
void LcdDrawVerticalLine(u16 x,u16 y,u16 length,u16 color)
{
	u16 i;
	for(i=0;i<length;i++)
	{
		LcdDrawPoint3(x,y+i,color);
	}
}

/*
函数功能:画矩形
函数形参:x,y:坐标
         length:长
				 width:宽
*/
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);
}

//两点画线
//x1,y1:起点坐标
//x2,y2:终点坐标  
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; //计算坐标增量 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; //设置单步方向 
	else if(delta_x==0)incx=0;//垂直线 
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;//水平线 
	else{incy=-1;delta_y=-delta_y;} 
	if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )//画线输出 
	{  
		LcdDrawPoint(uRow,uCol,color);//画点 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}  
} 


//在指定位置画一个指定大小的圆
//(x,y):中心点
//r    :半径
void LcdDraw_Circle(u16 x0,u16 y0,u8 r,u16 color)
{
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //判断下个点位置的标志
	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++;
		//使用Bresenham算法画圆     
		if(di<0)di +=4*a+6;	  
		else
		{
			di+=10+4*(a-b);   
			b--;
		} 						    
	}
} 

/*
函数功能:任意角度画直线 
参    数:
					w  :以圆心开始不要画的长度
					len:半径
					c  :颜色
					x,y:坐标
实际长度=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);
	}	
}


/*
函数功能:矩形颜色填充
参    数:(sx,sy),(ex,ey):矩形对角坐标
					color:要填充的颜色
*/
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);      				//设置光标位置 
		LcdWriteReg(0X2C);		  //开始写入GRAM
		for(j=0;j<xlen;j++)LcdWriteData(color);	    
	}	 
} 


/*
功能:任意角度画线
x0,y0:起始点坐标
a:角度
c:颜色
n:长度
*/
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是长度
	{
			x=i*cos(p)+x0;
			y=i*sin(p)+y0;
		if(mode==1)LcdDrawPoint(x,y,c);	//画点
		else if(mode==2) LcdDrawPoint2(x,y,c);	//画点
		else LcdDrawPoint3(x,y,c);	//画点
	}
}
/*
函数功能:画点(加粗)
函数形参:x,y:坐标
*/
void LcdDrawPoint2(u16 x,u16 y,u16 color)
{
	LcdSetCursor(x,y);		  //设置光标位置 
	LcdWriteReg(0X2C);		  //开始写入GRAM
	LcdWriteData(color);    //写数据
	LcdWriteData(color);    //写数据
	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
}
/*
函数功能:画点(变细)
函数形参:x,y:坐标
*/
void LcdDrawPoint3(u16 x,u16 y,u16 color)
{
	LcdSetCursor(x,y);		  //设置光标位置 
	LcdWriteReg(0X2C);		  //开始写入GRAM
	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
//	LcdWriteData(color);    //写数据
}

/*
函数功能:任意角度画线,标准加粗
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);
	}
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 项目简介
  • 2. 项目功能介绍
    • 2.1 实时时钟页面
      • 2.2 日历页面
      • 3. 项目实现主要程序讲解
        • 3.1 流程图
          • 3.2 ds18b2.c 代码
            • 3.3 lcd屏图形绘制核心算法
            相关产品与服务
            物联网开发平台
            腾讯云物联网开发平台(IoT Explorer)是面向智慧生活与产业物联应用的一站式物联网PaaS平台,为各行业用户提供一站式设备智能化服务。平台提供海量设备连接与消息通信能力,基于腾讯连连小程序应用开发能力、音视频能力及AI增值服务,聚合腾讯生态内容能力。提升传统行业设备智能化的效率,降低用户的开发运维成本。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档