一、概述
通过STM32的PC14和PC15管脚来模拟I2C通信,读写I2C接口的器件内部寄存器,具体定义如下:
#define PIN_SCL GPIO_Pin_14
#define PIN_SDA GPIO_Pin_15
延时函数为μs延时,例如Delay(4)表示延时4μs。
二、Static型函数定义
static __inline void TWI_SCL_0(void) { GPIOC->BSRRH = PIN_SCL; }
static __inline void TWI_SCL_1(void) { GPIOC->BSRRL = PIN_SCL; }
static __inline void TWI_SDA_0(void) { GPIOC->BSRRH = PIN_SDA; }
static __inline void TWI_SDA_1(void) { GPIOC->BSRRL = PIN_SDA; }
static __inline u8 TWI_SDA_STATE(void) { return (GPIOC->IDR & PIN_SDA) != 0; }
三、功能函数定义
void TWI_Init(void);
u8 TWI_Start(void);
u8 TWI_Start_SHT(void);
void TWI_Stop(void);
void TWI_SendByte(u8 Data);
u8 TWI_ReceiveByte(void);
void TWI_SendACK(void);
void TWI_SendNACK(void);
u8 TWI_WaitACK(void);
u8 TWI_WriteOneByte(u8 DAddr,u8 Addr,u8 Dat);
u8 TWI_ReadOneByte(u8 Daddr,u8 Addr);
四、功能函数详解
4.1 I2C端口初始化
说明:(1)SDA设置为开漏输出,这是双向数据线常规I/O方式。
(2)SCL设置为推挽输出
void TWI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC->AHB1ENR |= 1<<2;
RCC->APB1ENR |= 1<<28;
PWR->CR |= 1<<8;
RCC->BDCR &= ~(1<<0);
GPIO_InitStructure.GPIO_Pin = PIN_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = PIN_SCL;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC,&GPIO_InitStructure);
TWI_SDA_1();
TWI_SCL_0();
}
4.2 I2C发送启动函数
u8 TWI_Start(void)
{
TWI_SDA_1();
TWI_SCL_1();
Delay(4);
if(!TWI_SDA_STATE())//SDAÏßΪµÍµçƽÔò×ÜÏß棬Í˳ö
{
return TWI_FAILURE;
}
TWI_SDA_0();
Delay(4);
while(TWI_SDA_STATE())//SDAÏßΪ¸ßµçƽÔò×ÜÏß³ö´í£¬Í˳ö
{
return TWI_FAILURE;
}
TWI_SCL_0();
Delay(4);
return TWI_SUCCESS;
}
4.3 I2C停止函数
void TWI_Stop(void)
{
TWI_SDA_0();
TWI_SCL_0();
Delay(4);
TWI_SCL_1();
Delay(4);
TWI_SDA_1();
}
4.4 向从机发送应答信号
void TWI_SendACK(void)
{
TWI_SDA_0();
TWI_SCL_0();
Delay(4);
TWI_SCL_1();
Delay(4);
TWI_SCL_0();
}
4.5 发送无应答信号
void TWI_SendNACK(void)
{
TWI_SDA_1();
TWI_SCL_0();
Delay(4);
TWI_SCL_1();
Delay(4);
TWI_SCL_0();
}
4.6 等待从机应答信号
u8 TWI_WaitACK(void)
{
TWI_SCL_0();
TWI_SDA_1();
Delay(4);
TWI_SCL_1();
Delay(4);
while(TWI_SDA_STATE())
{
TWI_SCL_0();
return TWI_FAILURE;
}
TWI_SCL_0();
return TWI_SUCCESS;
}
4.7 发送一字节数据函数
void TWI_SendByte(u8 Data)
{
u8 i=8;
while(i--)
{
TWI_SCL_0();
Delay(1);
if(Data&0x80)
{
TWI_SDA_1();
}
else
{
TWI_SDA_0();
}
Data<<=1;
Delay(4);
TWI_SCL_1();
Delay(4);
}
TWI_SCL_0();
}
4.8 接收一字节数据函数
u8 TWI_ReceiveByte(void)
{
u8 i=8;
u8 Data = 0;
TWI_SDA_1();
while(i--)
{
Data <<= 1;
TWI_SCL_0();
Delay(4);
TWI_SCL_1();
Delay(4);
if(TWI_SDA_STATE())
{
Data |= 0x01;
}
}
TWI_SCL_0();
return Data;
}
五 、应用函数
5.1 向从机按地址写数据
u8 TWI_WriteOneByte(u8 DAddr,u8 Addr,u8 Dat)
{
if(!TWI_Start())
return TWI_FAILURE;
TWI_SendByte(DAddr);
TWI_WaitACK();
TWI_SendByte(Addr);
TWI_WaitACK();
TWI_SendByte(Dat);
TWI_WaitACK();
TWI_Stop();
return TWI_SUCCESS;
}
5.2 从从机按地址读数据
u8 TWI_ReadOneByte(u8 Daddr,u8 Addr)
{
u8 Dat;
if(!TWI_Start())
return TWI_FAILURE;
TWI_SendByte(Daddr);
if(!TWI_WaitACK())
{
TWI_Stop();
return TWI_FAILURE;
}
TWI_SendByte(Addr);
TWI_WaitACK();
TWI_Start();
TWI_SendByte(Daddr + 1);
TWI_WaitACK();
Dat = TWI_ReceiveByte();
TWI_SendNACK();
TWI_Stop();
return Dat;
}
5.3 RTC允许设置函数
u8 RTC_WriteTimeOff(void)
{
if(!TWI_WriteOneByte(DEVICE_ADDRESS_WRITE,0x0F,0x0))
{
return TWI_FAILURE;
}
TWI_WriteOneByte(DEVICE_ADDRESS_WRITE,0x10,0x0);
return TWI_SUCCESS;
}
5.4 RTC禁止设置函数
u8 RTC_WriteTimeOff(void)
{
if(!TWI_WriteOneByte(DEVICE_ADDRESS_WRITE,0x0F,0x0))
{
return TWI_FAILURE;
}
TWI_WriteOneByte(DEVICE_ADDRESS_WRITE,0x10,0x0);
return TWI_SUCCESS;
}
5.5 读实时数据寄存器
u8 TWI_ReadDate(S_Time *psRTC)
{
if(!TWI_Start())
return TWI_FAILURE;
TWI_SendByte(DEVICE_ADDRESS_WRITE+1);
if(!TWI_WaitACK())
{
TWI_Stop();
return TWI_FAILURE;
}
psRTC->Second = TWI_ReceiveByte();
TWI_SendACK();
psRTC->Minute = TWI_ReceiveByte();
TWI_SendACK();
psRTC->Hour = TWI_ReceiveByte()&0x7F;
TWI_SendACK();
psRTC->Week = TWI_ReceiveByte();
TWI_SendACK();
psRTC->Day = TWI_ReceiveByte();
TWI_SendACK();
psRTC->Month = TWI_ReceiveByte();
TWI_SendACK();
psRTC->Year = TWI_ReceiveByte();
TWI_SendNACK();
TWI_Stop();
return TWI_SUCCESS;
}
5.6 写实时数据寄存器
u8 TWI_WriteDate(S_Time SetRTC)
{
S_Time *psRTC;
psRTC = &SetRTC;
RTC_WriteTimeOn();
if(!TWI_Start())
return TWI_FAILURE;
TWI_SendByte(DEVICE_ADDRESS_WRITE);
if(!TWI_WaitACK())
{
TWI_Stop();
return TWI_FAILURE;
}
TWI_SendByte(SECOND_REGISTER_ADDRESS);
TWI_WaitACK();
TWI_SendByte(psRTC->Second);
TWI_WaitACK();
TWI_SendByte(psRTC->Minute);
TWI_WaitACK();
TWI_SendByte(psRTC->Hour | 0x80);
TWI_WaitACK();
TWI_SendByte(psRTC->Week);
TWI_WaitACK();
TWI_SendByte(psRTC->Day);
TWI_WaitACK();
TWI_SendByte(psRTC->Month);
TWI_WaitACK();
TWI_SendByte(psRTC->Year);
TWI_WaitACK();
TWI_Stop();
RTC_WriteTimeOff();
return TWI_SUCCESS;
}
六、总结
本文通过STM32F2系列的单片机读写RTC实时时钟芯片SD2405,设计上完全可行,并已在产品上使用。