IIC 通信
IIC 通用文件,文件是在NRF51xx 芯片基础,keil 平台开发测试通过,后期修改为STM32F2xx系列的配置。
文件百度云盘链接 : https://pan.baidu.com/s/1AFxanwzrAViaubtERZMRsA
注意:在用于STM32Fx 系列时注意引脚读取函数的选择!
下面是示波器现实,IIC通讯读的操作。
理论基础:
- SCL为高,SDA发生变化,即为发生了特殊状态(ACK, NACK, START, STOP)
- SCL为低,SDA发生变化,即为数据端发生跳变,这个是无影响的。
- IIC总线在数据传输时,时钟信号为高电平,数据线上的数据必须保持稳定,只有在SCL上的信号为低电平时,SDA线才允许变
-
IIC_confing.h 主要是SIMU_IIC.c 文件的一些结构体和端口设置, I2c_Str 结构体可以再添加数据属性,包括后期的数据,主要用于 SIMU_IIC.c 文件内部使用。
-
/**************************************************************************//** * @file IIC_confing.h * @brief For IIC communication * @author ning lv * @version 0.01 ****************************************************************************** * @section License ****************************************************************************** * *****************************************************************************/ #ifndef _I2C_CONFING_H_ #define _I2C_CONFING_H_ #ifdef __cplusplus extern "C" { #endif #include "SIMU_IIC.h" /* *** You can choose yours projects ...*/ //#define NRF51822 //试用在蓝牙芯片上 #define STM32F205 // /* *** Redefines the exact width signed integer type ...*/ //typedef unsigned char uint8; //typedef unsigned int uint32; //typedef signed char uint8_t; /* *** Define variables and structures ... */ typedef struct { uint32 SDA; uint32 SCL; uint32 GPIO; }I2c_Str; /* ***The global variable ... */ I2c_Str type_Struct; //all //sda \ scl typedef void(*pI2cLineF)(uint32 sda,uint32 scl); pI2cLineF _I2cLine = _NULL; // gpio typedef void(*pI2cGpioF)(uint32 gpo); pI2cGpioF _I2cGpio = _NULL; /* ***Chip selection ... */ #if defined NRF51822 #define CHOOSE_IN _TRUE #define CHOOSE_OUT _NULL #elif defined STM32F205 #define CHOOSE_IN (GPIO_Mode_IN ) #define CHOOSE_OUT (GPIO_Mode_OUT) #define GPIO_PORT ((GPIO_TypeDef*)type_Struct.GPIO) #endif /* ***Output 0/1 ... */ #define SDA_OUT_H ( Gpio_Pin_Wr(type_Struct.SDA,_TRUE) ) #define SDA_OUT_L ( Gpio_Pin_Wr(type_Struct.SDA,_NULL) ) #define SCL_OUT_H ( Gpio_Pin_Wr(type_Struct.SCL,_TRUE) ) #define SCL_OUT_L ( Gpio_Pin_Wr(type_Struct.SCL,_NULL) ) /* ***Choose output/input ... */ #define SDA_SET_IN ( I2c_Pin_Dir (type_Struct.SDA,CHOOSE_IN) ) #define SDA_SET_OUT ( I2c_Pin_Dir (type_Struct.SDA,CHOOSE_OUT) ) #define SCL_SET_IN_ ( I2c_Pin_Dir (type_Struct.SCL,CHOOSE_IN) ) #define SCL_SET_OUT ( I2c_Pin_Dir (type_Struct.SCL,CHOOSE_OUT) ) /* *** Reads lines ... */ #define RD_SDA_IN ( Gpio_Pin_Red(type_Struct.SDA) ) #define RD_SCL_IN ( Gpio_Pin_Red(type_Struct.SCL) ) /* *** times ... */ #define NOP() ( __nop() ) #define Iic_Delay(x) ( delay_us(x) ) #ifdef __cplusplus } #endif #endif /*_I2C_CONFING_H_*/
SIMU_IIC.c 文件主要的运行文件,开头是所需的芯片头文件,特别注意的是delay_ms();和delay_us();两个函数要根据芯片的不同,配置设备的不同定向修改,修改的过程中可以用示波器具体调试时间。
-
//Header files ... #include "IIC_confing.h" //master and the explanation is here!! #include "usart.h" //Chip selection ... #if defined NRF51822 #include "nrf_gpio.h" #elif defined STM32F205 #include <stm32f2xx_gpio.h> #endif /* ***Function declaration ...*/ void Delay5us(void); void Delay5us(void); void Delay10us(void); void Gpio_Pin_Wr(uint32 pin ,uint8 wr); void I2c_Pin_Dir(uint32 pin, uint8 dir); void Choose_I2c_Pin(uint32 sda,uint32 scl); void Gpio_Confing(uint32 gpo); //下面的可以发布在IIC.h 函数中,对外的接口设置 void I2c_Stop(void); void I2c_NoAck(void); void I2c_RecAck(void); void I2c_Reset (void); uint8 I2c_Start(void); uint8 I2c_WaitACK(void); uint8 I2c_RcvByte(void); void I2c_SendByte(uint8 c); uint8 Gpio_Pin_Red(uint32 pin); void IIC_confing_Pin(uint32 sda,uint32 scl, uint32 gpo); void delay_ms(uint32 volatile number_of_ms); void delay_us(uint32 volatile number_of_us); /**@brief Delay 1us */ void Delay1us(void) { NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); #if defined STM32F205 NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); #endif } /**@brief Delay 5us */ void Delay5us(void) { Delay1us(); Delay1us(); Delay1us(); Delay1us(); } /**@brief Delay 10us */ void Delay10us(void) { Delay5us(); Delay5us(); } /**@brief Delay(ms) * * @param[in] number_of_ms */ void delay_ms(uint32 volatile number_of_ms) { number_of_ms = number_of_ms * 1000; while(number_of_ms != 0) { number_of_ms--; Delay1us(); } } /**@brief Delay(us) * * @param[in] number_of_us */ void delay_us(uint32 volatile number_of_us) { while(number_of_us != 0) { number_of_us--; Delay1us(); } } /**@brief Select the I2C sda and scl pins. */ void Choose_I2c_Pin( uint32 sda,uint32 scl ) { type_Struct.SDA = sda; type_Struct.SCL = scl; } /**@brief Function Pointers set GPIO */ void Gpio_Confing( uint32 gpo ) { type_Struct.GPIO = gpo; } /**@brief Function Pointers set the sda and SCL pins */ void IIC_confing_Pin( uint32 sda,uint32 scl, uint32 gpo) { #if defined STM32F205 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); #endif _I2cGpio = (pI2cGpioF)Gpio_Confing; _I2cGpio(gpo); _I2cLine = (pI2cLineF)Choose_I2c_Pin ; _I2cLine(sda,scl); } /**@brief Iic_Pin_Dir 支持文件 STM32F2xx or NRF51822 * * @param[in] dir */ #if defined ( STM32F205 ) void STM32F205_Pin_Dir (uint32 pin, uint8 dir) { GPIO_InitTypeDef GPIO_InitStructure; if(GPIO_Mode_OUT == dir){ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; }else if(GPIO_Mode_IN == dir){ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; } GPIO_InitStructure.GPIO_Pin = pin; GPIO_Init(GPIO_PORT, &GPIO_InitStructure); } #elif defined ( NRF51822 ) void nRF51822_Pin_Dir (uint32 pin, uint8 dir) { if ( dir == 0 ) { nrf_gpio_cfg_output(pin); }else { nrf_gpio_cfg_input(pin,NRF_GPIO_PIN_PULLUP); } } #endif /**@brief The pin line outputs 0/1. * * @param[in] dir */ void I2c_Pin_Dir (uint32 pin, uint8 dir) { #if defined ( NRF51822 ) nRF51822_Pin_Dir (pin, dir); #elif defined ( STM32F205 ) STM32F205_Pin_Dir (pin, dir); #endif } /**@brief SDA/SCL line write 0/1. * * @param[in] pin ,wr */ void Gpio_Pin_Wr(uint32 pin ,uint8 wr) { if ( wr == 0 ) { #if defined ( NRF51822 ) nrf_gpio_pin_write(pin,0); #elif defined ( STM32F205 ) GPIO_WriteBit(GPIO_PORT , pin , 0); #endif } else { #if defined ( NRF51822 ) nrf_gpio_pin_write(pin,1); #elif defined ( STM32F205 ) GPIO_WriteBit(GPIO_PORT , pin , 1); #endif } } /**@brief SDA/SCL line read 0/1. * * @param[in] pin */ uint8 Gpio_Pin_Red(uint32 pin) { #if defined ( NRF51822 ) return ((uint8) nrf_gpio_pin_read(pin)); #elif defined ( STM32F205 ) return (uint8) GPIO_ReadInputDataBit(GPIO_PORT , pin); #endif } /**@brief IIC communication to prepare. * * @param[in] i2c_master */ uint8 I2c_Start(void) { /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */ I2c_Reset(); SCL_SET_OUT; SDA_SET_OUT; SDA_OUT_H; SCL_OUT_H; Iic_Delay(I2C_DELAY_TM); if( !RD_SDA_IN ) { return I2C_BUSY; //BUSY } SDA_OUT_L; Iic_Delay(I2C_DELAY_TM); if( RD_SDA_IN ) { return I2C_ERROR; //ERROR } SDA_OUT_L;/*CPU占线*/ return I2C_TRUE; } /**@brief IIC stop the communication . * * @param[in] i2c_master */ void I2c_Stop(void) { /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */ SCL_OUT_L; Iic_Delay(I2C_DELAY_TM); SDA_OUT_L; Iic_Delay(I2C_DELAY_TM); SCL_OUT_H; Iic_Delay(I2C_DELAY_TM); SDA_OUT_H; } /**@brief reset */ void I2c_Reset (void) { if( RD_SDA_IN == 0 //|| READ_SCL_IN == 0 ) { SCL_SET_OUT; SDA_SET_OUT; Iic_Delay(I2C_DELAY_TM); SDA_OUT_H; SCL_OUT_H; Iic_Delay(I2C_DELAY_TM); I2c_SendByte(0xFF); I2c_NoAck(); I2c_Stop(); } } /**@brief Send the data 'c' out,either as data or as an address. * * @param[in] C */ void I2c_SendByte(uint8 c) { uint8 i; i = 8; while(i--) { SCL_OUT_L; /*允许SDA 数据跳变*/ Iic_Delay(I2C_DELAY_TM); if( c&0x80) { SDA_OUT_H; } else { SDA_OUT_L; } c<<=1; SCL_OUT_H; /*SDA 数据保持 1us*/ Iic_Delay(I2C_DELAY_TM); } SCL_OUT_L; SDA_OUT_H; /*CPU 释放总线*/ } /**@brief Reads a bytes of data and returns it. * * @param[out] retc */ uint8 I2c_RcvByte(void) { uint8 i = 8; uint8 retc = 0; SDA_SET_IN; SDA_OUT_L;/*总线默认拉高*/ while(i--) { retc<<=1; SCL_OUT_L; /*CPU 允许 SDA 数据跳变*/ Iic_Delay(I2C_DELAY_TM); SCL_OUT_H; /*CPU 保持 SDA 数据1us*/ Iic_Delay(I2C_DELAY_TM); if( RD_SDA_IN ) { retc |= 0x01; } } SCL_OUT_L; SDA_SET_OUT; SDA_OUT_H; /*CPU 释放总线*/ return retc; } /**@brief watint ACK */ uint8 I2c_WaitACK(void) { uint8 errTime = 250; uint8 retFlag = I2C_TRUE; SCL_OUT_L; SDA_OUT_H; /*CPU 释放总线*/ Iic_Delay(I2C_DELAY_TM); SCL_OUT_H; /*CPU驱动SCL = 1, 此时器件会返回ACK应答*/ SDA_SET_IN; Iic_Delay(I2C_DELAY_TM); while((RD_SDA_IN)&&((errTime--) > 0)) { if(errTime == 0){ retFlag = I2C_FALSE; } } SCL_OUT_L; SDA_SET_OUT; return retFlag; } /**@brief ACK response */ void I2c_RecAck(void) { SCL_OUT_L; /*CPU 允许 SDA 数据跳变*/ Iic_Delay(I2C_DELAY_TM); SDA_OUT_L; /*CPU 拉低SDA ,ACK器件*/ Iic_Delay(I2C_DELAY_TM); SCL_OUT_H; /*CPU 保持 SDA 数据1us*/ Iic_Delay(I2C_DELAY_TM); SCL_OUT_L; Iic_Delay(I2C_DELAY_TM); SDA_OUT_H; /* CPU释放SDA总线 */ } /**@brief Don't reply */ void I2c_NoAck(void) { SCL_OUT_L; Iic_Delay(I2C_DELAY_TM); SDA_OUT_H; Iic_Delay(I2C_DELAY_TM); SCL_OUT_H; Iic_Delay(I2C_DELAY_TM); SCL_OUT_L; Iic_Delay(I2C_DELAY_TM); }
SIMCU_IIC.h对外发布函数接口和一些宏定义 , 函数 void IIC_confing_Pin( uint32 sda,uint32 scl, uint32 gpo);//设置 sda 和 scl 的引脚设置. 是主要调用的文件,它是基础。
-
#ifndef SIMU_IIC_H_ #define SIMU_IIC_H_ /* *** Define some of the things ...*/ #define _NULL 0 #define _TRUE 1 #define I2C_ERROR _NULL //returns #define I2C_FALSE _NULL #define I2C_TRUE _TRUE #define I2C_BUSY 3//3 #define I2C_DELAY_TM 5 //slot time (4.7us) /* *** Define variables and structures ... */ typedef unsigned char uint8; typedef unsigned int uint32; void I2c_Stop(void); void I2c_NoAck(void); void I2c_RecAck(void); void I2c_Reset (void); uint8 I2c_Start(void); uint8 I2c_WaitACK(void); uint8 I2c_RcvByte(void); void I2c_SendByte(uint8 c); uint8 Gpio_Pin_Red(uint32 pin); void delay_ms(uint32 volatile number_of_ms); void delay_us(uint32 volatile number_of_us); void IIC_confing_Pin( uint32 sda,uint32 scl, uint32 gpo);//设置 sda 和 scl 的引脚设置. #endif /*SIMU_IIC_H_*/
device_i2c.c 文件是给出的write和read实例文件。
-
#include "SIMU_IIC.h" #include "usart.h" #define DEVICE_SLAVEADDR_W 0xA0//0x40 #define DEVICE_SLAVEADDR_R 0xA1 uint8_t busy; uint8_t DEVICE_WriteByte (uint8_t addr,uint8_t *c,uint8_t len ) { uint8_t i = 0; lock_busy = 1; i = I2c_Start(); if(I2C_BUSY == i ) { printf(" \r\n I2C_BUSY \r\n"); goto DEVICE_WriteByte_FAIL; //return Fail; } else if (I2C_ERROR == i) { printf(" \r\n I2C_ERROR \r\n"); goto DEVICE_WriteByte_FAIL; //return Fail; } I2c_SendByte(DEVICE_SLAVEADDR_W); //0x40 写 if(!I2c_WaitACK()) { I2c_Stop(); printf(" \r\n 地址失败 :%02x !\r\n",DEVICE_SLAVEADDR_W); goto DEVICE_WriteByte_FAIL; //return Fail; } I2c_SendByte(addr); //addr if(!I2c_WaitACK()) { I2c_Stop(); printf(" \r\n 寄存器地址错误 :%02x !\r\n",DEVICE_SLAVEADDR_W); goto DEVICE_WriteByte_FAIL; //return Fail; } for(i=0;i<len;i++){ I2c_SendByte(*c); if(!I2c_WaitACK()) { printf(" \r\n 写入数据失败 \r\n"); } c++; } I2c_Stop(); busy = 0; return 1; DEVICE_WriteByte_FAIL: I2c_Stop(); busy = 0; return 0; } uint8 DEVICE_II_ReadByte (uint8_t addr,uint8_t * c,uint8_t len) { uint8 i; busy = 1; if(!I2c_Start()) goto DEVICE_II_ReadByte_FAIL; //return Fail; I2c_SendByte (DEVICE_SLAVEADDR_W); if(!I2c_WaitACK()) { I2c_Stop(); goto DEVICE_II_ReadByte_FAIL; //return Fail; } I2c_SendByte(addr); I2c_WaitACK(); I2c_Start(); I2c_SendByte(DEVICE_SLAVEADDR_R); I2c_WaitACK(); for(i=0;i<len;i++) { *c = I2c_RcvByte(); c++; } I2c_NoAck(); I2c_Stop(); busy = 0; return 1; DEVICE_II_ReadByte_FAIL: busy = 0; return 0; }