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

发布者:程序界的行者最新更新时间:2023-09-13 来源: elecfans关键字:STM32  日历 手机看文章 扫描二维码
随时随地手机看文章

1. 项目简介

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


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


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


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


主界面如下:

poYBAGKEY46AVVCpAAWh_62sYac070.png

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

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


2. 项目功能介绍

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

2.1 实时时钟页面

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

pYYBAGKEY4-AHi6nAAPn4yWBL_g362.png

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

poYBAGKEY5CACX9NAAbBa_Vv4m4335.png

2.2 日历页面

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

pYYBAGKEY5CAOpgeAAPEeTHCWks445.png

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

3.1 流程图

poYBAGKEY5CAPRDuAABcDfactPY781.png

3.2 ds18b2.c 代码

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

#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显示屏上,需要绘制线段、绘制圆、绘制矩形、绘制角度线段、绘制中文、绘制数字等等,下面列出这部分的核心代码。

 

/*

函数功能:画横直线

函数形参:x,y:坐标

        length:长度

*/

void LcdDrawThwartLine(u16 x,u16 y,u16 length,u16 color)

{

    u16 i;

    for(i=0;i0)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--;

        }                           

[1] [2]
关键字:STM32  日历 引用地址:基于STM32设计的指针式电子钟与日历

上一篇:设计一个基于STM32和RFID Reader读取RFID卡的系统
下一篇:STM32F4系列芯片几个无法启动的原因

推荐阅读最新更新时间:2024-11-01 11:33

STM32-嵌入式学习笔记02-中断应用概述
STM32中断非常强大,每个外设都能产生中断 中断的优先级数值越小,说明他的中断优先级越高 配置中断需要了解NVIC寄存器: NVIC是嵌套向量中断控制寄存器,控制中断的相关功能;它与内核紧密结合,是内核里的一个外设。管理着包括内核和片上的所有外设的中断相关功能。 因此配置中断需要参考下面两个头文件:core_cm3.h 和 misc.h 在配置中断的时候我们一般只配置ISER和ICER IP这3个寄存器: 1)ISER使能中断 2)ICER清除中断 3)设置中断的优先级 给出官方手册寄存器的资料 编程要领: 1)使能中断请求(外设中某个中断) 2)配置优先级分组 3)配置
[单片机]
STM32-嵌入式学习笔记02-中断应用概述
STM32中的PWM的频率和占空比的设置
网上看到一篇文章,不是很完整,但是有助于我理解,个人觉得还可以,具体的代码,网上有很多,大家可以参考参考计算一下。 下面的这个是stm32的定时器逻辑图,上来有助于理解: TIM3的ARR寄存器和PSC寄存器, 确定PWM频率。 这里配置的这两个定时器确定了PWM的频率,我的理解是:PWM的周期(频率)就是ARR寄存器值与PSC寄存器值相乘得来,但不是简单意义上的相乘,例如要设置PWM的频率参考上次通用定时器中设置溢出时间的算法,例如输出100HZ频率的PWM,首先,确定TIMx的时钟,除非APB1的时钟分频数设置为1,否则通用定时器TIMx的时钟是APB1时钟的2倍,这时的TIMx时钟为72MHz,用这个TIMx时钟72
[单片机]
<font color='red'>STM32</font>中的PWM的频率和占空比的设置
STM32系列单片机命名规则
示例: STM32 F 100 C 6 T 6 B XXX 1 2 3 4 5 6 7 8 9 从上面的料号可以看出以下信息: ST品牌ARM Cortex-Mx系列内核32位超值型MCU,LQFP -48封装 闪存容量32KB 温度范围-40℃-85℃; 1.产品系列: STM32代表ST品牌Cortex-Mx系列内核(ARM)的32位MCU; 2.产品类型: F:通用快闪(Flash Memory); L:低电压(1.65~3.6V);F类型中F0xx和 F1xx系列为2.0~3.6V; F2xx和F4xx系列为1.8~3.6V;W:无线系统芯片,开发版. 3.产品子系列
[单片机]
<font color='red'>STM32</font>系列单片机命名规则
STM32中485采用串口DMA发送,切换收发状态问题
RS485使用DMA发送,切换收发状态,有以下几种实现方式: 开启DMA的“发送完成中断”,在DMA的发送完成中断中,切换收发的状态。但是,这会导致最后的2个字节发送不出去,这是因为:DMA的“发送完成中断”出现在刚发送倒数第二个字节的起始位置,这个时候切换485的收发,若接收端不是奇校验的话 将会误收到0xFF 最后第一肯定也出不去。 网上提供的解决办法是:①在DMA的TC中断里面 加大于两个字节的延时 这是OK的。 ②在DMA的TC中断里面 开启USART的“发送完成中断” 去USART的中断里面去处理 这是OK的。 看数据手册,可以利用串口的“发送完成中断TC”实现。开启USART的DMA,开启DMA传输通道,开启USA
[单片机]
<font color='red'>STM32</font>中485采用串口DMA发送,切换收发状态问题
stm32ADC的DMA模式
//变量定义 __IO uint16_t ADCConvertedValue ; //ADC 外设的数据寄存器 #define ADC1_DR_Address ((uint32_t)0x4001244C) //ADC_DR(ADC规则数据寄存器),偏移量=0x4c ADC1(0x40012400-0x400127ff) //ADC1_GPIO配置 void ADC1_GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Configure PC.01 (ADC Channel11) as analog inpu
[单片机]
STM32单片机的调试接口硬件电路
如果要减小插座的数量,就用SWD模式的仿真,在这个模式下,如果用JLINK只要四根线就可以了,这四根线分别是:3.3V、GND、SWDIO、SWCLK 其中 STM32的JTMS/SWDIO接JTAG口的TMS; STM32的JTCK/SWCLK接JTAG口的TCK。 SWD PIN 1------3.3V PIN 4------GND PIN 7-------PA13(SWDIO) PIN 9-------PA14(SWCLK) 如果要用ULINK2,则再加多一条 NRST ,即5条。 这个接口你可自行定义,在使用时用 杜邦线跳接或做块转换接口板联接仿真器与目标板即可。
[单片机]
<font color='red'>STM32</font>单片机的调试接口硬件电路
应用笔记 | 浅谈STM32库里的回调函数
01 回调函数 有人对STM32固件库里的回调函数有些好奇甚至纠结,这里简单地介绍下,以供参考。其实从用法及功能上讲他们并没有什么特别的,跟其他函数一样,也是实现特定功能的代码段。一般来讲,所谓回调函数,泛指基于事件触发而被调用执行的函数,简单点说,就是条件满足了就调用的函数,往往会跟函数指针结合起来通过函数指针实现调用。 经常会有人基于类似下面的代码介绍回调函数: 在上面代码中,那四个有关加减乘除的函数可以看成回调函数,具体何时被调用,根据函数Compu te (float a,float b,float(* Ac ti on)(float a,float b))里的函数指针的赋值情况来定,被赋予哪个回调函数
[单片机]
应用笔记 | 浅谈<font color='red'>STM32</font>库里的回调函数
STM32中GPIO是如何工作的?想知道吗?
  推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。   一、推挽输出:可以输出高、低电平,连接数字器件;推挽结构一般是指两个三极管分别受两个互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源决定。   推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负
[单片机]
<font color='red'>STM32</font>中GPIO是如何工作的?想知道吗?
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved