GD32f303的硬件IIC.从机配置与接收流程

news/2024/11/15 8:34:39/

一、写在开头

        1、要注意硬件IIC配置相当坑,看起来没关系的两个函数,只要初始化配置化调用写反了就可能导致问题。比如:最终使能IIC的函数< i2c_enable(I2Cx) >与配置应答的函数< i2c_ack_config(I2Cx, I2C_ACK_ENABLE) >写反了就会导致配置失败。非常离谱。

        2、在写自己的中断函数时要注意好逻辑,从机发与从机收是两个套路。而且< i2c_interrupt_flag_clear() >函数不是万能的。要注意这个函数只能清除哪些标志位。

        2023.2.7新增---> 3、由于iic从移位寄存器传给发送寄存器时会触发把发送寄存器的值传给接收机的操作,因此特别注意要对这进行处理。

        2023.2.7新增---> 4、很多时候iic中断不能只思考单发或者单收的情况,有时候会同时进行读跟写,也就是读标志位跟写标志位会在一段时间内出现,在编程时不考虑这种情况就会出错。我现在继续回顾我的代码,当初认为完美的代码再看也就那样。

        2023.4.18新增--->5、iic主设备发送给从设备第一个字节前会先发一个0或上一次发送报文的尾字节的问题不会所有的设备都存在,在我目前接触的有的第一字节会出问题有的不会出问题,记得具体问题具体分析。最好能进debug或者买一个逻辑分析仪看看。

        2023.4.18新增--->6、如果频繁的发送报文,也就是频繁的钳位iic总线。这份代码会概率出问题。如果出问题了,在i2c0_rw_Data_slave()、i2c1_rw_Data_slave()的末尾的死等50次循环可以注释掉。这个循环是为了防止某些iic外设莫名奇妙的行为,但现在想想意义不大,反而更容易出问题了,去掉就行,保持中断的全速运行。

        5、GD32f303单片机的从机收发流程图如下:

                发:

                        收:<值得注意,stpdet标志位不可以使用i2c_interrupt_flag_clear()函数清除> 

二、我的硬件IIc.从机初始化流程<带应答>

        --下面时我最初的初始化代码,不要抄!!!有问题

void i2cSlaveInit(void)
{// enable clock rcu_periph_clock_enable(RCU_AF);rcu_periph_clock_enable(RCU_GPIOB);//看自己用的iic配置哪个io端口rcu_periph_clock_enable(RCU_I2Cx);// PB6:I2Cx_SCL, PB7:I2Cx_SDAgpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6);gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7);i2c_deinit(I2Cx);// I2C clock configure : 100kHz, i2c_clock_config(I2Cx, 100000, I2C_DTCY_2);// I2C address configure i2c_mode_addr_config(I2Cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2Cx_SLAVE_ADDRESS8);//注意地址,8bit,虽然不知道为什么写7bit的地址需要填入8bit,但注意就好// 中断配置 nvic_irq_enable(I2Cx_EV_IRQn, 0, 1);nvic_irq_enable(I2Cx_ER_IRQn, 0, 2);i2c_interrupt_enable(I2Cx, I2C_INT_ERR);i2c_interrupt_enable(I2Cx, I2C_INT_BUF);i2c_interrupt_enable(I2Cx, I2C_INT_EV);// enable I2Cx i2c_enable(I2Cx);// enable acki2c_ack_config(I2Cx, I2C_ACK_ENABLE);
}

        --下面是我最新的初始化代码

/*** @fn         : * @brief      : iic0从模式初始化* @return      {*}* @attention  : * @author     : LC* @param {uint32_t} address : 经左移1位的7bit地址*/
void i2c0SlaveInit(uint32_t address)
{/* enable af clock */rcu_periph_clock_enable(RCU_AF);/* enable GPIOB clock */rcu_periph_clock_enable(RCU_GPIOB);/* enable I2C0 clock */rcu_periph_clock_enable(RCU_I2C0);/* connect PB6 to I2C0_SCL *//* connect PB7 to I2C0_SDA */gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6);gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7);/* 取消初始化iic0 */i2c_deinit(I2C0);/* I2C clock configure : 100kHz, */i2c_clock_config(I2C0, 100000, I2C_DTCY_2);/* I2C address configure */i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, address);/* 中断配置 */nvic_irq_enable(I2C0_EV_IRQn, 3, 0);nvic_irq_enable(I2C0_ER_IRQn, 4, 0);/* enable the I2C0 interrupt */i2c_interrupt_enable(I2C0, I2C_INT_ERR);i2c_interrupt_enable(I2C0, I2C_INT_BUF);i2c_interrupt_enable(I2C0, I2C_INT_EV);/* enable I2C0 */i2c_enable(I2C0);/* enable acknowledge */i2c_ack_config(I2C0, I2C_ACK_ENABLE);
}/*** @fn         : * @brief      : iic1从模式初始化* @return      {*}* @attention  : * @author     : LC* @param {uint32_t} address : 经左移1位的7bit地址*/
void i2c1SlaveInit(uint32_t address)
{/* enable af clock */rcu_periph_clock_enable(RCU_AF);/* enable GPIOB clock */rcu_periph_clock_enable(RCU_GPIOB);/* enable I2C1 clock */rcu_periph_clock_enable(RCU_I2C1);/* connect PB6 to I2C1_SCL *//* connect PB7 to I2C1_SDA */gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_11);/* 取消初始化iic1 */i2c_deinit(I2C1);/* I2C clock configure : 100kHz, */i2c_clock_config(I2C1, 100000, I2C_DTCY_2);/* I2C address configure */i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, address);/* 中断配置 */nvic_irq_enable(I2C1_EV_IRQn, 3, 0);nvic_irq_enable(I2C1_ER_IRQn, 4, 0);/* enable the I2C0 interrupt */i2c_interrupt_enable(I2C1, I2C_INT_ERR);i2c_interrupt_enable(I2C1, I2C_INT_BUF);i2c_interrupt_enable(I2C1, I2C_INT_EV);/* enable I2C1 */i2c_enable(I2C1);/* enable acknowledge */i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}

三、我的硬件IIC.从机流程代码<收+发>

--下面时我最初的中断收发代码,不要抄!!!有问题

#define i2c_periph I2C0uint8_t buffer[20]; //接收的数据
extern uint8_t *i2c_data;//发送的数据,外部给出//单次接收有长度限制 20byte,发送没有
void i2c_rw_Data_slave(uint8_t *const i2c_rx, uint8_t *const i2c_tx)
{static uint8_t ADDSEND_FLAG = 0, wRFlag = 2;                // wRFalg ==0 是发送模式,==1 是接收模式uint8_t *const rxbuffer = i2c_rx, *const txbuffer = i2c_tx; //分别保存接收、发送的数据static uint8_t index = 0;/* wait until ADDSEND bit is set */if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_ADDSEND)){ //第一次addsendADDSEND_FLAG++;i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_ADDSEND);}else if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_BERR)){i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_BERR);}if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_TBE)) //确定是发{wRFlag = 0;}if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_RBNE)) //确定是收{wRFlag = 1;}if (ADDSEND_FLAG != 0){while (wRFlag != 2){if (wRFlag == 0) //发送{if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_TBE)){i2c_data_transmit(i2c_periph, txbuffer[index]);index++;}if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_AERR)){wRFlag = 2;index = 0;ADDSEND_FLAG = 0;i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_AERR);}}else if (wRFlag == 1) //接收{if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_RBNE)){if (index < 20){rxbuffer[index] = i2c_data_receive(i2c_periph);index++;}else{i2c_data_receive(i2c_periph); //过长丢弃}}if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_STPDET)){wRFlag = 2;index = 0;ADDSEND_FLAG = 0;I2C_STAT0(i2c_periph); // 清标志:I2C_INT_FLAG_STPDETI2C_CTL0(i2c_periph) = I2C_CTL0(i2c_periph);}}}}i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_AERR);I2C_STAT0(i2c_periph); // clear: I2C_INT_FLAG_STPDETI2C_CTL0(i2c_periph) = I2C_CTL0(i2c_periph);
}void I2C0_EventIRQ_Handler()
{i2c_rw_Data_slave(buffer, i2c_data);
}void I2C0_ErrorIRQ_Handler(void)
{
}

         --下面是我最新的中断代码

/*** @fn         : * @brief      : 单次接收有长度限制 20byte <不限制长度的接收是不可取的>,发送没有* @return      {*}* @attention  : * @author     : LC* @param {uint8_t} *i2c_send* @param {uint8_t} *i2c_receive*/
void i2c0_rw_Data_slave(uint8_t *const i2c_send, uint8_t *const i2c_receive)
{static uint8_t ADDSEND_FLAG = 0, wRFlag = 2;                // wRFalg ==0 是发送模式,==1 是接收模式uint8_t *const rxbuffer = i2c_receive, *const txbuffer = i2c_send; //分别保存接收、发送的数据static uint8_t index_rx = 0, index_tx = 0;if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)){ //检查addsend标志位ADDSEND_FLAG++;i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);//清理 ADDSEND bit }if (ADDSEND_FLAG != 0){switch(wRFlag){case 0://发送if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)){i2c_data_transmit(I2C0, txbuffer[index_tx]);index_tx++;}if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR)){wRFlag = 2;index_tx = 0;ADDSEND_FLAG = 0;i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_AERR);}break;case 1://接收if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE)){if (index_rx < 20){rxbuffer[ (index_rx>0)?index_rx-1 : index_rx ] = i2c_data_receive(I2C0);//因为iic的特性,第一个收到的是移位寄存器的数据,是不需要的index_rx++;}else{i2c_data_receive(I2C0); //过长丢弃}}if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_STPDET)){wRFlag = 2;index_rx = 0;ADDSEND_FLAG = 0;I2C_STAT0(I2C0); // clear: I2C_INT_FLAG_STPDETI2C_CTL0(I2C0) = I2C_CTL0(I2C0);}break;case 2:__nop();break;default://严重的错误,不应该会执行到这里break;}}if(ADDSEND_FLAG == 1 && i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE)){//确定是收wRFlag = 1;for(int i=0; i<50; i++){//硬等一段时间__nop();}}else if (ADDSEND_FLAG == 2 && i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)){ //确定是发wRFlag = 0;for(int i=0; i<50; i++){//硬等一段时间__nop();}}
}/*** @fn         : * @brief      : 单次接收有长度限制 20byte <不限制长度的接收是不可取的>,发送没有* @return      {*}* @attention  : * @author     : LC* @param {uint8_t} *i2c_send* @param {uint8_t} *i2c_receive*/
void i2c1_rw_Data_slave(uint8_t *const i2c_send, uint8_t *const i2c_receive)
{static uint8_t ADDSEND_FLAG = 0, wRFlag = 2;                // wRFalg ==0 是发送模式,==1 是接收模式uint8_t *const rxbuffer = i2c_receive, *const txbuffer = i2c_send; //分别保存接收、发送的数据static uint8_t index_rx = 0, index_tx = 0;if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND)){ //检查addsend标志位ADDSEND_FLAG++;i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);//清理 ADDSEND bit }if (ADDSEND_FLAG != 0){switch(wRFlag){case 0://发送if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)){i2c_data_transmit(I2C1, txbuffer[index_tx]);index_tx++;}if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR)){wRFlag = 2;index_tx = 0;ADDSEND_FLAG = 0;i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_AERR);}break;case 1://接收if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE)){if (index_rx < 20){rxbuffer[ (index_rx>0)?index_rx-1 : index_rx ] = i2c_data_receive(I2C1);//因为iic的特性,第一个收到的是移位寄存器的数据,是不需要的index_rx++;}else{i2c_data_receive(I2C1); //过长丢弃}}if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_STPDET)){wRFlag = 2;index_rx = 0;ADDSEND_FLAG = 0;I2C_STAT0(I2C1); // clear: I2C_INT_FLAG_STPDETI2C_CTL0(I2C1) = I2C_CTL0(I2C1);}break;case 2:__nop();break;default://严重的错误,不应该会执行到这里break;}}if(ADDSEND_FLAG == 1 && i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE)){//确定是收wRFlag = 1;for(int i=0; i<50; i++){//硬等一段时间__nop();}}else if (ADDSEND_FLAG == 2 && i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)){ //确定是发wRFlag = 0;for(int i=0; i<50; i++){//硬等一段时间__nop();}}
}/*** @fn         : * @brief      : iic0中断函数* @return      {*}* @attention  : * @author     : LC*/
void I2C0_EventIRQ_Handler()
{i2c0_rw_Data_slave(i2c0_send, i2c0_receiver);
}/*** @fn         :* @brief      :* @return      {*}* @attention  :* @author     : LC*/
void I2C0_ErrorIRQ_Handler(void)
{
}/*** @fn         : * @brief      : iic1中断函数* @return      {*}* @attention  : * @author     : LC*/
void I2C1_EventIRQ_Handler()
{i2c1_rw_Data_slave(i2c1_send, i2c1_receiver);
}/*** @fn         :* @brief      :* @return      {*}* @attention  :* @author     : LC*/
void I2C1_ErrorIRQ_Handler(void)
{
}

四、完整的文件

------ 头文件hal_iic.h <中断定义在gd32f30x_it.c文件里,把下面的中断函数写到中断函数体内即可>

#ifndef __HAL_IIC_H__
#define __HAL_IIC_H__#include <stdint.h>
#include <stdbool.h>
#include "FreeRTOS.h"
#include "task.h"#ifdef __cplusplus
extern "C" {
#endiftypedef enum {open_iic0=0x01,open_iic1=0x02}iic_select;void iic_Init(iic_select select, ...);/* iic0的中断回调函数 */void I2C0_EventIRQ_Handler(void);/* iic1的中断回调函数 */void I2C1_EventIRQ_Handler(void);void I2C0_ErrorIRQ_Handler(void);void I2C1_ErrorIRQ_Handler(void);
#ifdef __cplusplus
}
#endif#endif

------ 源文件hal_iicSlave.c

#include "hal_iic.h"
#include "log.h"
#include "stdarg.h"uint8_t *i2c0_send;
uint8_t i2c0_receiver[20];
uint8_t *i2c1_send;
uint8_t i2c1_receiver[20];/*** @fn         : * @brief      : iic0注册主设备读取时被读取的数据* @return      {*}* @attention  : * @author     : * @param {uint8_t} *array*/
void i2c0SlaveRegister(uint8_t *array)
{i2c0_send = array;
}/*** @fn         : * @brief      : iic1注册主设备读取时被读取的数据* @return      {*}* @attention  : * @author     : * @param {uint8_t} *array*/
void i2c1SlaveRegister(uint8_t *array)
{i2c1_send = array;
}/*** @fn         : * @brief      : iic0从模式初始化* @return      {*}* @attention  : * @author     : * @param {uint32_t} address : 经左移1位的7bit地址*/
void i2c0SlaveInit(uint32_t address)
{/* enable af clock */rcu_periph_clock_enable(RCU_AF);/* enable GPIOB clock */rcu_periph_clock_enable(RCU_GPIOB);/* enable I2C0 clock */rcu_periph_clock_enable(RCU_I2C0);/* connect PB6 to I2C0_SCL *//* connect PB7 to I2C0_SDA */gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6);gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7);/* 取消初始化iic0 */i2c_deinit(I2C0);/* I2C clock configure : 100kHz, */i2c_clock_config(I2C0, 100000, I2C_DTCY_2);/* I2C address configure */i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, address);/* 中断配置 */nvic_irq_enable(I2C0_EV_IRQn, 3, 0);nvic_irq_enable(I2C0_ER_IRQn, 4, 0);/* enable the I2C0 interrupt */i2c_interrupt_enable(I2C0, I2C_INT_ERR);i2c_interrupt_enable(I2C0, I2C_INT_BUF);i2c_interrupt_enable(I2C0, I2C_INT_EV);/* enable I2C0 */i2c_enable(I2C0);/* enable acknowledge */i2c_ack_config(I2C0, I2C_ACK_ENABLE);
}/*** @fn         : * @brief      : iic1从模式初始化* @return      {*}* @attention  : * @author     : * @param {uint32_t} address : 经左移1位的7bit地址*/
void i2c1SlaveInit(uint32_t address)
{/* enable af clock */rcu_periph_clock_enable(RCU_AF);/* enable GPIOB clock */rcu_periph_clock_enable(RCU_GPIOB);/* enable I2C1 clock */rcu_periph_clock_enable(RCU_I2C1);/* connect PB6 to I2C1_SCL *//* connect PB7 to I2C1_SDA */gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_11);/* 取消初始化iic1 */i2c_deinit(I2C1);/* I2C clock configure : 100kHz, */i2c_clock_config(I2C1, 100000, I2C_DTCY_2);/* I2C address configure */i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, address);/* 中断配置 */nvic_irq_enable(I2C1_EV_IRQn, 3, 0);nvic_irq_enable(I2C1_ER_IRQn, 4, 0);/* enable the I2C0 interrupt */i2c_interrupt_enable(I2C1, I2C_INT_ERR);i2c_interrupt_enable(I2C1, I2C_INT_BUF);i2c_interrupt_enable(I2C1, I2C_INT_EV);/* enable I2C1 */i2c_enable(I2C1);/* enable acknowledge */i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}/*** @fn         : * @brief      : 单次接收有长度限制 20byte <不限制长度的接收是不可取的>,发送没有* @return      {*}* @attention  : * @author     : * @param {uint8_t} *i2c_send* @param {uint8_t} *i2c_receive*/
void i2c0_rw_Data_slave(uint8_t *const i2c_send, uint8_t *const i2c_receive)
{static uint8_t ADDSEND_FLAG = 0, wRFlag = 2;                // wRFalg ==0 是发送模式,==1 是接收模式uint8_t *const rxbuffer = i2c_receive, *const txbuffer = i2c_send; //分别保存接收、发送的数据static uint8_t index_rx = 0, index_tx = 0;if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)){ //检查addsend标志位ADDSEND_FLAG++;i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);//清理 ADDSEND bit }if (ADDSEND_FLAG != 0){switch(wRFlag){case 0://发送if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)){i2c_data_transmit(I2C0, txbuffer[index_tx]);index_tx++;}if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR)){wRFlag = 2;index_tx = 0;ADDSEND_FLAG = 0;i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_AERR);}break;case 1://接收if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE)){if (index_rx < 20){rxbuffer[ (index_rx>0)?index_rx-1 : index_rx ] = i2c_data_receive(I2C0);//因为iic的特性,第一个收到的是移位寄存器的数据,是不需要的,但是在某些ic却没有这种情况,所以这里应该由自己需求决定要不要去掉第一个发送过来的字节index_rx++;}else{i2c_data_receive(I2C0); //过长丢弃}}if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_STPDET)){wRFlag = 2;index_rx = 0;ADDSEND_FLAG = 0;I2C_STAT0(I2C0); // clear: I2C_INT_FLAG_STPDETI2C_CTL0(I2C0) = I2C_CTL0(I2C0);}break;case 2:__nop();break;default://严重的错误,不应该会执行到这里break;}}if(ADDSEND_FLAG == 1 && i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE)){//确定是收wRFlag = 1;for(int i=0; i<50; i++){//硬等一段时间__nop();}}else if (ADDSEND_FLAG == 2 && i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)){ //确定是发wRFlag = 0;for(int i=0; i<50; i++){//硬等一段时间__nop();}}
}/*** @fn         : * @brief      : 单次接收有长度限制 20byte <不限制长度的接收是不可取的>,发送没有* @return      {*}* @attention  : * @author     : * @param {uint8_t} *i2c_send* @param {uint8_t} *i2c_receive*/
void i2c1_rw_Data_slave(uint8_t *const i2c_send, uint8_t *const i2c_receive)
{static uint8_t ADDSEND_FLAG = 0, wRFlag = 2;                // wRFalg ==0 是发送模式,==1 是接收模式uint8_t *const rxbuffer = i2c_receive, *const txbuffer = i2c_send; //分别保存接收、发送的数据static uint8_t index_rx = 0, index_tx = 0;if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND)){ //检查addsend标志位ADDSEND_FLAG++;i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);//清理 ADDSEND bit }if (ADDSEND_FLAG != 0){switch(wRFlag){case 0://发送if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)){i2c_data_transmit(I2C1, txbuffer[index_tx]);index_tx++;}if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR)){wRFlag = 2;index_tx = 0;ADDSEND_FLAG = 0;i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_AERR);}break;case 1://接收if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE)){if (index_rx < 20){rxbuffer[ (index_rx>0)?index_rx-1 : index_rx ] = i2c_data_receive(I2C1);//因为iic的特性,第一个收到的是移位寄存器的数据,是不需要的。但是在某些ic却没有这种情况,所以这里应该由自己需求决定要不要去掉第一个发送过来的字节index_rx++;}else{i2c_data_receive(I2C1); //过长丢弃}}if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_STPDET)){wRFlag = 2;index_rx = 0;ADDSEND_FLAG = 0;I2C_STAT0(I2C1); // clear: I2C_INT_FLAG_STPDETI2C_CTL0(I2C1) = I2C_CTL0(I2C1);}break;case 2:__nop();break;default://严重的错误,不应该会执行到这里break;}}if(ADDSEND_FLAG == 1 && i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE)){//确定是收wRFlag = 1;for(int i=0; i<50; i++){//硬等一段时间__nop();}}else if (ADDSEND_FLAG == 2 && i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)){ //确定是发wRFlag = 0;for(int i=0; i<50; i++){//硬等一段时间__nop();}}
}/*** @fn         : * @brief      : iic0中断函数* @return      {*}* @attention  : * @author     : */
void I2C0_EventIRQ_Handler()
{i2c0_rw_Data_slave(i2c0_send, i2c0_receiver);
}/*** @fn         :* @brief      :* @return      {*}* @attention  :* @author     : */
void I2C0_ErrorIRQ_Handler(void)
{
}/*** @fn         : * @brief      : iic1中断函数* @return      {*}* @attention  : * @author     : */
void I2C1_EventIRQ_Handler()
{i2c1_rw_Data_slave(i2c1_send, i2c1_receiver);
}/*** @fn         :* @brief      :* @return      {*}* @attention  :* @author     : */
void I2C1_ErrorIRQ_Handler(void)
{
}/*** @fn         : * @brief      : 选择要打开的iic外设,设置数据的输入输出,默认是100k的速度,地址可调        * @return      {*}* @attention  : 发送需要外部任务提供数组,接收需要外部任务提供指针* @author     : * @param {iic_select} select*              #open_iic0 :打开iic0*              #open_iic1 : 打开iic1* @param {...} ...*              #参数1 :第一个iic的send的数组的指针 uint8_t*          *              #参数2 :指向第一个iic的receive的指针 uint8_t*        *              #参数3 :指向第一个iic的从地址 uint8_t */
void iic_Init(iic_select select, ...)
{if((select & (open_iic0 | open_iic1)) != 0){va_list args; //定义一个可变参数列表  va_start(args,select);//初始化args指向强制参数arg的下一个参数;  if((select & open_iic0) == open_iic0){//打开iic0i2c0SlaveRegister((uint8_t *)va_arg(args,uint32_t));  //获取当前参数内容并将args指向下一个参数  *((uint8_t **)va_arg(args,uint32_t)) = i2c0_receiver;  //获取当前参数内容并将args指向下一个参数 i2c0SlaveInit(va_arg(args,uint32_t));  }if((select & open_iic1) == open_iic1){//打开iic1i2c1SlaveRegister((uint8_t *)va_arg(args,uint32_t));  //获取当前参数内容并将args指向下一个参数  *((uint8_t **)va_arg(args,uint32_t)) = i2c1_receiver;  //获取当前参数内容并将args指向下一个参数 i2c1SlaveInit(va_arg(args,uint32_t));}va_end(args);//释放args}else if(select != 0){logE("Attempt to open an iic that does not exist, input number is :%d, format is: ...iic3|iic2|iic1|iic0\r\n");}else{logW("call the function : iic_Init, but not select iic\r\n");}
}

        --- 使用示例<在代码的初始化函数里如下即可完成iic注册,自动收发到自己定义的数组里>

uint8_t iic0Send_Data[40]; 
uint8_t * iic0Receive_Data;
uint8_t iic1Send_Data[40]; 
uint8_t * iic1Receive_Data;iic_Init(open_iic0, iic0Send_Data, &iic0Receive_Data, 0xA0);
iic_Init(open_iic1, iic1Send_Data, &iic1Receive_Data, 0xA2);/* 下面是不推荐的写法 */
iic_Init(open_iic0|open_iic1, iic0Send_Data, &iic0Receive_Data, 0xA0, iic1Send_Data, &iic1Receive_Data, 0xA2);//必须先写iic0的实参后写iic1的实参


http://www.ppmy.cn/news/513003.html

相关文章

ICC---data setup

ICC—data setup 数据准备 ICC开始布局布线之前&#xff0c;应该检查输入数据准备是否完整&#xff0c;主要包括&#xff1a; MilkWay参考库 信息是以被称为“views”的形式存储的&#xff0c;例如&#xff1a; CEL&#xff1a;完整的版图信息FRAM: 用于布局布线的抽象化的…

ICC II 4 timing setup(MCMM的设置)

timing setup object 执行MCMM 的设置,根据分析和优化的需要定义Corner modes scenarios 加载 MCMM的约束; 应用 时序以及优化 的控制. zero-interconnect timing sanity check (0互连的时序稳定性检查) MCMM (multiple modes multiple corners) 今天的芯片必须适应多种工作…

PCIe ECAM机制访问PCIE的配置空间

1.PCIe ECAM机制 PCI Express Enhanced Configuration Access Mechanism (ECAM)是访问PCIe配置空间的一种机制。是将PCIe的配置空间映射到MEM空间&#xff0c;使用MEM访问其配置空间的一种实现。可参考NCB-PCI_Express_Base_5.0r1.0-2019-05-22.pdf的第7.2.2小节。 其地址映射…

PCIe设备的配置过程

PCIe设备的配置过程 文章目录 PCIe设备的配置过程参考资料&#xff1a;一、 PCIe系统硬件结构二、 PCIe系统软件层次三、事务层TLP格式3.1 Posted和Non-Posted3.2 TLP通用格式3.3 TLP头部 四. 配置与RC直连的设备4.1 怎么访问直连的设备4.2 配置EendPoint 五、 配置示例5.1 必备…

无法识别ICA文件

问题&#xff1a;无法识别ICA文件怎么办&#xff1f; 场景&#xff1a;该问题常发生在Windows系统&#xff0c;由于软件关联异常&#xff0c;无法打开云桌面的ICA文件&#xff0c;导致无法调用云桌面客户端。 【方案1】导入注册表项 步骤一、点击下载 ICA文件打开方式修复 …

G-PCC配置文件的生成

TMC13的scripts文件夹中的gen-cfg.sh文件可以将cfg文件里面的yaml文件转为cfg文件&#xff0c;这样在测试各个例子的时候就可以方便地进行配置了 步骤&#xff1a; 1. 下载git 和strawberryperl&#xff1a; git下载地址&#xff1a;https://git-scm.com/downloads strawbe…

ICC 安装说明

1、加载iso 2、install.sh 选择zwt.lic 3设置环境变量 source /opt/intel/composer_xe_2015.0.090/bin/compilervars.sh intel64 4、测试 icc -v

icc色彩配置文件_什么是色彩配置文件?

icc色彩配置文件 Color profiles define the colors we capture with our cameras and see on our displays. They control what colors are used and help provide consistency between devices. 颜色配置文件定义了我们用相机捕获的颜色并在显示屏上看到。 它们控制使用什么颜…