STM32F407通过GPIO脚仿真I2C总线驱动PCA9552,实现对PCA9552所有16位脚的控制的过完整代码
时间: 2023-06-27 17:05:57 浏览: 121
以下是基于STM32F407的GPIO模拟I2C总线控制PCA9552的完整代码:
```c
#include "stm32f4xx.h"
#include "delay.h"
/**************************定义常量**************************/
#define PCA9552_ADDR 0x40 // PCA9552器件地址
// PCA9552寄存器地址
#define PCA9552_INPUT0 0x00
#define PCA9552_INPUT1 0x01
#define PCA9552_OUTPUT0 0x02
#define PCA9552_OUTPUT1 0x03
#define PCA9552_POLARITY0 0x04
#define PCA9552_POLARITY1 0x05
#define PCA9552_CONFIG0 0x06
#define PCA9552_CONFIG1 0x07
/**************************函数声明**************************/
void I2C_Start(void);
void I2C_Stop(void);
void I2C_Ack(void);
void I2C_NAck(void);
uint8_t I2C_WaitAck(void);
void I2C_SendByte(uint8_t byte);
uint8_t I2C_ReadByte(void);
void I2C_WriteByte(uint8_t addr, uint8_t reg, uint8_t data);
uint8_t I2C_ReadByteData(uint8_t addr, uint8_t reg);
/**************************主函数**************************/
int main(void)
{
// 初始化GPIO
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// PCA9552配置
I2C_WriteByte(PCA9552_ADDR, PCA9552_CONFIG0, 0x00);
I2C_WriteByte(PCA9552_ADDR, PCA9552_CONFIG1, 0x00);
// 输出测试
I2C_WriteByte(PCA9552_ADDR, PCA9552_OUTPUT0, 0xAA);
I2C_WriteByte(PCA9552_ADDR, PCA9552_OUTPUT1, 0x55);
uint8_t input0 = I2C_ReadByteData(PCA9552_ADDR, PCA9552_INPUT0);
uint8_t input1 = I2C_ReadByteData(PCA9552_ADDR, PCA9552_INPUT1);
if (input0 == 0xAA && input1 == 0x55)
{
// 输出测试通过
while (1)
{
// 翻转所有脚
uint16_t output = 0xFFFF;
I2C_WriteByte(PCA9552_ADDR, PCA9552_OUTPUT0, output & 0xFF);
I2C_WriteByte(PCA9552_ADDR, PCA9552_OUTPUT1, output >> 8);
delay_ms(1000);
output = 0x0000;
I2C_WriteByte(PCA9552_ADDR, PCA9552_OUTPUT0, output & 0xFF);
I2C_WriteByte(PCA9552_ADDR, PCA9552_OUTPUT1, output >> 8);
delay_ms(1000);
}
}
else
{
// 输出测试失败
while (1);
}
}
/**************************函数定义**************************/
// I2C起始信号
void I2C_Start(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_6);
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
delay_us(4);
}
// I2C停止信号
void I2C_Stop(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_SetBits(GPIOB, GPIO_Pin_6);
delay_us(4);
}
// I2C应答信号
void I2C_Ack(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_SetBits(GPIOB, GPIO_Pin_6);
delay_us(4);
}
// I2C非应答信号
void I2C_NAck(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(4);
GPIO_SetBits(GPIOB, GPIO_Pin_6);
delay_us(4);
}
// 等待I2C应答信号
uint8_t I2C_WaitAck(void)
{
uint8_t ucErrTime = 0;
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(1);
GPIO_SetBits(GPIOB, GPIO_Pin_6);
delay_us(1);
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
delay_us(1);
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(1);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7))
{
ucErrTime++;
if (ucErrTime > 250)
{
I2C_Stop();
return 1;
}
}
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
return 0;
}
// I2C发送一个字节
void I2C_SendByte(uint8_t byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
if (byte & 0x80)
GPIO_SetBits(GPIOB, GPIO_Pin_7);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
byte <<= 1;
delay_us(2);
GPIO_SetBits(GPIOB, GPIO_Pin_6);
delay_us(2);
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
delay_us(2);
}
}
// I2C读取一个字节
uint8_t I2C_ReadByte(void)
{
uint8_t i, data = 0;
GPIO_SetBits(GPIOB, GPIO_Pin_7);
delay_us(2);
for (i = 0; i < 8; i++)
{
data <<= 1;
GPIO_SetBits(GPIOB, GPIO_Pin_6);
delay_us(2);
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7))
data |= 0x01;
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
delay_us(2);
}
return data;
}
// I2C写一个字节数据到指定寄存器
void I2C_WriteByte(uint8_t addr, uint8_t reg, uint8_t data)
{
I2C_Start();
I2C_SendByte(addr << 1);
I2C_WaitAck();
I2C_SendByte(reg);
I2C_WaitAck();
I2C_SendByte(data);
I2C_WaitAck();
I2C_Stop();
}
// I2C从指定寄存器读取一个字节数据
uint8_t I2C_ReadByteData(uint8_t addr, uint8_t reg)
{
uint8_t data;
I2C_Start();
I2C_SendByte(addr << 1);
I2C_WaitAck();
I2C_SendByte(reg);
I2C_WaitAck();
I2C_Start();
I2C_SendByte((addr << 1) | 1);
I2C_WaitAck();
data = I2C_ReadByte();
I2C_NAck();
I2C_Stop();
return data;
}
```
此代码模拟了STM32F407的GPIO口来控制I2C总线,并通过I2C控制PCA9552的输出脚。其中,函数`I2C_Start`、`I2C_Stop`、`I2C_Ack`、`I2C_NAck`、`I2C_WaitAck`、`I2C_SendByte`、`I2C_ReadByte`、`I2C_WriteByte`、`I2C_ReadByteData`分别实现了I2C的起始信号、停止信号、应答信号、非应答信号、等待应答信号、发送一个字节、读取一个字节、写一个字节数据到指定寄存器、从指定寄存器读取一个字节数据的功能。在主函数中,首先初始化了GPIO并配置PCA9552的寄存器,然后进行输出测试,最后实现了翻转所有输出脚的功能。
阅读全文