51单片机与AVR(SPI)单片机驱动DS1302

本代码来源于网络,记录下来怕忘记

CE信号高电平读写数据

读写时前8位为地址位,后8位为数据。在写数据时SCLK为下降沿开始,读数据为上升沿开始读数据。读写都是从D0-D7,且都为BCD码。写入时先将十进制转化为BCD码,在写入寄存器。读取时要把BCD码转化成十进制显示。

int bcd_decimal_code( int bcd)  //十进制转BCD
{
    return (bcd + (bcd/10) * 6);
}
int decimal_bcd_code(int decimal)  //BCD转十进制
{
    return (decimal - (decimal>>4) * 6);
}

51单片机模拟SPI驱动DS1320

#include <reg52.h>
#include <intrins.h>
#include <LCD1602.h>
#define uchar unsigned char
#define uint  unsigned int
sbit SCK_P = P3^6;		// 时钟芯片DS1302的SCK管脚
sbit SDA_P = P3^7;		// 时钟芯片DS1302的SDA管脚
sbit RST_P = P3^5;		// 时钟芯片DS1302的RST管脚
sbit key   = P1^7;
uchar TimeBuff_write[7]={17,9,1,6,18,30,40};				// 时间数组
uchar TimeBuff[7]      ={ 0,0,0,0, 0, 0, 0};
// TimeBuff[0] 代表年份,范围00-99
// TimeBuff[1] 代表月份,范围1-12
// TimeBuff[2] 代表日期,范围1-31
// TimeBuff[3] 代表星期,范围1-7
// TimeBuff[4] 代表小时,范围00-23
// TimeBuff[5] 代表分钟,范围00-59
// TimeBuff[6] 代表秒钟,范围00-59

/*********************************************************/
// 初始化DS1302
/*********************************************************/
void DS1302_Init(void)
{
		RST_P=0;			// RST脚置低	
		SCK_P=0;			// SCK脚置低	
		SDA_P=0;			// SDA脚置低				
} 
/*********************************************************/
// 从DS1302读出一字节数据
/*********************************************************/
uchar DS1302_Read_Byte(uchar addr) 
{	
		uchar i;	
		uchar temp;		
		RST_P=1;										
		/* 写入目标地址:addr*/			
		for(i=0;i<8;i++) 	
		{     		
				if(addr&0x01) 			
						SDA_P=1;		
				else 			
						SDA_P=0;				
				SCK_P=1;		
				_nop_();		
				SCK_P=0;		
				_nop_();				
				addr=addr>> 1;	
		}		
		/* 读出该地址的数据 */	
		for(i=0;i<8;i++) 	
		{		
				temp=temp>>1;				
				if(SDA_P) 			
						temp|= 0x80;		
				else 			
						temp&=0x7F;				
				SCK_P=1;		
				_nop_();		
				SCK_P=0;		
				_nop_();	
		}		
		RST_P=0;		
		return temp;
} 
/*********************************************************/
// 向DS1302写入一字节数据
/*********************************************************/
void DS1302_Write_Byte(uchar addr, uchar dat)
{	
		uchar i;		
		RST_P = 1;		
		/* 写入目标地址:addr*/	
		for(i=0;i<8;i++) 	
		{ 		
				if(addr&0x01) 			
						SDA_P=1;		
				else 			
						SDA_P=0; 		
				SCK_P=1;		
				_nop_();		
				SCK_P=0;		
				_nop_();				
				addr=addr>>1;	
		}		
		/* 写入数据:dat*/	
		for(i=0;i<8;i++) 	
		{		
				if(dat&0x01) 			
						SDA_P=1;	
				else 			
						SDA_P=0;			
				SCK_P=1;		
				_nop_();		
				SCK_P=0;		
				_nop_();				
				dat=dat>>1;	
		}		
		RST_P=0;					
} 
/*********************************************************/
// 向DS1302写入时间数据
/*********************************************************/
void DS1302_Write_Time() 
{  
		uchar i;	
		uchar temp1;	
		uchar temp2;		
		for(i=0;i<7;i++)			// 十进制转BCD码	
		{		
				temp1=(TimeBuff_write[i]/10)<<4;		
				temp2=TimeBuff_write[i]%10;		
				TimeBuff_write[i]=temp1+temp2;	
		}		
		DS1302_Write_Byte(0x8E,0x00);					// 关闭写保护
		DS1302_Write_Byte(0x80,0x80);					// 暂停时钟 	
		DS1302_Write_Byte(0x8C,TimeBuff_write[0]);			  // 年 	
		DS1302_Write_Byte(0x88,TimeBuff_write[1]);				// 月 	
		DS1302_Write_Byte(0x86,TimeBuff_write[2]);				// 日 	
		DS1302_Write_Byte(0x8A,TimeBuff_write[3]);			  // 星期	
		DS1302_Write_Byte(0x84,TimeBuff_write[4]);				// 时 	
		DS1302_Write_Byte(0x82,TimeBuff_write[5]);				// 分	
		DS1302_Write_Byte(0x80,TimeBuff_write[6]);				// 秒	
		DS1302_Write_Byte(0x80,TimeBuff_write[6]&0x7F);		// 运行时钟	
		DS1302_Write_Byte(0x8E,0x80);					            // 打开写保护  
} 
/*********************************************************/
// 从DS1302读出时间数据
/*********************************************************/
void DS1302_Read_Time()  
{ 	
		uchar i; 	
		TimeBuff[0]=DS1302_Read_Byte(0x8D);			// 年 	
		TimeBuff[1]=DS1302_Read_Byte(0x89);			// 月 	
		TimeBuff[2]=DS1302_Read_Byte(0x87);			// 日 	
		TimeBuff[3]=DS1302_Read_Byte(0x8B);			// 星期	
		TimeBuff[4]=DS1302_Read_Byte(0x85);			// 时 	
		TimeBuff[5]=DS1302_Read_Byte(0x83);			// 分 	
		TimeBuff[6]=(DS1302_Read_Byte(0x81))&0x7F;		// 秒  	
		for(i=0;i<7;i++)		// BCD转十进制	
		{           		
				TimeBuff[i]=(TimeBuff[i]/16)*10+TimeBuff[i]%16;	
		}
}
void delay10ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}
void main()
{ 
		uchar bcd=55; 
		init1602();
		DS1302_Init();
		key=1;
		while(1)
		{
				DS1302_Read_Time();
				
				disp1602(0,0,TimeBuff[4]/10+'0');
        disp1602(0,1,TimeBuff[4]%10+'0');
        disp1602(0,2,'-');
        disp1602(0,3,TimeBuff[5]/10+'0');
        disp1602(0,4,TimeBuff[5]%10+'0');
        disp1602(0,5,'-');
        disp1602(0,6,TimeBuff[6]/10+'0');
        disp1602(0,7,TimeBuff[6]%10+'0');
			
				if(key==0)
				{
						delay10ms();
						while(key==0);
//					bcd=(bcd + (bcd/10) * 6);    //单独写一个寄存器
//					DS1302_Write_Byte(0x82, bcd);//0x82为时寄存器,向时寄存器写入55
						DS1302_Write_Time() ;  //写入一组预设的数据
				}
		}
}

按键之后

 AVR SPI驱动DS1302

/*
 * DS1302.h
 *
 * Created: 2022/2/1 17:23:34
 *  Author: admin
 */ 


#ifndef DS1302_H_
#define DS1302_H_
#include <avr/io.h>
#include <avr/delay.h>
#include <GPIO_IO.h>
unsigned char CURDATE[7];

//读写操作位
#define CMD_READ			0x01
#define CMD_WRITE			0x00
//时钟 命令
#define CMD_SECOND			0x80	//秒
#define CMD_MINUTE			0x82	//分
#define CMD_HOUR			0x84	//时
#define CMD_DAY				0x86	//日
#define CMD_MONTH			0x88	//月
#define CMD_WEEK			0x8A	//星期 DATE
#define CMD_YEAR			0x8C	//年
#define CMD_CONTROL			0x8E	//控制(写保护)
#define CMD_TRICKLE_CHARGE	0x90	//涓流充电
#define CMD_CLOCK_BURST		0xBE	//连续读取
//时钟配置常量
#define CFG_CLOCK_HALT		0x80	//停止时钟控制位    SECOND	bit7
#define CFG_12_24			0x80	//12/24小时值选择位 HOUR		bit7
#define CFG_AM_PM			0x20	//AP/PM位          HOUR		bit5
#define CFG_PROTECT			0x80	//写保护控制位      CONTROL	bit7  打开写保护
#define CFG_UNPROTECT		0x00	//写保护控制位      CONTROL	bit7  关闭写保护
//涓流充电控制常量
#define CFG_TC_D1R2			0xA5	//high 1 Diode +2K Resistors
#define CFG_TC_D2R8			0xAB	//low  2 Diodes+8K Resistors
#define CFG_TC_DISABLED		0x00	//Disabled(TCS<>1010 or DS=00 or RS=00)
//RAM 命令
#define CMD_RAM_BASE		0xC0	//RAM0~RAM30<<1 地址需左移一位
#define CMD_RAM_BURST		0xFE	//连续读取

#endif /* DS1302_H_ */
/*
 * DS1302.c
 *
 * Created: 2022/2/1 17:22:35
 *  Author: admin
 */ 

#include <DS1302.h>
//M328p管脚定义
#define DS1302_CE			2		//PB2 SS 必须设为输出 ----DS1302 pin5
#define DS1302_MOSI			3		//PB3 MOSI要串10K电阻到MISO,然后把MISO跟DS1302_IO脚短接在一起的
#define DS1302_MISO			4		//PB4 MISO跟DS1302_IO脚短接在一起的---DS1302 pin6
#define DS1302_SCK			5		//PB5 SCK----DS1302 pin7

//宏定义
#define DiDS1302 GPIO_LOW('B',2)       //CE=0   DiDS1302 关闭SPI接口
#define EnDS1302 GPIO_HIGH('B',2)     //CE=1   EnDS1302  使能SPI接口

unsigned char DS1302_EXIST;
unsigned char INITDATE[8]={0x50,	//59秒
                           0x59,	//59分
                           0x23,	//23时  24小时制
                           0x06,	//06日
                           0x11,	//11月
                           0x04,	//星期四
                           0x05,	//2005年
                           0x80};	//写保护
unsigned char CURDATE[7];
//CURDATE[6]					//年 ,00~10
//CURDATE[4]					//月 ,01~12
//CURDATE[3]					//日 ,01~31(28/30/31)
//CURDATE[2]					//时 ,00~23
//CURDATE[1]					//分 ,00~59
//CURDATE[0]					//秒 ,00~59
//CURDATE[5]					//星期 ,1~7 一~日

//初始化SPI接口
void init_SPI(void)
{   
    PORTB=~((1<<DS1302_CE)|(1<<DS1302_MOSI)|(1<<DS1302_MISO)|(1<<DS1302_SCK));//DS1302带内部下拉电阻    
    DDRB =(1<<DS1302_CE)|(1<<DS1302_SCK)|(1<<DS1302_MOSI);//设定SPI接口    
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<DORD)|(1<<SPR0);// 使能SPI接口,主机模式,LSB低位在先,模式0,16分频,SPI时钟约460KHz		    
}
/*-----------------------------------------------------------------------
Single_SPI    : 使用SPI接口读写数据到DS1302
 
输入参数:	command:	命令选择;
			wdata:		写入的数据;
返回值		rdata:		读回的数据;	
   (SPI的收发是同时进行的)
-----------------------------------------------------------------------*/
unsigned char Single_SPI(unsigned char command,unsigned char wdata)
{
	unsigned char rdata;
    EnDS1302;							// 使能LCD
    _delay_us(10);
    SPDR = command;			 			// 传送命令到SPI寄存器
    loop_until_bit_is_set(SPSR,SPIF);	// 等待数据传送完?
    _delay_us(10);
    SPDR = wdata;			 			// 传送数据到SPI寄存器
    loop_until_bit_is_set(SPSR,SPIF);	// 等待数据传送完?
    rdata=SPDR;							// 读取数据
    DiDS1302;							// 关断LCD SPI通讯
    _delay_us(10);
    return rdata;
}

/*-----------------------------------------------------------------------
Burst_SPI    : 使用SPI接口读写一批数据到DS1302
 
输入参数:	CMD:		选择Clock/RAM,选择读写
			lenth:		数据长度
			pwdata:		写入数据的缓冲区;
			prdata:		读回数据的缓冲区;	
   (SPI的收发是同时进行的)
读CLOCK的数据从SECOND寄存器开始,到CONTROL寄存器,最大8字节
写CLOCK的数据必须一次写完8个字节
读写RAM的数据从 RAM0地址开始,到RAM30地址,最大31字节
-----------------------------------------------------------------------*/
void Burst_SPI(unsigned char CMD,unsigned char len,unsigned char *pwdata,unsigned char *prdata)
{
    EnDS1302;								// 使能SPI通讯
    _delay_us(10);
	SPDR=CMD;								// 传送命令到SPI寄存器
    loop_until_bit_is_set(SPSR,SPIF);		// 等待数据传送完?
    _delay_us(10);    
    while (len--)
    {
    	SPDR = *pwdata++;			 		// 传送数据到SPI寄存器
    	loop_until_bit_is_set(SPSR,SPIF);	// 等待数据传送完?
    	*prdata++=SPDR;						// 读取数据
	};
	DiDS1302;								// 关断SPI通讯
    _delay_us(10);
}

//初始化DS1302
void DS1302_Write_Time(void)
{
    unsigned char temp[8];
    Single_SPI(CMD_CONTROL   |CMD_WRITE, CFG_UNPROTECT);				//写允许
    
    INITDATE[1]=44;
    INITDATE[1]=(INITDATE[1] + (INITDATE[1]/10) * 6);
    Burst_SPI(CMD_CLOCK_BURST|CMD_WRITE,8,&INITDATE[0],&temp[0]);	//初始化时间
    Single_SPI(CMD_TRICKLE_CHARGE,       CFG_TC_D1R2);						//涓流充电选择
    Single_SPI(CMD_CONTROL   |CMD_WRITE, CFG_PROTECT);					//写保护
}
#ifndef F_CPU
#define  F_CPU 16000000UL
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <LCD1602.h>
#include <GPIO_IO.h>
#include <DS1302.h>

int main(void)
{
    uchar i;
    init1602();
    init_SPI();
    DS1302_Write_Time();
    while (1)
    { 
        Burst_SPI(CMD_CLOCK_BURST|CMD_READ,7,0,&CURDATE[0]);	//读取当前时间
        for(i=1;i<7;i++)		// BCD转十进制
        {
            CURDATE[i]=(CURDATE[i]/16)*10+CURDATE[i]%16;
        }
        CURDATE[0]=CURDATE[0]&0x7f;
        CURDATE[0]=(CURDATE[0]/16)*10+CURDATE[0]%16;
        disp1602(0,0,CURDATE[2]/10+'0');
        disp1602(0,1,CURDATE[2]%10+'0');
        disp1602(0,2,'-');
        disp1602(0,3,CURDATE[1]/10+'0');
        disp1602(0,4,CURDATE[1]%10+'0');
        disp1602(0,5,'-');
        disp1602(0,6,CURDATE[0]/10+'0');
        disp1602(0,7,CURDATE[0]%10+'0');
    }
}

 

#include <GPIO_IO.h>
#define BIT(x) (1 << (x))  //PORTB &=~BIT(7);置0     PORTB |=BIT(7);置1     PORTA ^= BIT(7);取反

void GPIO_HIGH(uchar x,uchar y)//GPIO置1
{
    if (x=='B')
        PORTB |=BIT(y);
    else if (x=='C')
        PORTC |=BIT(y);
    else if (x=='D')
        PORTD |=BIT(y);       
}
void GPIO_LOW(uchar x,uchar y)//GPIO置0
{
    if (x=='B')
        PORTB &=~BIT(y);
    else if (x=='C')
        PORTC &=~BIT(y);
    else if (x=='D')
        PORTD &=~BIT(y);
}
void GPIO_TURN(uchar x,uchar y)//GPIO翻转
{
    if (x=='B')
        PORTB ^= BIT(y);
    else if (x=='C')
        PORTC ^= BIT(y);
    else if (x=='D')
        PORTD ^= BIT(y);
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值