/* ********************************************************************************************************* * 函 数 名: SI4730_SendCmd * 功能说明: 向Si4730发送CMD * 形 参: _pCmdBuf : 命令数组 * _CmdLen : 命令串字节数 * 返 回 值: 0 失败(器件无应答), 1 成功 ********************************************************************************************************* */ uint8_t SI4730_SendCmd(uint8_t *_pCmdBuf, uint8_t _ucCmdLen) { uint8_t ack; uint8_t i; i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_W); ack = i2c_WaitAck(); if (ack != 0) { goto err; } for (i = 0; i < _ucCmdLen; i++) { i2c_SendByte(_pCmdBuf[i]); ack = i2c_WaitAck(); if (ack != 0) { goto err; } } i2c_Stop(); return 1; err: i2c_Stop(); return 0; }
/* ********************************************************************************************************* * 函 数 名: SI4730_PowerUp_FM_Revice * 功能说明: 配置Si4703为FM接收模式, 模拟模式(非数字模式) * 形 参:无 * 返 回 值: 0 失败, 1 成功 ********************************************************************************************************* */ uint8_t SI4730_PowerUp_FM_Revice(void) { uint8_t ack; uint8_t status; /* AN332 page = 277 Powerup in Analog Mode CMD 0x01 POWER_UP ARG1 0xC0 Set to FM Receive. Enable interrupts. ARG2 0x05 Set to Analog Audio Output STATUS →0x80 Reply Status. Clear-to-send high. */ i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_W); ack = i2c_WaitAck(); i2c_SendByte(0x01); ack = i2c_WaitAck(); i2c_SendByte(0xC0); ack = i2c_WaitAck(); i2c_SendByte(0x05); ack = i2c_WaitAck(); i2c_Stop(); /* 等待器件返回状态 0x80 */ { uint32_t i; for (i = 0; i < 2500; i++) { i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_R); /* 读 */ ack = i2c_WaitAck(); status = i2c_ReadByte(); i2c_NAck(); i2c_Stop(); if (status == 0x80) { break; } } /* 实测 535 次循环应该正常退出 */ if (i == 2500) { return 0; } } return 1; }
/* ********************************************************************************************************* * 函 数 名: MPU6050_WriteByte * 功能说明: 向 MPU-6050 寄存器写入一个数据 * 形 参: _ucRegAddr : 寄存器地址 * _ucRegData : 寄存器数据 * 返 回 值: 无 ********************************************************************************************************* */ void MPU6050_WriteByte(uint8_t _ucRegAddr, uint8_t _ucRegData) { i2c_Start(); /* 总线开始信号 */ i2c_SendByte(MPU6050_SLAVE_ADDRESS); /* 发送设备地址+写信号 */ i2c_WaitAck(); i2c_SendByte(_ucRegAddr); /* 内部寄存器地址 */ i2c_WaitAck(); i2c_SendByte(_ucRegData); /* 内部寄存器数据 */ i2c_WaitAck(); i2c_Stop(); /* 总线停止信号 */ }
/* ********************************************************************************************************* * 函 数 名: SI4730_GetRevision * 功能说明: 读取器件、固件信息。 返回8字节数据 * 形 参:_ReadBuf 返回结果存放在此缓冲区,请保证缓冲区大小大于等于8 * 返 回 值: 0 失败, 1 成功 ********************************************************************************************************* */ uint8_t SI4730_GetRevision(uint8_t *_ReadBuf) { uint8_t ack; uint8_t status; uint32_t i; /* AN223 page = 67 */ /* 发送 0x10 命令 */ i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_W); ack = i2c_WaitAck(); i2c_SendByte(0x10); ack = i2c_WaitAck(); i2c_Stop(); /* 等待器件状态为 0x80 */ for (i = 0; i < 50; i++) { i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_R); /* 读 */ ack = i2c_WaitAck(); status = i2c_ReadByte(); if (status == 0x80) { break; } } /* 实测 2 次循环应该正常退出 */ if (i == 50) { i2c_NAck(); i2c_Stop(); return 0; } /* 连续读取8个字节的器件返回信息 */ for (i = 0; i < 8; i++) { i2c_Ack(); _ReadBuf[i] = i2c_ReadByte(); } i2c_NAck(); i2c_Stop(); return 1; }
/* ********************************************************************************************************* * 函 数 名: MPU6050_ReadByte * 功能说明: 读取 MPU-6050 寄存器的数据 * 形 参: _ucRegAddr : 寄存器地址 * 返 回 值: 无 ********************************************************************************************************* */ uint8_t MPU6050_ReadByte(uint8_t _ucRegAddr) { uint8_t ucData; i2c_Start(); /* 总线开始信号 */ i2c_SendByte(MPU6050_SLAVE_ADDRESS); /* 发送设备地址+写信号 */ i2c_WaitAck(); i2c_SendByte(_ucRegAddr); /* 发送存储单元地址 */ i2c_WaitAck(); i2c_Start(); /* 总线开始信号 */ i2c_SendByte(MPU6050_SLAVE_ADDRESS+1); /* 发送设备地址+读信号 */ i2c_WaitAck(); ucData = i2c_ReadByte(); /* 读出寄存器数据 */ i2c_NAck(); i2c_Stop(); /* 总线停止信号 */ return ucData; }
/* ********************************************************************************************************* * 函 数 名: i2c_CheckDevice * 功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在 * 形 参:_Address:设备的I2C总线地址 * 返 回 值: 返回值 0 表示正确, 返回1表示未探测到 ********************************************************************************************************* */ uint8_t i2c_CheckDevice(uint8_t _Address) { uint8_t ucAck; i2c_Cfg(); /* 配置GPIO及速度*/ i2c_Start(); /* 发送启动信号 */ /* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */ i2c_SendByte(_Address | I2C_WR); ucAck=i2c_WaitAck(); i2c_Stop(); /* 发送停止信号 */ return ucAck; }
/* ********************************************************************************************************* * 函 数 名: SI4730_WaitStatus80 * 功能说明: 读取Si4730的状态,等于0x80时返回。 * 形 参: _uiTimeOut : 轮询次数 * _ucStopEn : 状态0x80检测成功后,是否发送STOP * 返 回 值: 0 失败(器件无应答), > 1 成功, 数字表示实际轮询次数 ********************************************************************************************************* */ uint32_t SI4730_WaitStatus80(uint32_t _uiTimeOut, uint8_t _ucStopEn) { uint8_t ack; uint8_t status; uint32_t i; /* 等待器件状态为 0x80 */ for (i = 0; i < _uiTimeOut; i++) { i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_R); /* 读 */ ack = i2c_WaitAck(); if (ack == 1) { i2c_NAck(); i2c_Stop(); return 0; /* 器件无应答,失败 */ } status = i2c_ReadByte(); if ((status == 0x80) || (status == 0x81)) /* 0x81 是为了执行0x23指令 读取信号质量 */ { break; } } if (i == _uiTimeOut) { i2c_NAck(); i2c_Stop(); return 0; /* 超时了,失败 */ } /* 成功了, 处理一下第1次就成功的情况 */ if (i == 0) { i = 1; } /* 因为有些命令还需要读取返回值,因此此处根据形参决定是否发送STOP */ if (_ucStopEn == 1) { i2c_NAck(); i2c_Stop(); } return i; }
/******************************************************************************* * 名 称: i2c_CheckDevice * 功 能: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在 * 入口参数: _Address:设备的I2C总线地址 * 出口参数: 返回值 0 表示正确, 返回1表示未探测到 * 作 者: Roger-WY * 创建日期: 2016-05-20 * 修 改: * 修改日期: * 备 注: *******************************************************************************/ uint8_t i2c_CheckDevice(uint8_t _Address) { uint8_t ucAck; Bsp_InitI2C(); if (I2C_SDA_READ() && I2C_SCL_READ()) { i2c_Start(); /* 发送启动信号 */ /* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */ i2c_SendByte(_Address | I2C_WR); ucAck = i2c_WaitAck(); /* 检测设备的ACK应答 */ i2c_Stop(); /* 发送停止信号 */ return ucAck; } return 1; /* I2C总线异常 */ }
/* ********************************************************************************************************* * 函 数 名: SI4730_SetAMFreqCap * 功能说明: 设置AM调谐频率 * 形 参:_uiFreq : 频率值, 单位 10kHz _usCap : 调谐电容 * 返 回 值: 0 失败, 1 成功 ********************************************************************************************************* */ uint8_t SI4730_SetAMFreqCap(uint32_t _uiFreq, uint16_t _usCap) { /* AN332 page = 70 */ /* CMD 0x40 AM_TUNE_FREQ ARG1 0x00 ARG2 0x03 Set frequency to 1000 kHz = 0x03E8 ARG3 0xE8 ARG4 0x00 Automatically select tuning capacitor ARG5 0x00 STATUS ?0x80 Reply Status. Clear-to-send high. */ /* 64 and 108 MHz in 10 kHz units. */ uint8_t ucCmdBuf[32]; uint32_t uiTimeOut; uint32_t i; uint8_t status; ucCmdBuf[0] = 0x40; ucCmdBuf[1] = 0x00; ucCmdBuf[2] = _uiFreq >> 8; ucCmdBuf[3] = _uiFreq; ucCmdBuf[4] = _usCap >> 8; ucCmdBuf[5] = _usCap; SI4730_SendCmd(ucCmdBuf, 6); uiTimeOut = SI4730_WaitStatus80(10000, 1); if (uiTimeOut == 0) { return 0; } /* 等待器件状态为 0x81 */ for (i = 0; i < 5000; i++) { /* 0x14. GET_INT_STATUS */ ucCmdBuf[0] = 0x14; SI4730_SendCmd(ucCmdBuf, 1); SI4730_Delay(10000); i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_R); /* 读 */ i2c_WaitAck(); status = i2c_ReadByte(); i2c_Stop(); if (status == 0x81) { break; } } if (i == 5000) { return 0; /* 失败 */ } return 1; }
/* ********************************************************************************************************* * 函 数 名: SI4730_SetFMFreq * 功能说明: 设置FM调谐频率 * 形 参:_uiFreq : 频率值, 单位 10kHz * 返 回 值: 0 失败, 1 成功 ********************************************************************************************************* */ uint8_t SI4730_SetFMFreq(uint32_t _uiFreq) { /* AN332 page = 70 */ /* CMD 0x20 FM_TUNE_FREQ ARG1 0x00 ARG2 0x27 Set frequency to 102.3 MHz = 0x27F6 ARG3 0xF6 ARG4 0x00 Set antenna tuning capacitor to auto. STATUS ?0x80 Reply Status. Clear-to-send high. */ /* 64 and 108 MHz in 10 kHz units. */ uint8_t ucCmdBuf[32]; uint32_t uiTimeOut; uint32_t i; uint8_t status; ucCmdBuf[0] = 0x20; ucCmdBuf[1] = 0x00; ucCmdBuf[2] = _uiFreq >> 8; ucCmdBuf[3] = _uiFreq; ucCmdBuf[4] = 0x00; SI4730_SendCmd(ucCmdBuf, 5); uiTimeOut = SI4730_WaitStatus80(1000, 1); if (uiTimeOut == 0) { return 0; } /* 等待器件状态为 0x81 */ for (i = 0; i < 5000; i++) { /* 0x14. GET_INT_STATUS */ ucCmdBuf[0] = 0x14; SI4730_SendCmd(ucCmdBuf, 1); SI4730_Delay(10000); i2c_Start(); i2c_SendByte(I2C_ADDR_SI4730_R); /* 读 */ i2c_WaitAck(); status = i2c_ReadByte(); i2c_Stop(); if (status == 0x81) { break; } } if (i == 5000) { return 0; /* 失败 */ } return 1; }
/* ********************************************************************************************************* * 函 数 名: MPU6050_ReadData * 功能说明: 读取 MPU-6050 数据寄存器, 结果保存在全局变量 g_tMPU6050. 主程序可以定时调用该程序刷新数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void MPU6050_ReadData(void) { uint8_t ucReadBuf[14]; uint8_t i; uint8_t ack; #if 1 /* 连续读 */ i2c_Start(); /* 总线开始信号 */ i2c_SendByte(MPU6050_SLAVE_ADDRESS); /* 发送设备地址+写信号 */ ack = i2c_WaitAck(); if (ack != 0) { i2c_Stop(); return; } i2c_SendByte(ACCEL_XOUT_H); /* 发送存储单元地址 */ ack = i2c_WaitAck(); if (ack != 0) { i2c_Stop(); return; } i2c_Start(); /* 总线开始信号 */ i2c_SendByte(MPU6050_SLAVE_ADDRESS + 1); /* 发送设备地址+读信号 */ ack = i2c_WaitAck(); if (ack != 0) { i2c_Stop(); return; } for (i = 0; i < 13; i++) { ucReadBuf[i] = i2c_ReadByte(); /* 读出寄存器数据 */ i2c_Ack(); } /* 读最后一个字节,时给 NAck */ ucReadBuf[13] = i2c_ReadByte(); i2c_NAck(); i2c_Stop(); /* 总线停止信号 */ #else /* 单字节读 */ for (i = 0 ; i < 14; i++) { ucReadBuf[i] = MPU6050_ReadByte(ACCEL_XOUT_H + i); } #endif /* 将读出的数据保存到全局结构体变量 */ g_tMPU6050.Accel_X = (ucReadBuf[0] << 8) + ucReadBuf[1]; g_tMPU6050.Accel_Y = (ucReadBuf[2] << 8) + ucReadBuf[3]; g_tMPU6050.Accel_Z = (ucReadBuf[4] << 8) + ucReadBuf[5]; g_tMPU6050.Temp = (int16_t)((ucReadBuf[6] << 8) + ucReadBuf[7]); g_tMPU6050.GYRO_X = (ucReadBuf[8] << 8) + ucReadBuf[9]; g_tMPU6050.GYRO_Y = (ucReadBuf[10] << 8) + ucReadBuf[11]; g_tMPU6050.GYRO_Z = (ucReadBuf[12] << 8) + ucReadBuf[13]; }
//自动等待回复的发送字节函数 u8 i2c_SendByteA(uint8_t _ucByte) { i2c_SendByte(_ucByte); return(i2c_WaitAck()); }
/* ********************************************************************************************************* * 函 数 名: ee_ReadBytes * 功能说明: 从串行EEPROM指定地址处开始读取若干数据 * 形 参:_usAddress : 起始地址 * _usSize : 数据长度,单位为字节 * _pReadBuf : 存放读到的数据的缓冲区指针 * 返 回 值: 0 表示失败,1表示成功 ********************************************************************************************************* */ uint8_t ee_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize) { uint16_t i; /* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */ /* 第1步:发起I2C总线启动信号 */ i2c_Start(); /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */ i2c_SendByte(EE_DEV_ADDR | I2C_WR); /* 此处是写指令 */ /* 第3步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */ i2c_SendByte((uint8_t)_usAddress); /* 第5步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } /* 第6步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */ i2c_Start(); /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */ i2c_SendByte(EE_DEV_ADDR | I2C_RD); /* 此处是读指令 */ /* 第8步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } /* 第9步:循环读取数据 */ for (i = 0; i < _usSize; i++) { _pReadBuf[i] = i2c_ReadByte(); /* 读1个字节 */ /* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack */ if (i != _usSize - 1) { i2c_Ack(); /* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) */ } else { i2c_NAck(); /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */ } } /* 发送I2C总线停止信号 */ i2c_Stop(); return 1; /* 执行成功 */ cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */ /* 发送I2C总线停止信号 */ i2c_Stop(); return 0; }
/* ********************************************************************************************************* * 函 数 名: ee_WriteBytes * 功能说明: 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率 * 形 参:_usAddress : 起始地址 * _usSize : 数据长度,单位为字节 * _pWriteBuf : 存放读到的数据的缓冲区指针 * 返 回 值: 0 表示失败,1表示成功 ********************************************************************************************************* */ uint8_t ee_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint16_t _usSize) { uint16_t i,m; uint16_t usAddr; /* 写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。 对于24xx02,page size = 8 简单的处理方法为:按字节写操作模式,没写1个字节,都发送地址 为了提高连续写的效率: 本函数采用page wirte操作。 */ usAddr = _usAddress; for (i = 0; i < _usSize; i++) { /* 当发送第1个字节或是页面首地址时,需要重新发起启动信号和地址 */ if ((i == 0) || (usAddr & (EE_PAGE_SIZE - 1)) == 0) { /* 第0步:发停止信号,启动内部写操作 */ i2c_Stop(); /* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms CLK频率为200KHz时,查询次数为30次左右 */ for (m = 0; m < 100; m++) { /* 第1步:发起I2C总线启动信号 */ i2c_Start(); /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */ i2c_SendByte(EE_DEV_ADDR | I2C_WR); /* 此处是写指令 */ /* 第3步:发送一个时钟,判断器件是否正确应答 */ if (i2c_WaitAck() == 0) { break; } } if (m == 1000) { goto cmd_fail; /* EEPROM器件写超时 */ } /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */ i2c_SendByte((uint8_t)usAddr); /* 第5步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } } /* 第6步:开始写入数据 */ i2c_SendByte(_pWriteBuf[i]); /* 第7步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } usAddr++; /* 地址增1 */ } /* 命令执行成功,发送I2C总线停止信号 */ i2c_Stop(); return 1; cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */ /* 发送I2C总线停止信号 */ i2c_Stop(); return 0; }