You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

264 lines
6.2 KiB
C

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "SWM221.h"
#include "IOI2C_SLV.h"
static char TxBuff[128] = {0};
static uint32_t TxSize = 0;
static volatile uint32_t TxIndx = 0;
static char RxBuff[128] = {0};
static uint32_t RxSize = 128; //最多能接收128个字节
static volatile uint32_t RxIndx = 0;
static volatile uint32_t BitTim = 0;
static volatile uint32_t IsBusy = 0; //检测到Start置位检测到Stop清零
static volatile uint32_t IsNACK = 0; //发送数据时收到NACK
static uint32_t RxBuff2[128] = {0}; //接收到Stop时将RxBuff中数据搬运到这里然后驱动可以继续用RxBuff接收数据位用户可通过从RxBuff2中读走数据
static volatile uint32_t RxSize2 = 0; //RxBuff2中有多少个数据可以被读出
static volatile uint32_t RxIndx2 = 0;
static void (*IOI2C_SLV_Func)(void);
static void IOI2C_SLV_SendByte(void);
static void IOI2C_SLV_ReadByte(void);
extern uint32_t IOI2C_SLV_EmptyCallback(char *TxBuff);
/******************************************************************************************************************************************
* 函数名称: IOI2C_SLV_Init()
* 功能说明: IOI2C_SLV初始化
* 输 入: 无
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void IOI2C_SLV_Init(void)
{
#define IOI2C_PORT GPIOA
#define IOI2C_SCL PIN2
#define IOI2C_SDA PIN3
#define IOI2C_IRQ GPIOA_IRQn
#define IOI2C_ISR GPIOA_Handler
GPIO_Init(IOI2C_PORT, IOI2C_SCL, 0, 1, 0, 1);
#define I2C_SCL_Value() GPIO_GetBit(IOI2C_PORT, IOI2C_SCL)
GPIO_Init(IOI2C_PORT, IOI2C_SDA, 0, 1, 0, 1);
#define I2C_SDA_OUTPUT() IOI2C_PORT->DIR |= (1 << IOI2C_SDA);
#define I2C_SDA_LOW() GPIO_ClrBit(IOI2C_PORT, IOI2C_SDA)
#define I2C_SDA_HIGH() GPIO_SetBit(IOI2C_PORT, IOI2C_SDA)
#define I2C_SDA_INPUT() IOI2C_PORT->DIR &=~(1 << IOI2C_SDA)
#define I2C_SDA_Value() GPIO_GetBit(IOI2C_PORT, IOI2C_SDA)
EXTI_Init(IOI2C_PORT, IOI2C_SCL, EXTI_BOTH_EDGE);
EXTI_Init(IOI2C_PORT, IOI2C_SDA, EXTI_BOTH_EDGE);
NVIC_EnableIRQ(IOI2C_IRQ);
EXTI_Open(IOI2C_PORT, IOI2C_SCL);
EXTI_Open(IOI2C_PORT, IOI2C_SDA);
}
/******************************************************************************************************************************************
* 函数名称: IOI2C_SLV_RxNotEmpty()
* 功能说明: IOI2C从机接收缓冲区中是否有数据可取出
* 输 入: 无
* 输 出: uint32_t 0 没有可取出数据 >0 可取出的数据个数
* 注意事项: 无
******************************************************************************************************************************************/
uint32_t IOI2C_SLV_RxNotEmpty(void)
{
return RxSize2;
}
/******************************************************************************************************************************************
* 函数名称: IOI2C_SLV_FetchByte()
* 功能说明: 从IOI2C从机接收缓冲区中取出一个字节
* 输 入: 无
* 输 出: char 取出的字节
* 注意事项: 无
******************************************************************************************************************************************/
char IOI2C_SLV_FetchByte(void)
{
RxSize2 -= 1;
return RxBuff2[RxIndx2++];
}
/******************************************************************************************************************************************
* 函数名称: IOI2C_SLV_FetchBytes()
* 功能说明: 从IOI2C从机接收缓冲区中取出n个字节
* 输 入: char buff[] 取出的数据存入此数组
* uint32_t len 要取出的数据的个数不得大于IOI2C_SLV_RxNotEmpty()返回值
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void IOI2C_SLV_FetchBytes(char buff[], uint32_t len)
{
uint32_t i;
for(i = 0; i < len; i++)
buff[i] = RxBuff2[RxIndx2+i];
RxIndx2 += len;
RxSize2 -= len;
}
static void IOI2C_SLV_SendByte(void)
{
if(IsNACK == 1)
{
I2C_SDA_INPUT();
goto noinc;
}
if(TxSize == 0)
{
TxSize = IOI2C_SLV_EmptyCallback(TxBuff);
TxIndx = 0;
}
if(BitTim == 0) I2C_SDA_OUTPUT(); //发送上一个字符时会将SDA切成输入脚以接收ACK
if(BitTim < 16)
{
if((BitTim % 2) == 0)
{
if(TxBuff[TxIndx] & (1 << (7 - BitTim/2)))
I2C_SDA_HIGH();
else
I2C_SDA_LOW();
}
}
else if(BitTim == 16)
{
I2C_SDA_INPUT();
}
else if(BitTim == 17)
{
if(I2C_SDA_Value()) //NACK
{
IsNACK = 1;
}
else
{
if(++TxIndx == TxSize)
{
TxIndx = TxSize - 1;
}
}
BitTim = 0;
goto noinc;
}
BitTim++;
noinc:
;
}
static void IOI2C_SLV_ReadByte(void)
{
if(BitTim == 0) I2C_SDA_INPUT(); //接收上一个字符时会将SDA切成输出脚以发送ACK
if(BitTim < 16)
{
if((BitTim % 2) == 1)
{
if(I2C_SDA_Value() == 1)
RxBuff[RxIndx] |= (1 << (7 - BitTim/2));
else
RxBuff[RxIndx] &= ~(1 << (7 - BitTim/2));
}
}
else if(BitTim == 16)
{
I2C_SDA_OUTPUT();
if(++RxIndx < RxSize)
{
I2C_SDA_LOW();
}
else
{
I2C_SDA_HIGH();
}
}
else if(BitTim == 17)
{
if((RxIndx == 1) && (RxBuff[0] & 0x01))
{
TxIndx = 0;
IsNACK = 0;
IOI2C_SLV_Func = IOI2C_SLV_SendByte;
}
BitTim = 0;
goto noinc;
}
BitTim++;
noinc:
;
}
/******************************************************************************************************************************************
* 函数名称: IOI2C_ISR()
* 功能说明: IOI2C SCL、SDA引脚双边沿中断服务函数
* 输 入: 无
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void IOI2C_ISR(void)
{
uint32_t i;
if(EXTI_State(IOI2C_PORT, IOI2C_SDA))
{
EXTI_Clear(IOI2C_PORT, IOI2C_SDA);
if(I2C_SCL_Value() == 1) //只有在SCL高电平时SDA的跳变才是Start和Stop
{
if(I2C_SDA_Value() == 0) //Start
{
RxIndx = 0;
BitTim = 0;
IsBusy = 1;
IOI2C_SLV_Func = IOI2C_SLV_ReadByte;
}
else //Stop
{
IsBusy = 0;
for(i = 0; i < RxIndx-1; i++)
{
RxBuff2[i] = RxBuff[1+i]; //RxBuff[]中第一个字节是从机地址
}
RxSize2 = i;
RxIndx2 = 0;
}
}
}
else if(EXTI_State(IOI2C_PORT, IOI2C_SCL))
{
EXTI_Clear(IOI2C_PORT, IOI2C_SCL);
if(IsBusy) IOI2C_SLV_Func();
}
}