1. 程式人生 > 實用技巧 >ESP8266 SDK開發: 外設篇-時鐘晶片DS1302使用和拓展知識<time.h>的使用

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可以聯網就不需要加時鐘,直接使用內部時鐘就可以了.(有備用電源的情況下)

我主要說明一下我封裝的檔案的使用和注意事項!

移植使用

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("\nyear=%d,mon=%d,mday=%d,hour=%d,min=%d,sec=%d\n",
                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("\nyear=%d,mon=%d,mday=%d,hour=%d,min=%d,sec=%d\n",
                lcTime.tm_year,
                lcTime.tm_mon,
                lcTime.tm_mday,
                lcTime.tm_hour,
                lcTime.tm_min,
                lcTime.tm_sec
                );

程式細節說明

1.移植使用到其它微控制器只需要修改標頭檔案包含,和檔案中指示的部分

2.關於設定或讀取時間的兩種模式(普通和突發)

注:突發模式解決的問題

普通模式下是一個位元組一個位元組的去讀取資料,假如我們當前的時間是 00:00:59,我們先讀秒,讀到的秒是 59,

然後再去讀分鐘,而就在讀完秒到還未開始讀分鐘的這段時間內,剛好時間進位了,變成了 00:01:00

那麼就讀錯了!結果咱讀的就變成 00:01:59

使用者使用的時候建議使用突發模式就可以.

拓展知識<time.h>

1.為啥要說這個

時間戳是啥?UTC時間是啥?北京時間是怎麼來的?微控制器中時間戳和具體時間之間的轉換怎麼做?

凡是涉及到時鐘的最好知道上面的問題,否則做相關專案或者程式的時候你會差一截!

2.時間戳