OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3034|回复: 6

基于STM32F103的OLED显示万年历(RTC)

[复制链接]

2

主题

13

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2019-7-25
在线时间
11 小时
发表于 2020-3-1 23:34:42 | 显示全部楼层 |阅读模式
1金钱
最近在写一个万年历的程序,用的RTC例程,为什么我更改完RTC_Set();里的时间,编译完程序后再烧入单片机OLED就不显示了,没更改时间前完全没问题(就是时间不对而已),再改回去OLED也不会亮,全黑。
file:///C:/Users/Administrator.DESKTOP-6ICRFRG/AppData/Roaming/Tencent/Users/472991323/TIM/WinTemp/RichOle/I%7DGQE9K%60T6IJW_B4L(%7DLYIN.png
4针OLED IIC接口 ,开发板是战舰v3

发帖.png
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

13

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2019-7-25
在线时间
11 小时
 楼主| 发表于 2020-3-1 23:45:11 | 显示全部楼层

#include "sys.h"
#include "OLED_I2C.h"
#include "delay.h"
#include "rtc.h"
#include "usart.h"

int main(void)
{
        u8 t;
//        u8 t1;
        u8 i;
       
        uart_init(115200);                 //串口初始化为115200
        RTC_Init();                                  //RTC初始化
        delay_init();                     //延时函数初始化
        I2C_Configuration();
        OLED_Init();
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2         //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
       
        OLED_Fill(0x00);//全屏灭
       
                OLED_ShowStr(3,0,"T",2);//T
                OLED_ShowStr(11,0,"I",2);//I
                OLED_ShowStr(19,0,"M",2);//M
                OLED_ShowStr(27,0,"E",2);//E
                OLED_ShowStr(35,0,":",2);//:
       
                while(RTC_Init())                //RTC初始化        ,一定要初始化成功
                {
                        OLED_ShowStr(0,6,"RTC ERROR!     ",2);
                        delay_ms(800);
                        OLED_ShowStr(0,6,"RTC Trying...    ",2);
                }
                       
                OLED_ShowStr(42,0,"    /  /     ",2);
                OLED_ShowStr(24,6,"  :  :  ",2);
       
        while(1)
        {
                OLED_ShowStr(3,0,"T",2);//T
                OLED_ShowStr(11,0,"I",2);//I
                OLED_ShowStr(19,0,"M",2);//M
                OLED_ShowStr(27,0,"E",2);//E
                OLED_ShowStr(35,0,":",2);//:
               
                if(t!=calendar.sec)
                {
                        t=calendar.sec;
                        OLED_ShowNum(42,0,calendar.w_year,4,2);                               
                        OLED_ShowNum(82,0,calendar.w_month,2,2);       
                        OLED_ShowNum(106,0,calendar.w_date,2,2);
                        switch(calendar.week)
                        {
                                case 0:
                                        OLED_ShowStr(24,3,"Sunday   ",2);
                                        break;
                                case 1:
                                        OLED_ShowStr(24,3,"Monday   ",2);
                                        break;
                                case 2:
                                        OLED_ShowStr(24,3,"Tuesday  ",2);
                                        break;
                                case 3:
                                        OLED_ShowStr(24,3,"Wednesday  ",2);
                                        break;
                                case 4:
                                        OLED_ShowStr(24,3,"Thursday ",2);
                                        break;
                                case 5:
                                        OLED_ShowStr(24,3,"Friday   ",2);
                                        break;
                                case 6:
                                        OLED_ShowStr(24,3,"Saturday     ",2);
                                        break;  
                        }
                        OLED_ShowNum(24,6,calendar.hour,2,2);
                        OLED_ShowNum(48,6,calendar.min,2,2);
                        OLED_ShowNum(72,6,calendar.sec,2,2);       
                }       
        }
}

*********************以上是主函数************************

/************************************************************************************
*  Copyright (c), 2014, HelTec Automatic Technology co.,LTD.
*            All rights reserved.
*
* Http:    www.heltec.cn
* Email:   cn.heltec@gmail.com
* WebShop: heltec.taobao.com
*
* File name: OLED_I2C.c
* Project  : HelTec.uvprij
* Processor: STM32F103C8T6
* Compiler : MDK fo ARM
*
* Author : 小林
* Version: 1.00
* Date   : 2014.4.8
* Email  : hello14blog@gmail.com
* Modification: none
*
* Description:128*64点阵的OLED显示屏驱动文件,仅适用于惠特自动化(heltec.taobao.com)的SD1306驱动IIC通信方式显示屏
*
* Others: none;
*
* Function List:
* 1. void I2C_Configuration(void) -- 配置CPU的硬件I2C
* 2. void I2C_WriteByte(uint8_t addr,uint8_t data) -- 向寄存器地址写一个byte的数据
* 3. void WriteCmd(unsigned char I2C_Command) -- 写命令
* 4. void WriteDat(unsigned char I2C_Data) -- 写数据
* 5. void OLED_Init(void) -- OLED屏初始化
* 6. void OLED_SetPos(unsigned char x, unsigned char y) -- 设置起始点坐标
* 7. void OLED_Fill(unsigned char fill_Data) -- 全屏填充
* 8. void OLED_CLS(void) -- 清屏
* 9. void OLED_ON(void) -- 唤醒
* 10. void OLED_OFF(void) -- 睡眠
* 11. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) -- 显示字符串(字体大小有6*8和8*16两种)
* 12. void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) -- 显示中文(中文需要先取模,然后放到codetab.h中)
* 13. void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) -- BMP图片
*
* History: none;
*
*************************************************************************************/

#include "OLED_I2C.h"
#include "delay.h"
#include "codetab.h"
#include "oledfont.h"                //12*12,16*16,24*24字符表,正点原子
#include <math.h>

void I2C_Configuration(void)
{
        I2C_InitTypeDef  I2C_InitStructure;
        GPIO_InitTypeDef  GPIO_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

        /*STM32F103C8T6芯片的硬件I2C: PB6 -- SCL; PB7 -- SDA */
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//I2C必须开漏输出
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        I2C_DeInit(I2C1);//使用I2C1
        I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
        I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
        I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主机的I2C地址,随便写的
        I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
        I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
        I2C_InitStructure.I2C_ClockSpeed = 400000;//400K

        I2C_Cmd(I2C1, ENABLE);
        I2C_Init(I2C1, &I2C_InitStructure);
}

void I2C_WriteByte(uint8_t addr,uint8_t data)
{
  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
       
        I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/

        I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

        I2C_SendData(I2C1, addr);//寄存器地址
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        I2C_SendData(I2C1, data);//发送数据
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
       
        I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
}

void WriteCmd(unsigned char I2C_Command)//写命令
{
        I2C_WriteByte(0x00, I2C_Command);
}

void WriteDat(unsigned char I2C_Data)//写数据
{
        I2C_WriteByte(0x40, I2C_Data);
}

void OLED_Init(void)
{
        delay_ms(100); //这里的延时很重要
       
        WriteCmd(0xAE); //display off
        WriteCmd(0x20);        //Set Memory Addressing Mode       
        WriteCmd(0x10);        //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
        WriteCmd(0xb0);        //Set Page Start Address for Page Addressing Mode,0-7
        WriteCmd(0xc8);        //Set COM Output Scan Direction
        WriteCmd(0x00); //---set low column address
        WriteCmd(0x10); //---set high column address
        WriteCmd(0x40); //--set start line address
        WriteCmd(0x81); //--set contrast control register
        WriteCmd(0xff); //亮度调节 0x00~0xff
        WriteCmd(0xa1); //--set segment re-map 0 to 127
        WriteCmd(0xa6); //--set normal display
        WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
        WriteCmd(0x3F); //
        WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
        WriteCmd(0xd3); //-set display offset
        WriteCmd(0x00); //-not offset
        WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
        WriteCmd(0xf0); //--set divide ratio
        WriteCmd(0xd9); //--set pre-charge period
        WriteCmd(0x22); //
        WriteCmd(0xda); //--set com pins hardware configuration
        WriteCmd(0x12);
        WriteCmd(0xdb); //--set vcomh
        WriteCmd(0x20); //0x20,0.77xVcc
        WriteCmd(0x8d); //--set DC-DC enable
        WriteCmd(0x14); //
        WriteCmd(0xaf); //--turn on oled panel
}

void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{
        WriteCmd(0xb0+y);
        WriteCmd(((x&0xf0)>>4)|0x10);
        WriteCmd((x&0x0f)|0x01);
}

void OLED_Fill(unsigned char fill_Data)//全屏填充
{
        unsigned char m,n;
        for(m=0;m<8;m++)
        {
                WriteCmd(0xb0+m);                //page0-page1
                WriteCmd(0x00);                //low column start address
                WriteCmd(0x10);                //high column start address
                for(n=0;n<128;n++)
                        {
                                WriteDat(fill_Data);
                        }
        }
}

void OLED_CLS(void)//清屏
{
        OLED_Fill(0x00);
}

//--------------------------------------------------------------
// Prototype      : void OLED_ON(void)
// Calls          :
// Parameters     : none
// Description    : 将OLED从休眠中唤醒
//--------------------------------------------------------------
void OLED_ON(void)
{
        WriteCmd(0X8D);  //设置电荷泵
        WriteCmd(0X14);  //开启电荷泵
        WriteCmd(0XAF);  //OLED唤醒
}

//--------------------------------------------------------------
// Prototype      : void OLED_OFF(void)
// Calls          :
// Parameters     : none
// Description    : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
        WriteCmd(0X8D);  //设置电荷泵
        WriteCmd(0X10);  //关闭电荷泵
        WriteCmd(0XAE);  //OLED休眠
}

//--------------------------------------------------------------
// Prototype      : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
// Calls          :
// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8; 2:8*16)
// Description    : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
//--------------------------------------------------------------
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
        unsigned char c = 0,i = 0,j = 0;
        switch(TextSize)
        {
                case 1:                                //6*8
                {
                        while(ch[j] != '\0')
                        {
                                c = ch[j] - 32;
                                if(x > 122)
                                {
                                        x = 0;
                                        y++;
                                }
                                OLED_SetPos(x,y);
                                for(i=0;i<6;i++)
                                        WriteDat(F6x8[c]);
                                x += 6;
                                j++;
                        }
                }break;
                case 2:                        //8*16
                {
                        while(ch[j] != '\0')
                        {
                                c = ch[j] - 32;
                                if(x > 120)
                                {
                                        x = 0;
                                        y++;
                                }
                                OLED_SetPos(x,y);
                                for(i=0;i<8;i++)
                                        WriteDat(F8X16[c*16+i]);
                                OLED_SetPos(x,y+1);
                                for(i=0;i<8;i++)
                                        WriteDat(F8X16[c*16+i+8]);
                                x += 8;
                                j++;
                        }
                }break;
        }
}

//--------------------------------------------------------------
// Prototype      : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
// Calls          :
// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引
// Description    : 显示codetab.h中的汉字,16*16点阵
//--------------------------------------------------------------
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
        unsigned char wm=0;
        unsigned int  adder=32*N;
        OLED_SetPos(x , y);
        for(wm = 0;wm < 16;wm++)
        {
                WriteDat(F16x16[adder]);
                adder += 1;
        }
        OLED_SetPos(x,y + 1);
        for(wm = 0;wm < 16;wm++)
        {
                WriteDat(F16x16[adder]);
                adder += 1;
        }
}

//--------------------------------------------------------------
// Prototype      : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
// Calls          :
// Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
// Description    : 显示BMP位图
//--------------------------------------------------------------
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
        unsigned int j=0;
        unsigned char x,y;

  if(y1%8==0)
                y = y1/8;
  else
                y = y1/8 + 1;
        for(y=y0;y<y1;y++)
        {
                OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
                {
                        WriteDat(BMP[j++]);
                }
        }
}


/****************************移植后修改***************************/
//显示2个数字
//x,y :起点坐标         
//len :数字的位数
//size:字体大小         size -- 字符大小(1:6*8; 2:8*16)
//mode:模式        0,填充模式;1,叠加模式
//num:数值(0~4294967295);         
//void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{                
        unsigned char c = 0,i = 0,j = 0;
        u32 temp;
        u32 ch[100];
        for(i=0;i<len;i++)
        {
                temp = pow(10,len-1-i);
                ch=(num/temp)%10;
        }
       
        switch(size)
        {
                case 1:                                        //6*8
                        while(len--)
                        {
                                c = ch[j] + 16;
                                if(x > 122)
                                {
                                        x = 0;
                                        y++;
                                }
                                OLED_SetPos(x,y);
                                for(i=0;i<6;i++)
                                        WriteDat(F6x8[c]);
                                x += 6;
                                j++;
                        }
                        break;
                case 2:                                //8*16
                {
                        while(len--)
                        {
                                c = ch[j] + 16;
                                if(x > 120)
                                {
                                        x = 0;
                                        y++;
                                }
                                OLED_SetPos(x,y);
                                for(i=0;i<8;i++)
                                        WriteDat(F8X16[c*16+i]);
                                OLED_SetPos(x,y+1);
                                for(i=0;i<8;i++)
                                        WriteDat(F8X16[c*16+i+8]);
                                x += 8;
                                j++;
                        }
                }break;
        }
}


*****************以上是OLED_I2C.c函数******

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "rtc.h"                     
//Mini STM32开发板
//RTC实时时钟 驱动代码                         
//正点原子@ALIENTEK
//2010/6/6
          
_calendar_obj calendar;//时钟结构体

static void RTC_NVIC_Config(void)
{       
  NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;                //RTC全局中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;        //先占优先级1位,从优先级3位
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //先占优先级0位,从优先级4位
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //使能该通道中断
        NVIC_Init(&NVIC_InitStructure);                //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}

//实时时钟配置
//初始化RTC时钟,同时检测时钟是否工作正常
//BKP->DR1用于保存是否第一次配置的设置
//返回0:正常
//其他:错误代码

u8 RTC_Init(void)
{
        //检查是不是第一次配置时钟
        u8 temp=0;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   
        PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
        if (BKP_ReadBackupRegister(BKP_DR1) != 0x5051)                //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
                {                                
                BKP_DeInit();        //复位备份区域        
                RCC_LSEConfig(RCC_LSE_ON);        //设置外部低速晶振(LSE),使用外设低速晶振
                while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)        //检查指定的RCC标志位设置与否,等待低速晶振就绪
                        {
                        temp++;
                        delay_ms(10);
                        }
                if(temp>=250)return 1;//初始化时钟失败,晶振有问题            
                RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
                RCC_RTCCLKCmd(ENABLE);        //使能RTC时钟  
                RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
                RTC_WaitForSynchro();                //等待RTC寄存器同步  
                RTC_ITConfig(RTC_IT_SEC, ENABLE);                //使能RTC秒中断
                RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
                RTC_EnterConfigMode();/// 允许配置       
                RTC_SetPrescaler(32767); //设置RTC预分频的值
                RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
                RTC_Set(2020,02,24,16,43,10);  //设置时间       
                RTC_ExitConfigMode(); //退出配置模式  
                BKP_WriteBackupRegister(BKP_DR1, 0X5051);        //向指定的后备寄存器中写入用户程序数据
                }
        else//系统继续计时
                {

                RTC_WaitForSynchro();        //等待最近一次对RTC寄存器的写操作完成
                RTC_ITConfig(RTC_IT_SEC, ENABLE);        //使能RTC秒中断
                RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
                }
        RTC_NVIC_Config();//RCT中断分组设置                                                         
        RTC_Get();//更新时间       
        return 0; //ok

}                                                     
//RTC时钟中断
//每秒触发一次  
//extern u16 tcnt;
void RTC_IRQHandler(void)
{                 
        if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
        {                                                       
                RTC_Get();//更新时间   
        }
        if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
        {
                RTC_ClearITPendingBit(RTC_IT_ALR);                //清闹钟中断                 
          RTC_Get();                                //更新时间   
          printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间       
               
          }                                                                                                    
        RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);                //清闹钟中断
        RTC_WaitForLastTask();                                                                                           
}
//判断是否是闰年函数
//月份   1  2  3  4  5  6  7  8  9  10 11 12
//闰年   31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 Is_Leap_Year(u16 year)
{                          
        if(year%4==0) //必须能被4整除
        {
                if(year%100==0)
                {
                        if(year%400==0)return 1;//如果以00结尾,还要能被400整除           
                        else return 0;   
                }else return 1;   
        }else return 0;       
}                                   
//设置时钟
//把输入的时钟转换为秒钟
//以1970年1月1日为基准
//1970~2099年为合法年份
//返回值:0,成功;其他:错误代码.
//月份数据表                                                                                         
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表          
//平年的月份日期表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
        u16 t;
        u32 seccount=0;
        if(syear<1970||syear>2099)return 1;          
        for(t=1970;t<syear;t++)        //把所有年份的秒钟相加
        {
                if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
                else seccount+=31536000;                          //平年的秒钟数
        }
        smon-=1;
        for(t=0;t<smon;t++)           //把前面月份的秒钟数相加
        {
                seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
                if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数          
        }
        seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
        seccount+=(u32)hour*3600;//小时秒钟数
    seccount+=(u32)min*60;         //分钟秒钟数
        seccount+=sec;//最后的秒钟加上去

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟  
        PWR_BackupAccessCmd(ENABLE);        //使能RTC和后备寄存器访问
        RTC_SetCounter(seccount);        //设置RTC计数器的值

        RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成         
        return 0;            
}

//初始化闹钟                  
//以1970年1月1日为基准
//1970~2099年为合法年份
//syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   
//返回值:0,成功;其他:错误代码.
u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
        u16 t;
        u32 seccount=0;
        if(syear<1970||syear>2099)return 1;          
        for(t=1970;t<syear;t++)        //把所有年份的秒钟相加
        {
                if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
                else seccount+=31536000;                          //平年的秒钟数
        }
        smon-=1;
        for(t=0;t<smon;t++)           //把前面月份的秒钟数相加
        {
                seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
                if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数          
        }
        seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
        seccount+=(u32)hour*3600;//小时秒钟数
    seccount+=(u32)min*60;         //分钟秒钟数
        seccount+=sec;//最后的秒钟加上去                             
        //设置时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   
        PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
        //上面三步是必须的!
       
        RTC_SetAlarm(seccount);

        RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成         
       
        return 0;            
}


//得到当前的时间
//返回值:0,成功;其他:错误代码.
u8 RTC_Get(void)
{
        static u16 daycnt=0;
        u32 timecount=0;
        u32 temp=0;
        u16 temp1=0;          
    timecount=RTC_GetCounter();         
        temp=timecount/86400;   //得到天数(秒钟数对应的)
        if(daycnt!=temp)//超过一天了
        {          
                daycnt=temp;
                temp1=1970;        //从1970年开始
                while(temp>=365)
                {                                 
                        if(Is_Leap_Year(temp1))//是闰年
                        {
                                if(temp>=366)temp-=366;//闰年的秒钟数
                                else {temp1++;break;}  
                        }
                        else temp-=365;          //平年
                        temp1++;  
                }   
                calendar.w_year=temp1;//得到年份
                temp1=0;
                while(temp>=28)//超过了一个月
                {
                        if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份
                        {
                                if(temp>=29)temp-=29;//闰年的秒钟数
                                else break;
                        }
                        else
                        {
                                if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
                                else break;
                        }
                        temp1++;  
                }
                calendar.w_month=temp1+1;        //得到月份
                calendar.w_date=temp+1;          //得到日期
        }
        temp=timecount%86400;                     //得到秒钟数             
        calendar.hour=temp/3600;             //小时
        calendar.min=(temp%3600)/60;         //分钟       
        calendar.sec=(temp%3600)%60;         //秒钟
        calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期   
        return 0;
}         
//获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//输入参数:公历年月日
//返回值:星期号                                                                                                                                                                                 
u8 RTC_Get_Week(u16 year,u8 month,u8 day)
{       
        u16 temp2;
        u8 yearH,yearL;
       
        yearH=year/100;        yearL=year%100;
        // 如果为21世纪,年份数加100  
        if (yearH>19)yearL+=100;
        // 所过闰年数只算1900年之后的  
        temp2=yearL+yearL/4;
        temp2=temp2%7;
        temp2=temp2+day+table_week[month-1];
        if (yearL%4==0&&month<3)temp2--;
        return(temp2%7);
}                          

















**以上是RTC.c文件****直接移植的例程,除时间外没有改动
回复

使用道具 举报

109

主题

5564

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
10566
金钱
10566
注册时间
2017-2-18
在线时间
1913 小时
发表于 2020-3-2 14:42:40 | 显示全部楼层
RTC_SET函数的02改为2试下,没效果的话先仿真器清楚芯片内的程序
然后再去仿真调试代码看下代码
回复

使用道具 举报

2

主题

13

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2019-7-25
在线时间
11 小时
 楼主| 发表于 2020-3-2 17:56:40 | 显示全部楼层
peng1554 发表于 2020-3-2 14:42
RTC_SET函数的02改为2试下,没效果的话先仿真器清楚芯片内的程序
然后再去仿真调试代码看下代码

感谢回复

哪里的问题找到了,但是不知道原因。把RTC初始化函数屏蔽掉就没事了→→&#128073;RTC_Init();
回复

使用道具 举报

2

主题

13

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2019-7-25
在线时间
11 小时
 楼主| 发表于 2020-3-2 17:57:50 | 显示全部楼层
本帖最后由 油炸自行车 于 2020-3-2 18:00 编辑
油炸自行车 发表于 2020-3-2 17:56
感谢回复

哪里的问题找到了,但是不知道原因。把RTC初始化函数屏蔽掉就没事了→就→是→它→→RTC_Init() ...

/*********************以下是修改完后的主函数*********************/
/*********************和原来相比仅仅是屏蔽了RCT初始化函数而已*********************/

#include "sys.h"
#include "OLED_I2C.h"
#include "delay.h"
#include "rtc.h"
#include "usart.h"


int main(void)
{
        u8 t;
//        u8 t1;
//        u8 i;
        
        uart_init(115200);                 //串口初始化为115200
//        RTC_Init();                                  //RTC初始化
        delay_init();                     //延时函数初始化
        I2C_Configuration();
        OLED_Init();
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2         //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
        
        OLED_Fill(0x00);//全屏灭
//                delay_ms(20000);
//                for(i=0;i<8;i++)
//                {
//                        OLED_ShowCN(0+i*16,0,i);//测试显示中文
//                }
//                delay_ms(20000);
//                OLED_Fill(0x00);//全屏灭
        
                OLED_ShowStr(3,0,"T",2);//T
                OLED_ShowStr(11,0,"I",2);//I
                OLED_ShowStr(19,0,"M",2);//M
                OLED_ShowStr(27,0,"E",2);//E
                OLED_ShowStr(35,0,":",2);//:
        
                while(RTC_Init())                //RTC初始化        ,一定要初始化成功
                {
                        OLED_ShowStr(0,6,"RTC ERROR!     ",2);
                        delay_ms(800);
                        OLED_ShowStr(0,6,"RTC Trying...    ",2);
                }
                        
                OLED_ShowStr(42,0,"    /  /     ",2);
                OLED_ShowStr(24,6,"  :  :  ",2);
        
        while(1)
        {
                OLED_ShowStr(3,0,"T",2);//T
                OLED_ShowStr(11,0,"I",2);//I
                OLED_ShowStr(19,0,"M",2);//M
                OLED_ShowStr(27,0,"E",2);//E
                OLED_ShowStr(35,0,":",2);//:
               
                if(t!=calendar.sec)
                {
                        t=calendar.sec;
                        OLED_ShowNum(42,0,calendar.w_year,4,2);                                
                        OLED_ShowNum(82,0,calendar.w_month,2,2);        
                        OLED_ShowNum(106,0,calendar.w_date,2,2);
                        switch(calendar.week)
                        {
                                case 0:
                                        OLED_ShowStr(24,3,"Sunday   ",2);
                                        break;
                                case 1:
                                        OLED_ShowStr(24,3,"Monday   ",2);
                                        break;
                                case 2:
                                        OLED_ShowStr(24,3,"Tuesday  ",2);
                                        break;
                                case 3:
                                        OLED_ShowStr(24,3,"Wednesday  ",2);
                                        break;
                                case 4:
                                        OLED_ShowStr(24,3,"Thursday ",2);
                                        break;
                                case 5:
                                        OLED_ShowStr(24,3,"Friday   ",2);
                                        break;
                                case 6:
                                        OLED_ShowStr(24,3,"Saturday     ",2);
                                        break;  
                        }
                        OLED_ShowNum(24,6,calendar.hour,2,2);
                        OLED_ShowNum(48,6,calendar.min,2,2);
                        OLED_ShowNum(72,6,calendar.sec,2,2);        
                }        
        }
}

回复

使用道具 举报

109

主题

5564

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
10566
金钱
10566
注册时间
2017-2-18
在线时间
1913 小时
发表于 2020-3-2 18:40:26 | 显示全部楼层
油炸自行车 发表于 2020-3-2 17:56
感谢回复

哪里的问题找到了,但是不知道原因。把RTC初始化函数屏蔽掉就没事了→→&#128073;RTC_Init() ...

之前改动过RTC_SET()吗
回复

使用道具 举报

2

主题

13

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2019-7-25
在线时间
11 小时
 楼主| 发表于 2020-3-22 23:00:14 | 显示全部楼层
peng1554 发表于 2020-3-2 18:40
之前改动过RTC_SET()吗

记不清了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-4 11:48

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表