1 #ifndef _IIC_H 2 #define _IIC_H 3 4 #include "stdio.h" 5 #include "stm32f1xx_hal.h" 6 7 8 /* 定义控制 SDA SCL 的宏 标准库版 9 #define I2C_SDA_UP GPIO_SetBits (GPIOC,GPIO_PIN_8) //SDA高电平 10 #define I2C_SDA_LOW GPIO_ResetBits(GPIOC,GPIO_PIN_8) //SDA低电平 11 #define I2C_SCL_UP GPIO_SetBits (GPIOC,GPIO_PIN_9) //SCL高电平 12 #define I2C_SCL_LOW GPIO_ResetBits(GPIOC,GPIO_PIN_9) //SCL低电平 13 */ 14 15 16 /* 定义控制 SDA SCL 的宏 HAL库版 */ 17 18 #define I2C_SDA_UP HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET) //SDA高电平 19 #define I2C_SDA_LOW HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET) //SDA低电平 20 #define I2C_SCL_UP HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_SET) //SCL高电平 21 #define I2C_SCL_LOW HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET) //SCL低电平 22 23 24 25 /* 获取 SDA SCL 引脚状态,标准库版也是用相同逻辑 */ 26 27 #define I2C_SDA HAL_GPIO_ReadPin(GPIOC ,GPIO_PIN_8) //获取SDA引脚状态 28 #define I2C_SCL HAL_GPIO_ReadPin(GPIOC ,GPIO_PIN_9) //获取SCL引脚状态 29 30 31 void iic_stare(void); //* 开始信号 32 void i2c_ack(void); //* 应答信号 33 void I2C_No_ack(void); //* 非应答信号 34 void i2c_stop(void); //* 停止信号 35 char i2c_wit_ack(void); //* 等待应答 36 void i2c_send(uint8_t dat); //* 发送数据 37 uint8_t i2c_read(void); //* 接收数据 38 39 void SDA_OUT(void); //* SDA 设置为输出 40 void SDA_IN(void); //* SDA 设置为输入 41 42 void delay_us(uint32_t i); //*延时 43 44 #endif
/***************************************************************************** * * * File: 软件模拟IIC, HAL库版本,标准库也 * * 可用,只需要做一些相对应修改即可 * * * *****************************************************************************/#include "iic.h"/******************************************************************************* * 函 数 名 : i2c_stare * 函数功能 : iic开始信号,SCL高电平时,SDA出现一个下跳沿表示启动信号 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void i2c_stare(void) {SDA_OUT(); I2C_SDA_UP;I2C_SCL_UP;delay_us(4);I2C_SDA_LOW; //启动开始信号delay_us(4);I2C_SCL_LOW; //钳住I2C总线,准备发送或接收数据 }/******************************************************************************* * 函 数 名 : i2c_stop * 函数功能 : iic停止信号,SCL高电平时,SDA出现一个上跳沿表示停止信号 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void i2c_stop(void) {SDA_OUT(); //sda线输出I2C_SDA_LOW; //发送结束条件的数据信号 I2C_SCL_UP;delay_us(4); //结束条件建立时间大于4μI2C_SDA_UP; //发送I2C总线结束信号delay_us(4);I2C_SCL_LOW; }/******************************************************************************* * 函 数 名 : i2c_send * 函数功能 : iic发送数据 * 输 入 : uint8_t dat,要发送的数据 * 输 出 : 无 *******************************************************************************/ void i2c_send(uint8_t dat) {unsigned char temp;SDA_OUT();for(temp=0x80;temp!=0;temp>>=1){if((temp & dat)== 0){I2C_SDA_LOW;}else{I2C_SDA_UP;}delay_us(1);I2C_SCL_UP;delay_us(4);I2C_SCL_LOW;} }/******************************************************************************* * 函 数 名 : i2c_read * 函数功能 : iic接收数据 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ uint8_t i2c_read(void) {unsigned char temp;unsigned char dat;I2C_SDA_UP; //释放总线准备接收 SDA_IN();for(temp=0x80;temp!=0;temp>>=1){delay_us(1);I2C_SCL_UP;if(I2C_SDA==1){dat|=temp;}else{dat&=~temp;}I2C_SCL_LOW;}return dat; }/******************************************************************************* * 函 数 名 : i2c_wit_ack * 函数功能 : iic等待应答 * 输 入 : 无 * 输 出 : 0/1,返回1表示无应答信号,返回0表示应答 *******************************************************************************/ char i2c_wit_ack(void) {uint8_t con=0;I2C_SDA_UP; //释放数据线,准备接收应答delay_us(1);I2C_SCL_UP; //CPU驱动SCL = 1, 此时器件会返回ACK应答 SDA_IN(); delay_us(1);while( I2C_SDA ) //CPU读取SDA口线状态 {con++;if(con>255){i2c_stop();return 1; //无应答信号 }}I2C_SCL_LOW; delay_us(1);return 0; //有应答 }/******************************************************************************* * 函 数 名 : i2c_ack * 函数功能 : iic应答信号 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void i2c_ack(void) {SDA_OUT();I2C_SDA_LOW;delay_us(1);I2C_SCL_UP; //CPU产生1个时钟delay_us(4); //时钟低电平周期大于4μI2C_SCL_LOW; //清时钟线,钳住I2C总线以便继续接收delay_us(4);I2C_SDA_UP; //CPU释放SDA总线 }/******************************************************************************* * 函 数 名 : I2C_No_ack * 函数功能 : iic非应答信号 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void I2C_No_ack(void) {SDA_OUT();I2C_SDA_UP;delay_us(1);I2C_SCL_UP;delay_us(4);I2C_SCL_LOW; delay_us(4); }/******************************************************************************* * 函 数 名 : SDA_OUT * 函数功能 : SDA 设置为输出 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void SDA_OUT(void) { /* 标准库使用,修改端口引脚可用GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct); */ /* HAL库使用,HAL库注意要把初始化函数的静态标记去掉 */GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = SDA_Pin; //使用STM3cubemx是定义好的SDA_Pin为GPIO_PIN_8的标签GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); }/******************************************************************************* * 函 数 名 : SDA_IN * 函数功能 : SDA 设置为输入 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void SDA_IN(void) {/* 标准库使用,修改端口引脚可用GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct); */ /* HAL库使用, HAL库注意要把初始化函数的静态标记去掉 */GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = SDA_Pin ; //使用STM3cubemx是定义好的SDA_Pin为GPIO_PIN_8的标签GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); } /******************************************************************************* * 函 数 名 : delay_us * 函数功能 : 延时函数,延时us * 输 入 : i * 输 出 : 无 *******************************************************************************/ void delay_us(uint32_t i) {uint32_t temp;SysTick->LOAD=9*i; //设置重装数值, 72MHZ时SysTick->CTRL=0X01; //使能,减到零是无动作,采用外部时钟源SysTick->VAL=0; //清零计数器do{temp=SysTick->CTRL; //读取当前倒计数值 }while((temp&0x01)&&(!(temp&(1<<16)))); //等待时间到达 SysTick->CTRL=0; //关闭计数器SysTick->VAL=0; //清空计数器 }
该代码,标准库可用,HAL库也可用,只需要代码做一些修改即可!