zoukankan      html  css  js  c++  java
  • ESP8266 SDK开发: 外设篇-时钟芯片DS1302使用和拓展知识<time.h>的使用

    <p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/Learn8266ForSDK" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>

    说明

    因为帮别人做一个小东西,WiFi呢不能联网,但是需要时间,所以加了一个DS1302.

    注:只要WiFi可以联网就不需要加时钟,直接使用内部时钟就可以了,你可以每隔一段时间使用ntc获取时间然后改写内部时钟

    我主要说明一下我封装的文件的使用和注意事项!

    连接图示

    注意:需要拆掉OLED

    WiFi   GPIO14 -- RST   DS1302

    WiFi   GPIO12 -- DAT   DS1302

    WiFi   GPIO13 -- CLK   DS1302

    移植使用

    1.程序代码不仅仅局限于此节使用

    /*
     * DS1302.C
     *
     *  Created on: 2020年12月23日
     *      Author: yang
     *      使用:设置时间
            struct ds1302struct lcTime;
            lcTime.tm_year = 20;//年(芯片只能存储两位 00-99,具体看手册)
            lcTime.tm_mon = 12;//月
            lcTime.tm_mday = 23;//日
            lcTime.tm_hour = 22;//时
            lcTime.tm_min = 55;//分
            lcTime.tm_sec = 5;//秒
            ds1302_set_time(&lcTime,1);
    
            使用:获取时间
            struct ds1302struct lcTime;
            ds1302_read_time(&lcTime,1);//获取时钟的时间
            //打印 年 月 日 时 分 秒
            os_printf("
    year=%d,mon=%d,mday=%d,hour=%d,min=%d,sec=%d
    ",
                    lcTime.tm_year,
                    lcTime.tm_mon,
                    lcTime.tm_mday,
                    lcTime.tm_hour,
                    lcTime.tm_min,
                    lcTime.tm_sec
                    );
     */
    #define DS1302_C_
    #include <time.h>
    #include "driver/DS1302.h"
    #include "eagle_soc.h"
    #include "osapi.h"
    #include "gpio.h"
    
    //初始化引脚,移植其它单片机请替换内部函数
    void ICACHE_FLASH_ATTR
    ds1302_gpio_init(void) {
        ETS_GPIO_INTR_DISABLE();
    
        WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
    
        PIN_FUNC_SELECT(DS1302_RST_MUX, DS1302_RST_FUNC);
        PIN_FUNC_SELECT(DS1302_DAT_MUX, DS1302_DAT_FUNC);
        PIN_FUNC_SELECT(DS1302_CLK_MUX, DS1302_CLK_FUNC);
    
        GPIO_OUTPUT_SET(DS1302_RST_GPIO, 0);
        GPIO_OUTPUT_SET(DS1302_DAT_GPIO, 0);
        GPIO_OUTPUT_SET(DS1302_CLK_GPIO, 0);
    
        ETS_GPIO_INTR_ENABLE() ;
    }
    
    //延时us,移植其它单片机请替换内部函数
    void ICACHE_FLASH_ATTR
    ds1302_delay_us(char us){
        os_delay_us(us);
    }
    //设置时钟引脚输出高低电平,移植其它单片机请替换内部函数
    void ICACHE_FLASH_ATTR
    ds1302_clk_set(char HL){
        if(HL==1)
            GPIO_OUTPUT_SET(DS1302_CLK_GPIO, 1);
        else
            GPIO_OUTPUT_SET(DS1302_CLK_GPIO, 0);
    }
    //设置RST引脚输出高低电平,移植其它单片机请替换内部函数
    void ICACHE_FLASH_ATTR
    ds1302_rst_set(char HL){
        if(HL==1)
            GPIO_OUTPUT_SET(DS1302_RST_GPIO, 1);
        else
            GPIO_OUTPUT_SET(DS1302_RST_GPIO, 0);
    }
    //设置数据引脚输出高低电平,移植其它单片机请替换内部函数
    void ICACHE_FLASH_ATTR
    ds1302_dat_set(char HL){
        if(HL==1)
            GPIO_OUTPUT_SET(DS1302_DAT_GPIO, 1);
        else
            GPIO_OUTPUT_SET(DS1302_DAT_GPIO, 0);
    }
    
    //获取数据引脚的高低电平,移植其它单片机请替换内部函数
    char ICACHE_FLASH_ATTR
    ds1302_dat_get(){
        return GPIO_INPUT_GET(DS1302_DAT_GPIO);
    }
    
    
    /**
    * @brief  写一个字节数据到芯片
    * @param  data:要写入的数据
    * @param  None
    * @param  None
    * @retval None
    * @example
    **/
    void ICACHE_FLASH_ATTR
    ds1302_write_byte(char data){
        char i=0;
    
        for (i = 0; i < 8; i++){
            ds1302_clk_set(0);//先保持CLK为低电平
            ds1302_delay_us(1);
    
            //准备数据
            if (data & 0x01)
                ds1302_dat_set(1);
            else
                ds1302_dat_set(0);
    
            //产生上升沿
            ds1302_delay_us(1);
            ds1302_clk_set(1);
            ds1302_delay_us(1);
    
            data = data >> 1;
        }
    }
    
    
    /**
    * @brief  读取一个字节数据
    * @param  None
    * @param  None
    * @param  None
    * @retval None
    * @example
    **/
    char ICACHE_FLASH_ATTR
    ds1302_read_byte(){
        char i=0, temp=0;
    
        //读取数据
        for (i = 0; i < 8;i++) {
            ds1302_clk_set(0);//产生了第一个下降沿
            ds1302_delay_us(1);
    
            temp = temp >> 1;
            if (ds1302_dat_get()){//获取数据
                temp |= 0x80;
            }
    
            ds1302_delay_us(1);
            ds1302_clk_set(1);
            ds1302_delay_us(1);
        }
        return temp;
    }
    
    /**
    * @brief  写数据到芯片
    * @param  addr:要写入的地址
    * @param  data:要写入的数据
    * @param  rc:1-操作内部RAM
    * @retval None
    * @example
    **/
    void ICACHE_FLASH_ATTR
    ds1302_write_data(char addr,char data,char rc){
        ds1302_clk_set(0);//先保持CLK为低电平
        ds1302_delay_us(1);
        ds1302_rst_set(1);//启用传输
        ds1302_delay_us(1);
    
        addr = addr & 0xFE;//数据最低位,置0(写入数据)
        if(rc==1) addr = addr | 0x40; //操作RAM
        ds1302_write_byte(addr);
        ds1302_write_byte(data);
    
        ds1302_rst_set(0);//停止传输
        ds1302_delay_us(1);
    }
    
    
    /**
    * @brief  读取数据
    * @param  addr:读取的地址
    * @param  rc:1-操作内部RAM
    * @param  None
    * @retval None
    * @example
    **/
    char ICACHE_FLASH_ATTR
    ds1302_read_data(char addr,char rc){
        char temp;
        ds1302_clk_set(0);//先保持CLK为低电平
        ds1302_delay_us(1);
        ds1302_rst_set(1);//启用传输
        ds1302_delay_us(1);
    
        addr = addr | 0x01;//数据最低位置1(读取数据)
        if(rc==1) addr = addr | 0x40; //操作RAM
        ds1302_write_byte(addr);
    
        temp = ds1302_read_byte();
    
        ds1302_rst_set(0);//停止传输
        ds1302_delay_us(1);
        return temp;
    }
    
    /**
    * @brief  写数据到芯片(突发模式)
    * @param  data:要写入的8字节数据
    * @param  None
    * @param  None
    * @retval None
    * @example
    **/
    void ICACHE_FLASH_ATTR
    ds1302_write_data_burst(char *data){
        int i=0;
        ds1302_clk_set(0);//先保持CLK为低电平
        ds1302_delay_us(1);
        ds1302_rst_set(1);//启用传输
        ds1302_delay_us(1);
    
        ds1302_write_byte(ds1302_burstwr_add);
    
        for (i=0; i<8; i++){ //连续写入 8 字节数据
            ds1302_write_byte(data[i]);
        }
    
        ds1302_rst_set(0);//停止传输
        ds1302_delay_us(1);
    }
    
    /**
    * @brief  读取数据(突发模式)
    * @param  data:读取的地址
    * @param  None
    * @param  None
    * @retval None
    * @example
    **/
    void ICACHE_FLASH_ATTR
    ds1302_read_data_burst(char *data){
        int i=0;
        ds1302_clk_set(0);//先保持CLK为低电平
        ds1302_delay_us(1);
        ds1302_rst_set(1);//启用传输
        ds1302_delay_us(1);
    
        ds1302_write_byte(ds1302_burstre_add);
        for (i=0; i<8; i++){ //连续写入 8 字节数据
            data[i] = ds1302_read_byte();
        }
    
        ds1302_rst_set(0);//停止传输
        ds1302_delay_us(1);
    }
    
    /**
    * @brief  设置芯片的时间
    * @param  tm
    * @param  model:0-普通模式  1-突发模式
    * @param  None
    * @retval None
    * @example
    * struct ds1302struct lcTime;
    * lcTime.tm_year = 2020;
    * lcTime.tm_mon = 1;
    * lcTime.tm_mday = 1;
    * lcTime.tm_hour = 12;
    * lcTime.tm_min = 10;
    * lcTime.tm_sec = 30;
    * ds1302_set_time(&lcTime,1);
    **/
    void ICACHE_FLASH_ATTR
    ds1302_set_time(struct ds1302struct *lcTime,char model){
        char temp[8];//突发模式下缓存数据
    //    char value,valueH,valueL;
    //因为芯片高四位存储十位,低四位存储个位
    //假设用户输入12  那么需要高位是 0001  低位是 0010   也就是0x12  然后存储到芯片中
    //    valueH = (lcTime->tm_year/10)<<4;
    //    valueL = lcTime->tm_year%10;
    //    value = valueH | valueL;
        if(model){//突发模式
            temp[0] = (lcTime->tm_sec/10)<<4|lcTime->tm_sec%10;        //
            temp[1] = (lcTime->tm_min/10)<<4|lcTime->tm_min%10;        //
            temp[2] = (lcTime->tm_hour/10)<<4|lcTime->tm_hour%10;    //
            temp[3] = (lcTime->tm_mday/10)<<4|lcTime->tm_mday%10;    //
            temp[4] = (lcTime->tm_mon/10)<<4|lcTime->tm_mon%10;        //
            temp[5] = (lcTime->tm_wday/10)<<4|lcTime->tm_wday%10;    //星期
            temp[6] = (lcTime->tm_year/10)<<4|lcTime->tm_year%10;    ////最后一位是写保护寄存器,全是0就可以,所以不需要设置
            ds1302_write_data_burst(temp);
        }
        else{
            ds1302_write_data(ds1302_control_add,ds1302_unlock,0);        //关闭写保护
            ds1302_write_data(ds1302_sec_add,ds1302_clkoff,0);            //暂停时钟
            //ds1302_write_data(ds1302_charger_add,ds1302_lv5);        //涓流充电
            ds1302_write_data(ds1302_year_add,(lcTime->tm_year/10)<<4|lcTime->tm_year%10,0);//
            ds1302_write_data(ds1302_month_add,(lcTime->tm_mon/10)<<4|lcTime->tm_mon%10,0);    //
            ds1302_write_data(ds1302_date_add,(lcTime->tm_mday/10)<<4|lcTime->tm_mday%10,0);//
            ds1302_write_data(ds1302_hr_add,(lcTime->tm_hour/10)<<4|lcTime->tm_hour%10,0);    //
            ds1302_write_data(ds1302_min_add,(lcTime->tm_min/10)<<4|lcTime->tm_min%10,0);    //
            ds1302_write_data(ds1302_sec_add,(lcTime->tm_sec/10)<<4|lcTime->tm_sec%10,0);    //
            ds1302_write_data(ds1302_day_add,(lcTime->tm_wday/10)<<4|lcTime->tm_wday%10,0);    //
            ds1302_write_data(ds1302_control_add,ds1302_lock,0);        //打开写保护
        }
    }
    
    
    /**
    * @brief  获取芯片的时间
    * @param  tm
    * @param  model:0-普通模式  1-突发模式
    * @param  None
    * @retval None
    * @example
    * struct ds1302struct lcTime;
    * ds1302_read_time(&lcTime,1);
    * int year = lcTime.tm_year;
    * int mon = lcTime.tm_mon;
    * int mday = lcTime.tm_mday;
    * char hour = lcTime.tm_hour;
    * char min = lcTime.tm_min;
    * char sec = lcTime.tm_sec;
    **/
    void ICACHE_FLASH_ATTR
    ds1302_read_time(struct ds1302struct *lcTime,char model){
        char temp[8];//突发模式下缓存数据
        char value,valueH,valueL;
        //提示:所有数据的高四位代表十位,低四位代表个位
        //有些数据的MSB最高位代表其它含义,请参见DS1302手册
    
        if(model){//突发模式
            ds1302_read_data_burst(temp);
            valueH = (temp[6]>>4)&0x0f;
            valueL = temp[6]&0x0f;
            lcTime->tm_year = valueH*10 + valueL;
    
            valueH = (temp[5]>>4)&0x0f;
            valueL = temp[5]&0x0f;
            lcTime->tm_wday = valueH*10 + valueL;
    
            valueH = (temp[4]>>4)&0x0f;
            valueL = temp[4]&0x0f;
            lcTime->tm_mon = valueH*10 + valueL;
    
            valueH = (temp[3]>>4)&0x0f;
            valueL = temp[3]&0x0f;
            lcTime->tm_mday = valueH*10 + valueL;
    
            valueH = (temp[2]>>4)&0x0f;
            valueL = temp[2]&0x0f;
            lcTime->tm_hour = valueH*10 + valueL;
    
            valueH = (temp[1]>>4)&0x0f;
            valueL = temp[1]&0x0f;
            lcTime->tm_min = valueH*10 + valueL;
    
            valueH = (temp[0]>>4)&0x0f;
            valueL = temp[0]&0x0f;
            lcTime->tm_sec = valueH*10 + valueL;
        }else{
            value = ds1302_read_data(ds1302_year_add,0);     //
            valueH = (value>>4)&0x0f;
            valueL = value&0x0f;
            lcTime->tm_year = valueH*10 + valueL;
    
            value = ds1302_read_data(ds1302_month_add,0);     //
            valueH = (value>>4)&0x0f;
            valueL = value&0x0f;
            lcTime->tm_mon = valueH*10 + valueL;
    
            value = ds1302_read_data(ds1302_date_add,0);     //
            valueH = (value>>4)&0x0f;
            valueL = value&0x0f;
            lcTime->tm_mday = valueH*10 + valueL;
    
            value = ds1302_read_data(ds1302_hr_add,0);         //
            valueH = (value>>4)&0x0f;
            valueL = value&0x0f;
            lcTime->tm_hour = valueH*10 + valueL;
    
            value = ds1302_read_data(ds1302_min_add,0);         //
            valueH = (value>>4)&0x0f;
            valueL = value&0x0f;
            lcTime->tm_min = valueH*10 + valueL;
    
            value = (ds1302_read_data(ds1302_sec_add,0))&0x7f;//秒,屏蔽秒的第7位,避免超出59
            valueH = (value>>4)&0x0f;
            valueL = value&0x0f;
            lcTime->tm_sec = valueH*10 + valueL;
    
            value = ds1302_read_data(ds1302_day_add,0);         //
            valueH = (value>>4)&0x0f;
            valueL = value&0x0f;
            lcTime->tm_wday = valueH*10 + valueL;
        }
    }
    /*
     * DS1302.h
     *
     *  Created on: 2020年12月23日
     *      Author: yang
     */
    
    #ifndef APP_INCLUDE_DRIVER_DS1302_H_
    #define APP_INCLUDE_DRIVER_DS1302_H_
    
    
    #ifndef DS1302_C_
    #define DS1302_Cx_ extern
    #else
    #define DS1302_Cx_
    #endif
    
    #include "c_types.h"
    
    //移植其它单片机,请修改下面的程序
    /*GPIO14 -- RST*/
    #define DS1302_RST_MUX PERIPHS_IO_MUX_MTMS_U
    #define DS1302_RST_GPIO 14
    #define DS1302_RST_FUNC FUNC_GPIO14
    /*GPIO12 -- DTA*/
    #define DS1302_DAT_MUX PERIPHS_IO_MUX_MTDI_U
    #define DS1302_DAT_GPIO 12
    #define DS1302_DAT_FUNC FUNC_GPIO12
    /*GPIO13 -- CLK*/
    #define DS1302_CLK_MUX PERIPHS_IO_MUX_MTCK_U
    #define DS1302_CLK_GPIO 13
    #define DS1302_CLK_FUNC FUNC_GPIO13
    
    
    //命令, 地址
    #define ds1302_sec_add            0x80        //秒数据地址
    #define ds1302_min_add            0x82        //分数据地址
    #define ds1302_hr_add            0x84        //时数据地址
    #define ds1302_date_add            0x86        //日数据地址
    #define ds1302_month_add        0x88        //月数据地址
    #define ds1302_day_add            0x8a        //星期数据地址
    #define ds1302_year_add            0x8c        //年数据地址
    #define ds1302_control_add        0x8e        //控制数据地址
    #define ds1302_charger_add        0x90        //充电寄存区
    #define ds1302_burstwr_add        0xbe        //突发模式写数据
    #define ds1302_burstre_add        0xbf        //突发模式读数据
    #define ds1302_ram_add            0xc0        //RAM地址
    //配置
    #define ds1302_clkoff        0x80        //暂停时钟
    #define ds1302_lock            0x80        //打开写保护
    #define ds1302_unlock        0x00        //关闭写保护
    #define ds1302_lv6            0xa5        //0.7v压降,2K阻值,2.15ma
    #define ds1302_lv5            0xa9        //1.4v压降,2K阻值,1.80ma
    #define ds1302_lv4            0xa6        //0.7v压降,4K阻值,1.07ma
    #define ds1302_lv3            0xaa        //1.7v压降,4K阻值,0.90ma
    #define ds1302_lv2            0xa7        //0.7v压降,8K阻值,0.50ma
    
    struct ds1302struct
    {
      int    tm_sec;//
      int    tm_min;//
      int    tm_hour;//
      int    tm_mday;//
      int    tm_mon;//
      int    tm_year;//
      int    tm_wday;//星期
    };
    
    
    //初始化引脚,移植其它单片机请替换内部函数
    void ds1302_gpio_init(void);
    //延时us,移植其它单片机请替换内部函数
    void ds1302_delay_us(char us);
    //设置时钟引脚输出高低电平,移植其它单片机请替换内部函数
    void ds1302_clk_set(char HL);
    //设置RST引脚输出高低电平,移植其它单片机请替换内部函数
    void ds1302_rst_set(char HL);
    //设置数据引脚输出高低电平,移植其它单片机请替换内部函数
    void ds1302_dat_set(char HL);
    //获取数据引脚的高低电平,移植其它单片机请替换内部函数
    char ds1302_dat_get();
    
    
    /**
    * @brief  写一个字节数据到芯片
    * @param  data:要写入的数据
    * @param  None
    * @param  None
    * @retval None
    * @example
    **/
    void ds1302_write_byte(char data);
    
    
    /**
    * @brief  读取一个字节数据
    * @param  None
    * @param  None
    * @param  None
    * @retval None
    * @example
    **/
    char ds1302_read_byte();
    
    
    /**
    * @brief  写数据到芯片
    * @param  addr:要写入的地址
    * @param  data:要写入的数据
    * @param  rc:1-操作内部RAM
    * @retval None
    * @example
    **/
    void ds1302_write_data(char addr,char data,char rc);
    
    
    /**
    * @brief  读取数据
    * @param  addr:读取的地址
    * @param  rc:1-操作内部RAM
    * @param  None
    * @retval None
    * @example
    **/
    char ds1302_read_data(char addr,char rc);
    
    
    /**
    * @brief  设置芯片的时间
    * @param  tm
    * @param  model:0-普通模式  1-突发模式
    * @param  None
    * @retval None
    * @example
    * struct ds1302struct lcTime;
    * lcTime.tm_year = 2020;
    * lcTime.tm_mon = 1;
    * lcTime.tm_mday = 1;
    * lcTime.tm_hour = 12;
    * lcTime.tm_min = 10;
    * lcTime.tm_sec = 30;
    * ds1302_set_time(&lcTime,1);
    **/
    void ds1302_set_time(struct ds1302struct *lcTime,char model);
    
    
    /**
    * @brief  获取芯片的时间
    * @param  tm
    * @param  model:0-普通模式  1-突发模式
    * @param  None
    * @retval None
    * @example
    * struct ds1302struct lcTime;
    * ds1302_read_time(&lcTime,1);
    * int year = lcTime.tm_year;
    * int mon = lcTime.tm_mon;
    * int mday = lcTime.tm_mday;
    * char hour = lcTime.tm_hour;
    * char min = lcTime.tm_min;
    * char sec = lcTime.tm_sec;
    **/
    void ds1302_read_time(struct ds1302struct *lcTime,char model);
    
    
    #endif /* APP_INCLUDE_DRIVER_DS1302_H_ */

    2.把程序文件拷贝到如下位置

    3.引脚连接定义

    4.设置时间

    system_init_done_cb(system_init_done);
    
    
    void ICACHE_FLASH_ATTR
    system_init_done(void)
    {
        struct ds1302struct lcTime;
    
        ds1302_gpio_init();//初始化引脚
    
        lcTime.tm_year = 20;//年(芯片只能存储两位 00-99,具体看手册)
        lcTime.tm_mon = 12;//
        lcTime.tm_mday = 23;//
        lcTime.tm_hour = 22;//
        lcTime.tm_min = 55;//
        lcTime.tm_sec = 5;//
        ds1302_set_time(&lcTime,1);
    }

    5.获取时间

    struct ds1302struct lcTime;
    
    ds1302_read_time(&lcTime,1);//获取时钟的时间
            //打印 年 月 日 时 分 秒
            os_printf("
    year=%d,mon=%d,mday=%d,hour=%d,min=%d,sec=%d
    ",
                    lcTime.tm_year,
                    lcTime.tm_mon,
                    lcTime.tm_mday,
                    lcTime.tm_hour,
                    lcTime.tm_min,
                    lcTime.tm_sec
                    );

    6.测试

    程序细节说明

    1.移植使用到其它单片机只需要修改头文件包含,和文件中指示的部分

    2.关于设置或读取时间的两种模式(普通和突发)

    注:突发模式解决的问题

    普通模式下是一个字节一个字节的去读取数据,假如我们当前的时间是 00:00:59,我们先读秒,读到的秒是 59,

    然后再去读分钟,而就在读完秒到还未开始读分钟的这段时间内,刚好时间进位了,变成了 00:01:00

    那么就读错了!结果咱读的就变成  00:01:59

    用户使用的时候建议使用突发模式就可以.

    3.关于BCD

    首先不要管什么BCD这个名词

    只要记住一句话:芯片寄存器的高4位记录的是十位,低4位记录的是个位

    假设想设置秒数为12秒

    那么应该设置为  0001  0010  也就是把0x12写到里面

    用数学公式转一下

    int sec = 12;   char sechex=0;

    sechex = (sec/10)<<4 | sec%10;   //sechex就是 0x12

    //解释:把这个数的十位取出来,然后放到高四位上去,然后加上余数 .

    0x12如何转成 12

    int sec = 0;   char sechex=0x12

    sec  = (sechex>>4)*10 + sechex&0x0F

    //解释:把这个数右移4位获取高四位的十进制数,然后乘以10,然后加上个位数.

    拓展知识<time.h>

    1.为啥要说这个

    时间戳是啥?UTC时间是啥?北京时间是怎么来的?单片机中时间戳和具体时间之间的转换怎么做?

    凡是涉及到时钟的最好知道上面的问题,否则做相关项目或者程序的时候你会差一截!

    2.时间戳

  • 相关阅读:
    只需 4 步,手把手教你如何实现滤镜功能
    paip.提升用户体验---c++ qt自定义窗体(1)---标题栏的绘制
    socket网络编程的一些基础知识
    图像处理、模式识别、模式分类、机器视觉推荐图书
    数据挖掘、机器学习和模式识别关系与区别
    Qt4_VS10 程序打包发布
    Qt之多线程
    QT中.pro文件的写法
    高斯定理的证明
    《Linear Algebra and Its Applications》-chaper3-行列式-行列式初等变换
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/14183540.html
Copyright © 2011-2022 走看看