高级会员

- 积分
- 520
- 金钱
- 520
- 注册时间
- 2018-8-15
- 在线时间
- 85 小时
|
/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define EEPROM_GPIO_PORT_I2C GPIOB /* GPIO端口 */
#define EEPROM_RCC_I2C_PORT RCC_AHBPeriph_GPIOB /* GPIO端口时钟 */
#define EEPROM_I2C_SCL_PIN GPIO_Pin_8 /* 连接到SCL时钟线的GPIO */
#define EEPROM_I2C_SDA_PIN GPIO_Pin_9 /* 连接到SDA数据线的GPIO */
/* 定义读写SCL和SDA的宏,已增加代码的可移植性和可阅读性 */
#if 0 /* 条件编译: 1 选择GPIO的库函数实现IO读写 */
#define EEPROM_I2C_SCL_1() GPIO_SetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SCL_PIN) /* SCL = 1 */
#define EEPROM_I2C_SCL_0() GPIO_ResetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SCL_PIN) /* SCL = 0 */
#define EEPROM_I2C_SDA_1() GPIO_SetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SDA_PIN) /* SDA = 1 */
#define EEPROM_I2C_SDA_0() GPIO_ResetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SDA_PIN) /* SDA = 0 */
#define EEPROM_I2C_SDA_READ() GPIO_ReadInputDataBit(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SDA_PIN) /* 读SDA口线状态 */
#else /* 这个分支选择直接寄存器操作实现IO读写 */
/* 注意:如下写法,在IAR最高级别优化时,会被编译器错误优化 */
#define EEPROM_I2C_SCL_1() EEPROM_GPIO_PORT_I2C->BSRR = EEPROM_I2C_SCL_PIN /* SCL = 1 */
#define EEPROM_I2C_SCL_0() EEPROM_GPIO_PORT_I2C->BRR = EEPROM_I2C_SCL_PIN /* SCL = 0 */
#define EEPROM_I2C_SDA_1() EEPROM_GPIO_PORT_I2C->BSRR = EEPROM_I2C_SDA_PIN /* SDA = 1 */
#define EEPROM_I2C_SDA_0() EEPROM_GPIO_PORT_I2C->BRR = EEPROM_I2C_SDA_PIN /* SDA = 0 */
#define EEPROM_I2C_SDA_READ() ((EEPROM_GPIO_PORT_I2C->IDR & EEPROM_I2C_SDA_PIN) != 0) /* 读SDA口线状态 */
#endif
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick->LOAD=6*nus; //设置重装数值, 48MHZ时
SysTick->CTRL=0X01; //使能,减到零是无动作,采用外部时钟源
SysTick->VAL=0; //清零计数器
do
{
temp=SysTick->CTRL; //读取当前倒计数值
}
while((temp&0x01)&&(!(temp&(1<<16)))); //等待时间到达
SysTick->CTRL=0; //关闭计数器
SysTick->VAL=0; //清空计数器
}
void SDA_OUT()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN; //LED引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //高速输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //开漏输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //上拉
GPIO_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure);
}
void SDA_IN()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */
GPIO_InitStructure.GPIO_Pin =EEPROM_I2C_SDA_PIN; //LED引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //高速输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //开漏输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //上拉
GPIO_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure);
}
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN |EEPROM_I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure);
GPIO_SetBits(EEPROM_GPIO_PORT_I2C,EEPROM_I2C_SCL_PIN|EEPROM_I2C_SDA_PIN);
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
EEPROM_I2C_SDA_1();
EEPROM_I2C_SCL_1();
delay_us(4);
//i2c_Delay();
EEPROM_I2C_SDA_0();//START:when CLK is high,DATA change form high to low
//i2c_Delay();
delay_us(4);
EEPROM_I2C_SCL_0();//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
EEPROM_I2C_SCL_0();
EEPROM_I2C_SDA_0();//STOP:when CLK is high DATA change form low to high
// i2c_Delay();
delay_us(4);
EEPROM_I2C_SCL_1();
EEPROM_I2C_SDA_1();//发送I2C总线结束信号
// i2c_Delay();
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
uint8_t ucErrTime=0;
SDA_OUT();
EEPROM_I2C_SDA_1();
//i2c_Delay();
delay_us(1);
SDA_IN(); //SDA设置为输入
EEPROM_I2C_SCL_1();
delay_us(1);
//i2c_Delay();
while(EEPROM_I2C_SDA_READ())
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
EEPROM_I2C_SCL_0();//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
EEPROM_I2C_SCL_0();
SDA_OUT();
EEPROM_I2C_SDA_0();
//i2c_Delay();
delay_us(2);
EEPROM_I2C_SCL_1();
//i2c_Delay();
delay_us(2);
EEPROM_I2C_SCL_0();
}
//不产生ACK应答
void IIC_NAck(void)
{
EEPROM_I2C_SCL_0();
SDA_OUT();
EEPROM_I2C_SDA_1();
//i2c_Delay();
delay_us(2);
EEPROM_I2C_SCL_1();
//i2c_Delay();
delay_us(2);
EEPROM_I2C_SCL_0();
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
EEPROM_I2C_SCL_0();//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
if((txd&0x80)>>7)
EEPROM_I2C_SDA_1();
else
EEPROM_I2C_SDA_0();
txd<<=1;
//i2c_Delay(); //对TEA5767这三个延时都是必须的
delay_us(2);
EEPROM_I2C_SCL_1();
delay_us(2);
//i2c_Delay();
EEPROM_I2C_SCL_0();
i2c_Delay();
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
EEPROM_I2C_SCL_0();
//i2c_Delay();
delay_us(2);
EEPROM_I2C_SCL_1();
receive<<=1;
if(EEPROM_I2C_SDA_READ())
receive++;
delay_us(1);
//i2c_Delay();
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
这是小弟从原子哥IIC实验拷过来的程序,用在我的F030上,一直读出来的数据都是0xFF,请求各位大佬指出错在什么地方
|
|