指针式电子钟与万年历设计方案

发布者:JoyfulExplorer最新更新时间:2024-06-26 来源: 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控制的,效率比较高。

主界面如下:

指针式电子钟与万年历设计方案


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png


2. 项目功能介绍

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

2.1 实时时钟页面

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

指针式电子钟与万年历设计方案


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

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

指针式电子钟与万年历设计方案


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

2.2 日历页面

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

指针式电子钟与万年历设计方案


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

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

3.1 流程图

指针式电子钟与万年历设计方案

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--;

        }                           

    }

/*

函数功能:任意角度画直线 

参    数:

                    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;i++)>;i++)>

关键字:万年历  STM32 引用地址:指针式电子钟与万年历设计方案

上一篇:PCB叠层设计与阻抗分析
下一篇:一个低功耗应用的案例分析

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

STM32 之 EXTI
按键的硬件结构有一点一定要注意,要在GPIO段上拉电阻,否则GPIO设置成浮空输入后,会造成端口电平不稳定,中断效果不理想。 另外EXTI的映射关系可以看下图,是和管脚号对应的,比较好记 (1)Main C语言: Codee#14817 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 实验平台 : ST 官方三合一套件 + 硬件 : STM32F103C8T6 + 开发平台 : IAR For ARM 5.40 + 仿真器 : J-Link + 日期 : 2010-11-4 + 频率
[单片机]
<font color='red'>STM32</font> 之 EXTI
STM32到GD32移植攻略
使用STM32的芯片的朋友,可以很方便的将移植到GD32上面,下面就具体移植过程分享一下: 整个移植过程可以分为硬件和软件两个方面。 硬件方面: 首先要确定先前所使用ST芯片的flash大小和管脚数量,然后替换成GD相同大小Flash和管脚数量的芯片。 简单来说就是STM32F103xxxx替换成GD32F103xxxx。 GD和ST的命名规则相同。 软件方面: 以Keil开发环境为例,打开头文件“stm32f10x.h” 找到定义 #define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500) 替换为 #define HSE_STARTUP_TIMEOUT ((uint16_t)0xFFFF) 重新
[单片机]
STM32 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压
问题   今天在使用 STM32F407 的 ADC 时遇到一个问题:ADC 的参考电压都是通过 Vref+ 引脚提供的并作为ADC转换器的基准电压(部分 MCU 没有 Vref+ 引脚)。当我们使用的 Vref+ 是直接取自用 VDD 电压时,当 VDD 电压波动比较大时或稳压性能比较差时,转换结果自然就不准确了! 供电方案   MCU 的参考手册都会有一章节单独介绍 MCU 的电源管理,针对不同的 MCU(封装不同等)其外部电源如何连接也是有要求的,我们在 MCU 上一般都会发现如下引脚: VDD = 2.0 to 3.6 V: external power supply for I/Os and the internal
[单片机]
<font color='red'>STM32</font> 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压
STM32 F1 TIM2 4通道PWM同时出波配置
void TIM2_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
[单片机]
意法半导体发布STM32C0系列MCU 让成本敏感的8位应用也能享受32 位性能
意法半导体发布STM32C0系列MCU 让成本敏感的8位应用也能享受32 位性能 STM32系列高性价比入门级产品,现已量产并发货,享受 10 年产品寿命保障 2023年1月31日,中国 ---- 服务多重电子应用领域、全球排名前列的半导体公司意法半导体(STMicroelectronics,简称ST;)推出迄今为止STM32 微控制器 (MCU)产品家族中性价比最高的STM32C0系列产品,为开发者降低STM32入门门槛 。 全球已有数十亿个智能工业、医疗和消费产品采用 STM32 MCU 。STM32现有产品型号达数千种,让产品设计人员总能选到价格适中、功能和性能皆满意的产品。 在保障供货的同时, 意法
[单片机]
意法半导体发布STM32C0系列MCU  让成本敏感的8位应用也能享受32 位性能
STM32在MDK中使用外部RAM浅解
使用简介: 开发板 神舟王STM32F207开发板 问题描述: 在使用emwin的时候由于占用的变量较多,出现了STM32F207内部RAM不够用的尴尬局面,开发板自带了4M的外部SRAM,因此考虑速度和存储的平衡,使用芯片内部RAM作为堆栈区使用,外部RAM则用来存储其他变量 修改内容: 启动文件即startup_stm32f2xx.s文件 1.添加标志量:DATA_IN_ExtSRAM EQU 1 ;主要是方便控制切换使用内部和外部RAM 2.修改栈区: IF DATA_IN_ExtSRAM == 1 __initial_sp EQU 0x20000000 + Stack_Size
[单片机]
<font color='red'>STM32</font>在MDK中使用外部RAM浅解
STM32 CAN接收/发送错误寄存器如何清零?
CAN总线是一种常用的串行总线,其具有高可靠性、高速率、容错能力强等特点,广泛应用于汽车电子、制造业自动化、工程控制等领域。在CAN总线的标准中,每一个节点都有一个CAN控制器,CAN控制器通过内部寄存器和接口与CAN总线连接。其中,在CAN传输过程中,如果出现错误,会在CAN控制器内部错误寄存器中记录错误信息。因此,在使用STM32进行CAN接收/发送时,及时清零错误寄存器是非常重要的。 一、STM32的CAN错误寄存器 STM32是一款常用的单片机,内置了CAN控制器,其错误寄存器分为两种类型: 1.接收错误寄存器:即CAN接收错误寄存器,用于记录CAN接收过程中出现的错误信息; 2.发送错误寄存器:即CAN发送错误寄存器,用
[单片机]
stm32中断解释
一,中断优先级: STM32(Cortex-M3)中的优先级概念 STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。 具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。 当 两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后 才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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