STM32F103ZET6对DS12C887+时间模块的驱动
对于项目的一个小模块部分,如果因为驱动程序的问题而半天不能正常操作,这样的事还是挺令人抓狂的,在此整理出DS12C887+时间模块的驱动程序,属于大家的参考,也属于自己的积累。
DS12C887+的基本功能大家应该都了解,不太了解的可以百度下,这里就根据手册附上一些特别有用的内容哈!
在EDIP封装的引脚图上有6个悬空引脚,在实际的芯片上这些引脚也都是没有的。
首先是头文件:
#ifndef __DS12C887_H
#define __DS12C887_H
#include "sys.h"
/************************************
AD0-AD7——>PF0-PF7
IRQ——>PE0 中断中断请求输出,低电平有效
CS——>PE1
AS——>PE2
RW——>PE3
DS——>PE4
SQW 方波输出
MOT 总线时序选择,接地,1:Motorola模式,0:Intel模式。
RST 复位脚,接VCC
************************************/
#define DS12C887_CS PEout(1) //片选
#define DS12C887_AS PEout(2) //上升沿锁存,下降沿清除
#define DS12C887_RW PEout(3) //1读,0写
#define DS12C887_DS PEout(4) //读允许位
//PF0~7作为数据线
#define DS12C887_DATAOUT(x) GPIO_Write(GPIOF,x);//数据输出
#define DS12C887_DATAIN GPIO_ReadInputData(GPIOF)&0x00ff;//数据输入
//IO方向设置
#define DS12C887_DATE_IN() {GPIOF->CRL&=0xf00000000;GPIOF->CRL|=0x88888888;GPIOF->ODR|=0xff;} //上拉输入
#define DS12C887_DATE_OUT() {GPIOF->CRL&=0xf00000000;GPIOF->CRL|=0x33333333;} //推挽输出
void Write_DS12C887(u8 add,u8 date);//写数据
u8 Read_DS12C887(u8 add); //读数据
void Read_DS12C887Date(u8 *temp0); //读时间
void DS12C887_Init(void); //初始化
#endif
除了VCC和GND接到电源外,通常MOT接地选用Motorola操作模式,RST复位脚接VCC。
接下来是源代码:
#include "ds12c887.h"
#include "delay.h"
void Write_DS12C887(u8 add,u8 date)
{
DS12C887_CS=0;
DS12C887_AS=1;
DS12C887_DS=1;
DS12C887_RW=1;
DS12C887_DATE_OUT();
DS12C887_DATAOUT(add);
delay_us(100);
DS12C887_AS=0;
DS12C887_RW=0;
DS12C887_DATAOUT(date);
delay_us(100);
DS12C887_RW=1;
DS12C887_AS=1;
DS12C887_CS=1;
}
u8 Read_DS12C887(u8 add)
{
u8 DS12C887_DATE;
DS12C887_AS=1;
DS12C887_DS=1;
DS12C887_RW=1;
DS12C887_CS=0;
DS12C887_DATE_OUT();
DS12C887_DATAOUT(add);
delay_us(100);
DS12C887_AS=0;
DS12C887_DS=0;
DS12C887_DATAOUT(0xff);
DS12C887_DATE_IN();
DS12C887_DATE=DS12C887_DATAIN;
DS12C887_DS=1;
DS12C887_AS=1;
DS12C887_CS=1;
return DS12C887_DATE;
}
//写入一个7字节数组,年/月/日/星期/时/分/秒
void Read_DS12C887Date(u8 *temp0)
{
*temp0=Read_DS12C887(9); //年
*(temp0+1)=Read_DS12C887(8); //月
*(temp0+2)=Read_DS12C887(7); //日
*(temp0+3)=Read_DS12C887(6); //星期
*(temp0+4)=Read_DS12C887(4); //时
*(temp0+5)=Read_DS12C887(2); //分
*(temp0+6)=Read_DS12C887(0); //秒
}
void DS12C887_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOF, ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOE,&GPIO_InitStruct);
GPIO_SetBits(GPIOE,0x78|GPIO_ReadOutputData(GPIOE));//控制脚初始化,置1
GPIO_InitStruct.GPIO_Pin=0xff;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOF,&GPIO_InitStruct);
GPIO_SetBits(GPIOF,0xff);
Write_DS12C887(0x0a,0x20);//打开振荡器
Write_DS12C887(0x0b,0x26);//设置24小时模式,数据为二进制,开启闹铃
// Write_DS12C887(0,xxx); //秒
// Write_DS12C887(2,xxx); //分
// Write_DS12C887(4,xxx); //小时
// Write_DS12C887(6,xxx); //星期
// Write_DS12C887(7,xxx); //日
// Write_DS12C887(8,xxx); //月
// Write_DS12C887(9,xxx); //年
// Write_DS12C887(1,xxx); //秒闹钟
// Write_DS12C887(3,xxx); //分闹钟
// Write_DS12C887(5,xxx); //小时闹钟
}
源代码中的“xxx”为自己设定的值,可根据自己的情况来修改。当数据设置为二进制模式时,寄存器表如下:
如想要设置脉冲输出,可对应下表来选择输出的频率:
如输出8192Hz的方波:
Write_DS12C887(0x0b,0x2e); //设置方波输出,SQWE位置高,
Write_DS12C887(0x0a,0x23); //频率8192Hz,设置频率。
当然,还可以设置两个DS12C887+同时进行方波输出,可以看下它们的输出时钟精度。
0s处:
0.5s处:
1s处:
约错开了四分之一个周期,则1秒约错开了0.03ms。