本代码来源于网络,记录下来怕忘记
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);
}