//STC15W4K56S4单片机读写时钟芯片RX8025T,可以在OLED屏和串口显示参数,单片机用内部11.0592晶震,串口9600,N.8.1. 直接复制代码就能跑起来,很方便,代码都在main函数里,方便大家学习和移植到其他IDE,这个电路板也是我设计的,上面还有个温湿度传感器,AHT20.需要图纸和驱动可联系我,赵科17717361475/2023.12.8
//** Descriptions:
//------------------------------------------------------------------------------------
#define MAIN_Fosc 11059200L //定义主时钟
#include "15W4KxxS4.H"
#include <intrins.h> // 加入此头文件后,可使用_nop_库函数
#include <string.h> // 加入此头文件后,可使用strstr库函数
#include "stdio.h"
#define uint8 unsigned char //0-256
#define uint16 unsigned int //0-65535
#define uint32 unsigned long //-100亿--+100亿
#define BAUD 9600
#define TM (65536 - (MAIN_Fosc/4/BAUD))
#define Buf_Max 20 //串口7S1这里要设定到34,日期就可以正常显示了
#define S2_S 0x01
#define S2RI 0x01
#define S2TI 0x02
#define S3RI 0x01
#define S3TI 0x02
#define S4RI 0x01
#define S4TI 0x02
#define Write 0X64
#define Read 0X65
uint8 xdata Rec_Buf1[Buf_Max];//4个串口的接收缓存
uint8 xdata Rec_Buf2[Buf_Max];
uint8 xdata Rec_Buf3[Buf_Max];
uint8 xdata Rec_Buf4[Buf_Max];
uint8 i = 0; //串口3数组计数器
uint8 j = 0; //串口4数组计数器
#define ACK 0
#define NOACK 1
sbit RX8025SCL = P0^2;
sbit RX8025SDA = P0^3;
//extern u8 xdata RX8025TimeBuffH[];RX8025SDA
u8 xdata RX8025YMD[]="2020-12-07"; //这里不设定参数,下面数组设
u8 xdata RX8025HMS[]="12:34:56";
u8 xdata RX8025TimeBuffH[]={11,24,9,4,8,12,23};//修改日期时钟,中间的是星期
u8 xdata RX8025TImeBuffB[]={0X01,0X02,0X03,0X04,0X05,0X06,0X07};
//----------------------------------------------------------------------------------------
//-----------------------串口1初始化函数.注意该芯片有4个串口,1口中断优先级最高
void Uart1_Init(void)
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xE0; //设置定时初始值
TH1 = 0xFE; //设置定时初始值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器
}
//---------------------------------- 串口1发送数据函数
void SendDataByUart1(uint8 dat)
{
SBUF = dat; //写数据到UART数据寄存器
while(TI == 0); //在停止位没有发送时,TI为0即一直等待
TI = 0; //清除TI位(该位必须软件清零)
}
//------------------------===========串口1发送字符串函数
void SendStringByUart1(uint8 *s)
{
while(*s)
{
SendDataByUart1(*s++);//将字符串中的字符一个一个发送
}
}
//----------------------清除串口1缓存内容函数
void CLR_Buf1(void)
{
uint8 k;
for(k=0;k<Buf_Max;k++) //将串口1缓存数组的值都清为零
{
Rec_Buf1[k] = 0;
}
i = 0;
}
//-----------------------------------串口1握手判断函数
bit Hand1(uint8 *a)
{
if(strstr(Rec_Buf1,a)!=NULL) //判断字符串a是否是字符串Rec_Buf1的子串
return 1; //如果字符串a是字符串Rec_Buf1的子串
else
return 0; //如果字符串a不是字符串Rec_Buf1的子串
}
//------------------------------------下面串口1接收中断-----------------------
void Uart1() interrupt UART1_VECTOR using 1
{
ES = 0; // 串口1中断关闭
if (RI) //串行接收到停止位的中间时刻时,该位置1
{
RI = 0; //清除RI位 (该位必须软件清零)
Rec_Buf1[i] = SBUF; //把串口1缓存SBUF寄存器数据依次存放到数组Rec_Buf1中
i++;
if(i>Buf_Max) //接收数大于定义接收数组最大个数时,覆盖接收数组之前值
{
i = 0;
}
}
ES = 1; // 串口1中断打开
}
//================================================================================
//----------------------------------------------------------------------------------------
/*********BCD码转十六进制************/
u8 BCDtoHEX(u8 BCD )
{
return ( ( (BCD/16)*10) +BCD%16 );
}
/**********十六进制转BCD码*************/
u8 HEXtoBCD(u8 Hex)
{
return ( ((Hex/10)<<4) +Hex%10 );
}
/*********I2C延时***********/
void I2CWait()
{
u8 i;
for(i=0;i<10;i++)
{
_nop_();_nop_();_nop_();_nop_();
}
}
bit I2C_Start2()
{
RX8025SDA = 1; //释放总线
RX8025SCL = 1;
I2CWait();
if(!RX8025SDA) return 0; //总线忙退出
RX8025SDA = 0;
I2CWait();
while(RX8025SDA) return 0; //总线为高电平则总线出错,退出
RX8025SCL = 0;
I2CWait();
//return 1;
}
void I2C_Stop()
{
RX8025SCL = 0;
RX8025SDA = 0;
I2CWait();
RX8025SCL = 1;
I2CWait();
RX8025SDA = 1;
}
/********主机向从机发送ACK****
a=0,发送ACk a=1,发送NO ACK
******************************/
void I2CSendACK(u8 a)
{
RX8025SDA = a;
RX8025SCL = 0;
I2CWait();
RX8025SCL = 1;
I2CWait();
RX8025SCL = 0;
}
/*********主机读取从机ACK信号***/
bit I2CReceivedACK()
{
u8 errtime=255;
RX8025SCL = 0;
RX8025SDA = 1; //释放总线
I2CWait();
RX8025SCL = 1;
I2CWait();
while(RX8025SDA) //读取 SDA上的电平,变为低电平,即有从机回复ACK信号
{
errtime--;
if(!errtime) //超时退出
{
RX8025SCL=0;
return 0;
}
}
RX8025SCL=0;
return 1;
}
/******************************************
主机向从机发送一字节数据-->dat
order=0:先发送LSB,最后发送MSB
order=1:先发送MSB;最后发送LSB
之所以设置order这个入口参数,是为了程序方便
移植,适应多个IIC芯片,只需设置order就能改变
数据传输方向,RX8025芯片 order 一直为 1
******************************************/
void IIC_Send_Byte(u8 dat, bit order)
{
u8 i;
if(order)
{
for(i=0;i<8;i++)
{
RX8025SDA = dat&0X80;
RX8025SCL = 1;
I2CWait();
RX8025SCL = 0;
dat<<=1;
I2CWait();
}
}
else
{
for(i=0;i<8;i++)
{
RX8025SDA = dat&0X01;
RX8025SCL = 1;
I2CWait();
RX8025SCL = 0;
dat>>=1;
I2CWait();
}
}
}
/*********读取一字节数据*********
order=0:先读取LSB,最后读取MSB
order=1:先去读MSB,最后读取LSB
********************************/
u8 IIC_Receive_Byte(bit order)
{
u8 i,j,Rdat;
RX8025SDA = 1; //释放总线
if(order) //MSB-->LSB
{
for(i=0;i<8;i++)
{
RX8025SCL = 0;
I2CWait();
Rdat =( Rdat<<1 )| RX8025SDA;
RX8025SCL = 1;
I2CWait();
}
}
else //LSB-->MSB
{
for(i=0;i<8;i++)
{
RX8025SCL = 0;
I2CWait();
j=RX8025SDA;
Rdat =( Rdat>>1 )| (j<<7);
RX8025SCL = 1;
I2CWait();
}
}
RX8025SCL=0;
return Rdat;
}
/******读取RX8025一个寄存器的数据*****/
//u8 Read_RX8025_Byte(u8 add)
//{
// u8 Ridat;
// I2C_Start2();
// IIC_Send_Byte(Write,1);
// if(!I2CReceivedACK()) //判断有无ACK信号
// I2C_Stop();
// IIC_Send_Byte(add,1);
// if(!I2CReceivedACK()) //判断有无ACK信号
// I2C_Stop();
//
// I2C_Start2();
// IIC_Send_Byte(Read,1);
// if(!I2CReceivedACK()) //判断有无ACK信号
// I2C_Stop();
// Ridat = IIC_Receive_Byte(1); //读取数据
// I2CSendACK(1);
// I2C_Stop();
// return Ridat;
//}
//--单独向一个寄存器写数据
void Write_RX8025_Byt(u8 add,u8 dat)
{
u8 Bdat;
Bdat = dat;
//Bdat = HEXtoBCD(dat); //将十六进制转换为BCD码
//---开始写入数据
I2C_Start2();
IIC_Send_Byte(Write,1);
if(!I2CReceivedACK()) //判断有无ACK信号
I2C_Stop();
IIC_Send_Byte(add<<4,1); //--根据手册在写入时地址要右移4位
if(!I2CReceivedACK()) //判断有无ACK信号
I2C_Stop();
IIC_Send_Byte(Bdat,1);
I2CReceivedACK();
I2C_Stop();
}
//--连续读取时间、日历数据--
//--add:读取的起始地址
//--Num:读取数据的个数
//--标准IIC连续读寄存器时序
void Read_RX8025_Dat(u8 add, u8 Num)
{
u8 i;
//---先写读寄存器地址
I2C_Start2();
IIC_Send_Byte(Write,1);
if(!I2CReceivedACK()) //判断有无ACK信号
I2C_Stop();
IIC_Send_Byte(add,1); //秒寄存器地址
if(!I2CReceivedACK()) //判断有无ACK信号
I2C_Stop();
//---连续读取数据
I2C_Start2();
IIC_Send_Byte(Read,1);
if(!I2CReceivedACK()) //判断有无ACK信号
I2C_Stop();
for(i=0;i<Num;i++)
{
RX8025TImeBuffB[i] = IIC_Receive_Byte(1); //读取数据
if(i!=6)I2CSendACK(0);
}
I2CSendACK(1);
I2C_Stop();
for(i=0;i<Num;i++)
{
RX8025TimeBuffH[i] = BCDtoHEX(RX8025TImeBuffB[i]);
}
}
/*****向RX8025连续写num个数据******/
void Write_RX8025_Byte(u8 add,u8 *Buff)
{
u8 i;
//---先写读寄存器地址
I2C_Start2();
IIC_Send_Byte(Write,1);
if(!I2CReceivedACK()) //判断有无ACK信号
I2C_Stop();
IIC_Send_Byte(add<<4,1);
if(!I2CReceivedACK()) //判断有无ACK信号
I2C_Stop();
for(i=0;i<7;i++) //--连续写入7个时间日历数据
{
Buff[i] = HEXtoBCD(Buff[i]);
IIC_Send_Byte(Buff[i],1);
I2CReceivedACK();
}
I2C_Stop();
}
void RX8025_Init()
{
//--12/24小时寄存器地址为0X0E,
Write_RX8025_Byt(0X0E,0X20); //RX8025-T 24小时制
// Write_RX8025_Byt(0X0E,0X00); //RX8025-T 12小时制
}
void DisplayTime()
{
//--显示RX8025的时间
Read_RX8025_Dat(0,7);
RX8025YMD[2] = RX8025TimeBuffH[6]/10; //+0X30; 年
RX8025YMD[3] = RX8025TimeBuffH[6]%10; //+0X30;
RX8025YMD[5] = RX8025TimeBuffH[5]/10; //+0X30; 月
RX8025YMD[6] = RX8025TimeBuffH[5]%10; //+0X30;
RX8025YMD[8] = RX8025TimeBuffH[4]/10;// +0X30; 日
RX8025YMD[9] = RX8025TimeBuffH[4]%10; //+0X30;
RX8025HMS[0] = RX8025TimeBuffH[2]/10;// +0X30; 时
RX8025HMS[1] = RX8025TimeBuffH[2]%10; //+0X30;
RX8025HMS[3] = RX8025TimeBuffH[1]%100/10; //+0X30; 分
RX8025HMS[4] = RX8025TimeBuffH[1]%10;// +0X30;
RX8025HMS[6] = RX8025TimeBuffH[0]%100/10; //+0X30; 秒
RX8025HMS[7] = RX8025TimeBuffH[0]%10; //+0X30;
// Write_ASCII3X16_N(0,7,0,"T3:RX8025");
// Write_ASCII3X16_N(0,8,0,RX8025YMD);
// Write_ASCII3X16_N(2,9,0,RX8025HMS); Write_6x16Font_N(12,9,0,WeekD);
}
//========================================================================
void delay_msT(uint16 i) //延时 i ms,不是十分精准,当i大于58时误差会超过1ms
{
for(;i>0;i--)
{
delay_1ms();
WDT_CONTR = 0x35;//
}
}
//----------------------------------------------------------------------------------------------------
int main()
{
P0M0=0x00,P0M1=0x00;//我自己加的代码 3
P2M0=0x00,P2M1=0x00;//我自己加的代码 3
P1M0=0x00,P1M1=0x00;//我自己加的代码 3
P4M0=0x00,P4M1=0x00;//我自己加的代码 3
P5M0=0x00,P5M1=0x00;//我自己加的代码
Uart1_Init();
RX8025_Init();
Write_RX8025_Byte(0,RX8025TimeBuffH);//RX8025时钟芯片里写入日期时间参数,2020-5-1-12:00:00,
while(1)
{ WDT_CONTR = 0x35;//喂狗
DisplayTime();
SendDataByUart1(0x32);
SendDataByUart1(0x30);
SendDataByUart1(RX8025YMD[2]+0x30);//串口发 年
SendDataByUart1(RX8025YMD[3]+0x30);
SendDataByUart1(0x20);//发空格
SendDataByUart1(RX8025YMD[5]+0x30);//串口发 月
SendDataByUart1(RX8025YMD[6]+0x30);
SendDataByUart1(0x20);
SendDataByUart1(RX8025YMD[8]+0x30);//串口发 日
SendDataByUart1(RX8025YMD[9]+0x30);
SendDataByUart1(0x20);
SendDataByUart1(RX8025HMS[0]+0x30);//串口发 时
SendDataByUart1(RX8025HMS[1]+0x30);//
SendDataByUart1(0x3a);//发冒号
SendDataByUart1(RX8025HMS[3]+0x30);//串口发 分
SendDataByUart1(RX8025HMS[4]+0x30);//
SendDataByUart1(0x3a);
SendDataByUart1(RX8025HMS[6]+0x30);//串口发 秒
SendDataByUart1(RX8025HMS[7]+0x30);//
delay_msT(4000);
delay_msT(4000);
}
}