基于STM32的RTC简易日期时间显示

 功能介绍:

       1、由STM32F103和OLED显示器构成一个完整的日期、时间、温度显示系统。日期时间使用STM32F103内部日历系统数据。

       2、具有4个控制按键,分别为“SET”,“+”,“-”,“→”四个键,功能描述如下:“SET” 按下时钟进入修改时间设置模式,指示要修改的日期和时间显示字段,对应的该字年、月、日、时、分、秒会有LED灯亮。

        3、在设置模式下按动“→”键,可依次循环改变年月日时分秒,标识当前可修改的日期时间字段,此时按“+”、“-”键分别增加、或减少对应的数字,每个字段数字变化有效范围依据所修改的字段有效范围改变。按第七下退出设置模式。

需要的硬件:

        1、STM32F103C8T6核心板

        2、4针OLED显示屏

        3、面包板、跳线、7个LED灯、4个按键、杜邦线

        4、STLINKV2

所需的软件:

        1、STM32CUBEMX

        2、STM32CUBEIDE

        3、STM32CubeProgrammer

软件相关配置:

        1、使用的硬件资源如下:

        2、选择SWD调试模式,不选单片机只能下载一次程序,下一次就下载不了了

        3、使能时钟,并配置时钟为72MHZ

        4、使能RTC实时时钟,并按如下设置

        5、使能定时器TIM3,并按如下设置

        6、使能IIC,这个是给OLED屏使用的

        7、使能ADC1内部温度测量通道,并按如下设置

        8、所有GPIO口的设置如下

        9、勾选如下设置

        10、生成工程

实物照片:

演示视频

video_20231106_221210

用户代码:

        1、oled.c

#include "oled.h"

/**********************************************************
 * 初始化命令,根据芯片手册书写
 ***********************************************************/
uint8_t CMD_Data[]={
0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,

0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,

0xD8, 0x30, 0x8D, 0x14, 0xAF};


void WriteCmd(void)
{
	uint8_t i = 0;
	for(i=0; i<27; i++)
	{
		HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&CMD_Data[i],1,0x100);
	}
}
/**
 * @function: void OLED_Init(void)
 * @description: OLED初始化
 * @return {*}
 */
void OLED_Init(void)
{
	HAL_Delay(200);

	WriteCmd();
}


/**
 * @function: void OLED_WR_CMD(uint8_t cmd)
 * @description: 向设备写控制命令
 * @param {uint8_t} cmd 芯片手册规定的命令
 * @return {*}
 */
void OLED_WR_CMD(uint8_t cmd)
{
	HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
}

/**
 * @function: void OLED_WR_DATA(uint8_t data)
 * @description: 向设备写控制数据
 * @param {uint8_t} data 数据
 * @return {*}
 */
void OLED_WR_DATA(uint8_t data)
{
	HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);
}

/**
 * @function: void OLED_On(void)
 * @description: 更新显示

 * @return {*}
 */
void OLED_On(void)
{
	uint8_t i,n;
	for(i=0;i<8;i++)
	{
		OLED_WR_CMD(0xb0+i);    //设置页地址(0~7)
		OLED_WR_CMD(0x00);      //设置显示位置—列低地址
		OLED_WR_CMD(0x10);      //设置显示位置—列高地址
		for(n=0;n<128;n++)
			OLED_WR_DATA(1);
	}
}


/**
 * @function: OLED_Clear(void)
 * @description: 清屏,整个屏幕是黑色的!和没点亮一样!!!
 * @return {*}
 */
void OLED_Clear(void)
{
	uint8_t i,n;
	for(i=0;i<8;i++)
	{
		OLED_WR_CMD(0xb0+i);    //设置页地址(0~7)
		OLED_WR_CMD(0x00);      //设置显示位置—列低地址
		OLED_WR_CMD(0x10);      //设置显示位置—列高地址
		for(n=0;n<128;n++)
			OLED_WR_DATA(0);
	}
}

/**
 * @function: void OLED_Display_On(void)
 * @description: 开启OLED显示
 * @return {*}
 */
void OLED_Display_On(void)
{
	OLED_WR_CMD(0X8D);  //SET DCDC命令
	OLED_WR_CMD(0X14);  //DCDC ON
	OLED_WR_CMD(0XAF);  //DISPLAY ON,打开显示
}


/**
 * @function: void OLED_Display_Off(void)
 * @description: 关闭OLED显示
 * @return {*}
 */
void OLED_Display_Off(void)
{
	OLED_WR_CMD(0X8D);  //SET DCDC命令
	OLED_WR_CMD(0X10);  //DCDC OFF
	OLED_WR_CMD(0XAE);  //DISPLAY OFF,关闭显示
}

/**
 * @function: void OLED_Set_Pos(uint8_t x, uint8_t y)
 * @description: 坐标设置
 * @param {uint8_t} x,y
 * @return {*}
 */
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
	OLED_WR_CMD(0xb0+y);	//设置页地址(0~7)
	OLED_WR_CMD(((x&0xf0)>>4)|0x10); //设置显示位置—列低地址
	OLED_WR_CMD(x&0x0f);	//设置显示位置—列高地址
}


/**
 * @function: unsigned int oled_pow(uint8_t m,uint8_t n)
 * @description: m^n函数
 * @param {uint8_t} m,n
 * @return {unsigned int} result
 */
unsigned int oled_pow(uint8_t m,uint8_t n)
{
	unsigned int result=1;
	while(n--)result*=m;
	return result;
}

/**
 * @function: void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size,uint8_t Color_Turn)
 * @description: 在OLED12864特定位置开始显示一个字符
 * @param {uint8_t} x字符开始显示的横坐标
 * @param {uint8_t} y字符开始显示的纵坐标
 * @param {uint8_t} chr待显示的字符
 * @param {uint8_t} Char_Size待显示字符的字体大小,选择字体 16/12
 * @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
 * @return {*}
 */
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size,uint8_t Color_Turn)
{
	unsigned char c=0,i=0;
		c=chr-' ';//得到偏移后的值
		if(x>128-1){x=0;y=y+2;}
		if(Char_Size ==16)
		{
			OLED_Set_Pos(x,y);
			for(i=0;i<8;i++)
				{
				  if(Color_Turn)
					  OLED_WR_DATA(~F8X16[c*16+i]);
				  else
					  OLED_WR_DATA(F8X16[c*16+i]);
				}
			OLED_Set_Pos(x,y+1);
			for(i=0;i<8;i++)
			    {
				  if(Color_Turn)
					  OLED_WR_DATA(~F8X16[c*16+i+8]);
				  else
					  OLED_WR_DATA(F8X16[c*16+i+8]);
			    }

			}
	     else
	     {
				OLED_Set_Pos(x,y);
				for(i=0;i<6;i++)
			    {
				  if(Color_Turn)
					  OLED_WR_DATA(~F6x8[c][i]);
				  else
					  OLED_WR_DATA(F6x8[c][i]);
			    }
		  }
}

/**
 * @function: void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_tChar_Size, uint8_t Color_Turn)
 * @description: 在OLED12864特定位置开始显示字符串
 * @param {uint8_t} x待显示字符串的开始横坐标x:0~127
 * @param {uint8_t} y待显示字符串的开始纵坐标 y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
 * @param {uint8_t} *chr待显示的字符串
 * @param {uint8_t} Char_Size待显示字符串的字体大小,选择字体 16/12,16为8X16,12为6x8
 * @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
 * @return {*}
 */
void OLED_ShowString(uint8_t x,uint8_t y,char*chr,uint8_t Char_Size, uint8_t Color_Turn)
{
	uint8_t  j=0;
	while (chr[j]!='\0')
	{		OLED_ShowChar(x,y,chr[j],Char_Size, Color_Turn);
			if (Char_Size == 12) //6X8的字体列加6,显示下一个字符
				x += 6;
			else  //8X16的字体列加8,显示下一个字符
				x += 8;

			if (x > 122 && Char_Size==12) //TextSize6x8如果一行不够显示了,从下一行继续显示
			{
				x = 0;
				y++;
			}
			if (x > 120 && Char_Size== 16) //TextSize8x16如果一行不够显示了,从下一行继续显示
			{
				x = 0;
				y++;
			}
			j++;
	}
}

/**
 * @function: void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2, Color_Turn)
 * @description: 显示数字
 * @param {uint8_t} x待显示的数字起始横坐标,x:0~126
 * @param {uint8_t} y待显示的数字起始纵坐标, y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
 * @param {unsigned int} num:输入的数据
 * @param {uint8_t } len:输入的数据位数
 * @param {uint8_t} size2:输入的数据大小,选择 16/12,16为8X16,12为6x8
 * @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
 * @return {*}
 */
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2, uint8_t Color_Turn)
{
	uint8_t t,temp;
	uint8_t enshow=0;
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2, Color_Turn);
				continue;
			}else enshow=1;

		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2, Color_Turn);
	}
}


/**
 * @function: void OLED_Showdecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn)
 * @description: 显示正负浮点数
 * @param {uint8_t} x待显示的数字起始横坐标,x:0~126
 * @param {uint8_t} y待显示的数字起始纵坐标, y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
 * @param {float} num:输入的浮点型数据
 * @param {uint8_t } z_ len:整数部分的位数
 * @param {uint8_t } f_len: 小数部分的位数
 * @param {uint8_t} size2:输入的数据大小,选择 16/12,16为8X16,12为6x8
 * @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
 * @return {*}
 */
void OLED_Showdecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn)
{
	uint8_t t,temp,i=0;//i为负数标志位
	uint8_t enshow;
	int z_temp,f_temp;
	if(num<0)
	{
		z_len+=1;
		i=1;
		num=-num;
	}
	z_temp=(int)num;
	//整数部分
	for(t=0;t<z_len;t++)
	{
		temp=(z_temp/oled_pow(10,z_len-t-1))%10;
		if(enshow==0 && t<(z_len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2, Color_Turn);
				continue;
			}
			else
			enshow=1;
		}
		OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2, Color_Turn);
	}
	//小数点
	OLED_ShowChar(x+(size2/2)*(z_len),y,'.',size2, Color_Turn);

	f_temp=(int)((num-z_temp)*(oled_pow(10,f_len)));
  //小数部分
	for(t=0;t<f_len;t++)
	{
		temp=(f_temp/oled_pow(10,f_len-t-1))%10;
		OLED_ShowChar(x+(size2/2)*(t+z_len)+5,y,temp+'0',size2, Color_Turn);
	}
	if(i==1)//如果为负,就将最前的一位赋值‘-’
	{
		OLED_ShowChar(x,y,'-',size2, Color_Turn);
		i=0;
	}
}



/**
 * @function: void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no, uint8_t Color_Turn)
 * @description: 在OLED特定位置开始显示16X16汉字
 * @param {uint8_t} x待显示的汉字起始横坐标x: 0~112,两列汉字之间需要间隔16
 * @param {uint8_t} y待显示的汉字起始纵坐标 y: 0~6 , 两行汉字之间需要间隔2
 * @param {uint8_t} no待显示的汉字编号
 * @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
 * @return {*}
 */
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no, uint8_t Color_Turn)
{
	uint8_t t=0;
	OLED_Set_Pos(x,y);
    for(t=0;t<16;t++)
		{
				if (Color_Turn)
					OLED_WR_DATA(~Hzk[2*no][t]); //显示汉字的上半部分
				else
					OLED_WR_DATA(Hzk[2*no][t]); //显示汉字的上半部分
        }

		OLED_Set_Pos(x,y+1);
    for(t=0;t<16;t++)
		{
				if (Color_Turn)
					OLED_WR_DATA(~Hzk[2*no+1][t]); //显示汉字的上半部分
				else
					OLED_WR_DATA(Hzk[2*no+1][t]);//显示汉字的上半部分

         }
}

/**
 * @function: void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *  BMP,uint8_t Color_Turn)
 * @description: 在OLED特定区域显示BMP图片
 * @param {uint8_t} x0图像开始显示横坐标  x0:0~127
 * @param {uint8_t} y0图像开始显示纵坐标  y0:0~7
 * @param {uint8_t} x1图像结束显示横坐标  x1:1~128
 * @param {uint8_t} y1图像结束显示纵坐标  y1:1~8
 * @param {uint8_t} *BMP待显示的图像数据
 * @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
 * @return {*}
 */
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *  BMP,uint8_t Color_Turn)
{
   uint32_t j = 0;
   uint8_t x = 0, y = 0;

  if(y1%8==0)
		y = y1/8;
  else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
		{
			if (Color_Turn)
				OLED_WR_DATA(~BMP[j++]);//显示反相图片
			else
				OLED_WR_DATA(BMP[j++]);//显示图片

		}
	}
}


/**
 * @function: void OLED_HorizontalShift(uint8_t direction)
 * @description: 屏幕内容水平全屏滚动播放
 * @param {uint8_t} direction			LEFT	   0x27     	RIGHT  0x26
 * @return {*}
 */
void OLED_HorizontalShift(uint8_t direction)

{
	OLED_WR_CMD(0x2e);//停止滚动
	OLED_WR_CMD(direction);//设置滚动方向
	OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
	OLED_WR_CMD(0x00);//设置开始页地址
	OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频
    //  0x00-5帧, 0x01-64帧, 0x02-128帧, 0x03-256帧, 0x04-3帧, 0x05-4帧, 0x06-25帧, 0x07-2帧,
	OLED_WR_CMD(0x07);//设置结束页地址
	OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
	OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
	OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}

/**
 * @function: void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end)
 * @description: 屏幕部分内容水平滚动播放
 * @param {uint8_t} direction			LEFT	   0x27     	RIGHT  0x26
 * @param {uint8_t} start 开始页地址  0x00~0x07
 * @param {uint8_t} end  结束页地址  0x01~0x07
 * @return {*}
 */
void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end)
{
	OLED_WR_CMD(0x2e);//停止滚动
	OLED_WR_CMD(direction);//设置滚动方向
	OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
	OLED_WR_CMD(start);//设置开始页地址
	OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频,0x07即滚动速度2帧
	OLED_WR_CMD(end);//设置结束页地址
	OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
	OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
	OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据

}

/**
 * @function: void OLED_VerticalAndHorizontalShift(uint8_t direction)
 * @description: 屏幕内容垂直水平全屏滚动播放
 * @param {uint8_t} direction				右上滚动	 0x29
 *                                                            左上滚动   0x2A
 * @return {*}
 */
void OLED_VerticalAndHorizontalShift(uint8_t direction)
{
	OLED_WR_CMD(0x2e);//停止滚动
	OLED_WR_CMD(direction);//设置滚动方向
	OLED_WR_CMD(0x01);//虚拟字节设置
	OLED_WR_CMD(0x00);//设置开始页地址
	OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频,即滚动速度
	OLED_WR_CMD(0x07);//设置结束页地址
	OLED_WR_CMD(0x01);//垂直滚动偏移量
	OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
	OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
	OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}

/**
 * @function: void OLED_DisplayMode(uint8_t mode)
 * @description: 屏幕内容取反显示
 * @param {uint8_t} direction			ON	0xA7  ,
 *                                                          OFF	0xA6	默认此模式,设置像素点亮
 * @return {*}
 */
void OLED_DisplayMode(uint8_t mode)
{
	OLED_WR_CMD(mode);
}

/**
 * @function: void OLED_IntensityControl(uint8_t intensity)
 * @description: 屏幕亮度调节
 * @param  {uint8_t} intensity	0x00~0xFF,RESET=0x7F
 * @return {*}
 */
void OLED_IntensityControl(uint8_t intensity)
{
	OLED_WR_CMD(0x81);
	OLED_WR_CMD(intensity);
}

        2、oled.h

//oled.h
#ifndef OLED_OLED_H_
#define OLED_OLED_H_

#include "stm32f1xx_hal.h"
#include "oledfont.h"
extern I2C_HandleTypeDef  hi2c1;


void WriteCmd(void);
void OLED_WR_CMD(uint8_t cmd);
void OLED_WR_DATA(uint8_t data);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Set_Pos(uint8_t x, uint8_t y);
void OLED_On(void);
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2,uint8_t Color_Turn);
void OLED_Showdecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn);
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size,uint8_t Color_Turn);
void OLED_ShowString(uint8_t x,uint8_t y,char*chr,uint8_t Char_Size,uint8_t Color_Turn);
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no,uint8_t Color_Turn);
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *  BMP,uint8_t Color_Turn);
void OLED_HorizontalShift(uint8_t direction);
void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end);
void OLED_VerticalAndHorizontalShift(uint8_t direction);
void OLED_DisplayMode(uint8_t mode);
void OLED_IntensityControl(uint8_t intensity);



#endif /* OLED_OLED_H_ */

        3、更改日期、时间函数key_set()


void key_set(void){
    unsigned char ic =0;
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0){
        while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0);
        OLED_Clear();
        OLED_ShowString(0, 6, "SETTING", 16, 0);
        while((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0)||(ic<6)){
            if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11)==0){
                while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11)==0);
                ic++;
                if(ic>6)
                    ic=0;
            }
            if(ic==0){
                if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0){
                    while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0);
                     SetDate.Year++;
 					if(SetDate.Year>99)
 						SetDate.Year=0;
                }
                if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0){
                    while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0);
                    SetDate.Year--;
                }
                HAL_RTC_SetDate(&hrtc,&SetDate,RTC_FORMAT_BIN);
                HAL_RTC_GetDate(&hrtc, &SetDate, RTC_FORMAT_BIN);
                sprintf(tbuf,"Date:20%02d-%02d-%02d",SetDate.Year,
                SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
                OLED_ShowString(0, 0, tbuf, 16, 0);
                sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
                SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
                OLED_ShowString(0, 2, tbuf, 16, 0);
                OLED_ShowString(0, 4, "Year     ", 16, 0);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0,GPIO_PIN_SET);
            }
            if(ic==1){
                if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0){
                    while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0);
                     SetDate.Month++;
                    if(SetDate.Month>12)
                        SetDate.Month=1;
                }
                if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0){
                    while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0);
                    if(SetDate.Month>1)
                    	SetDate.Month--;
                }
                HAL_RTC_SetDate(&hrtc,&SetDate,RTC_FORMAT_BIN);
                HAL_RTC_GetDate(&hrtc, &SetDate, RTC_FORMAT_BIN);
                sprintf(tbuf,"Date:20%02d-%02d-%02d",SetDate.Year,
                SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
                OLED_ShowString(0, 0, tbuf, 16, 0);
                sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
                SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
                OLED_ShowString(0, 2, tbuf, 16, 0);
                OLED_ShowString(0, 4, "Month    ", 16, 0);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0,GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_SET);
            }
            if(ic==2){
                if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0){
                    while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0);
                    SetDate.Date++;
                    if(SetDate.Date>31)
                    	SetDate.Date = 1;
                }
                if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0){
                    while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0);
                    if(SetDate.Date>1)
                    	SetDate.Date--;
                }
                HAL_RTC_SetDate(&hrtc,&SetDate,RTC_FORMAT_BIN);
                HAL_RTC_GetDate(&hrtc, &SetDate, RTC_FORMAT_BIN);
                sprintf(tbuf,"Date:20%02d-%02d-%02d",SetDate.Year,
                SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
                OLED_ShowString(0, 0, tbuf, 16, 0);
                sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
                SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
                OLED_ShowString(0, 2, tbuf, 16, 0);
                OLED_ShowString(0, 4, "Date    ", 16, 0);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2,GPIO_PIN_SET);
            }
            if(ic==3){
                if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0){
                    while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0);
                    SetTime.Hours++;
                    if(SetTime.Hours>23)
                    	SetTime.Hours=0;

                }
                if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0){
                    while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0);
                    if(SetTime.Hours>0)
                    	SetTime.Hours--;
                }
                HAL_RTC_SetTime(&hrtc,&SetTime,RTC_FORMAT_BIN);
                HAL_RTC_GetTime(&hrtc, &SetTime, RTC_FORMAT_BIN);
                sprintf(tbuf,"Date:20%02d-%02d-%02d",SetDate.Year,
                SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
                OLED_ShowString(0, 0, tbuf, 16, 0);
                sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
                SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
                OLED_ShowString(0, 2, tbuf, 16, 0);
                OLED_ShowString(0, 4, "Hours    ", 16, 0);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2,GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,GPIO_PIN_SET);
            }
            if(ic==4){
                if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0){
                    while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0);
                    SetTime.Minutes++;
                    if(SetTime.Minutes>59)
                    	SetTime.Minutes=0;
                }
                if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0){
                    while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0);

                    if(SetTime.Minutes>0)
                    	SetTime.Minutes--;
                }
                HAL_RTC_SetTime(&hrtc,&SetTime,RTC_FORMAT_BIN);
                HAL_RTC_GetTime(&hrtc, &SetTime, RTC_FORMAT_BIN);
                sprintf(tbuf,"Date:20%02d-%02d-%02d",SetDate.Year,
                SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
                OLED_ShowString(0, 0, tbuf, 16, 0);
                sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
                SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
                OLED_ShowString(0, 2, tbuf, 16, 0);
                OLED_ShowString(0, 4, "Minutes    ", 16, 0);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,GPIO_PIN_SET);
            }
            if(ic==5){
                if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0){
                    while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)==0);
                    SetTime.Seconds++;
                    if(SetTime.Seconds>59)
                    	SetTime.Seconds=0;
                }
                if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0){
                    while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0);
                    if(SetTime.Seconds>0)
                    	SetTime.Seconds--;
                }
                HAL_RTC_SetTime(&hrtc,&SetTime,RTC_FORMAT_BIN);
                HAL_RTC_GetTime(&hrtc, &SetTime, RTC_FORMAT_BIN);
                sprintf(tbuf,"Date:20%02d-%02d-%02d",SetDate.Year,
                SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
                OLED_ShowString(0, 0, tbuf, 16, 0);
                sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
                SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
                OLED_ShowString(0, 2, tbuf, 16, 0);
                OLED_ShowString(0, 4, "Seconds    ", 16, 0);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5,GPIO_PIN_SET);
            }
            if(ic==6){
                OLED_Clear();
                    sprintf(tbuf,"20%02d-%02d-%02d",SetDate.Year,
                    SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
                    OLED_ShowString(0, 0, tbuf, 16, 0);
                sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
                SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
                OLED_ShowString(0, 2, tbuf, 16, 0);
                ic=0;
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5,GPIO_PIN_RESET);
                break;
            }
        }

    }

}

        4、获取日期、时间函数GetCalender()

void GetCalender(void){

  	HAL_RTC_GetTime(&hrtc, &SetTime, RTC_FORMAT_BIN);
  	HAL_RTC_GetDate(&hrtc, &SetDate, RTC_FORMAT_BIN);
    sprintf(tbuf,"Date:20%02d-%02d-%02d",SetDate.Year,
    SetDate.Month,SetDate.Date); //将日期的数据打包到tbuf数组中
  	OLED_ShowString(0, 0, tbuf, 16, 0);
  	sprintf(tbuf,"Time:%02d:%02d:%02d",SetTime.Hours,
  	SetTime.Minutes,SetTime.Seconds); //将时间的数据打包到tbuf数组中
  	OLED_ShowString(0, 2, tbuf, 16, 0);
}

        5、获取温度函数GetTemperature()

void GetTemperature(void)
{
	float Temperature,AD_Value,Vol_Value;
	HAL_ADC_Start(&hadc1);	//启动ADC转换
	HAL_ADC_PollForConversion(&hadc1,10);	//等待转换完成,10ms表示超时时间
	AD_Value = HAL_ADC_GetValue(&hadc1);	//读取ADC转换数据(12位数据)
	Vol_Value = AD_Value*(3.3/4096);	//AD值乘以分辨率即为电压值
	Temperature = (1.43 - Vol_Value)/0.0043 + 25;	//根据公式算出温度值
	OLED_ShowString(0, 4, "Temp:", 16, 0);
	OLED_Showdecimal(44,4,Temperature,2,2,16,0);
	OLED_ShowString(88, 4, "C", 16, 0);
}

        6、main.c的关键代码


#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "rtc.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "oled.h"
#include "stdio.h"
RTC_TimeTypeDef GetTime ;
RTC_DateTypeDef GetDate ;
RTC_TimeTypeDef SetTime ;
RTC_DateTypeDef SetDate ;
RTC_TimeTypeDef	SetAlarm;
char tbuf[40];
char tbu[40];
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_I2C1_Init();
  MX_TIM3_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADCEx_Calibration_Start(&hadc1);
  HAL_TIM_Base_Start_IT(&htim3);
  OLED_Init();
  OLED_Clear();
//  OLED_ShowString(0, 0, "tlm", 16, 1);
  	HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
  	HAL_RTC_GetDate(&hrtc, &GetDate, RTC_FORMAT_BIN);
  	sprintf(tbuf,"Date:20%02d-%02d-%02d",GetDate.Year,
  	GetDate.Month,GetDate.Date); //将日期的数据打包到tbuf数组中
  	OLED_ShowString(0, 0, tbuf, 16, 0);
  	sprintf(tbuf,"Time:%02d:%02d:%02d",GetTime.Hours,
  	GetTime.Minutes,GetTime.Seconds); //将时间的数据打包到tbuf数组中
  	OLED_ShowString(0, 2, tbuf, 16, 0);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  key_set();
	  GetCalender();
	  GetTemperature();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

结束:

附完整的工程文件:链接:https://pan.baidu.com/s/1fy7jTGq4uOygJyMbkUzYNw 
提取码:9k4t

  • 19
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STM32RTC内部时钟模块是基于实时时钟(RTC)的硬件模块,用于提供准确的日期和时间信息。以下是基于STM32RTC内部时钟模块的工作原理: 1. 时钟源选择:STM32RTC可以使用两种时钟源:低速外部晶体振荡器(LSE)和内部低速时钟(LSI)。LSE通常提供更高的精度,而LSI则是一个内部振荡器。 2. 时钟预分频:时钟预分频器用于将RTC输入时钟分频为更低的频率,以适应RTC的要求。这有助于降低功耗,并且可以根据需要调整RTC时钟频率。 3. 分频器和计数器:RTC内部包含一个分频器和一个计数器。分频器将输入时钟进一步分频,并将其提供给计数器。计数器在每个时钟周期上递增,从而实现对时间的记录。 4. 日期和时间表示:RTC内部使用二进制码来表示日期和时间。日期和时间信息存储在相应的寄存器中,包括年、月、日、小时、分钟和秒等。 5. 闹钟功能:RTC模块还提供了闹钟功能,可以设置特定日期和时间,当达到闹钟设定的日期和时间时,RTC可以触发中断或事件。 6. 电池备份:为了确保在主电源中断时仍能保持准确的日期和时间记录,RTC模块通常与备份电池连接。备份电池提供持久的电源,以供RTC模块继续运行。 7. 校准:为了提高RTC的精确度,可以使用外部参考源(如LSE)对RTC进行校准。校准可以调整RTC的时钟频率,以使其与外部参考源同步。 总之,基于STM32RTC内部时钟模块的工作原理涉及时钟源选择、时钟预分频、分频器和计数器、日期和时间表示、闹钟功能、电池备份和校准等关键步骤。这些功能使得STM32RTC可以提供准确的日期和时间信息,并支持定时功能和持久性存储。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值