这是电路图,用了3个595驱动两个4位共阴数码管,按键、蜂鸣器、指示灯都忘记画了
#define DS1302_SCK_PIN GPIO_Pin_7 //ds1302sck
#define DS1302_IO_PIN GPIO_Pin_6 //ds1302io
#define DS1302_CE_PIN GPIO_Pin_5 //ce
#define KEY1 GPIO_Pin_15 //按键
#define KEY2 GPIO_Pin_14
#define KEY3 GPIO_Pin_13
#define KEY4 GPIO_Pin_12
#define DEEP GPIO_Pin_11//蜂鸣器
#define LIGHT GPIO_Pin_8//指示灯
这些是代码里引脚的IO定义
做好的效果,还有些BUG,需要完善
功能有显示时间 时分秒 年月日 周
修改时间(星期是通过算法算出来的)
闹钟
单片机源程序如下:
- #include "stm32f10x.h" //STM32头文件
- #include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "flash.h"
- #define FLASH_START_ADDR 0x0801f000 //写入的起始地址
- //READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};//读取时间的命令地址,已经通过读写操作来直接实现这些地址
- //WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};//写时间的命令地址
- my_time TIME = {0}; //显示时间的结构体
- u8 smgduan[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
- u8 nz[2]={8,20};
- u8 b=0,c=0x00,d=0x00;
- u8 k1=0,k4=0,w=4,num=0;
- u8 key1,key4;
- u16 j,i,a;
- //---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---////---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---//
- u8 init_time[] = {0,0X18,0x20,0x25,0x11,0x07,0x18}; //初始化时间:秒 分 时 日 月 周 年
- u8 write[]= {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};//写秒void display_real_time(void);
- u8 setime[7];
- u8 timedata[8];
- u8 weixian[8]={0x10,0x20,0x40,0x80,0x01,0x02,0x04,0x08};
- static void ds1302_gpio_init(void);
- static void ds1302_writebyte(u8 byte_1);//写一个字节; byte是保留字,不能作为变量
- static void ds1302_writedata(u8 addr,u8 data_);//给某地址写数据,data是c51内部的关键字,表示将变量定义在数据存储区,故此处用data_;
- static u8 ds1302_readbyte(void);//读一个字节
- static u8 ds1302_readdata(u8 addr);//读取某寄存器数据;
- static void DS1302_delay_us(u16 time); //简单延时1us
- void changetime(void);//改变显示内容
- char switchkey1(void);//判断KEY1按下的时间
- char switchkey4(void);//判断KEY4按下的时间
- void shiftout(u8 num);//595函数
- void putOut(char a,char b,char c);//595函数2
- void setimeput1(char w);//日期显示
- void setimeput(char w);//SETMODE 显示
- void setimes(void);//设置时间函数
- void clok(void); //闹钟
- void nzs(u8 a);//闹钟开关
- void fs(char w);
- int main()
- {
- ds1302_gpio_init();
- //USART1_Init(115200);
- //DS1302_Init();
- while(1)
- {
- //while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1));
- //while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY4));
- key1=0;
- key4=0;
- d=0xff;
- c=0xff;
- a=FLASH_R(FLASH_START_ADDR);//从指定页的地址读FLASH
- b=a&1;
- key1=switchkey1();
- key4=switchkey4();
- display_real_time();
- setimeput1(4);
- if(key1>=99)
- setimes();
- if(key1>10&&key1<50)
- changetime();
- if(key4<90&&key4>=30)
- clok();
- if(GPIO_ReadInputDataBit(DS1302_PORT,KEY2)==0)
- {delay_ms(20);
- if( GPIO_ReadInputDataBit(DS1302_PORT,KEY2)==0)
- b=!b;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY2));
- a=nz[0]*1000+nz[1]*10+b;
- delay_ms(10);
- FLASH_W(FLASH_START_ADDR,a);
- }
- nzs(b&1);
- GPIO_WriteBit(GPIOA,LIGHT,(BitAction)(b));
- }
- }
- void feng()
- {
- GPIO_WriteBit(DS1302_PORT,DEEP,(BitAction)(0));
- delay_ms(100);
- GPIO_WriteBit(DS1302_PORT,DEEP,(BitAction)(1));
- delay_ms(20);
- }
- void nzs(u8 b)
- {
- if(b==1)
- {
- nz[0]=a/1000;
- nz[1]=(a-(nz[0]*1000))/10;
- if(setime[4]==nz[0]&&setime[5]==nz[1])
- {
- while(setime[4]==nz[0]&&setime[5]==nz[1]&&GPIO_ReadInputDataBit(DS1302_PORT,KEY2))
- {
- feng();
- display_real_time();
- setimeput1(4);
- }
- }
- else
- GPIO_WriteBit(DS1302_PORT,DEEP,(BitAction)(1));
- }
- else
- GPIO_WriteBit(DS1302_PORT,DEEP,(BitAction)(1));
- }
- char switchkey1(void)//判断按键1按下的时间
- {
- if(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0)
- delay_ms(10);
- if(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0)
- {
- k1=0;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1)&&k1<150)
- {
- delay_ms(10);
- k1++;
- }
- }
- return k1;
- }
- char switchkey4(void)//判断按键4按下的时间
- {
- if( GPIO_ReadInputDataBit(DS1302_PORT,KEY4)==0)
- delay_ms(10);
- if( GPIO_ReadInputDataBit(DS1302_PORT,KEY4)==0)
- {
- k4=0;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY4)&&k4<150)
- {
- delay_ms(10);
- k4++;
- }
- }
- return k4;
- }
- void changetime(void)//按键1改变显示内容
- { num=0;
- i=0;
- while((c&0x10))
- {
- setimeput1(0);
- delay_ms(1);
- if(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0)
- { delay_ms(10);
- if(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0)
- while(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0&&num<42)
- {
- delay_ms(25);
- num++;
- }
- }
- if(num>40||i>4000)
- break;
- if(num<10&&num>2)
- { c=1;
- while(c&0x01)
- {
- for(j=0;j<60;j++)
- {
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(0));
- shiftout(smgduan[TIME.week]);
- shiftout(~0x04);
- shiftout(0);
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(1));
- delay_us(20);
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(0));
- shiftout(255);
- shiftout(255);
- shiftout(255);
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(1));
- delay_us(30);
- }
- delay_ms(1);
- i++;
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1))
- {
- delay_ms(10);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1))
- {
- while(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0&&num<42)
- {
- delay_ms(25);
- num++;
- }
- c=0x00;
- }
-
- }
- if(num>40||i>4000)
- break;
- }
- }
- }
- }
- void setimeput(char w) //SET MODE 时间显示
- {
- //for(i=0;i<5;i+=2)
- // {
- // timedata[i]=setime[w]/10;
- // timedata[i+1]=setime[w]%10;
- // w++;
- // }
- fs(w);
- for(i=0;i<2;i++)
- {
- for(i=0;i<4;i++)
- {
- putOut(0,~weixian[i],timedata[i]);
- delay_us(50);
- }
- for(i=4;i<8;i++)
- {
- putOut(timedata[i],~weixian[i],0);
- delay_us(50);
- }
- }
- }
- //0x10,0x20,0x40,0x80,0x01,0x02,0x04,0x08
- void fs(char w)
- {
- timedata[0]=setime[w]/10;
- timedata[1]=setime[w]%10;
- timedata[2]=10;
- w++;
- timedata[3]=setime[w]/10;
- timedata[4]=setime[w]%10;
- timedata[5]=10;
- w++;
- timedata[6]=setime[w]/10;
- timedata[7]=setime[w]%10;
- }
-
-
-
- void setimeput1(char w) //时间显示函数
- {
- //for(i=0;i<5;i+=2)
- // {
- // timedata[i]=setime[w]/10;
- // timedata[i+1]=setime[w]%10;
- // w++;
- // }
- fs(w);
- for(j=0;j<10;j++)
- {
- for(i=0;i<2;i++)
- {
- for(i=0;i<4;i++)
- {
- putOut(0,~weixian[i],timedata[i]);
- delay_us(100);
- }
- for(i=4;i<8;i++)
- {
- putOut(timedata[i],~weixian[i],0);
- delay_us(100);
- }
- }
- }
- }
- void putOut(char a,char b,char c) //595函数
- {
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(0));
- shiftout(255);
- shiftout(255);
- shiftout(255);
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(1));
- delay_us(1);
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(0));
- shiftout(smgduan[a]);
- shiftout(b);
- shiftout(smgduan[c]);
- GPIO_WriteBit(GPIOA,GPIO_Pin_3,(BitAction)(1));
- delay_us(50);
- }
- void setimes(void)//设置时间函数
- {
- u8 s2=0,week;
- num=0;
- i=0;
- while(d&0x10)
- {
- i++;
- setimeput(w);
- delay_us(500);
- if(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0)
- {
- delay_ms(10);
- if(GPIO_ReadInputDataBit(DS1302_PORT,KEY1)==0)
- {
- if(s2<2)
- {
- init_time[0]=(setime[6]/10)*16+setime[6]%10;
- init_time[1]=(setime[5]/10)*16+setime[5]%10;
- init_time[2]=(setime[4]/10)*16+setime[4]%10;
- num=0;
- w=0;
- }
- if(s2>1&&s2<4)
- {
- init_time[3]=(setime[2]/10)*16+setime[2]%10;
- init_time[4]=(setime[1]/10)*16+setime[1]%10;
- init_time[6]=(setime[0]/10)*16+setime[0]%10;
- DS1302_Init();
- delay_ms(10);
- setime[3]=0;
- if (setime[1]==1||setime[1]== 2)
- {
- setime[1]+=12;
- setime[0]-=1;
- }
- setime[3]=(setime[2] + 1 + 2 * setime[1] + 3 * (setime[1] + 1) / 5
- + setime[0] + setime[0] / 4 - setime[0] / 100 + setime[0]/ 400) % 7;
- week=setime[3]%10;
- if(setime[3]%10==0)
- week=7;
- init_time[5]=week;
- DS1302_Init();
- delay_ms(10);
- d=~d;
- }
- s2++;
- if(s2>4)
- {
- d=0x00;
- break;
- }
- }
- if(s2>4)
- break;
- if(i>8000)
- break;
- }
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY4))
- {delay_ms(10);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY4))
- {
- num++;
- if(num>2)
- num=0;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY4));
- }
- }
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY2))
- {delay_ms(15);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY2))
- {
- setime[w+num]=setime[w+num]+1;
- if(setime[4]>23||setime[w+num]>59)
- setime[w+num]=0;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY2));
- }
- }
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY3))
- {delay_ms(15);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY3))
- {
- if(w+num==4&&setime[4]==0)
- setime[0]=23;
- if(setime[w+num]==0&&w+num!=4)
- setime[w+num]=59;
-
- setime[w+num]=setime[w+num]-1;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY3));
- }
- }
- if(s2>2)
- break;
- }
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1));
- }
- void clok(void)
- {
- nz[0]=a/1000;
- nz[1]=(a-(nz[0]*1000))/10;
- num=0;
- while(b&0x1)
- {
- w=0;
- timedata[0]=nz[w]/10;
- timedata[1]=nz[w]%10;
- timedata[2]=10;
- w++;
- timedata[3]=nz[w]/10;
- timedata[4]=nz[w]%10;
- for(i=0;i<4;i++)
- {
- putOut(timedata[4],~weixian[4],0);
- delay_us(30);
- for(i=0;i<4;i++)
- {
- putOut(0,~weixian[i],timedata[i]);
- delay_us(50);
- }
-
- }
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY2))
- {delay_ms(15);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY2))
- {
- nz[num]=nz[num]+1;
- if(nz[0]>23)
- nz[0]=0;
- if(nz[num]>59)
- nz[num]=0;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY2));
- }
- }
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY3))
- {delay_ms(15);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY3))
- {
- if(num==0&&nz[0]==0)
- nz[0]=23;
- if(nz[num]==0&&num!=0)
- nz[num]=59;
-
- nz[num]=nz[num]-1;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY3));
- }
- }
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1))
- {
- delay_ms(15);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1))
- {
- num++;
- if(num>1)
- num=0;
- while(!GPIO_ReadInputDataBit(DS1302_PORT,KEY1));
- }
- }
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY4))
- {
- delay_ms(15);
- if(!GPIO_ReadInputDataBit(DS1302_PORT,KEY4))
- {
- b=!b;
- a=nz[0]*1000+nz[1]*10+b;
- delay_ms(10);
- FLASH_W(FLASH_START_ADDR,a); //从指定页的地址写入FLASH
- }
- }
- delay_us(500);
- }
- }
-
- //基本IO设置
- static void ds1302_gpio_init(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
-
- //开启GPIOD的时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
-
- //设置GPIO的基本参数
- GPIO_InitStruct.GPIO_Pin = DS1302_SCK_PIN | DS1302_CE_PIN|KEY1|KEY2|KEY3|KEY4;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //这两个普通端口设为推挽输出
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度50MHz
- GPIO_Init(DS1302_PORT, &GPIO_InitStruct);
- //设置GPIO的基本参数
- GPIO_InitStruct.GPIO_Pin = KEY1|KEY2|KEY3|KEY4 ;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //输入
- GPIO_Init(DS1302_PORT, &GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = DS1302_IO_PIN|DEEP; //这里最好设成开漏,当然也可以普通推挽,但是需要后面一直切换输入输出模式
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出,需要接上拉,不需要切换输入输出了。
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度50MHz
- GPIO_Init(DS1302_PORT, &GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin =GPIO_Pin_3|GPIO_Pin_2|GPIO_Pin_5|LIGHT; //选择端口号(0~15或all)
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- }
- //写一个字节
- //数据和地址都是从最低位开始传输的
- static void ds1302_writebyte(u8 byte_1)
- {
- u8 i = 0;
- u8 t = 0x01;
-
- for(i = 0;i<8;i++)
- {
- if((byte_1 & t) != 0) //之前的问题出在这里,32的位带操作不能赋值0和1之外的值。
- {
- DS1302_DATOUT = 1;
- }
- else
- {
- DS1302_DATOUT = 0;
- }
-
- DS1302_delay_us(2);
- DS1302_SCK = 1; //上升沿写入
- DS1302_delay_us(2);
- DS1302_SCK = 0;
- DS1302_delay_us(2);
-
- t<<= 1;
- }
- DS1302_DATOUT = 1; //释放IO,后面读取的话会准确很多
- DS1302_delay_us(2); //因为如果写完之后IO被置了低电平,开漏输出模式下读取的时候会有影响,最好先拉高,再读取
- }
- //地址写数据
- static void ds1302_writedata(u8 addr,u8 data_)
- {
- DS1302_CE = 0; DS1302_delay_us(2);
- DS1302_SCK = 0; DS1302_delay_us(2);
- DS1302_CE = 1; DS1302_delay_us(2); //使能片选信号
-
- ds1302_writebyte(addr); //方便后面写入,转化之后是地址寄存器的值,
- ds1302_writebyte(data_);
- DS1302_CE = 0; DS1302_delay_us(2);//传送数据结束,失能片选
- DS1302_SCK = 0; DS1302_delay_us(2);//拉低,准备下一次写数据
- }
- //读取一个字节,上升沿读取
- static u8 ds1302_readbyte(void)
- {
- u8 i = 0;
- u8 data_ = 0;
-
- //因为上面已经把端口设置为开漏,电路外部接了山拉电阻,可以不切换输入输出模式,直接使用。
- // DS1302_DAT_INPUT();
-
- DS1302_SCK = 0;
- DS1302_delay_us(3);
- for(i=0;i<7;i++) //这里发现设为8的话输出数据不对,很乱
- {
- if((DS1302_DATIN) == 1)
- {
- data_ = data_ | 0x80; //低位在前,逐位读取,刚开始不对,估计是这个的问题
- }
- data_>>= 1;
- DS1302_delay_us(3);
-
- DS1302_SCK = 1;
- DS1302_delay_us(3);
- DS1302_SCK = 0;
- DS1302_delay_us(3);
- }
- return (data_);
- }
- //读取寄存器的值
- static u8 ds1302_readdata(u8 addr)
- {
- u8 data_ = 0;
- DS1302_CE = 0; DS1302_delay_us(2);
- DS1302_SCK = 0; DS1302_delay_us(2);
- DS1302_CE = 1; DS1302_delay_us(2); //读写操作时CE必须为高,切在SCK为低时改变
-
- ds1302_writebyte((addr<<1)|0x81); //写入读时间的命令
- data_ = ds1302_readbyte();
-
- DS1302_SCK = 1; DS1302_delay_us(2);
- DS1302_CE = 0; DS1302_delay_us(2);
- DS1302_DATOUT = 0; DS1302_delay_us(3); //这里很多人说需要拉低,但是我发现去掉这个也可以显示啊,不过为了保险,还是加上。
- DS1302_DATOUT = 1; DS1302_delay_us(2);
-
- return data_;
- }
- void DS1302_Init(void)
- {
- u8 i = 0;
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
电子时钟.7z
(184.72 KB, 下载次数: 675)
|