jianghuai/SYSTEM/bsp_i2c_gpio.c
2024-05-07 09:36:09 +08:00

314 lines
8.2 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*********************************************************************************************************
*
* 模块名称 : I2C总线驱动模块
* 文件名称 : bsp_i2c_gpio.c
* 版 本 : V1.0
* 说 明 : 用gpio模拟i2c总线, 适用于STM32F4系列CPU。该模块不包括应用层命令帧仅包括I2C总线基本操作函数。
*
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2015-05-21 armfly 正式发布
*
* Copyright (C), 2015-2016, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/
/*
应用说明:
在访问I2C设备前请先调用 i2c_CheckDevice() 检测I2C设备是否正常该函数会配置GPIO
*/
#include "stm32f10x.h"
#include "bsp_i2c_gpio.h"
/*
安富莱STM32-V4开发板 i2c总线GPIO:
PB6/I2C1_SCL
PB7/I2C1_SDA
*/
/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define RCC_I2C_PORT RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define PORT_I2C_SCL GPIOB /* GPIO端口 */
#define PIN_I2C_SCL GPIO_Pin_6 /* GPIO引脚 */
#define PORT_I2C_SDA GPIOB /* GPIO端口 */
#define PIN_I2C_SDA GPIO_Pin_7 /* GPIO引脚 */
#define I2C_SCL_PIN GPIO_Pin_6 /* 连接到SCL时钟线的GPIO */
#define I2C_SDA_PIN GPIO_Pin_7 /* 连接到SDA数据线的GPIO */
/* 定义读写SCL和SDA的宏 */
#define I2C_SCL_1() PORT_I2C_SCL->BSRR = I2C_SCL_PIN /* SCL = 1 */
#define I2C_SCL_0() PORT_I2C_SCL->BRR = I2C_SCL_PIN /* SCL = 0 */
#define I2C_SDA_1() PORT_I2C_SDA->BSRR = I2C_SDA_PIN /* SDA = 1 */
#define I2C_SDA_0() PORT_I2C_SDA->BRR = I2C_SDA_PIN /* SDA = 0 */
#define I2C_SDA_READ() ((PORT_I2C_SDA->IDR & I2C_SDA_PIN) != 0) /* 读SDA口线状态 */
#define I2C_SCL_READ() ((PORT_I2C_SCL->IDR & I2C_SCL_PIN) != 0) /* 读SCL口线状态 */
/*
*********************************************************************************************************
* 函 数 名: bsp_InitI2C
* 功能说明: 配置I2C总线的GPIO采用模拟IO的方式实现
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitI2C(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出模式 */
GPIO_InitStructure.GPIO_Pin = PIN_I2C_SCL;
GPIO_Init(PORT_I2C_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出模式 */
GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure);
/* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */
// IIC_Stop();
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 ???
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Delay
* 功能说明: I2C总线位延迟最快400KHz
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
uint16_t i;
/* 
CPU主频168MHz时在内部Flash运行, MDK工程不优化。用台式示波器观测波形。
循环次数为5时SCL频率 = 1.78MHz (读耗时: 92ms, 读写正常,但是用示波器探头碰上就读写失败。时序接近临界)
循环次数为10时SCL频率 = 1.1MHz (读耗时: 138ms, 读速度: 118724B/s)
循环次数为30时SCL频率 = 440KHz SCL高电平时间1.0usSCL低电平时间1.2us
上拉电阻选择2.2K欧时SCL上升沿时间约0.5us如果选4.7K欧则上升沿约1us
实际应用选择400KHz左右的速率即可
*/
for (i = 0; i < 60; i++);
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线启动信号
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void IIC_Start(void)
{
/* 当SCL高电平时SDA出现一个下跳沿表示I2C总线启动信号 */
I2C_SDA_1();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_0();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线停止信号
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void IIC_Stop(void)
{
/* 当SCL高电平时SDA出现一个上跳沿表示I2C总线停止信号 */
I2C_SDA_0();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_1();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_SendByte
* 功能说明: CPU向I2C总线设备发送8bit数据
* 形 参: _ucByte 等待发送的字节
* 返 回 值: 无
*********************************************************************************************************
*/
void IIC_Send_Byte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
I2C_SDA_1();
}
else
{
I2C_SDA_0();
}
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
if (i == 7)
{
I2C_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
/*
*********************************************************************************************************
* 函 数 名: i2c_ReadByte
* 功能说明: CPU从I2C总线设备读取8bit数据
* 形 参: 无
* 返 回 值: 读到的数据
*********************************************************************************************************
*/
u8 IIC_Read_Byte(unsigned char ack)
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
I2C_SCL_1();
i2c_Delay();
if (I2C_SDA_READ())
{
value++;
}
I2C_SCL_0();
i2c_Delay();
}
if (!ack)
IIC_NAck();//??nACK
else
IIC_Ack(); //??ACK
return value;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_WaitAck
* 功能说明: CPU产生一个时钟并读取器件的ACK应答信号
* 形 参: 无
* 返 回 值: 返回0表示正确应答1表示无器件响应
*********************************************************************************************************
*/
uint8_t IIC_Wait_Ack(void)
{
uint8_t re;
I2C_SDA_1(); /* CPU释放SDA总线 */
i2c_Delay();
I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
i2c_Delay();
if (I2C_SDA_READ()) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;
}
I2C_SCL_0();
i2c_Delay();
return re;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void IIC_Ack(void)
{
I2C_SDA_0(); /* CPU驱动SDA = 0 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
I2C_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: i2c_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void IIC_NAck(void)
{
I2C_SDA_1(); /* CPU驱动SDA = 1 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
///*
//*********************************************************************************************************
//* 函 数 名: i2c_CheckDevice
//* 功能说明: 检测I2C总线设备CPU向发送设备地址然后读取设备应答来判断该设备是否存在
//* 形 参: _Address设备的I2C总线地址
//* 返 回 值: 返回值 0 表示正确, 返回1表示未探测到
//*********************************************************************************************************
//*/
//#define ADS1015_ADDRESS 0x48
// u8 AD1015_Check(u8 i2cAddress)
//{
// uint8_t ucAck;
// if (I2C_SDA_READ() && I2C_SCL_READ())
// {
// IIC_Start(); /* 发送启动信号 */
// /* 发送设备地址+读写控制bit0 = w 1 = r) bit7 先传 */
// IIC_Send_Byte(i2cAddress | I2C_WR);
// ucAck = IIC_Wait_Ack(); /* 检测设备的ACK应答 */
// IIC_Stop(); /* 发送停止信号 */
// return ucAck;
// }
// return 1; /* I2C总线异常 */
//}
/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/