使用GPIO模拟I2C成功驱动DS1302日历模块之后,便尝试继续驱动DS1307日历模块。这两个模块的驱动有些不同,DS1307也许是符合标准I2C通讯的,而DS1302则不需要器件的I2C地址,只要直接对其进行读写操作。下图是两个模块的实物,DS1307模块上还集成了AT24C32flash,本次尚未对其操作。
这是模块的另一面,DS1302上添加了三个上拉电阻。
测试过程不顺利,从网上搜索了多个参考例子,但读出的数据全是零,显然是没有驱动成功。然后又准备改用硬件I2C来驱动,先参照范例程序对I2C的读写操作进行了分析,我将I2C读、写操作的函数放在一起比较,基本上了解其操作过程,下面是对比的结果。
- /**
- * @brief Receives in master mode an amount of data in blocking mode.
- 在主模式下以阻塞模式接收大量数据。
- * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
- * the configuration information for the specified I2C.
- * @param DevAddress Target device address: The device 7 bits address value
- * in datasheet must be shifted to the left before calling the interface
- * @param pData Pointer to data buffer
- * @param Size Amount of data to be sent
- * @param Timeout Timeout duration
- * @retval HAL status
- */
- HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
- HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
- {
- uint32_t tickstart;
- if (hi2c->State == HAL_I2C_STATE_READY)
- {
- /* Process Locked锁定进程 */
- __HAL_LOCK(hi2c);
- /* Init tickstart for timeout management超时管理开始计时 */
- tickstart = HAL_GetTick();
- if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK)
- {
- return HAL_ERROR;
- }
- hi2c->State = HAL_I2C_STATE_BUSY_TX;
- hi2c->Mode = HAL_I2C_MODE_MASTER;
- hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
- /* Prepare transfer parameters准备传输参数 */
- hi2c->pBuffPtr = pData;
- hi2c->XferCount = Size;
- hi2c->XferISR = NULL;
-
- /* Send Slave Address发送从机地址 */
- /* Set NBYTES to write and reload if hi2c->XferCount > MAX_NBYTE_SIZE and generate RESTART
- 如果hi2c->xfercount>max戋nbyte戋u size并生成restart,则将nbytes设置为write和reload */
- if (hi2c->XferCount > MAX_NBYTE_SIZE)
- {
- hi2c->XferSize = MAX_NBYTE_SIZE;
- //T I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE);
- //R I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
- }
- else
- {
- hi2c->XferSize = hi2c->XferCount;
- //T I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_WRITE);
- //R I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
- }
- while (hi2c->XferCount > 0U)
- {
- /* Wait until TXIS flag is set等待Txis标志设置完毕 */
- //T if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
- /* Wait until RXNE flag is set等待rxne标志设置完毕 */
- //R if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
- {
- return HAL_ERROR;
- }
- /* Write data to TXDR将数据写入TXDR */
- //T hi2c->Instance->TXDR = *hi2c->pBuffPtr;
- /* Read data from RXDR */
- //R *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->RXDR;
- /* Increment Buffer pointer移动缓冲区指针 */
- hi2c->pBuffPtr++;
- hi2c->XferCount--;
- hi2c->XferSize--;
- if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U))
- {
- /* Wait until TCR flag is set等待设置TCR标志 */
- if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK)
- {
- return HAL_ERROR;
- }
- if (hi2c->XferCount > MAX_NBYTE_SIZE)
- {
- hi2c->XferSize = MAX_NBYTE_SIZE;
- I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
- }
- else
- {
- hi2c->XferSize = hi2c->XferCount;
- I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
- }
- }
- }
- /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated
- 无需检查TC标志,在自动结束模式下自动生成停止 */
- /* Wait until STOPF flag is set等待设置stopf标志 */
- if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
- {
- return HAL_ERROR;
- }
- /* Clear STOP Flag */
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
- /* Clear Configuration Register 2清除配置寄存器2 */
- I2C_RESET_CR2(hi2c);
- hi2c->State = HAL_I2C_STATE_READY;
- hi2c->Mode = HAL_I2C_MODE_NONE;
- /* Process Unlocked解锁 */
- __HAL_UNLOCK(hi2c);
- return HAL_OK;
- }
- else
- {
- return HAL_BUSY;
- }
- }
复制代码
然后参照范例写了对DS1307进行读写操作的函数,但调试了两天都不成功,不知道是错在了那里,下面是对DS1307进行读写操作的代码。
- #define I2C_ADDRESS DS1307_ADDR
- /******************************************************************************************
- * 函数名称: DS1307_I2C_Read()
- * 功能说明: 从DS1307地址addr开始获取size个字节的数据,获取的数据存储在全局变量DS_Buff中
- * 输 入: uint8_t addr 获取数据的开始地址
- * uint8_t size 要获取的数据个数(1~8)
- * 输 出: ui08 0=RET_OK 成功从DS1307获取数据 >0=从DS1307获取数据过程中出现错误
- ******************************************************************************************/
- uint8_t DS1307_I2C_Read(uint8_t addr,uint8_t size)
- {
- DS_Buff[0] = addr; //将要读取的起始地址发送给DS1307
- while (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)I2C_ADDRESS|1, (uint8_t *)DS_Buff, 1, 10000) != HAL_OK)
- {
- if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
- {
- LCD_write_ASCII(0,3,1,(uint8_t *)"DS1307WR Error");
- return 1;
- }
- }
- while (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)I2C_ADDRESS|0, (uint8_t *)DS_Buff, size, 10000) != HAL_OK)
- {
- if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
- {
- LCD_write_ASCII(0,3,1,(uint8_t *)"DS1307RD Error");
- return 2;
- }
- }
- return 0;
- }
- /******************************************************************************************
- * 函数名称: DS1307_I2C_Write()
- * 功能说明: 从DS1307地址addr开始写入size个字节的数据,数据存储在全局变量DS_Buff中
- * 输 入: uint8_t addr 写入数据的开始地址
- * uint8_t size 要写入的数据个数(1~8)
- * 输 出: ui08 0=RET_OK 成功写入数据 >0=从DS1307写入数据过程中出现错误
- ******************************************************************************************/
- uint8_t DS1307_I2C_Write(uint8_t addr,uint8_t size)
- {
- uint8_t i;
- i = DS_Buff[0];
- DS_Buff[0] = addr; //将要写入的起始地址发送给DS1307
- while (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)I2C_ADDRESS|1, (uint8_t *)DS_Buff, 1, 10000) != HAL_OK)
- {
- if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
- {
- LCD_write_ASCII(0,3,1,(uint8_t *)"DS1307TX Error");
- return 1;
- }
- }
- DS_Buff[0] = i;
- while (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)I2C_ADDRESS|1, (uint8_t *)DS_Buff, size, 10000) != HAL_OK)
- {
- if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
- {
- LCD_write_ASCII(0,3,1,(uint8_t *)"DS1307TX Error");
- return 2;
- }
- }
- return 0;
- }
复制代码
这是初始化DS1307的代码,首先读出秒寄存器数据,判断其是否在工作,若尚未在工作就对其进行初始设置。在这里就出错了,读不出正确数据。
- /******************************************************************************************
- * 函数名称: DS1307_Init()
- * 功能说明: 用当前日期(yesr,month,day,hour,minute)初始化DS1307
- * 输 入: 无
- * 输 出: uint8_t 0=RET_OK 初始化成功 1=RET_ERR 初始化出错
- ******************************************************************************************/
- uint8_t DS1307_Init(void)
- {
- uint8_t temp;
-
- // temp = DS1307_Read(0,1);
- temp = DS1307_I2C_Read(0,1);
- if(temp > 0)
- LCD_write_ASCII(0,3,1,(uint8_t *)"DS1307 R Error"); //读秒数据,判断DS1307是否在工作
- else
- LCD_write_ASCII(0,3,1,(uint8_t *)"DS1307 Read OK");
- HAL_Delay(1000);
- LCD_write_value(0,4,5,0,0,temp);
-
- if(DS_Buff[0]>127){
- /*
- DS1307_Reg.yer.b.yer10 = 1; //年
- DS1307_Reg.yer.b.yer1 = 9;
- DS1307_Reg.mon.b.mon10 = 0; //月
- DS1307_Reg.mon.b.mon1 = 9;
- DS1307_Reg.dat.b.dat10 = 0; //日
- DS1307_Reg.dat.b.dat1 = 9;
- DS1307_Reg.day.b.day = 3; //周
- DS1307_Reg.hur.b.hur10 = 1; //时
- DS1307_Reg.hur.b.hur1 = 0;
- DS1307_Reg.min.b.min10 = 0; //分
- DS1307_Reg.min.b.min1 = 0;
- DS1307_Reg.sec.b.sec10 = 0; //秒
- DS1307_Reg.sec.b.sec1 = 0;
- DS1307_Reg.sec.b.CLK_H = 0; //开启时钟
- DS1307_Reg.sqw.b.SQWE = 1; //使能方波输出
- DS1307_Reg.sqw.b.RS = 0; //方波频率选择:1Hz
- */
- year = 2019;
- month = 9;
- day = 12;
- week = 4;
- hour = 12;
- minute = 30;
-
- DS_Buff[0] = 0; //秒
- temp = ((minute/10)<<4|(minute%10));
- DS_Buff[1] = temp; //分
- temp = ((hour/10)<<4|(hour%10));
- DS_Buff[2] = temp; //时
- temp = ((day/10)<<4|(day%10));
- DS_Buff[3] = temp; //日
-
- DS_Buff[4] = week; //星期
- temp = ((month/10)<<4|(month%10));
- DS_Buff[5] = temp; //月
- temp = ((year%100)/10<<4|(year%10));
- DS_Buff[6] = temp; //年
-
- DS_Buff[7] = 32; //0010 0000 = 允许按1Hz输出方波
- // return DS1307_Write(0,8);
- return DS1307_I2C_Write(0,8);
- }
- else
- return 1;
- }
- /******************************************************************************************
- * 函数名称: DS1307_Config()
- * 功能说明: 配置DS1307_OUT中断引脚
- * 输 入: 无
- * 输 出: 无
- ******************************************************************************************/
- void DS1307_Config(void)
- {
- /*
- GPIO_InitTypeDef GPIO_InitStruct;
- GPIO_InitStruct.Pin = DS_OUT;
- GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(DS_PORT, &GPIO_InitStruct);
- */
-
- SI2C_Config(); //配置I2C
- }
- /******************************************************************************************
- * 函数名称: DS1307_read_date()
- * 功能说明: 读取DS1307日期时间数据
- * 输 入: 无
- * 输 出: 无
- ******************************************************************************************/
- void DS1307_read_date(void)
- {
- // DS1307_Read(0,7); //读取前7个字节数据
- DS1307_I2C_Read(0,7); //读取前7个字节数据
- second = ((DS_Buff[0]&0x70)>>4)*10 + (DS_Buff[0]&0x0F);//秒,屏蔽秒的第7位的标志
- minute = ((DS_Buff[1]&0x70)>>4)*10 + (DS_Buff[1]&0x0F);//分(取低7位)
- hour = ((DS_Buff[2]&0x10)>>4)*10 + (DS_Buff[2]&0x0F); //时(取低5位)
- week = (DS_Buff[3]&0x07); //周(取低3位)
- day = ((DS_Buff[4]&0x30)>>4)*10 + (DS_Buff[4]&0x0F); //日(取低6位)
- month = ((DS_Buff[5]&0x10)>>4)*10 + (DS_Buff[5]&0x0F); //月(取低5位)
- year = 2000 + (DS_Buff[6]>>4)*10 + (DS_Buff[6]&0x0F); //年
- }
- /******************************************************************************************
- * 函数名称: DS1307_write_date()
- * 功能说明: 读取DS1307日期时间数据
- * 输 入: 无
- * 输 出: 无
- ******************************************************************************************/
- void DS1307_write_date(void)
- {
- uint8_t temp;
-
- DS_Buff[0] = 0; //秒
- temp = ((minute/10)<<4|(minute%10));
- DS_Buff[1] = temp; //分
- temp = ((hour/10)<<4|(hour%10));
- DS_Buff[2] = temp; //时
- temp = ((day/10)<<4|(day%10));
- DS_Buff[3] = temp; //日
-
- DS_Buff[4] = week; //星期
- temp = ((month/10)<<4|(month%10));
- DS_Buff[5] = temp; //月
- temp = ((year%100)/10<<4|(year%10));
- DS_Buff[6] = temp; //年
-
- // DS1307_Write(0,7); //写入前7个字节数据
- DS1307_I2C_Write(0,7); //写入前7个字节数据
- }
复制代码
|
DS1302不需要器件地址,直接对芯片进行读写操作,而DS1307则需要首先在I2C总线上输出从设备地址,得到应答后再进行通讯,而且我买的这个模块DS1307与AT24C32两个芯片的SCL和SDA是连通的,也就是挂在同一I2C总线上,需要通过器件地址来操作其中的芯片,所以应该是标准的I2C通讯。