DS1302时钟STM32移植

tech2022-07-14  175

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);//禁止写 }

就写到这吧,实在没啥文采。 快开学了,加油。

最新回复(0)