DS1302时钟 STM32移植
原来自己画板子做了一个点阵屏。现在想把它用来显示时间,于是就移植了这个DS1302,为什么不用DS3231,因为便宜,我有。我这个带网络校正时间的,所以精度要求不高,DS1302足够。
在移植的时候遇到了几个问题,首先是把STC8A的程序放带STM32里读不出来数据,一直 显示ff。考虑到是IO管脚即要输入又要输出。这个需要配置。
配置之后继续读发现可以读出来数据了,但是有的是对的,有的是错的。也就是说数据乱码的,首先考虑的是时序的问题,再三检查之后确定程序没问题。最后发现是配置输入输出的时候的问题。
读不出来数据即读出来是0xff ?
答: 配置输入输出模式。
void DS1302_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个设置IO的结构体
RCC_APB2PeriphClockCmd(DS1302_Port_RCC,ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //准备设置PB4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //上拉输入,默认状态是高电平
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//管脚的速度
GPIO_Init(GPIOB, &GPIO_InitStructure); //设置PB4
}
}
void DS1302_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个设置IO的结构体
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(DS1302_Port_RCC,ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //准备设置PB4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入,默认状态是高电平
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//管脚的速度
GPIO_Init(GPIOB, &GPIO_InitStructure); //设置PB4
}
}
这是一种配置方法,还有一种是寄存器配置,更简单。
#define DS1302_DAT_INPUT() {GPIOB->CRL&= 0X0FFFFFFF;GPIOB->CRL|= 0x80000000;} //输入
#define DS1302_DAT_OUTPUT() {GPIOB->CRL&= 0X0FFFFFFF;GPIOB->CRL|= 0x30000000;} //输出
读出来的数据是1S正确1S错误?
答: 这种情况我百度搜的说是要把三个引脚各加1个10K的上拉电阻,我用面包板接上之后发现没有变化,最后发现在管脚初始化的时候要配置为开漏(GPIO_Mode_Out_OD)。 我是只在IO这个管脚接一个10K电阻,然后配置为开漏模式,而不是原来的推挽。
现在读出来数据正常。
贴几张图片。
下面给出代码:
DS1302.h
#ifndef DS1302
#define DS1302
#define DS1302_Port_RCC RCC_APB2Periph_GPIOB //时钟
#define DS1302_PIN GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9 //引脚
#define DS1302_PORT GPIOB //端口
#define DS1302_IO_IN_STA GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7) //PB9控制KEY1,读取电平状态,可以判断KEY1是否按下
#define DS1302_DAT_INPUT() {GPIOB->CRL&= 0X0FFFFFFF;GPIOB->CRL|= 0x80000000;} //输入
#define DS1302_DAT_OUTPUT() {GPIOB->CRL&= 0X0FFFFFFF;GPIOB->CRL|= 0x30000000;} //输出
#define DS1302_IO PBout(7) // 数据线
#define DS1302_CE PBout(8) // 片选
#define DS1302_SCLK PBout(9) // 时钟
extern uchar DS1302_Time_Buffer[7];//存放时间的数组
void DS1302_Init(void);//初始化
void DS1302_Read_Time(void);//读取时间
void DS1302_Modify_Time(void); // 修改时间写到寄存器中
//void DS1302_Time_Stop();//暂停时间
//void DS1302_Time_Start();//开始时间
//uchar DS1302_Read_Data(uchar addr);
//void DS1302_Modify_Time();
#endif
DS1302.c
#include<All.h>
uchar Write_Addr_Buffer[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};//写入地址
uchar Read_Addr_Buffer[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};//读取地址
uchar DS1302_Time_Buffer[7]={00,0x00,0x16,0x01,0x09,0x02,0x20};//秒,分,时,日,月,周,年
void DS1302_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个设置IO的结构体
RCC_APB2PeriphClockCmd(DS1302_Port_RCC,ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //准备设置PB4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //上拉输入,默认状态是高电平
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//管脚的速度
GPIO_Init(GPIOB, &GPIO_InitStructure); //设置PB4
}
void DS1302_Gpio_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(DS1302_Port_RCC,ENABLE);//系统时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; //定义管脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//管脚输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//管脚的速度
GPIO_Init(DS1302_PORT,&GPIO_InitStructure); //初始化端口
//DS1302_DAT_OUTPUT();
DS1302_IO_OUT();
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //定义管脚
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//管脚输出模式
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//管脚的速度
// GPIO_Init(DS1302_PORT,&GPIO_InitStructure); //初始化端口
}
void DS1302_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个设置IO的结构体
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(DS1302_Port_RCC,ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //准备设置PB4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入,默认状态是高电平
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//管脚的速度
GPIO_Init(GPIOB, &GPIO_InitStructure); //设置PB4
}
/*********************************
* @函数名:DS1302_Write_Reg
* @描 述:写数据命令
* @说 明:
* @参 数:addr 要写入的寄存器的地址 dat 要写入的数据
* @返回值:无
*********************************/
void DS1302_Write_Reg(uchar addr,uchar dat)
{
uchar i;
DS1302_CE=0;
delay_us(20);
DS1302_SCLK=0;
DS1302_CE=1;
for(i=0;i<8;i++)
{
// DS1302_IO=addr&0x01;//先发送低位
if(addr&0x01)
DS1302_IO = 1;
else
DS1302_IO =0;
addr>>=1;
DS1302_SCLK=1;//上升沿读取数据
delay_us(20);
DS1302_SCLK=0;
delay_us(20);
}
for(i=0;i<8;i++)
{
// DS1302_IO=dat&0x01;//先发送低位
if(dat&0x01)
DS1302_IO = 1;
else
DS1302_IO =0;
dat>>=1;
DS1302_SCLK=1;//上升沿读取数据
delay_us(20);
DS1302_SCLK=0;
delay_us(20);
}
DS1302_SCLK=1;//上升沿读取数据
delay_us(20);
delay_us(20);
DS1302_CE=0;
delay_us(20);
}
/*********************************
* @函数名:DS1302_Read_Data
* @描 述:读数据
* @说 明:
* @参 数:addr 要读出的寄存器的地址
* @返回值:dat 读出的数据
*********************************/
uchar DS1302_Read_Data(uchar addr)
{
uchar i;
uchar dat1,dat;
DS1302_CE=0;
delay_us(20);
DS1302_SCLK=0;
DS1302_CE=1;
for(i=0;i<8;i++)
{
// DS1302_IO=addr&0x01;//先发送低位
if(addr&0x01)
DS1302_IO = 1;
else
DS1302_IO =0;
addr>>=1;
DS1302_SCLK=1;//上升沿读取数据
delay_us(20);
DS1302_SCLK=0;
delay_us(20);
}
DS1302_IO_IN(); // 切换为输入模式
//DS1302_DAT_INPUT();
for(i=0;i<8;i++)
{
dat1=DS1302_IO_IN_STA;
// if(DS1302_IO_IN_STA == 1)
// dat1 = 1;
// else
// dat1 = 0;
dat=(dat>>1)|(dat1<<7);
DS1302_SCLK=1;//上升沿读取数据
delay_us(20);
DS1302_SCLK=0;
delay_us(20);
}
DS1302_SCLK=1;//上升沿读取数据
delay_us(20);
//DS1302_DAT_OUTPUT(); // 切换为输出模式
DS1302_IO_OUT();
delay_us(20);
DS1302_CE=0;
delay_us(20);
DS1302_IO=0;//不能少
return dat;
}
/*********************************
* @函数名:DS1302_Init
* @描 述:初始化
* @说 明: 修改时间也可以用这个 掉电走时特别奇怪(有疑问)
* @参 数:无
* @返回值:无
*********************************/
void DS1302_Init(void)
{
uchar i;
uchar dat; //读取第一个RAM的值
DS1302_Gpio_Init(); // 管脚初始化
//掉电走时处理
dat = DS1302_Read_Data (0xc1); //读第一个RAM寄存器
u1_printf("读出来的值是%x\r\n", dat);
if(dat != 0xaa) //如果这个寄存器不是0xaa 要初始化
{
u1_printf("进图\r\n");
/*初始化时间时 dat != 0xaa 掉电走时 dat == 0xaa*/
DS1302_Write_Reg(0x8e,0x00);//允许写 wp = 0
DS1302_Write_Reg(0xc0,0xaa); //往第一个RAM写入0xaa
for(i=0;i<7;i++) //初始化
{
DS1302_Write_Reg(Write_Addr_Buffer[i],DS1302_Time_Buffer[i]); //写入初始化时间
}
DS1302_Write_Reg(0x8e,0x80);//写保护 wp = 1
}
//else 不初始化
}
/*********************************
* @函数名:DS1302_Read_Time
* @描 述:读出寄存器的时间
* @说 明:
* @参 数:无
* @返回值:无
*********************************/
void DS1302_Read_Time()
{
uchar i;
for(i=0;i<7;i++)
{
DS1302_Time_Buffer[i]=DS1302_Read_Data(Read_Addr_Buffer[i]);//读出时间
}
//处理 不计算秒的最高位
DS1302_Time_Buffer[0] &= 0x7f; //把最高位置0
}
/*********************************
* @函数名:DS1302_Modify_Time
* @描 述:修改寄存器中的时间
* @说 明:
* @参 数:
* @返回值:无
*********************************/
void DS1302_Modify_Time(void)
{
uchar i;
DS1302_Write_Reg(0x8e,0x00);//允许写
for(i=0;i<7;i++)
{
DS1302_Write_Reg(Write_Addr_Buffer[i],DS1302_Time_Buffer[i]);
}
DS1302_Write_Reg(0x8e,0x80);//写保护
}
/*********************************
* @函数名:DS1302_Time_Stop
* @描 述:时间暂停
* @说 明:秒寄存器的最高位CH 置1 时钟振荡器暂停 置0 时钟开始
* @参 数:无
* @返回值:无
*********************************/
void DS1302_Time_Stop()
{
uchar Second;//定义一个变量获取秒的数据
Second=DS1302_Read_Data(0x81);//取出秒的时间
Second |= 0x80; //把最高位置1 其他的都保持不变
DS1302_Write_Reg(0x8e,0x00);//允许写
DS1302_Write_Reg(0x80,Second);//秒暂停位 保持暂停的时间秒不变
DS1302_Write_Reg(0x8e,0x80);//禁止写
}
/*********************************
* @函数名:DS1302_Time_Start
* @描 述:开始计时
* @说 明:秒寄存器的最高位CH 置1 时钟振荡器暂停 置0 时钟开始
* @参 数:无
* @返回值:无
*********************************/
void DS1302_Time_Start()
{
uchar Second;//定义一个变量获取秒的数据
Second=DS1302_Read_Data(0x81);//取出秒的时间
Second &= 0x7f; //把最高位置0 其他的都保持不变
DS1302_Write_Reg(0x8e,0x00);//允许写
DS1302_Write_Reg(0x80,Second);//开始计时//second 还是原来的值
DS1302_Write_Reg(0x8e,0x80);//禁止写
}
就写到这吧,实在没啥文采。
快开学了,加油。