一开始网上搜了很多代码,把好多子程序都放进去了,心想万一以后能用到。
端口设置如下。
GPIO_InitTypeDef GPIO_InitStruct;
DS1302_CLK_RCC_CLK_ENABLE();/*open GPIO clock*/
GPIO_InitStruct.Pin = DS1302_CLK;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;//GPIO_PULLUP;//GPIO_NOPULL
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DS1302_CLK_PORT, &GPIO_InitStruct);
下载过后,没有反应,读的数据不是5A,就是FF。再看手册,再网搜代码。
STM32F103用IO口和DS1302模块通信_迷宫中的我-CSDN博客 这个是目前最接近我的胃口的代码。
因为这个作者也使用了HAL库。我仔细对比了数据手册和代码,确认是上升沿有效写入,下降沿有效读出。先送出数据,设计上升沿,完成写操作。设计下降沿,读入数据,完成读操作。为了完成基本功能,删除了整片读写函数,增加了信号操作的几个延时 。
整个代码只有两个操作。
1)写命令字节(DS1302的IO线改为输出方式),写数据字节(DS1302的IO线改为输出方式)。
2)写命令字节(DS1302的IO线改为输出方式),读数据(DS1302的IO线改为输入方式)。
单步运行,发现输入输出设定的标志位搞反了。
/**********配置数据IO端口 输出 **********/
if(FLAG==0x00)//-------这里原来是01,改成00就对了
{
GPIO_InitStruct.Pin = DS1302_DAT;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;//GPIO_PULLUP
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStruct);
}/**********配置数据IO端口 输入**********/
if(FLAG==0x01)//------这里原来是00,改成01就对了
{
GPIO_InitStruct.Pin = DS1302_DAT;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;//配置输入,DS1302_DAT pin has an internal 40kΩ (typ) pulldown resistor to ground.
GPIO_InitStruct.Pull = GPIO_NOPULL;//GPIO_PULLUP;//GPIO_NOPULL
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;//GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStruct);
}
去掉杜邦线,直接找合适的插座与DS1302的插针连接。
再次运行,终于读到了正确数据。就是16进制到bcd的转换还不习惯。赶紧再熟悉一下。
重要的代码如下。
/********************************************************
****函数名称:void DS_WriteByte(uint8_t data)
****函数作用:DS1302写一个字节
****输入参数:要写的数据,
****输出参数:
********************************************************/
void DS1302_WriteByte(uint8_t data)
{
uint8_t i=0;
DS1302_Set_IO(FLAG_OUT);//DS1302_DAT_setOUT()
for(i=0;i<8;i++)
{
if(data&0x01)
DS1302_DAT_H();//数据线放上数据,先发低位
else
DS1302_DAT_L();
DS1302_CLK_L();//时钟线拉低
DS1302_delay(2);
DS1302_CLK_H();//时钟上升沿写入数据
DS1302_delay(2);
data>>=1;
}
DS1302_DAT_L();
}
/********************************************************
****函数名称:void DS_WriteSingleReg(uint8_t reg,uint8_t data)
****函数作用:写数据DS寄存器
****输入参数:reg,寄存器 data,数据
****输出参数:
********************************************************/
void DS1302_WriteSingleReg(uint8_t reg,uint8_t data)
{
DS1302_RST_L();//禁止数据传输 !!!这条很重要
DS1302_CLK_L();//确保写数据前SCLK为低电平
DS1302_delay(2);
DS1302_RST_H(); //RET=1;//启动DS1302总线
DS1302_delay(3);
DS1302_WriteByte(reg);
DS1302_WriteByte(data);
DS1302_RST_L();// CE=0;
DS1302_CLK_L();//CLK=0;
}
/********************************************************
****函数名称:uint8_t DS_ReadByte(void)
****函数作用:读取一个字节数据
****输入参数:
****输出参数:读出的数据 LSB 先出。
写数据是在SCLK的上升沿实现,而读数据在SCLK的下降沿实现,所以,在单字节读时序中,
写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了!
这个就是DS1302操作中最特别的地方。当然读出来的数据也是最低位开始。
********************************************************/
uint8_t DS1302_ReadByte(void)
{
uint8_t bit=0;
uint8_t input_value=0;
uint8_t i=0;
DS1302_Set_IO(FLAG_IN);//DS1302_DAT_setIN();//配置IO为输入
DS1302_delay(2);
for(i=0;i<8;i++)
{
DS1302_CLK_H();DS1302_delay(5);
DS1302_CLK_L();DS1302_delay(10);//时钟线拉低,时钟下降沿读数据。读之前为DS1302_WriteByte,最后为DS1302_CLK_H
bit=(HAL_GPIO_ReadPin(DS1302_DAT_PORT,DS1302_DAT));
input_value |= (bit << i);
}
DS1302_Set_IO(FLAG_OUT);//配置IO为输出,恢复正常状态
DS1302_delay(2);
return input_value;
}
/********************************************************
****函数名称:uint8_t DS1302_ReadSingleReg(uint8_t reg)
****函数作用:读取寄存器的值
****输入参数:寄存器,reg发送所在地址
****输出参数:值
********************************************************/
uint8_t DS1302_ReadSingleReg(uint8_t reg)
{
uint8_t data=0;
uint8_t mm,nn,value;
DS1302_RST_L();//禁止数据传输 !!!这条很重要
DS1302_CLK_L();//确保写数据前SCLK为低电平
DS1302_delay(2);
DS1302_RST_H();//RET=1;//启动DS1302总线,当CE被从0置为1时,时钟线必须为逻辑0。
DS1302_delay(2);
DS1302_WriteByte(reg);
data=DS1302_ReadByte();
DS1302_RST_L(); DS1302_delay(2);DS1302_CLK_L();
//数据处理转化十进制
mm=data/16;
nn=data%16;
value=mm*10+nn;
return value;
}
//在DS1302.c中,读完时间后调用printf 打印到串口输出,计算机用串口调试助手接收,“时间”这两个字会出现中文乱码
printf("时间:%d-%d-%d %d:%d:%d %d \n",TimeData.year,TimeData.month,TimeData.day,TimeData.hour,TimeData.minute,TimeData.second,TimeData.week);
把上面一行放在主程序中,串口接收汉字正常。怎么肥事?