// 这里中断和轮询还没有做管脚初始化区分
IIC_SLVAE_STATUS IIC_Slave_Gpio_Init(void)
{
// 使用PA04--SCK PA03--SDA 输入上拉
SDA_SCK_GPIO_EN;
GPIO_InitTypeDef GPIO_InitStruct = {0};
REGBITS_SET(SDA_GPIO_PROT->PUR, SDA_GPIO_PIN);
// REGBITS_CLR(SDA_GPIO_PROT->PDR, SDA_GPIO_PIN);
REGBITS_SET(SCK_GPIO_PORT->PUR, SCK_GPIO_PIN);
// REGBITS_CLR(SCK_GPIO_PORT->PDR, SCK_GPIO_PIN);
#if IIC_SLAVE_POLLING_MODE
// 使用PB04--SCK PB03--SDA 输入上拉
// 开漏模式
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pins = SDA_GPIO_PIN;
SDA_WRITE_H;
GPIO_Init(SDA_GPIO_PROT, &GPIO_InitStruct);
// 输入模式
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_InitStruct.Pins = SCK_GPIO_PIN; // 防止有问题,单个初始化
GPIO_Init(SCK_GPIO_PORT, &GPIO_InitStruct);
#elif IIC_SLAVE_INTTERUPT_MODE
// 下降沿中断模式
GPIO_InitStruct.IT = GPIO_IT_FALLING;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_InitStruct.Pins = SDA_GPIO_PIN;
SDA_WRITE_H;
GPIO_Init(SDA_GPIO_PROT, &GPIO_InitStruct);
// 输入模式
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_InitStruct.Pins = SCK_GPIO_PIN; // 防止有问题,单个初始化
GPIO_Init(SCK_GPIO_PORT, &GPIO_InitStruct);
//清除中断标志并使能NVIC
SDA_GPIO_CLEAR_IT_FLAG;
SCK_GPIO_CLEAR_IT_FLAG;
NVIC_SetPriority(SDA_SCK_IRQn, 0); // 最高优先级
NVIC_EnableIRQ(SDA_SCK_IRQn);
#endif
if (SDA_READ == GPIO_Pin_RESET || SDA_READ == GPIO_Pin_RESET) { // 此时的SDA 和SCK要为高为状态
return STATUS_NO;
}
#if IIC_SLAVE_TEST_EN
// 测试脚 PB5--输出上拉
__RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pins = GPIO_PIN_5;
GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
TEST_PIN_L;
#endif
return STATUS_OK;
}
#if IIC_SLAVE_POLLING_MODE
static inline IIC_SLVAE_STATUS IIC_Slave_Start(void)
{
if (SDA_READ == GPIO_Pin_RESET && SCK_READ == GPIO_Pin_SET) { // 接收到起始位
TEST_PIN_L;
iicSlaveStruct.startFlag = 1;
iicSlaveStruct.rxDataCnt = 0;
iicSlaveStruct.startRxDataCntRecord = iicSlaveStruct.rxDataCnt; // 记录当前起始位的第一个数据位置
} else {
return STATUS_NO;
}
// 消耗掉起始位,等待位低
uint32_t overCnt = 0;
while(1) {
if(SCK_READ == GPIO_Pin_RESET) {
break; // 进入起始位 开始接收数据
}
overCnt++;
if (overCnt > IIC_RX_OVERTIME_CNT) {
return IIC_START_OVERTIME;
}
};
// 开始接收数据
iicSlaveStruct.startFlag = 0; // 清除标志
iicSlaveStruct.addressWriteReadFlag = 0; // 第一次默认地址写,从机接收数据
iicSlaveStruct.rxByteBitCnt = 0;
iicSlaveStruct.rxDataCnt = 0;
iicSlaveStruct.rxTempData = 0;
iicSlaveStruct.ackMasterFlag = 0;
#if DJI_Drone
iicSlaveStruct.ackMasterFlagEn = 0;
iicSlaveStruct.rxDataBuf[1] = 0; // 这个特殊处理一下
#endif
return STATUS_OK;
}
#endif
inline void IIC_Slave_Mater_Read_Tx_Handle_Register(void(*txDataHandle)(uint8_t *buf, uint8_t size, IIC_SlaveReadTxDataHandleStruct *txStruct))
{
iicSlaveStruct.txDataHandle = txDataHandle;
}
inline void IIC_Slave_Rx_Handle_Register(void(*rxDataHandle)(uint8_t *buf, uint8_t size))
{
iicSlaveStruct.rxDataHandle = rxDataHandle;
}
static inline IIC_SLVAE_STATUS IIC_Slave_Send_Data(void)
{
// 待会发送的数量接上
if (iicSlaveStruct.addressWriteReadFlag == 1 && iicSlaveStruct.ackMasterFlag == 0) {
iicSlaveStruct.txByteBitCnt = 0;
iicSlaveStruct.txDataCnt = 0;
if (iicSlaveStruct.txDataHandle != NULL) { // 填充发送数据
//回调slaveTxDataHandle这个函数,根据命令号控制是否发送数据,赋值相应的buff数据和size字节数
iicSlaveStruct.txDataHandle(iicSlaveStruct.rxDataBuf, iicSlaveStruct.rxDataCnt, &iicSlaveStruct.txStruct);
}
iicSlaveStruct.rxDataCnt = 0;
while(1) {
if (iicSlaveStruct.txByteBitCnt == 8) { // 数据发送完毕,开始接收应答
SDA_WRITE_H; // 1个字节发送完毕,开始释放数据线来接收主机应答
iicSlaveStruct.readMasterAckFlag = 1;
iicSlaveStruct.txByteBitCnt = 0;
iicSlaveStruct.txDataCnt++;
} else {
if (iicSlaveStruct.txDataCnt < iicSlaveStruct.txStruct.size) { //iicSlaveStruct.txStruct.size不发数据是0
if (iicSlaveStruct.txStruct.txBuf[iicSlaveStruct.txDataCnt] & (0x80 >> iicSlaveStruct.txByteBitCnt)) { // 发送高位在先
SDA_WRITE_H;
} else {
SDA_WRITE_L;
}
} else {
SDA_WRITE_H; // 数据超过就发送0xFF
}
iicSlaveStruct.txByteBitCnt++;
}
IIC_SLVAE_STATUS result = IIC_SCK_L() ;
if (result != STATUS_OK) {
return result;
}
result = IIC_SCK_H();
if (result != STATUS_OK) {
return result;
}
}
}
return STATUS_OK;
}
static inline void IIC_Slave_Receive_Data(void)
{
// sck为高,开始读取数据
if (iicSlaveStruct.addressWriteReadFlag == 0 && iicSlaveStruct.ackMasterFlag == 0) { //如果为1就是应答,主机读取
if (SDA_READ == GPIO_Pin_SET) {
iicSlaveStruct.rxTempData |= 0x80 >> iicSlaveStruct.rxByteBitCnt; // 高位发送在先
}
iicSlaveStruct.rxByteBitCnt++;
if (iicSlaveStruct.rxByteBitCnt == 8) {
iicSlaveStruct.ackMasterFlag = 1; // 开始回复应答
iicSlaveStruct.rxDataBuf[iicSlaveStruct.rxDataCnt] = iicSlaveStruct.rxTempData;
iicSlaveStruct.rxByteBitCnt = 0; // 重新计数
iicSlaveStruct.rxTempData = 0;
iicSlaveStruct.rxDataCnt++;
if (iicSlaveStruct.rxDataCnt >= sizeof(iicSlaveStruct.rxDataBuf)) {
iicSlaveStruct.rxDataCnt = sizeof(iicSlaveStruct.rxDataBuf) - 1;
}
if (iicSlaveStruct.rxDataBuf[1] == 0x2f) {
PB03_SETHIGH(); //打开IO给66供电
PB04_SETHIGH();
}
if (iicSlaveStruct.startFlag == 1) { // 判断读写和命令进行应答
iicSlaveStruct.startFlag = 0;
if (iicSlaveStruct.rxDataBuf[iicSlaveStruct.startRxDataCntRecord] == IIC_Slave_Read_Adress) { //主机读状态
iicSlaveStruct.addressWriteReadFlag = 1; // 进入写的状态
#if DJI_Drone
if (iicSlaveStruct.rxDataBuf[1] == 0x2f) {
CLOSE_BMS_IIC;
PB03_SETLOW(); //关闭IO口输出,认证芯片断电(降低功耗)
PB04_SETLOW();
}
#endif
} else { // 从新进入接收状态
iicSlaveStruct.addressWriteReadFlag = 0; // 第一次默认地址写,从机接收数据
iicSlaveStruct.rxByteBitCnt = 0;
iicSlaveStruct.rxDataCnt = 0;
iicSlaveStruct.rxTempData = 0;
}
}
}
} else {
iicSlaveStruct.ackMasterFlag = 0;
}
}
static inline void IIC_Slave_Send_Ack(void)
{
// 开始发送数据
// 发送的时候不处理
if (iicSlaveStruct.ackMasterFlag == 1) { // 应答主机
#if DJI_Drone
if (iicSlaveStruct.rxDataBuf[1] == 0xC2 || iicSlaveStruct.ackMasterFlagEn == 1) {
iicSlaveStruct.ackMasterFlagEn = 0;
CLOSE_BMS_IIC;
SDA_WRITE_L;
}
#else
SDA_WRITE_L;
#endif
} else {
SDA_WRITE_H;
}
}
static inline IIC_SLVAE_STATUS IIC_SCK_L(void)
{
uint32_t overCnt = IIC_RX_OVERTIME_CNT;
while(overCnt--) { // 低电平准备数据循环
if(SCK_READ == GPIO_Pin_SET) {
return STATUS_OK; // 进入数据读取区
}
}
return IIC_WAIT_H_OVERTIME;
}
static inline IIC_SLVAE_STATUS IIC_SCK_H(void)
{
uint32_t overCnt = IIC_RX_OVERTIME_CNT;
uint8_t endReadFlag = 0;
if (SDA_READ == GPIO_Pin_RESET) { // 这里是SCK电平高时,等待位低的过程中检测SDA是否有变化,来判断起始位和终止位
endReadFlag = 1;
} else {
endReadFlag = 0;
}
while(overCnt--) { // 高电平读取数据循环
if (iicSlaveStruct.readMasterAckFlag == 1) { // 接收应答
iicSlaveStruct.readMasterAckFlag = 0;
if (SDA_READ == GPIO_Pin_SET) {
return IIC_MASTER_ACK_FAIL;
}
}
if(SCK_READ == GPIO_Pin_RESET) {
return STATUS_OK; // 进入数据准备区
} else if (endReadFlag == 1 && SDA_READ == GPIO_Pin_SET) { // 检测到结束标志
iicSlaveStruct.endFlag = 1;
return IIC_END_SIGNLE;
} else if (endReadFlag == 0 && SDA_READ == GPIO_Pin_RESET) { // 检测到起始标志
iicSlaveStruct.startFlag = 1;
iicSlaveStruct.startRxDataCntRecord = iicSlaveStruct.rxDataCnt;
iicSlaveStruct.rxByteBitCnt = 0; // 清除位接收
iicSlaveStruct.rxTempData = 0;
iicSlaveStruct.txByteBitCnt = 0;
}
}
return IIC_WAIT_L_OVERTIME;
}
static inline void IIC_Slave_RX_TX_Handle(void)
{
while(1) {
if (IIC_Slave_Send_Data() != STATUS_OK) {
SDA_WRITE_H; // 释放SDA
break;
}
IIC_Slave_Send_Ack();
iicSlaveStruct.result = IIC_SCK_L();
if (iicSlaveStruct.result != STATUS_OK) {
break;
}
IIC_Slave_Receive_Data();
iicSlaveStruct.result = IIC_SCK_H(); //接收完整一帧数据,IIC_END_SIGNLE返回后退出本次接收
if (iicSlaveStruct.result == IIC_END_SIGNLE) { // 搞成一个宏,结束这次接收
break;
} else if (iicSlaveStruct.result != STATUS_OK) {
break;
}
}
}
#if IIC_SLAVE_POLLING_MODE
// 待会接收和发送数据要内联函数封装分开
// 先轮询接收
static IIC_SLVAE_STATUS IIC_Slave_Rx_Data(void)
{
IIC_SLVAE_STATUS result;
result = IIC_Slave_Start();
if (result != STATUS_OK) {
if (result == STATUS_NO) {
return STATUS_OK; // 没有起始位,也可以正常
}
return IIC_START_OVERTIME;
}
// 开始接收数据
// sck为低
IIC_Slave_RX_TX_Handle();
OPEN_BMS_IIC;
SDA_WRITE_H; // 释放SDA
return iicSlaveStruct.result;
}
#endif
#if IIC_SLAVE_INTTERUPT_MODE
void IIC_SDA_Inttrupt_Handle(void)
{
TEST_PIN_L;
iicSlaveStruct.startFlag = 1;
iicSlaveStruct.startRxDataCntRecord = iicSlaveStruct.rxDataCnt; // 记录当前起始位的第一个数据位置
iicSlaveStruct.addressWriteReadFlag = 0; // 第一次默认地址写
SCK_INTERRUPT_MODE;
}
void IIC_SCK_Intterupt_Handle(void)
{
SDA_OPEN_LEAK_MODE;
iicSlaveStruct.startFlag = 0; // 清除标志
iicSlaveStruct.addressWriteReadFlag = 0; // 第一次默认地址写,从机接收数据
iicSlaveStruct.rxByteBitCnt = 0;
iicSlaveStruct.rxDataCnt = 0;
iicSlaveStruct.rxTempData = 0;
iicSlaveStruct.ackMasterFlag = 0;
#if DJI_Drone
iicSlaveStruct.ackMasterFlagEn = 0;
iicSlaveStruct.rxDataBuf[1] = 0; // 这个特殊处理一下
#endif
// 开始接收数据
IIC_Slave_RX_TX_Handle();
OPEN_BMS_IIC;
SCK_INTPU_MODE;
SDA_WRITE_H; // 释放SDA
SDA_INTERRUPT_MODE; // 接收完数据要开启中断模式
}
// 放在管脚中断里面跑
inline void IIC_Slave_IRQ_Handle(void)
{
if (SCK_READ == GPIO_Pin_SET && SDA_READ == GPIO_Pin_RESET && iicSlaveStruct.startFlag == 0) { // 接收到起始位
IIC_SDA_Inttrupt_Handle();
} else if (SCK_READ == GPIO_Pin_RESET) { // 开始处理数据
if (SDA_READ == GPIO_Pin_RESET && iicSlaveStruct.startFlag == 1) {
IIC_SCK_Intterupt_Handle();
iicSlaveStruct.rxTxFlag = 1;
}
iicSlaveStruct.startFlag = 0; // 接收发送完数据或者错误进来都要清楚这个标志位
}
SDA_GPIO_CLEAR_IT_FLAG;
SCK_GPIO_CLEAR_IT_FLAG;
}
#endif
uint8_t Get_IIC_Slave_RxTxFlag(void)
{
return iicSlaveStruct.rxTxFlag; // 该标志为1 代表iicSlave有接收或者发送数据标志, iicSlave只会置位,不会清除该标志
}
void Set_IIC_Slave_RxTxFlag(uint8_t flag)
{
if (flag) {
iicSlaveStruct.rxTxFlag = 1;
} else {
iicSlaveStruct.rxTxFlag = 0;
}
}
void IIC_Slave_Disable(void)
{
//清除中断标志并使能NVIC
SDA_GPIO_CLEAR_IT_FLAG;
SCK_GPIO_CLEAR_IT_FLAG;
__disable_irq();
NVIC_DisableIRQ(SDA_SCK_IRQn);
__enable_irq();
SDA_OPEN_LEAK_MODE;
SDA_WRITE_H; // 释放SDA
SCK_INTPU_MODE;
iicSlaveStruct.startFlag = 0;
}
void IIC_Slave_Enable(void)
{
SDA_GPIO_CLEAR_IT_FLAG;
SCK_GPIO_CLEAR_IT_FLAG;
SDA_INTERRUPT_MODE;
__disable_irq();
NVIC_EnableIRQ(SDA_SCK_IRQn);
__enable_irq();
}
// 看函数说明
// 函数参数:
// pin: 0位SDA管脚, 1位SCK管脚
// mode 管脚模式,可以位下面三个值:GPIO_MODE_INPUT_PULLUP、GPIO_MODE_INPUT_PULLDOWN、GPIO_MODE_INPUT
// ItEdge 唤醒中断边沿,可以位下面三个值: GPIO_IT_RISING、GPIO_IT_FALLING 、GPIO_IT_RISING | GPIO_IT_FALLING
void IIC_Slave_Sleep_Entry(uint32_t pin, uint32_t mode, uint32_t ItEdge)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (pin == 0) {
GPIO_InitStruct.IT = ItEdge;
GPIO_InitStruct.Mode = mode;
GPIO_InitStruct.Pins = SDA_GPIO_PIN;
GPIO_Init(SDA_GPIO_PROT, &GPIO_InitStruct);
SDA_GPIO_CLEAR_IT_FLAG;
} else {
GPIO_InitStruct.IT = ItEdge;
GPIO_InitStruct.Mode = mode;
GPIO_InitStruct.Pins = SCK_GPIO_PIN;
GPIO_Init(SCK_GPIO_PORT, &GPIO_InitStruct);
SCK_GPIO_CLEAR_IT_FLAG;
}
//清除中断标志并使能NVIC
NVIC_SetPriority(SDA_SCK_IRQn, 0); // 最高优先级
NVIC_EnableIRQ(SDA_SCK_IRQn);
}
void IIC_Slave_WakeUp_Handle(void)
{
IIC_Slave_Gpio_Init();
}
void IIC_Slave_Task(void)
{
#if IIC_SLAVE_POLLING_MODE
IIC_SLVAE_STATUS result = IIC_Slave_Rx_Data();
if (result != STATUS_OK) {
SDA_WRITE_H; // 释放SDA
}
#endif
//接收完整一帧数据,退出一帧数据的接收,取一帧数据
if (iicSlaveStruct.rxDataCnt != 0) {
if (iicSlaveStruct.rxDataHandle != NULL) {
iicSlaveStruct.rxDataHandle(iicSlaveStruct.rxDataBuf, iicSlaveStruct.rxDataCnt);
}
iicSlaveStruct.rxDataCnt = 0;
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_50707044/article/details/141261783
|