I2C通信以及stm32单片机程序详解
1、初始化IO口:
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
#define READ_SDA PBin(7) //输入SDA
(1)在固件库中操作IDR寄存器读取IO端口数据是通过GPIO_ReadInputDataBit函数实现的:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
比如 要读GPIOA.5的电平状态,那么方法是: GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);
返回值是1(Bit_SET)或者0(Bit_RESET);
在STM32固件库中,通过BSRR和BRR寄存器设置GPIO端口输出是通过函数 GPIO_SetBits()和函数GPIO_ResetBits()来完成的。
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) ;
在多数情况下,都是采用这两个函数来设置GPIO端口的输入和输出状态。
比如要设置GPIOB.5输出1,方法为:
GPIO_SetBits(GPIOB, GPIO_Pin_5);
如果要设置GPIOB.5输出0,方法为:
GPIO_ResetBits (GPIOB, GPIO_Pin_5);
(2)位带操作:
宏定义:
#define LED0 PBout(5)
#define LED1 PEout(5)
位带操作来实现操作某个IO口的1个位,通过位带操作PB5输出高低电平的方法如下:
LED0=1; //通过位带操作控制引脚PB5输出高电平
LED0=0; //通过位带操作控制引脚PB5输出低电平
比如,要PORTA的第七个IO口输出1,PAout(6)=1;
要判断PORTA的第15个位是否等于1,则可以使用if(PAin(14)==1)…;
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 输出高
}
2、初始化时钟线SCL与数据线SDA,此时可以看到这两个引脚都是输出引脚,根据I2C通信协议可知:SDA信号线上不仅仅只输出信号,有时也有输入信号,也就是说SDA信号线的引脚有时需要配置成输出,有时需要配置成输入,程序如下:
void IIC_setSDAMode_Out(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //PB7推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void IIC_setSDAMode_In(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU ; //推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
3、信号线的引脚初始化状态配置好后,开始写I2C通信协议,程序如下:
(1)起始信号:
void IIC_Start(void)
{
IIC_setSDAMode_Out(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
注意:起始信号产生后,SCL信号线为低电平状态
(2)写单字节函数:
void IIC_Send_Byte(u8 txd)
{
u8 t;
IIC_setSDAMode_Out();
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
注意:写单字节函数完成后,SCL信号线为低电平状态
(3)读单字节函数:
u8 IIC_Read_Byte()
{
unsigned char i,receive=0;
IIC_setSDAMode_In();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=1;
receive<<=1;
receive|=(unsigned char)READ_SDA;
IIC_SCL=0;
delay_us(2);
}
return receive;
}
注意:读单字节函数完成后,SCL信号线为低电平状态
(4)应答信号:
u8 IIC_Wait_Ack(void)
{
u8 a;
IIC_setSDAMode_In(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us