tag 标签: ds1302

相关博文
  • 热度 4
    2023-1-11 12:36
    2200 次阅读|
    0 个评论
    【MC3172】MC3172驱动DS1302时钟设计 前言 距离上一次评测MC3172已经过去一段时间。当时本来打算着手实现MC3172驱动DS1302时钟模块实现电子钟。当时由于疫情以及其他事情。导致没能写出驱动功能。现发布这篇博客将DS1302时钟驱动代码补档。 1实现原理 如何实现配置内核定时器编写延时函数以及根据官方串口例程修改成输出需要的显示轮询打印时间的功能已经在我的上一篇博客“ 原创 【MC3172】基于MC3172串口打印的计时器设计 ”中有提到。如果不会这一部分配置的。感兴趣的也可以参考博客中的配置讲解。里面也有我配置好的代码包可供大家下载使用。 接下来我主要讲解DS1302时钟的驱动原理。 这里我先说一下我的整体思路。因为MC3172这款芯片是新研发的芯片。相对来说驱动一些外设的资料比较少。所以我们在使用芯片写其他功能的时候就需要参考其他资源多的开发板的驱动程序。将其中的细节研究清楚。并把相关代码修改成MC3172可以使用的代码。就是整个配置流程。不过这需要对单片机功能的细节把控清楚。最终才能保证不出现代码错误的情况下。保证原理正确即可调通结果。 这张图是DS1302时钟时序图。我已经将关键电平时间做了相关标注。被标注的时间是我们可以控制的时间。这一部分时间最好在逻辑分析仪下具体观察每一小段电平时间是否严格符合时序图规定。 比如。 Tcc 这一段时间是 1us 。就表示在 SCLK 的上升沿到来之前。我们至少需要在 RST 拉高后延时 1us 的时间。 其他的标注地方的理解也同理。 时序图还有个关键部分。就是数据线IO除了我们发送数据。还需要从DS1302读回数据。这样就涉及到一个IO切换问题(由读转换为写或者写转换为读)。以及如何确定我们稳定读取到了DS1302时钟芯片返回的数据(有可能我们写时序有误而接收不到返回数据。或者我们读数据时给的时间太少。导致数据不稳定没有读取到)。这两个问题至关重要。也是我之前所说的细节问题。不同的单片机实际上我认为差别就在这些小功能的细节上。而MC3172的IO功能。读写功能互斥。启动一个不能启动另一个。就需要我们把读功能打开并关闭写功能。然后去读数据。读完数据后如果需要写。就需要把写功能打开并关闭读功能。相关代码如下 SDA_SET_READ_EN; SDA_SET_WRITE_UEN; for(i = 0; i < 8; i++) //读数据都是先移动再读取 { SCL_L; //时序图上可以看出下降沿后开始数据稳定可以读数据 = 1; delay_us(3); 3) { dat |= 0x80; } SCL_H; delay_us(3); } SDA_SET_WRITE_EN; SDA_SET_READ_UEN; 这里我只贴了部分细节 。通过 SDA_SET_READ_EN ; 宏定义使能读。 SDA_SET_WRITE_EN ; 宏定义使能写 。第二个读数据稳定就体现在了 dat = 1; 这一句后面的延时。这里就是给读取数据的一个时间。因此这里的读取为保证数据稳定。推荐稍长的时间。 5~ 10 us 均可 。 下面贴出 DS 1302 驱动各部分编写的函数 //写一字节函数 void Write_Byte(u8 address) { u8 i; for(i = 0; i < 8; i++) { SCL_L; if(address & 0x01) { SDA_H; } else { SDA_L; } = 1; SCL_H; delay_us(1); } } //指定地址address写数据dat函数 void DS1302_WriteByte(u8 address, u8 dat) { // u8 i; RST_L; // NOP(); SCL_L; // NOP(); RST_H; NOP();NOP();NOP(); NOP();NOP();NOP(); Write_Byte(address); Write_Byte(((dat / 10) << 4) | (dat % 10)); // dat = ((dat / 10) << 4) | (dat % 10); } //指定地址读取数据函数 u8 DS1302_ReadByte(u8 address) { u8 dat, i, dat1, dat2; u16 dat_get = 0; RST_L; // NOP(); SCL_L; // NOP(); RST_H; NOP();NOP();NOP(); NOP();NOP();NOP(); Write_Byte(address); // _nop_();_nop_();_nop_(); // _nop_();_nop_();_nop_(); SDA_SET_READ_EN; SDA_SET_WRITE_UEN; for(i = 0; i < 8; i++) //读数据都是先移动再读取 { SCL_L; //时序图上可以看出下降沿后开始数据稳定可以读数据 = 1; delay_us(3); 3) { dat |= 0x80; } SCL_H; delay_us(3); } SDA_SET_WRITE_EN; SDA_SET_READ_UEN; SDA_L; //为了输出的稳定SDA要置0 // dat = dat - 6; //BCD码减去6得到bcd码de十进制数值下的十六进制表示。 dat1 = dat / 16; dat2 = dat % 16; dat = dat1 * 10 + dat2; return dat; } //DS1302初始化 void DS1302_init() { u8 i, add; add = 0x80; DS1302_WriteByte(0x8E, 0x00); for(i = 0; i < 7; i++) { DS1302_WriteByte(add, init ); add += 2; } DS1302_WriteByte(0x8E, 0x80); } //DS1302时间获取 void DS1302_Get() { u8 i, add; add = 0x81; DS1302_WriteByte(0x8E, 0x00); //清除保护 for(i = 0; i < 3; i++) { time = DS1302_ReadByte(add); //写入时是秒分时往里写读的时候是时分秒外读 add += 2; } DS1302_WriteByte(0x8E, 0x80); } IO 引脚宏定义 #include "../MC3172/MC3172.h" #include "./GPIO_GPCOM_TIMER_Example.c" #define SYS_CORE_CLK_MHZ 48 //PD1 CLK SCL PD3 DAT SDA PD5 RST CE #define SCL_H GPIO_SET_OUTPUT_PIN_TO_1(GPIOD_BASE_ADDR ,GPIO_PIN1) #define SCL_L GPIO_SET_OUTPUT_PIN_TO_0(GPIOD_BASE_ADDR ,GPIO_PIN1) #define SDA_H GPIO_SET_OUTPUT_PIN_TO_1(GPIOD_BASE_ADDR ,GPIO_PIN3) #define SDA_L GPIO_SET_OUTPUT_PIN_TO_0(GPIOD_BASE_ADDR ,GPIO_PIN3) #define RST_H GPIO_SET_OUTPUT_PIN_TO_1(GPIOD_BASE_ADDR ,GPIO_PIN5) #define RST_L GPIO_SET_OUTPUT_PIN_TO_0(GPIOD_BASE_ADDR ,GPIO_PIN5) #define SDA_SET_READ_EN GPIO_SET_INPUT_EN_VALUE(GPIOD_BASE_ADDR ,GPIO_PIN3,GPIO_SET_ENABLE) //读使能 #define SDA_SET_READ_UEN GPIO_SET_INPUT_EN_VALUE(GPIOD_BASE_ADDR ,GPIO_PIN3,GPIO_SET_DISABLE) //读失能 #define SDA_SET_WRITE_EN GPIO_SET_OUTPUT_EN_VALUE(GPIOD_BASE_ADDR ,GPIO_PIN3,GPIO_SET_ENABLE) //写使能 #define SDA_SET_WRITE_UEN GPIO_SET_OUTPUT_EN_VALUE(GPIOD_BASE_ADDR ,GPIO_PIN3,GPIO_SET_DISABLE) //写失能 #define SDA_READ_FAST GPIO_GET_INPUT_VALUE_FAST(GPIOD_BASE_ADDR) #define SDA_READ GPIO_GET_INPUT_VALUE_SAFE(GPIOD_BASE_ADDR) //#define SDA_SET_PULLDOWN GPIO_SET_PULL_DOWN_VALUE(GPIOD_BASE_ADDR,GPIO_PIN3,0x00000008) u8 init ; 2主体功能及展示。 主要功能就是在屏幕上显示Real_Time:23:24:13。这样的格式打印的时间。具体内容我将通过视频演示 开发板接线实物图如下所示 PB3是板子TX。接串口模块的RXD。PB2是RX接串口模块的TX。然后PD1到PD3依次接DS1302的时钟线CLK。数据线DAT。复位端RST。 这里由于核心板的电源没有多余排针引出。因此我用了一块废板的共脚排针。通过共脚排针为DS1302供电。 3之后计划做的事。 研究一下这个板子的线程通信方法以及如何像带有中断的单片机一样利用定时器计时。这样之后可以借此移植其他板子的超声波测距函数。这块板子总体来说很不错。我希望大家也多多支持感芯科技。
  • 热度 24
    2013-12-30 09:38
    1656 次阅读|
    0 个评论
    将DS1302时钟走时更准确的方法   用DS1302制作电子时钟,由于32678K的晶振误差原因造成时钟走时不准确,大家使用的晶振精度都不高,每天误差都差6到10秒,如果购买高精度的晶振价格又非常高,不如用单片机的计时器编程走时更准确,可以进行误差调整,本人作了几个用DS1302时钟,由于32678K晶振的原因,每天都快6-9秒之间,原来用的方法是每天自动校一次,由于每天的误差不是整数,比如每天快7.6秒,这样每天就得自动校8秒,又造成每天慢0.4秒,每月误差又是12秒,走时还是不准确,本人改成了每差1秒校正一次的方法,原理是:比如每天快7.6秒,24*60/7.6=189,也就是189分钟快1秒,每189分钟就自动校一次时钟,这样校时理论上每年的误差最大不到6秒,本人的时钟4个月误差不到1秒,属于相当准确喽,现在提供给大家分享。 设计原理是: 由于程序的大小和原理不同,每分钟读取DS1302的次数也不同,这样先设置二个变量,一个是分钟比较变量,用于判断分钟不等相等时计数器变量加1,另一个是校时计数变量,用于校时时间计数,当计数器变量等于189时,DS1302自动修正一次,程序如下:  代码: 变量设置 BJBL DATA 20H ;分钟比较变量,用于判断分钟不等相等时计数器加1 JSBL DATA 21H ;校时计数变量,用于校时时间计数 MOV BJBL,#00H MOV JSBL,#00H 自动校时子程序 AUTOXS: MOV A,MIN CJNE A,BJBL,AS1 JMP AS2 AS1: MOV BJBL,A MOV A,JSBL INC A MOV JSBL,A AS2: MOV A,JSBL CJNE A,#0D3H,AS5 MOV A,SEC CJNE A,#01H,AS5 ;秒等于1时校回到0秒 MOV R1,#8EH ;写保护寄存器 MOV R0,#00H ;允许写入 LCALL WRITE ;调用写DS1302程序 MOV R1,#80H ;写秒寄存器 MOV R0,#00H ;启动振荡器工作 LCALL WRITE ;调用写DS1302程序 MOV R1,#8EH ;写保护寄存器 MOV R0,#80H ;禁止写入 LCALL WRITE ;调用写DS1302程序 MOV JSBL,#00H AS5: RET 将此子程序在每次读取DS1302时调用   参考网上自动校时的程序,按照他的思路重新写了一个,目前能用了,现在正在测试中。 思路是这样的:首先参照标准时间,让时钟运行24小时,看看24小时内秒运行误差,我的是快2秒左右。按照24*60/2=720进行计算,得到结果是每720分钟快1秒,也就是只要每720分钟后,时钟再走1秒后,重新向1302秒寄存器写入00即可,就能达到每720分钟减1秒效果   #define CHECHPERIOD 720 #define MINUTE_ADDRESS 0x80; #define SECOND_ADDRESS 0x82;   unsigned int bjminute = 0; //比较变量,用于判断分钟不相等时计数器加1 unsigned int jscount = 0; //校时计数变量,用于校时时间计数 void AutoCheckTime(void) { unsigned char minute = 0; unsigned char second = 0;   minute = readDS1302(MINUTE_ADDRESS);   if(minute != bjminute) { bjminute = minute;   jscount = jscount +1; } else  { if( jsbl == CHECHPERIOD) { second = readDS1302(SECOND_ADDRESS); if(second == 0x01)//秒等于1时,写秒值0 { WriteDS1302(0x00,SECOND_ADDRESS); jscount = 0; } } }   使用EPSON 的RS8025  就可以解决这个问题了,内部集成晶振; 几块钱就解决问题; 再不行就用GPS校时 也就100块钱多一点的价位吧。到淘宝上搜“5680A”,大把的是,这个东西是最便宜最容易买到的铷原子钟模块了,10MHz标准频率输出,呵呵,如果用来做时钟的话,你用到它报废,误差也不会到一秒钟的
  • 热度 26
    2013-4-22 13:05
    8443 次阅读|
    0 个评论
    DS1302时钟走时不准、单片机调晶振频率 wxleasyland 2013.4.22   STC单片机STC12C5160S2+11.0592MHZ晶振+DS1302时钟芯片   一、 DS1302 不准   买了DS1302模块小板,用它来走时,发现配的32768晶振不准,走得偏快,可能是CL=12.5PF的。   再买CL=6PF的32768晶振,装上,还是很不准,走得偏快。可能晶振是假6pf的。CL=6PF的32768晶振很难买,早知道就买DS1307了,这个是配12.5PF晶振的。   折腾不起了,放弃32768晶振的想法,用板上的11.0592MHZ晶振来走时,并每小时更新一次DS1302的时间(在30分钟时更新,以免走日期不准)。这样可以校正11.0592MHZ晶振来使走时达到1PPM,而且频率容易测量。 而DS1302没有测试频率输出,测频率很困难,要校到1PPM有难度!!   二、校正单片机晶振频率   对单片机11.0592MHZ晶振的振荡电容进行校正。   表笔有电容,如果直接接在XTAL2或XTAL1上,则频率影响很大,测出的频率降低了很多。   牺牲一个“与门”芯片74HC00接在XTAL2上,串二级“与门”,以便测晶振频率。 如果只串一级“与门”,表笔测一级“与门”输出口的频率时,发现频率也是有点影响,降低了一点点。串二级“与门”,影响就很小了,可以接受。 发现,测得二级“与门”输出口的频率与测得单片机分频出来的频率换算后是一致的!!! 所以可以根据单片机分频出来(比如对端口的翻转)的频率,来反映晶振振荡频率。 STC单片机是1T的,比较快,而且端口可以设成定时器脉冲输出,很方便测量频率。   测出晶振频率偏大40~50PPM,增加电容并联在XTAL2对地的电容上,频率减少了,最后能调到1PPM左右。
  • 热度 23
    2013-4-22 13:04
    9327 次阅读|
    1 个评论
    DS1302时钟芯片单片机通讯不上的原因-上拉电阻很重要 wxleasyland 2013.4.22   STC单片机STC12C5160S2+11.0592MHZ晶振+DS1302时钟芯片 经实验: DS1302的数据脚是双向的,一定要接10K上拉电阻,不能只用单片机弱上拉,不然双向通讯不成功,可能是因为弱上拉时端口电平翻转慢,造成读数不准。 RST脚和CLK脚是单向的,可以不用接上拉电阻,单片机弱上拉是可以的。 所以通讯时,上拉电阻很重要,一定要配上。
  • 热度 38
    2012-12-11 14:54
    6163 次阅读|
    11 个评论
    这几天用proteus做了一个定时/计时器。 把它贴出来,想要程序源码的给我发e-mail 2007年11月18日   updata 程序下载页面。 http://blog.ednchina.com/emot/75928/message.aspx
相关资源