> 文档中心 > GD32MCU硬件I2C学习(一)

GD32MCU硬件I2C学习(一)

1.1 硬件I2C介绍
在项目中遇见与MCU通信接口协议为I2C的设备时,可通过GPIO口软件模拟I2C和使用MCU自身的硬件I2C资源。两者各有优势,软件模拟可以不受GPIO口限制,也可以主控制器MCU的选择上降低成本,但也存在I2C设备对通信速率有特定的要求或者需要较高的传输速率时,会存在时序调试困难、start/stop/ack/noack/read/write等都需要软件实现、GPIO口翻转速率限制等原因导致软件模拟I2C通信速率有一定的限制。硬件I2C则不存在上述问题,I2C通信速率可配置100k/400k/1M(NXP芯片做到了3.4M),通信时序中的绝大部分都由硬件完成,我们只需要按照逻辑配置好相应的寄存器即可,但也存在受特定GPIO口限制、相应成本高等缺点。本文主要是基GD32MCU介绍硬件I2C的配置和注意的事项,关于I2C协议概念介绍只是简要提及。
1.2 GD32 mcu硬件I2C的主要特性
1、同一接口既可实现主机功能又可实现从机功能;
2、主从机之间的双向数据传输;
3、支持7位和10位的地址模式和广播寻址;
4、支持I2C多主机模式;
5、速率100k\400k\1M;
6、从机模式下可配置SCL主动拉低;
7、支持DMA模式;
8、支持SMBUS;
9、事件中断和错误中断;
10、支持PEC错误校验。
1.3 主机发送和接收实现(速率100k/400k/1M 地址10bit or 7bit)

 //.h文件#ifndef MAIN_H#define MAIN_H#include "gd32f3x0.h"#define I2Cx_Pinx_AFx_BIT(gpiox,pinx,afx) (((uint32_t)gpiox)|((uint32_t)(pinx)<<4)|(uint32_t)(afx))/*send_slaver address*/typedef enum{  Send_7Address=0x42,  Send_7Address_2=0x44,  send_gual=0x00,  Send_10Address=0x232}Send_Address_Enum;/*define pin speed enum*/typedef enum{ standard_speed=100000, High_speed=400000, More_HighSpeed=1000000}I2Cx_Speed_enum;/*define I2Cx SDA Pin enum*/typedef enum{ //define I2C0 I2C0_SDA_GPIOx1=I2Cx_Pinx_AFx_BIT(GPIOA,10,4), I2C0_SDA_GPIOx2=I2Cx_Pinx_AFx_BIT(GPIOB,7,1), I2C0_SDA_GPIOx3=I2Cx_Pinx_AFx_BIT(GPIOB,9,1), //define I2C1 I2C1_SDA_GPIOx4=I2Cx_Pinx_AFx_BIT(GPIOA,1,4), I2C1_SDA_GPIOx5=I2Cx_Pinx_AFx_BIT(GPIOB,11,1), I2C1_SDA_GPIOx6=I2Cx_Pinx_AFx_BIT(GPIOF,7,0)}I2Cx_PinSDA_Enum;/*define I2Cx SCL Pin enum*/typedef enum{ //define I2C0 I2C0_SCL_GPIOy1=I2Cx_Pinx_AFx_BIT(GPIOA,9,4), I2C0_SCL_GPIOy2=I2Cx_Pinx_AFx_BIT(GPIOB,6,1), I2C1_SCL_GPIOy3=I2Cx_Pinx_AFx_BIT(GPIOB,8,1), //define I2C1 I2C1_SCL_GPIOy4=I2Cx_Pinx_AFx_BIT(GPIOA,0,4), I2C1_SCL_GPIOy5=I2Cx_Pinx_AFx_BIT(GPIOB,10,1), I2C1_SCL_GPIOy6=I2Cx_Pinx_AFx_BIT(GPIOB,6,0)}I2Cx_PinSCL_Enum;/*define I2Cx address model*/typedef enum{  I2Cx_Address_7bit=I2C_ADDFORMAT_7BITS,  I2Cx_Address_10bit=I2C_ADDFORMAT_10BITS}Address_Model_Enum;/*define I2Cx slaver address*/typedef enum{    Slaver_7Address=0x40,Slaver_10Address=0x230}Slaver_Address_Enum;/*define I2CX init param*/typedef struct {uint32_t Memory_address;I2Cx_PinSDA_Enum gpio_sdapin;I2Cx_PinSCL_Enum gpio_sclpin;rcu_periph_enum I2Cx_Periph;I2Cx_Speed_enum I2c_speed;Address_Model_Enum address_model;Send_Address_Enum address;Slaver_Address_Enum slaver_address;}Param_Typedef;/*I2C gpio init function*/void I2Cx_Init(Param_Typedef* i2c_init);/*I2C gpiopin enable*/void I2Cx_Pin_ClockEnable(I2Cx_PinSDA_Enum gpio_sdapin,I2Cx_PinSCL_Enum gpio_sclpin);/*I2C master send buffer 7 and 10 address*/void Master_SendData_address(uint8_t* SendBuffer,uint8_t DataNum,Param_Typedef *i2c_init);/*I2C master receive data 7 and 10 address*/void Master_ReceiveData(uint8_t* ReceiveBuffer,uint8_t DataNum,Param_Typedef *i2c_init);/*I2C 7 bit address prepare send*/void Send_7Prepare(Param_Typedef *i2c_init);/*I2C 10 bit address prepare send*/void Send_10Prepare(Param_Typedef *i2c_init);/*I2C 10 bit address prepare receive*/void Receive_10Prepare(Param_Typedef *i2c_init);/*Master receive 7 address prepare*/void Receive_7Prepare(Param_Typedef *i2c_init);#endif /* MAIN_H *///.c文件#include "gd32f3x0.h"#include #include "gd32f350r_eval.h"#include "main.h"#include "systick.h"#define I2C0_Measure//#define I2C1_Measure#define BufferNum 20uint8_t write_buffer[BufferNum]={0};//send data bufferuint8_t receive_buffer[BufferNum]={0};//receive data bufferParam_Typedef I2Cx_Param;/*define I2Cx Param struct array*/static Param_Typedef Para_Aarry[]={/*I2C0 param array*/{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},/*I2C1 param array*/{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},};/*testing sequence enum*/typedef enum{/*Measure I2C0*/I2C0_Seven_Address_standard=0,I2C0_Ten_Address_standard,I2C0_Seven_Address_high,I2C0_Ten_Address_high,I2C0_Seven_Address_more_high,/*Measure I2C1*/I2C1_Seven_Address_standard,I2C1_Ten_Address_standard,I2C1_Seven_Address_high,I2C1_Ten_Address_high,I2C1_Seven_Address_more_high}Test_Sequence_Enum;/*Configure Param of I2Cx Send data*/void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence);/*Configure Param of I2Cx receive data*/void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence);/*I2Cx param init*/void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence);/*!    \brief      main function    \param[in]  none    \param[out] none    \retval     none*/int main(void){ uint8_t num=0;   /*configure EVAL_COM1*/   gd_eval_com_init(EVAL_COM); systick_config(); for(num=0;num<BufferNum;num++){ write_buffer[num]=num; } #ifdef I2C0_Measure /*Test Sequence I2C0 send*/ Configure_I2CX_Send(I2C0_Seven_Address_standard); Configure_I2CX_Send(I2C0_Ten_Address_standard); Configure_I2CX_Send(I2C0_Seven_Address_high); Configure_I2CX_Send(I2C0_Ten_Address_high); Configure_I2CX_Send(I2C0_Seven_Address_more_high); /*Test Sequence I2C0 receive*/ Configure_I2CX_Receive(I2C0_Seven_Address_standard); Configure_I2CX_Receive(I2C0_Ten_Address_standard); Configure_I2CX_Receive(I2C0_Seven_Address_high); Configure_I2CX_Receive(I2C0_Ten_Address_high); Configure_I2CX_Receive(I2C0_Seven_Address_more_high); #elif defined I2C1_Measure /*Test Sequence I2C1 send*/ Configure_I2CX_Send(I2C1_Seven_Address_standard); Configure_I2CX_Send(I2C1_Ten_Address_standard); Configure_I2CX_Send(I2C1_Seven_Address_high); Configure_I2CX_Send(I2C1_Ten_Address_high); Configure_I2CX_Send(I2C1_Seven_Address_more_high); /*Test Sequence I2C1 receive*/ Configure_I2CX_Receive(I2C1_Seven_Address_standard); Configure_I2CX_Receive(I2C1_Ten_Address_standard); Configure_I2CX_Receive(I2C1_Seven_Address_high); Configure_I2CX_Receive(I2C1_Ten_Address_high); Configure_I2CX_Receive(I2C1_Seven_Address_more_high); #endif   while(1){  }}/*!    \brief      Configure Param of I2Cx I2Cx Send data    \param[in]  Test_Sequence_Enum measure_sequence //test sequence    \param[out] none    \retval     none*/void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence){switch(measure_sequence){case I2C0_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C0 Seven Address standard send success\n");  break;case I2C0_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);      printf("I2C0_Ten_Address_standard send success\n");  break;case I2C0_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);      printf("I2C0_Seven_Address_high send success\n");  break;case I2C0_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_high send success\n");  break;case I2C0_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Seven_Address_more_high send success\n");  break;case I2C1_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1 Seven Address standard send success\n");  break;case I2C1_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_standard send success\n");  break;case I2C1_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_high send success\n");  break;case I2C1_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_high send success\n");  break;case I2C1_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_more_high send success\n");  break;default:break;}}/*!    \brief      Configure Param of receive data    \param[in]  Test_Sequence_Enum measure_sequence //test sequence    \param[out] none    \retval     none*/void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence){ switch(measure_sequence){case I2C0_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Seven_Address_standard receive data success!!\n");  break;case I2C0_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_standard receive data success!!\n");  break;case I2C0_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Seven_Address_high receive data success!!\n");  break;case I2C0_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_high receive data success!!\n");  break;case I2C0_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_high receive data success!!\n");  break;case I2C1_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_standard receive data success!!\n");  break;case I2C1_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);    printf("I2C1_Ten_Address_standard receive data success!!\n");  break;case I2C1_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_high receive data success!!\n");  break;case I2C1_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_high receive data success!!\n");  break;case I2C1_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);  delay_1ms(3000);//delay 3s wait slaver init success!      Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_high receive data success!!\n");  break;default:break;}}/*!    \brief      Configure Param of I2Cx receive data    \param[in]  Test_Sequence_Enum measure_sequence //test sequence    \param[out] none    \retval     none*/void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence){   i2c_param->Memory_address=Param_Array[measure_sequence].Memory_address; i2c_param->gpio_sclpin=Param_Array[measure_sequence].gpio_sclpin; i2c_param->gpio_sdapin=Param_Array[measure_sequence].gpio_sdapin; i2c_param->address=Param_Array[measure_sequence].address; i2c_param->address_model=Param_Array[measure_sequence].address_model; i2c_param->I2Cx_Periph=Param_Array[measure_sequence].I2Cx_Periph; i2c_param->I2c_speed=Param_Array[measure_sequence].I2c_speed; i2c_param->slaver_address=Param_Array[measure_sequence].slaver_address;}/*!    \brief      I2C init    \param[in]  I2Cx_PinSDA_Enum SDA pin     I2Cx_PinSCL_Enum SCL pinrcu_periph_enum  I2C periph     I2Cx_Speed_enum check clock frequenceAddress_Model_Enum 7 or 10 address check Slaver_Address_Enum 7 or 10 address     \param[out] none    \retval     none*/void I2Cx_Init(Param_Typedef *i2c_init){uint32_t gpiox_sda,pinx_sda,afx_sda,gpiox_scl,pinx_scl,afx_scl;I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);//SCL and SDA GPIO enable/*GPIO sda configure*/gpiox_sda=(uint32_t)((i2c_init->gpio_sdapin)& 0xffffff00);pinx_sda=(0x01<<((i2c_init->gpio_sdapin & 0xf0) >> 4));afx_sda=AF((i2c_init->gpio_sdapin & 0x0f));I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);gpio_af_set(gpiox_sda, afx_sda, pinx_sda);//IO口引脚复用功能gpio_mode_set(gpiox_sda, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_sda);//GPIO口、备用功能、端口上拉模式、具体引脚gpio_output_options_set(gpiox_sda, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,pinx_sda);//GPIO口、推挽输出及开漏输出、输出速率、具体引脚/*GPIO scl configure*/gpiox_scl=(uint32_t)((i2c_init->gpio_sclpin)& 0xffffff00);pinx_scl=(0x01<<((i2c_init->gpio_sclpin & 0xf0) >> 4));afx_scl=AF((i2c_init->gpio_sclpin & 0x0f));gpio_af_set(gpiox_scl, afx_scl,pinx_scl);//IO口引脚复用功能gpio_mode_set(gpiox_scl, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_scl);//GPIO口、备用功能、端口上拉模式、具体引脚/*--------------------------------I2C module initaial configure------------------------------------*//*enable I2C clock*/rcu_periph_clock_enable(i2c_init->I2Cx_Periph);//使能I2C时钟/*configure I2C clock*/  i2c_clock_config(i2c_init->Memory_address,i2c_init->I2c_speed,I2C_DTCY_2);//I2C的基地址、I2C数据传输速度、I2C的快速模式/*configure I2C address*/  i2c_mode_addr_config(i2c_init->Memory_address,I2C_I2CMODE_ENABLE,i2c_init->address_model,i2c_init->slaver_address);//I2C基地址、I2C模式、7位地址模式、I2C从机地址/*enable I2C0*/  i2c_enable(i2c_init->Memory_address);//I2C外设使能  /*enable acknowledge*/i2c_ack_config(i2c_init->Memory_address,I2C_ACK_ENABLE);//选择是否发送应答信号}/*!    \brief      I2C GPIO Clock enable    \param[in]  I2Cx_PinSDA_Enum SDA pin     I2Cx_PinSCL_Enum SCL pin    \param[out] none    \retval     none*/void I2Cx_Pin_ClockEnable(I2Cx_PinSDA_Enum gpio_sdapin,I2Cx_PinSCL_Enum gpio_sclpin){uint32_t gpiox_sda,gpiox_scl;gpiox_sda=(uint32_t)(gpio_sdapin & 0xffffff00);gpiox_scl=(uint32_t)(gpio_sclpin & 0xffffff00);/*SDA enable*/if(gpiox_sda==GPIOB){  rcu_periph_clock_enable(RCU_GPIOB);}else if(gpiox_sda==GPIOA){  rcu_periph_clock_enable(RCU_GPIOC);}else if(gpiox_sda==GPIOF){rcu_periph_clock_enable(RCU_GPIOF);}/*SCL enable*/if(gpiox_scl==GPIOB){  rcu_periph_clock_enable(RCU_GPIOB);}else if(gpiox_scl==GPIOA){  rcu_periph_clock_enable(RCU_GPIOA);}}/*!    \brief      Master send data 7 and 10 address    \param[in]  SendBuffer send array     DataNum send data num    \param[out] none    \retval     none*/void Master_SendData_address(uint8_t* SendBuffer,uint8_t DataNum,Param_Typedef *i2c_init){ uint8_t num;/*wait until I2C bus is idle*/while(i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_I2CBSY)){}/*send a start condition to I2C bus*/i2c_start_on_bus(i2c_init->Memory_address);//在I2C总线上产生一个开始信号/*wait until SBSEND bit is set  judge start whether send*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_SBSEND)){}//I2C_STAT0(i2c_init->Memory_address);//read I2C_STAT0 to clear ADDSENDif(i2c_init->address_model==I2Cx_Address_7bit){  Send_7Prepare(i2c_init);}else if(i2c_init->address_model==I2Cx_Address_10bit){  Send_10Prepare(i2c_init);}/*wait until the transmit data buffer is empty */  while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_TBE)){}for(num=0;num<DataNum;num++){  i2c_data_transmit(i2c_init->Memory_address,SendBuffer[num]);while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_BTC)){}}  /*send a stop condition to I2C bus*/  i2c_stop_on_bus(i2c_init->Memory_address);//在总线上发送停止信号位    /*wait until the stop condition is finished*/  while(I2C_CTL0(i2c_init->Memory_address)&0x0200);//等待结束信号发送  //printf("master send data success");}/*!    \brief      Master receive data    \param[in]  ReceiveBuffer receive data array     DataNum receive data num  address  slaver address    \param[out] none    \retval     none*/void Master_ReceiveData(uint8_t* ReceiveBuffer,uint8_t DataNum,Param_Typedef *i2c_init){/*wait until I2C bus is idle*/while(i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_I2CBSY));/*send a start condition to I2C bus*/i2c_start_on_bus(i2c_init->Memory_address);//在I2C总线上产生一个开始信号/*wait until SBSEND bit is set  judge start whether send*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_SBSEND));if(i2c_init->address==Send_7Address){ Receive_7Prepare(i2c_init);}else if(i2c_init->address==Send_10Address){ Receive_10Prepare(i2c_init);}if(DataNum==1){ /*disable acknowledge*/ i2c_ack_config(i2c_init->Memory_address,I2C_ACK_DISABLE);//选择是否发送应答信号 /*send a stop condition to I2C bus*/     i2c_stop_on_bus(i2c_init->Memory_address);//在总线上发送停止信号位 /*I2C_DATA is not empty*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));  *ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATA  } while(DataNum){      if(DataNum==2){   while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));  *ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATA  DataNum-=1;   ReceiveBuffer++;  /*disable acknowledge*/      i2c_ack_config(i2c_init->Memory_address,I2C_ACK_DISABLE);//选择是否发送应答信号      /*send a stop condition to I2C bus*/ i2c_stop_on_bus(i2c_init->Memory_address);//在总线上发送停止信号位    } /*I2C_DATA is not empty*/    while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));     *ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATA     DataNum-=1;     ReceiveBuffer++;    }   /*wait until the stop condition is finished*/  while(I2C_CTL0(i2c_init->Memory_address)&0x0200);//判断stop结束位已经发送  /*enable acknowledge*/  i2c_ack_config(i2c_init->Memory_address,I2C_ACK_ENABLE);//软件发送应答信号使能  i2c_ackpos_config(i2c_init->Memory_address,I2C_ACKPOS_CURRENT);//ACKEN位决定对当前正在接收的字节是否发送ACK/NACK;PECTRANS位表明PEC 是否处于移位寄存器中//printf("master receive data success");}/*!    \brief      Master send 7 address prepare    \param[in]  none    \param[out] none    \retval     none*/void Send_7Prepare(Param_Typedef *i2c_init){ /*send slave address to I2C bus*/ i2c_master_addressing(i2c_init->Memory_address,i2c_init->address,I2C_TRANSMITTER);//发送从机地址+写、清除SBSEND位、I2C设备发送方 /*wait until ADDSEND bit is set*/ while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND)){ } /*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/ i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位}/*!    \brief      Master receive 7 address prepare    \param[in]  none    \param[out] none    \retval     none*/void Receive_7Prepare(Param_Typedef *i2c_init){ /*send slave address to I2C bus */ i2c_master_addressing(i2c_init->Memory_address,i2c_init->address,I2C_RECEIVER);//发送从机地址+写、清除SBSEND位、I2C设备发送方 /* wait until ADDSEND bit is set */ while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND)){ } /*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/ i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位}/*!    \brief      Master send 10 address prepare    \param[in]  none    \param[out] none    \retval     none*/void Send_10Prepare(Param_Typedef *i2c_init){  uint32_t adrH10,adrL10;  adrH10=(((i2c_init->address & 0x300)>>7)|0xf0);//10位地址头(高2位)  adrL10=i2c_init->address & 0xff;//10位地址(低8位)  /*send slave  address adr10 to I2C bus */  i2c_master_addressing(i2c_init->Memory_address,(uint8_t)adrH10, I2C_TRANSMITTER);  /* wait until ADDSEND bit is set */  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADD10SEND));  i2c_data_transmit(i2c_init->Memory_address,adrL10);  /*wait until ADDSEND bit is set*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));   /*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/  i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位}/*!    \brief      Master receive 10 address prepare    \param[in]  none    \param[out] none    \retval     none*/void Receive_10Prepare(Param_Typedef *i2c_init){    uint32_t adrH10,adrL10;    adrH10=(((i2c_init->address & 0x300)>>7)|0xf0);//10位地址头(高2位)adrL10=i2c_init->address & 0xff;//10位地址(低8位)/*send slave address to I2C bus*/  i2c_master_addressing(i2c_init->Memory_address,(uint8_t)adrH10, I2C_TRANSMITTER);//发送从机10地址头+写、清除SBSEND位、I2C设备发送方/*wait until ADDSEND bit is set*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADD10SEND));i2c_data_transmit(i2c_init->Memory_address,adrL10);/* wait until ADDSEND bit is set */  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/  i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位  /*send a start condition to I2C bus*/i2c_start_on_bus(i2c_init->Memory_address);//在I2C总线上产生一个开始信号/*wait until SBSEND bit is set  judge start whether send*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_SBSEND));i2c_master_addressing(i2c_init->Memory_address,(uint8_t)adrH10,I2C_RECEIVER);  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));//等待ADDSEND位置1 硬件置1/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/  i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位}/* retarget the C library printf function to the USART */int fputc(int ch, FILE *f){    usart_data_transmit(EVAL_COM, (uint8_t)ch);    while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));    return ch;}/*!    \brief      this function handles SysTick exception    \param[in]  none    \param[out] none    \retval     none*/void SysTick_Handler(void){    delay_decrement();}

上述程序实现了主机发送和接收,速率100k/400k/1M,发送从机地址10bit、7bit,程序方便移植,只需将对应的.c和.h添加到工程中即可。当I2C的通信速率为1M时,需配置I2C模块所挂载的pclk时钟为3的整数倍或者25的整数倍,否则主机的SCL实际的时钟会有一定的误差,大于或者小于1M,大于1M可能导致通信失败(GD mcu官方手册有提到)。I2C总线空闲时,默认为高电平,因为GPIO口内部自带的上拉驱动能力不够,配置为开漏输出,需外接上拉电阻,GPIO的输出速率要选择最大(代码中选择的是50M)增加GPIO口输出能力,否则通过示波器查看发现SCL时钟波形不是正规的波形,也可能造成通信失败。不同GPIO口输出速率下,SCL时钟输出波形如下图所示。
上图为上到下GPIO口输出速率依次增大SCL输出波形图
1.4 从机发送和接收(速率100k\400k\1M,地址10bit or 7bit)
I2C的从机的通信时钟由主机提供,故不需要配置时钟,I2C初始化后默认为从机模式,发送start信号后,由从机模式转换为主机模式。

#include "gd32f3x0.h"#include #include "gd32f350r_eval.h"#include "main.h"#include "systick.h"#define I2C0_Measure//#define I2C1_Measure#define BufferNum 20uint8_t write_buffer[BufferNum]={0};//send data bufferuint8_t receive_buffer[BufferNum]={0};//receive data bufferParam_Typedef I2Cx_Param;/*define I2Cx Param struct array*/static Param_Typedef Para_Aarry[]={/*I2C0 param array*/{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},/*I2C1 param array*/{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},};/*testing sequence enum*/typedef enum{/*Measure I2C0*/I2C0_Seven_Address_standard=0,I2C0_Ten_Address_standard,I2C0_Seven_Address_high,I2C0_Ten_Address_high,I2C0_Seven_Address_more_high,/*Measure I2C1*/I2C1_Seven_Address_standard,I2C1_Ten_Address_standard,I2C1_Seven_Address_high,I2C1_Ten_Address_high,I2C1_Seven_Address_more_high}Test_Sequence_Enum;/*Configure Param of I2Cx Send data*/void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence);/*Configure Param of I2Cx receive data*/void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence);/*I2Cx param init*/void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence);/*!    \brief      main function    \param[in]  none    \param[out] none    \retval     none*/int main(void){ uint8_t num=0; for(num=0;num<BufferNum;num++){ write_buffer[num]=num; }   //printf("I2C slaver measuring\n"); #ifdef I2C0_Measure /*Test Sequence I2C0 receive*/ Configure_I2CX_Receive(I2C0_Seven_Address_standard); Configure_I2CX_Receive(I2C0_Ten_Address_standard); Configure_I2CX_Receive(I2C0_Seven_Address_high); Configure_I2CX_Receive(I2C0_Ten_Address_high); Configure_I2CX_Receive(I2C0_Seven_Address_more_high); /*Test Sequence I2C0 send*/ Configure_I2CX_Send(I2C0_Seven_Address_standard); Configure_I2CX_Send(I2C0_Ten_Address_standard); Configure_I2CX_Send(I2C0_Seven_Address_high); Configure_I2CX_Send(I2C0_Ten_Address_high); Configure_I2CX_Send(I2C0_Seven_Address_more_high); #elif defined I2C1_Measure /*Test Sequence I2C1 receive*/ Configure_I2CX_Receive(I2C1_Seven_Address_standard); Configure_I2CX_Receive(I2C1_Ten_Address_standard); Configure_I2CX_Receive(I2C1_Seven_Address_high); Configure_I2CX_Receive(I2C1_Ten_Address_high); Configure_I2CX_Receive(I2C1_Seven_Address_more_high); /*Test Sequence I2C1 send*/ Configure_I2CX_Send(I2C1_Seven_Address_standard); Configure_I2CX_Send(I2C1_Ten_Address_standard); Configure_I2CX_Send(I2C1_Seven_Address_high); Configure_I2CX_Send(I2C1_Ten_Address_high); Configure_I2CX_Send(I2C1_Seven_Address_more_high); #endif   while(1){  }}/*!    \brief      Configure Param of I2Cx I2Cx Send data    \param[in]  Test_Sequence_Enum measure_sequence //test sequence    \param[out] none    \retval     none*/void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence){switch(measure_sequence){case I2C0_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C0 Seven Address standard send success\n");  break;case I2C0_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);      printf("I2C0_Ten_Address_standard send success\n");  break;case I2C0_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);      printf("I2C0_Seven_Address_high send success\n");  break;case I2C0_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_high send success\n");  break;case I2C0_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Seven_Address_more_high send success\n");  break;case I2C1_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1 Seven Address standard send success\n");  break;case I2C1_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_standard send success\n");  break;case I2C1_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_high send success\n");  break;case I2C1_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_high send success\n");  break;case I2C1_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);      Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_more_high send success\n");  break;default:break;}}/*!    \brief      Configure Param of receive data    \param[in]  Test_Sequence_Enum measure_sequence //test sequence    \param[out] none    \retval     none*/void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence){ switch(measure_sequence){case I2C0_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Seven_Address_standard receive data success!!\n");  break;case I2C0_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_standard receive data success!!\n");  break;case I2C0_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Seven_Address_high receive data success!!\n");  break;case I2C0_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_high receive data success!!\n");  break;case I2C0_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C0_Ten_Address_high receive data success!!\n");  break;case I2C1_Seven_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_standard receive data success!!\n");  break;case I2C1_Ten_Address_standard:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);      I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);    printf("I2C1_Ten_Address_standard receive data success!!\n");  break;case I2C1_Seven_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Seven_Address_high receive data success!!\n");  break;case I2C1_Ten_Address_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);  I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_high receive data success!!\n");  break;case I2C1_Seven_Address_more_high:  Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);  I2Cx_Init(&I2Cx_Param);      Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);  printf("I2C1_Ten_Address_high receive data success!!\n");  break;default:break;}}/*!    \brief      Configure Param of I2Cx receive data    \param[in]  Test_Sequence_Enum measure_sequence //test sequence    \param[out] none    \retval     none*/void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence){   i2c_param->Memory_address=Param_Array[measure_sequence].Memory_address; i2c_param->gpio_sclpin=Param_Array[measure_sequence].gpio_sclpin; i2c_param->gpio_sdapin=Param_Array[measure_sequence].gpio_sdapin; i2c_param->address=Param_Array[measure_sequence].address; i2c_param->address_model=Param_Array[measure_sequence].address_model; i2c_param->I2Cx_Periph=Param_Array[measure_sequence].I2Cx_Periph; i2c_param->I2c_speed=Param_Array[measure_sequence].I2c_speed; i2c_param->slaver_address=Param_Array[measure_sequence].slaver_address;}/*!    \brief      I2C init    \param[in]  I2Cx_PinSDA_Enum SDA pin     I2Cx_PinSCL_Enum SCL pinrcu_periph_enum  I2C periph     I2Cx_Speed_enum check clock frequenceAddress_Model_Enum 7 or 10 address check Slaver_Address_Enum 7 or 10 address     \param[out] none    \retval     none*/void I2Cx_Init(Param_Typedef *i2c_init){uint32_t gpiox_sda,pinx_sda,afx_sda,gpiox_scl,pinx_scl,afx_scl;I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);//SCL and SDA GPIO enable/*GPIO sda configure*/gpiox_sda=(uint32_t)((i2c_init->gpio_sdapin)& 0xffffff00);pinx_sda=(0x01<<((i2c_init->gpio_sdapin & 0xf0) >> 4));afx_sda=AF((i2c_init->gpio_sdapin & 0x0f));I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);gpio_af_set(gpiox_sda, afx_sda, pinx_sda);//IO口引脚复用功能gpio_mode_set(gpiox_sda, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_sda);//GPIO口、备用功能、端口上拉模式、具体引脚gpio_output_options_set(gpiox_sda, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,pinx_sda);//GPIO口、推挽输出及开漏输出、输出速率、具体引脚/*GPIO scl configure*/gpiox_scl=(uint32_t)((i2c_init->gpio_sclpin)& 0xffffff00);pinx_scl=(0x01<<((i2c_init->gpio_sclpin & 0xf0) >> 4));afx_scl=AF((i2c_init->gpio_sclpin & 0x0f));gpio_af_set(gpiox_scl, afx_scl,pinx_scl);//IO口引脚复用功能gpio_mode_set(gpiox_scl, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_scl);//GPIO口、备用功能、端口上拉模式、具体引脚gpio_output_options_set(gpiox_scl, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,pinx_scl);//GPIO口、推挽输出及开漏输出、输出速率、具体引脚/*--------------------------------I2C module initaial configure------------------------------------*//*enable I2C clock*/rcu_periph_clock_enable(i2c_init->I2Cx_Periph);//使能I2C时钟/*configure I2C clock*/  i2c_clock_config(i2c_init->Memory_address,i2c_init->I2c_speed,I2C_DTCY_2);//I2C的基地址、I2C数据传输速度、I2C的快速模式/*configure I2C address*/  i2c_mode_addr_config(i2c_init->Memory_address,I2C_I2CMODE_ENABLE,i2c_init->address_model,i2c_init->slaver_address);//I2C基地址、I2C模式、7位地址模式、I2C从机地址/*enable I2C0*/  i2c_enable(i2c_init->Memory_address);//I2C外设使能  /*enable acknowledge*/i2c_ack_config(i2c_init->Memory_address,I2C_ACK_ENABLE);//选择是否发送应答信号}/*!    \brief      I2C GPIO Clock enable    \param[in]  I2Cx_PinSDA_Enum SDA pin     I2Cx_PinSCL_Enum SCL pin    \param[out] none    \retval     none*/void I2Cx_Pin_ClockEnable(I2Cx_PinSDA_Enum gpio_sdapin,I2Cx_PinSCL_Enum gpio_sclpin){uint32_t gpiox_sda,gpiox_scl;gpiox_sda=(uint32_t)(gpio_sdapin & 0xffffff00);gpiox_scl=(uint32_t)(gpio_sclpin & 0xffffff00);/*SDA enable*/if(gpiox_sda==GPIOB){  rcu_periph_clock_enable(RCU_GPIOB);}else if(gpiox_sda==GPIOA){  rcu_periph_clock_enable(RCU_GPIOC);}else if(gpiox_sda==GPIOF){rcu_periph_clock_enable(RCU_GPIOF);}/*SCL enable*/if(gpiox_scl==GPIOB){  rcu_periph_clock_enable(RCU_GPIOB);}else if(gpiox_scl==GPIOA){  rcu_periph_clock_enable(RCU_GPIOA);}}/*!    \brief      Slaver receive data    \param[in]  uint8_t* SendBuffer //receive buffer     uint8_t DataNum //receive data num  Param_Typedef *i2c_init //define I2CX init param    \param[out] none    \retval     none*/void Slaver_ReceiveData_address(uint8_t* ReceiveBuffer,uint8_t DataNum,Param_Typedef *i2c_init){/*waiting I2C_FLAG_ADDSEND is set 1*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));  /*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/  i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位  while(DataNum){/*I2C_DATA is not empty*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));*ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATAReceiveBuffer+=1;DataNum-=1;}while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_STPDET));/*clear STPDET flag*/I2C_STAT0(i2c_init->Memory_address);I2C_CTL0(i2c_init->Memory_address)=0x0000;//printf("slaver receive data success!!\n");}/*!    \brief      I2C slaver send buffer 7 and 10 address    \param[in]  uint8_t* SendBuffer  //receive buffer     uint8_t DataNum      //receive data num  Param_Typedef *i2c_init //define I2CX init param    \param[out] none    \retval     none*/void Slaver_SendData_address(uint8_t* SendBuffer,uint8_t DataNum,Param_Typedef *i2c_init){uint8_t num;/*waiting I2C_FLAG_ADDSEND is set 1*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));  /*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/  i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位if(i2c_init->address_model==I2Cx_Address_10bit){  /*wait until ADDSEND bit is set*/    while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/    i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位}/*wait until the transmit data buffer is empty*/  while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_TBE));//send one byte to I2C BUSi2c_data_transmit(i2c_init->Memory_address,*SendBuffer);SendBuffer+=1;while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_BTC));//send two byte to I2C BUSi2c_data_transmit(i2c_init->Memory_address,*SendBuffer);SendBuffer+=1;for(num=0;num<(DataNum-2);num++){  /*I2C_DATA is not empty*/  while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_BTC));i2c_data_transmit(i2c_init->Memory_address,*SendBuffer);    SendBuffer+=1;}/*wait until the transmit data buffer is empty*/  while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_AERR));//clear I2C AERR flagi2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_AERR);}/* retarget the C library printf function to the USART */int fputc(int ch, FILE *f){    usart_data_transmit(EVAL_COM, (uint8_t)ch);    while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));    return ch;}/*!    \brief      this function handles SysTick exception    \param[in]  none    \param[out] none    \retval     none*/void SysTick_Handler(void){    delay_decrement();}

以上从机接收和发送代码和主机一一对应,两者可作为测试使用。I2C从机支持双地址、10bit地址和广播地址模式(0x00)。双地址模式:I2C从机设备可对两个地址响应。广播地址模式:所有I2C从机设备默认的响应地址。

//双地址模式 i2c_dualaddr_enable(I2C0,0x44);//广播地址 i2c_slave_response_to_gcall_config(I2C0, I2C_GCEN_ENABLE);

1.5 主机中断接收发送程序

//主机中断发送int main(void){ uint8_t num=0;   /*configure EVAL_COM1*/   gd_eval_com_init(EVAL_COM); systick_config(); for(num=0;num<BufferNum;num++){ write_buffer[num]=num; } printf("I2C master send by interrupt measuring!!!"); Param_Init(&I2Cx_Param,Para_Aarry,I2C_Measuring); I2Cx_Init(&I2Cx_Param); nvic_irq_enable(I2Cx_EV_IRQn,0,0);/*!< I2C0 event interrupt priority and enable*/   nvic_irq_enable(I2Cx_ER_IRQn,0,1);/*!< I2C0 erro  interrupt priority and enable*/ i2c_interrupt_enable(I2C_x,I2C_INT_ERR);//error interrupt enable  i2c_interrupt_enable(I2C_x,I2C_INT_EV);//event interrupt enable i2c_interrupt_enable(I2C_x,I2C_INT_BUF);//buffer interrupt enable   delay_1ms(3000);    /*wait until I2C bus is idle*/   while(i2c_flag_get(I2C_x,I2C_FLAG_I2CBSY)); /*send a start condition to I2C bus*/i2c_start_on_bus(I2C_x);//在I2C总线上产生一个开始信号  while(!Send_InterruptFlag);/*wait until the stop condition is finished*/  while(I2C_CTL0(I2C_x)&0x0200);//等待结束信号发送  printf("I2C0 master interrupt send success!!");    while(1){  }}/*!    \brief      this function handles I2C0 Event    \param[in]  none    \param[out] none    \retval     none*/void I2C0_EV_IRQHandler(void){if(i2c_flag_get(I2C_x,I2C_FLAG_SBSEND)){ I2C_STAT0(I2C_x); /*send slave address to I2C bus */     i2c_master_addressing(I2C_x,0x42,I2C_TRANSMITTER);//发送从机地址+写、清除SBSEND位、I2C设备发送方}else if(i2c_flag_get(I2C_x,I2C_FLAG_ADDSEND)){   i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位}else if(i2c_flag_get(I2C_x,I2C_FLAG_TBE)){if(Data<20){     i2c_data_transmit(I2C_x,write_buffer[Data]);   Data+=1;}else{ i2c_stop_on_bus(I2C_x);//在总线上发送停止信号位Send_InterruptFlag=1;i2c_interrupt_disable(I2C_x,I2C_INT_ERR);//error interrupt enable      i2c_interrupt_disable(I2C_x,I2C_INT_EV);//event interrupt enable     i2c_interrupt_disable(I2C_x,I2C_INT_BUF);//buffer interrupt enable}}}/*!    \brief      this function handles I2C0 Error    \param[in]  none    \param[out] none    \retval     none*/void I2C0_ER_IRQHandler(void){//SMBus Alert statusif(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);}//timeout signal in SMBus modeif(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);}//PEC error when receiving dataif(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);}//over-run or under-run situation occurs in slave modeif(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);}//acknowledge errorif(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_AERR);}//arbitration lost in master modeif(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){   i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);}//a bus error if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_BERR);}}//主机接收中断/*!    \brief      this function handles I2C0 Event    \param[in]  none    \param[out] none    \retval     none*/void I2C0_EV_IRQHandler(void){if(i2c_flag_get(I2C_x,I2C_FLAG_SBSEND)){ I2C_STAT0(I2C_x); /*send slave address to I2C bus */     i2c_master_addressing(I2C_x,0x42,I2C_RECEIVER);//发送从机地址+写、清除SBSEND位、I2C设备发送方}if(i2c_flag_get(I2C_x,I2C_FLAG_ADDSEND)){   i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位}if(i2c_flag_get(I2C_x,I2C_FLAG_RBNE)){ if(Data==18){ receive_buffer[Data]=i2c_data_receive(I2C_x); Data+=1; /*disable acknowledge*/     i2c_ack_config(I2C_x,I2C_ACK_DISABLE);//选择是否发送应答信号 i2c_stop_on_bus(I2C_x);//在总线上发送停止信号位 }else if(Data<18){     receive_buffer[Data]=i2c_data_receive(I2C_x);   Data+=1; }else if(Data==19) {   receive_buffer[Data]=i2c_data_receive(I2C_x);Receive_InterruptFlag=1;i2c_interrupt_disable(I2C_x,I2C_INT_ERR);//error interrupt enable      i2c_interrupt_disable(I2C_x,I2C_INT_EV);//event interrupt enable     i2c_interrupt_disable(I2C_x,I2C_INT_BUF);//buffer interrupt enable   } }}/*!    \brief      this function handles I2C0 Error    \param[in]  none    \param[out] none    \retval     none*/void I2C0_ER_IRQHandle(void){//SMBus Alert statusif(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);}//timeout signal in SMBus modeif(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);}//PEC error when receiving dataif(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);}//over-run or under-run situation occurs in slave modeif(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);}//acknowledge errorif(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_AERR);}//arbitration lost in master modeif(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){   i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);}//a bus error if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_BERR);}}

如果项目程序有多个中断,尽可能将I2C主机接收的中断优先级设为最高,否则会存在主机多接收一个数据,原因:当主机接收一个数据时,RBNE置1,在未读取DATA寄存器中的数据时,被更高的优先级任务打断,I2C总线上又接收一个数据到移位寄存器,此时BTC标志位置1。当中断恢复时,主机读取DATA寄存器中的数据。因为此时BTC已经置1,BTC清除的条件是需先读state状态寄存器,再读DATA寄存器,此时读DATA寄存器,无法清除BTC,使移位寄存器中的数据无法移到数据寄存器,I2C总线SCL被拉低,已阻止接收下一个数据,此时I2C还认为接收两个数据,会再次进中断读取DATA寄存器,BTC清零,移位寄存器数据移到Data寄存器,再次读取下一个数据,会造成接收的数据中有两个前后重复的数据。
1.6 从机中断接收和发送

//从机中断接收/*!    \brief      this function handles I2C0 Event    \param[in]  none    \param[out] none    \retval     none*/void I2C0_EV_IRQHandler(void){if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_ADDSEND)){/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/    i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位}else if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_TBE)){ if(Data<20){i2c_data_transmit(I2C_x,writer_buffer[Data]);Data+=1;  }else{ Send_InterruptFlag=1; i2c_interrupt_disable(I2C_x,I2C_INT_ERR);     i2c_interrupt_disable(I2C_x,I2C_INT_EV);     i2c_interrupt_disable(I2C_x,I2C_INT_BUF); } }}/*!    \brief      this function handles I2C0 Error    \param[in]  none    \param[out] none    \retval     none*/void I2C0_ER_IRQHandle(void){//SMBus Alert statusif(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);}//timeout signal in SMBus modeif(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);}//PEC error when receiving dataif(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);}//over-run or under-run situation occurs in slave modeif(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);}//acknowledge errorif(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_AERR);}//arbitration lost in master modeif(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){   i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);}//a bus error if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_BERR);}}//从机中断发送/*!    \brief      this function handles I2C0 Event    \param[in]  none    \param[out] none    \retval     none*/void I2C0_EV_IRQHandler(void){if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_ADDSEND)){/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/    i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位}else if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_TBE)){ if(Data<20){i2c_data_transmit(I2C_x,writer_buffer[Data]);Data+=1;  }else{ Send_InterruptFlag=1; i2c_interrupt_disable(I2C_x,I2C_INT_ERR);     i2c_interrupt_disable(I2C_x,I2C_INT_EV);     i2c_interrupt_disable(I2C_x,I2C_INT_BUF); } }}/*!    \brief      this function handles I2C0 Error    \param[in]  none    \param[out] none    \retval     none*/void I2C0_ER_IRQHandle(void){//SMBus Alert statusif(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);}//timeout signal in SMBus modeif(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){   i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);}//PEC error when receiving dataif(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);}//over-run or under-run situation occurs in slave modeif(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);}//acknowledge errorif(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_AERR);}//arbitration lost in master modeif(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){   i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);}//a bus error if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){   i2c_flag_clear(I2C_x,I2C_FLAG_BERR);}}

主机发送每一个byte数据时,从机都需发送ACK信号,而从机发送数据时,当主机接收到最后一个字节的数据时,给从机发NACK信号,从机接收到NACK信号后,就知道主机要结束通信了。从机SCL拉低功能作用是:从机在接收数据时,由于需要处理其他事情,比如打印一些调试信息,可能没有及时读取DATA寄存器中的数据,这时从机会拉低SCL时钟线已阻止主机发送下一个字节数据,也就是再告诉主机“我正在忙啦!您稍等片刻”,I2C中对这个拉低时间没有具体要求,但是在SMBUS中,对SCL拉低的时间规定为25ms,如果25ms从机还在拉低SCL硬件就会强制发送stop信号结束此次通信(也就是说主机的忍耐是有限度的哈!!)。
这篇就先写这么多,I2C硬件的其他主要特性及代码实现在后面介绍。