123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- #include "IIC.h"
- #define GPIO_PORT_I2C GPIOB /* GPIO端口 */
- #define RCC_I2C_PORT RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
- #define I2C_SCL_PIN GPIO_Pin_1 /* 连接到SCL时钟线的GPIO */
- #define I2C_SDA_PIN GPIO_Pin_0 /* 连接到SDA数据线的GPIO */
- /* 定义读写SCL和SDA的宏,已增加代码的可移植性和可阅读性 */
- #if 0 /* 条件编译: 1 选择GPIO的库函数实现IO读写 */
- #define I2C_SCL_1() GPIO_SetBits(GPIO_PORT_I2C, I2C_SCL_PIN) /* SCL = 1 */
- #define I2C_SCL_0() GPIO_ResetBits(GPIO_PORT_I2C, I2C_SCL_PIN) /* SCL = 0 */
-
- #define I2C_SDA_1() GPIO_SetBits(GPIO_PORT_I2C, I2C_SDA_PIN) /* SDA = 1 */
- #define I2C_SDA_0() GPIO_ResetBits(GPIO_PORT_I2C, I2C_SDA_PIN) /* SDA = 0 */
-
- #define I2C_SDA_READ() GPIO_ReadInputDataBit(GPIO_PORT_I2C, I2C_SDA_PIN) /* 读SDA口线状态 */
- #else /* 这个分支选择直接寄存器操作实现IO读写 */
- /* 注意:如下写法,在IAR最高级别优化时,会被编译器错误优化 */
- #define I2C_SCL_1() GPIO_PORT_I2C->BSRR = I2C_SCL_PIN /* SCL = 1 */
- #define I2C_SCL_0() GPIO_PORT_I2C->BRR = I2C_SCL_PIN /* SCL = 0 */
-
- #define I2C_SDA_1() GPIO_PORT_I2C->BSRR = I2C_SDA_PIN /* SDA = 1 */
- #define I2C_SDA_0() GPIO_PORT_I2C->BRR = I2C_SDA_PIN /* SDA = 0 */
-
- #define I2C_SDA_READ() ((GPIO_PORT_I2C->IDR & I2C_SDA_PIN) != 0) /* 读SDA口线状态 */
- #endif
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_delay
- * 功能说明: I2C总线位延迟,最快400KHz
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void IIC_delay(void)
- {
- uint8_t i;
- /*
- 下面的时间是通过安富莱AX-Pro逻辑分析仪测试得到的。
- CPU主频72MHz时,在内部Flash运行, MDK工程不优化
- 循环次数为10时,SCL频率 = 205KHz
- 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
- 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
-
- IAR工程编译效率高,不能设置为7
- */
- for (i = 0; i < 10; i++);
- }
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_start
- * 功能说明: CPU发起I2C总线启动信号
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void IIC_start(void)
- {
- /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
- I2C_SDA_1();
- I2C_SCL_1();
- IIC_delay();
- I2C_SDA_0();
- IIC_delay();
- I2C_SCL_0();
- IIC_delay();
- }
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_start
- * 功能说明: CPU发起I2C总线停止信号
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void IIC_stop(void)
- {
- /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
- I2C_SDA_0();
- I2C_SCL_1();
- IIC_delay();
- I2C_SDA_1();
- }
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_send_byte
- * 功能说明: 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();
- }
- IIC_delay();
- I2C_SCL_1();
- IIC_delay();
- I2C_SCL_0();
- if (i == 7)
- {
- I2C_SDA_1(); // 释放总线
- }
- _ucByte <<= 1; /* 左移一个bit */
- IIC_delay();
- }
- }
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_read_byte
- * 功能说明: CPU从I2C总线设备读取8bit数据
- * 形 参:无
- * 返 回 值: 读到的数据
- *********************************************************************************************************
- */
- uint8_t IIC_read_byte(u8 ack)
- {
- uint8_t i;
- uint8_t value;
- /* 读到第1个bit为数据的bit7 */
- value = 0;
- for (i = 0; i < 8; i++)
- {
- value <<= 1;
- I2C_SCL_1();
- IIC_delay();
- if (I2C_SDA_READ())
- {
- value++;
- }
- I2C_SCL_0();
- IIC_delay();
- }
- if(ack==0)
- IIC_nack();
- else
- IIC_ack();
- return value;
- }
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_wait_ack
- * 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
- * 形 参:无
- * 返 回 值: 返回0表示正确应答,1表示无器件响应
- *********************************************************************************************************
- */
- uint8_t IIC_wait_ack(void)
- {
- uint8_t re;
- I2C_SDA_1(); /* CPU释放SDA总线 */
- IIC_delay();
- I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
- IIC_delay();
- if (I2C_SDA_READ()) /* CPU读取SDA口线状态 */
- {
- re = 1;
- }
- else
- {
- re = 0;
- }
- I2C_SCL_0();
- IIC_delay();
- return re;
- }
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_ack
- * 功能说明: CPU产生一个ACK信号
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void IIC_ack(void)
- {
- I2C_SDA_0(); /* CPU驱动SDA = 0 */
- IIC_delay();
- I2C_SCL_1(); /* CPU产生1个时钟 */
- IIC_delay();
- I2C_SCL_0();
- IIC_delay();
- I2C_SDA_1(); /* CPU释放SDA总线 */
- }
- /*
- *********************************************************************************************************
- * 函 数 名: IIC_nack
- * 功能说明: CPU产生1个NACK信号
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void IIC_nack(void)
- {
- I2C_SDA_1(); /* CPU驱动SDA = 1 */
- IIC_delay();
- I2C_SCL_1(); /* CPU产生1个时钟 */
- IIC_delay();
- I2C_SCL_0();
- IIC_delay();
- }
- /*
- *********************************************************************************************************
- * 函 数 名: i2c_GPIO_Config
- * 功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void IIC_init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */
- GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出 */
- GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure);
- /* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */
- IIC_stop();
- }
|