ds1302就是一个新买的时钟
DS1302的原理大家可以参考
欧浩源老师的视频
【进阶强化03】蓝桥杯中DS1302的基本应用
或者是西风老师的视频
第四讲 DS1302模块
大家可以去了解iic总线的工作原理和ds1302的工作原理
我自己看的是这个up主的介绍 我只是看了怎么使用ds1302 具体的显示代码还是结合欧浩源老师的代码来写的
【蓝桥杯单片机入门】8.DS1302时钟芯片(硬件介绍+软件编程)
我这里就简单展示一下这个具体的用法
首先是引脚的定义 iic总线的数据脚需要自己定义 这段定义我是写在iic.c中的
这个原理图截图如下
然后就是使用
首先要写入一个初始值 就是给新买的时钟设置时间
图片来自up主小菜OvO
附上真爱粉图片
读取的时候 不需要对0x8e操作,其他操作反过来就可以了
下面直接看代码吧 这里使用的是传入的数组地址 这个数组是什么呢 就是我们提前设置好的时间数组和用于存放读取数据的数组 还有DS1302的寄存器地址数组
这个是设置在 mian.c 里面的数组 (设置数组的方法是来自欧浩源老师)
u8 w_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};//写入寄存器地址
u8 r_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};//读取寄存器地址
u8 time[7]={0x49,0x40,0x20,0x27,0x03,0x03,0x24};//想要设置的时间 这个是24年 周三 3月 27号 20:40:49
u8 time1[7];// 用于存放读取的数据
void time_w (u8* w_addr, u8* time)
{
// 设置DS1302的写使能,0x8e为启动写命令的地址,0x00为写使能的值
Write_Ds1302_Byte(0x8e, 0x00);
// 循环写入7个时间寄存器的数据
for (u8 n = 0; n < 7; n++)
{
// 写入对应地址的数据
Write_Ds1302_Byte(w_addr[n], time[n]);
}
// 设置DS1302的写禁止,0x80为禁止写入的值
Write_Ds1302_Byte(0x8e, 0x80);
}
/**
* @brief 从DS1302实时时钟芯片读取时间
*
* @param r_addr 要读取的地址数组,包含了DS1302的7个时间寄存器的地址
* @param time 存储读取到的时间数据的数组
*/
void time_r (u8* r_addr, u8* time)
{
u8 n;
// 循环读取7个时间寄存器的数据
for (n = 0; n < 7; n++)
{
// 读取对应地址的数据并存储到time数组中
time[n] = Read_Ds1302_Byte(r_addr[n]);
}
}
//这个u8 就是unsigned char
展示一下全部代码 采用了模块化编程
首先是数码管部分
smg.h
#ifndef __SMG_H
#define __SMG_H
#include "main.h"
void smg_display(u8 pos,u8 value);
void selecthc573(u8 channel);
void smg_clear();
#endif
smg.c
#include "main.h"
void selecthc573(u8 channel){
switch(channel){
case 4:
P2=(P2&0x1f)|0x80;
break;
case 5:
P2=(P2&0x1f)|0xa0;
break;
case 6:
P2=(P2&0x1f)|0xc0;
break;
case 7:
P2=(P2&0x1f)|0xe0;
break;
}
}
void smg_display(u8 pos,u8 value){
selecthc573(6);
P0=0x01<<pos;
selecthc573(7);
P0=0xff;
P0=value;
}
void smg_clear(){
int n;
for(n=0;n<8;n++){
smg_display(n,0xff);
}
}
ds1302.h
#ifndef __DS1302_H
#define __DS1302_H
#include "main.h"
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte ( unsigned char address );
void time_w(u8* w_addr,u8* time);
void time_r(u8* r_addr,u8* time);
#endif
ds1302.c
/* # DS1302代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "main.h"
sbit SCK=P1^7;//对照原理图补充
sbit SDA=P2^3;
sbit RST=P1^3;
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
void time_w (u8* w_addr,u8* time)
{
u8 n;
Write_Ds1302_Byte(0x8e,0x00);
for(n=0;n<7;n++){
Write_Ds1302_Byte(w_addr[n],time[n]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
void time_r(u8* r_addr,u8* time)
{
u8 n;
for(n=0;n<7;n++){
time[n]=Read_Ds1302_Byte(r_addr[n]);
}
}
main.h
#ifndef __MAIN_H
#define __MAIN_H
typedef unsigned char u8;
typedef unsigned int u16;
#include <reg52.h>
#include "ds1302.h"
#include <intrins.h>
#include "smg.h"
#endif
main.c
#include "main.h"
u8 code smg_duanma[18]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
0xbf,0x7f};
u8 w_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
u8 r_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
u8 time[7]={0x49,0x40,0x20,0x27,0x03,0x03,0x24};
u8 time1[7];
u8 count=0;
void delay(u16 t){
int n;
while(t--){
for(n=0;n<12;n++);
}
}
void ds1302_display1(){
smg_display(0,smg_duanma[time1[6]/16]);
delay(50);
smg_display(1,smg_duanma[time1[6]%16]);
delay(50);
smg_display(2,smg_duanma[16]);
delay(50);
smg_display(3,smg_duanma[time1[4]/16]);
delay(50);
smg_display(4,smg_duanma[time1[4]%16]);
delay(50);
smg_display(5,smg_duanma[16]);
delay(50);
smg_display(6,smg_duanma[time1[3]/16]);
delay(50);
smg_display(7,smg_duanma[time1[3]%16]);
delay(50);
smg_display(0,0xff);
}
void ds1302_display2(){
smg_display(7,smg_duanma[time1[5]%16]);
}
void ds1302_display3(){
smg_display(0,smg_duanma[time1[2]/16]);
delay(50);
smg_display(1,smg_duanma[time1[2]%16]);
delay(50);
smg_display(2,smg_duanma[16]);
delay(50);
smg_display(3,smg_duanma[time1[1]/16]);
delay(50);
smg_display(4,smg_duanma[time1[1]%16]);
delay(50);
smg_display(5,smg_duanma[16]);
delay(50);
smg_display(6,smg_duanma[time1[0]/16]);
delay(50);
smg_display(7,smg_duanma[time1[0]%16]);
delay(50);
smg_display(0,0xff);
}
void init_t0(){//初始化定时器函数
TMOD=0x01;//设置定时器模式 这个是16位定时器 手动装载初值
TH0=(65536-50000)/256;//设置初值 转换成16进制 存放高位
TL0=(65536-50000)%256;//低位
ET0=1;//允许定时器0中断
EA=1;//总中断开关
TR0=1;//定时器!启动!!!!
}
void servicetimer0() interrupt 1{// 定时中断函数的标志 不可以忘记写
TH0=(65536-50000)/256;//因为不会自动装载初值 所以需要手动装载
TL0=(65536-50000)%256;
count++;
}
void main(){
time_w(w_addr,time);
init_t0();
while(1)
{
time_r(r_addr,time1);
if(count<60){
ds1302_display1();
}
if(count>=60&&count<120){
smg_clear();
delay(50);
ds1302_display2();
}
if(count>=120&&count<180){
ds1302_display3();
}
if(count==180){
count=0;
}
}
}
这段其实可以写成switch的形式
效果展示
DS1302功能演示
还有PCF8591 超声波 555定时器 冲冲冲