写点什么

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

作者:DS小龙哥
  • 2022 年 1 月 07 日
  • 本文字数:4714 字

    阅读完需:约 15 分钟

1. 项目简介

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


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


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


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


主界面如下:



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


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

2. 项目功能介绍

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

2.1 实时时钟页面

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



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


2.2 日历页面

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


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

3.1 流程图

3.2 ds18b2.c 代码

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


#include "ds18b20.h"#include "delay.h"  
//复位DS18B20void 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/0u8 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 显示屏上,需要绘制线段、绘制圆、绘制矩形、绘制角度线段、绘制中文、绘制数字等等,下面列出这部分的核心代码。


/*函数功能:画横直线函数形参: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); }}
复制代码


用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
基于STM32设计的指针式电子钟与日历