32G12K128 FreeRTOS 下读取DS1302失败
我采用论坛上DS1302的例程,读取DS1302失败。我用逻辑分析仪抓了波形,SPI时钟大约3us,延时应该够了。请问调试经验丰富的人,能否从波形图上看出问题所在。 在STC32G12K128微控制器上使用FreeRTOS实时操作系统读取DS1302实时时钟模块时遇到读取失败的问题,可能涉及多个方面的原因。以下是一些可能的原因及相应的解决方案,供您参考和排查。1. 硬件连接问题
首先,确保DS1302模块与STC32G12K128微控制器的硬件连接正确无误。DS1302通常需要以下引脚连接:
VCC:电源正极,通常为3.3V或5V。
GND:电源地。
CLK:时钟信号,连接到微控制器的GPIO引脚。
DAT:数据信号,连接到微控制器的GPIO引脚。
RST:复位信号,连接到微控制器的GPIO引脚。
请检查这些引脚是否连接正确,并确保电源电压符合DS1302的要求。
2. 引脚配置与初始化
在软件中,确保正确配置了与DS1302通信的GPIO引脚。通常需要将CLK、DAT和RST引脚配置为输出模式,并在初始化时设置适当的电平状态。例如:
c
void DS1302Init(void) {
GPIOInitTypeDef GPIOInitStruct;
// 配置CLK、DAT、RST引脚为输出模式
GPIOInitStruct.Pin = DS1302CLKPIN | DS1302DATPIN | DS1302RSTPIN;
GPIOInitStruct.Mode = GPIOMODEOUTPUTPP;
GPIOInitStruct.Pull = GPIONOPULL;
GPIOInitStruct.Speed = GPIOSPEEDFREQLOW;
HALGPIOInit(DS1302GPIOPORT, &GPIOInitStruct);
// 初始化引脚状态
HALGPIOWritePin(DS1302GPIOPORT, DS1302RSTPIN, GPIOPINRESET);
HALGPIOWritePin(DS1302GPIOPORT, DS1302CLKPIN, GPIOPINRESET);
HALGPIOWritePin(DS1302GPIOPORT, DS1302DATPIN, GPIOPINRESET);
}
3. 时序问题
DS1302的通信协议对时序有严格的要求。确保在读取和写入数据时,严格按照DS1302的时序图进行操作。以下是一个简单的读取字节的示例:
```c
uint8t DS1302ReadByte(void) {
uint8t data = 0;
uint8t i;
for (i = 0; i < 8; i++) {
HALGPIOWritePin(DS1302GPIOPORT, DS1302CLKPIN, GPIOPINSET);
HALDelay(1); // 适当延时
data |= HALGPIOReadPin(DS1302GPIOPORT, DS1302DATPIN)
[本文内容由国芯人工智能辅助生成,仅供参考]
普中开发板上测过的例程参考下:
#define Protrct_Enable 0x80 //使能写保护
#define Protect_Disable 0x00 //禁用写保护
#define Write_Protect 0x8e //定义写保护寄存器地址
#define Write_TCS 0x90 //定义写充电寄存器地址
#define Write_Year 0x8c //定义写年寄存器地址
#define Write_Week 0x8a //定义写星期寄存器地址
#define Write_Month 0x88 //定义写月寄存器地址
#define Write_Date 0x86 //定义写日寄存器地址
#define Write_Hour 0x84 //定义写小时寄存器地址
#define Write_Minute 0x82 //定义写分钟寄存器地址
#define Write_Second 0x80 //定义写秒钟寄存器地址
#define Read_TCS 0x91 //定义读充电寄存器地址
#define Read_Year 0x8d //定义读年寄存器地址
#define Read_Week 0x8b //定义读星期寄存器地址
#define Read_Month 0x89 //定义读月寄存器地址
#define Read_Date 0x87 //定义读日寄存器地址
#define Read_Hour 0x85 //定义读小时寄存器地址
#define Read_Minute 0x83 //定义读分钟寄存器地址
#define Read_Second 0x81 //定义读秒钟寄存器地址
#define TCS_OFF 0xa0 //设置DS1302充电方式为关闭
#define TCS_1D2K 0xa5 //设置DS1302充电方式为1个二极管,2K电阻
#define TCS_1D4K 0xa6 //设置DS1302充电方式为1个二极管,4K电阻
#define TCS_1D8K 0xa7 //设置DS1302充电方式为1个二极管,8K电阻
#define TCS_2D2K 0xa9 //设置DS1302充电方式为2个二极管,2K电阻
#define TCS_2D4K 0xaa //设置DS1302充电方式为2个二极管,4K电阻
#define TCS_2D8K 0xab //设置DS1302充电方式为2个二极管,8K电阻
#define Init_Year 0x19 //初始化年
#define Init_Week 0x03 //初始化星期
#define Init_Month 0x08 //初始化月
#define Init_Date 0x28 //初始化日
#define Init_Hour 0x14 //初始化小时
#define Init_Minute 0x13 //初始化分钟
#define Init_Second 0x00 //初始化秒钟/*----------------------------DS1302写数据----------------------------*/
//void Write_DS1302 (unsigned char addr,unsigned char dat)
//{
// unsigned char i,temp; //声明移位次数、临时变量
// DS1302_RST=0; //拉低DS1302_RST,禁止DS1302数据传输
// DS1302_CLK=0; //拉低DS1302_CLK
// DS1302_RST=1; //DS1302_RST为高,使能DS1302数据传输
// for(i=8;i>0;i--) //循环移位8次
// {
// DS1302_CLK=0; //拉低DS1302_CLK
// temp=addr; //把地址赋值给临时变量
// DS1302_DAT=(bit)(temp&0x01); //每次传输低字节,数据放到数据端口
// DS1302_CLK=1; //拉高DS1302_CLK,锁存数据
// addr>>=1; //地址右移一位
// }
// for(i=8;i>0;i--) //循环移位8次
// {
// DS1302_CLK=0; //拉低DS1302_CLK
// temp=dat; //把数据赋值给临时变量
// DS1302_DAT=(bit)(temp&0x01); //只取最低一位
// DS1302_CLK=1; //拉高DS1302_CLK,锁存数据
// dat>>=1; //右移一位
// }
// DS1302_CLK=0; //拉低DS1302_CLK
// DS1302_RST=0; //拉低DS1302_RST,禁止DS1302数据传输
//}
/*----------------------------DS1302读数据----------------------------*/
unsigned char Read_DS1302(unsigned char addr)
{
unsigned char i,temp,dat,dat1;
DS1302_RST=0; //拉低DS1302_RST,禁止DS1302数据传输
DS1302_CLK=0; //拉低DS1302_CLK
DS1302_RST=1; //DS1302_RST为高,使能DS1302数据传输
for(i=8;i>0;i--) //循环移位8次
{
DS1302_CLK=0; //拉低DS1302_CLK
temp=addr; //把地址赋值给临时变量
DS1302_DAT=(bit)(temp&0x01); //每次传输低位
DS1302_CLK=1; //拉高DS1302_CLK,锁存数据
addr>>=1; //addr右移一位
}
P3M0=P3M0&0x3d;
for(i=8;i>0;i--) //循环移位8次
{
ACC>>=1; //ACC右移一位
DS1302_CLK=1; //先拉高DS1302_CLK
DS1302_CLK=0; //拉低DS1302_CLK,准备读取数据
ACC_7=DS1302_DAT; //读取数据,ACC_7为存放数据变量的最高位一位
}
P3M0=P3M0|0x02;
DS1302_CLK=0; //拉低DS1302_CLK
DS1302_RST=0; //拉低DS1302_RST,禁止DS1302数据传输
dat=ACC; //把ACC赋值给dat
dat1=dat&0xf0; //数据进制转换, 提取高四位
dat1>>=4; //移动到低四位,作为十位
dat=dat&0x0f; //提取低四位,作为个位
dat=dat+dat1*10; //得到的十进制数
return dat; //返回十进制值
}
/*----------------------------初始化DS1302----------------------------*/
//void Init_DS1302(void)
//{
// Write_DS1302(Write_Protect,Protect_Disable); //禁用写保护
// Write_DS1302(Write_TCS,TCS_2D8K); //初始化充电方式
// Write_DS1302(Write_Year,Init_Year); //初始化年
// Write_DS1302(Write_Week,Init_Week); //初始化星期
// Write_DS1302(Write_Month,Init_Month); //初始化月
// Write_DS1302(Write_Date,Init_Date); //初始化日
// Write_DS1302(Write_Hour,Init_Hour); //初始化小时
// Write_DS1302(Write_Minute,Init_Minute); //初始化分钟
// Write_DS1302(Write_Second,Init_Second); //初始化秒钟
// Write_DS1302(Write_Protect,Protrct_Enable); //使能写保护
//}
感谢楼上各位老师,问题解决了。最初我是参考这个帖子DS1302 自用代码 (通用) - 老鸟反刍/吐槽,新手乐园,毕业设计 国芯技术交流网站 - AI32位8051交流社区,移植代码的。读时间寄存器参考了这段代码。//========================================================================
// 读取时间
// ***********************************************************************
//========================================================================
void Ds1302ReadTime()
{
unsigned char n;
unsigned char dd="";
for (n=0; n<7; n++)
{
TIME = Ds1302Read(READ_RTC_ADDR);
}
for (n=0; n<7; n++)
{
TIME = Ds1302Read(READ_RTC_ADDR);
}
Year=BCD_DEC(TIME);
Week=BCD_DEC(TIME);
Month=BCD_DEC(TIME);
day=BCD_DEC(TIME);
Hour=BCD_DEC(TIME);
Minute=BCD_DEC(TIME);
Second=BCD_DEC(TIME);
} 我做了一些改动,我用addr =0x81 读秒寄存器,每读一次地址加2. 结果读第二轮时,没有把地址恢复到0x81.经过这次教训,我也感觉这段代码重复读2次,似乎没有必要,没有对读出来的时间寄存器的数据做时间有效性的校验,读取多次,也只是使用最后一次的数据。提高不了读取成功的机率。除非芯片本身固有的特性,第二轮读取的数据成功几率更高。
页:
[1]