[其他ST产品] STM32F103RC硬件I2C从入坑到出坑

[复制链接]
1481|32
 楼主| 4c1l 发表于 2023-2-24 23:28 | 显示全部楼层 |阅读模式
第一天
手上有啥资源可利用的?
1.一块MPU6050
2.一块stm32f103rc最小系统版,上面移植了ucos3,跑了几个任务,包括一个LCD任务(优先级最低)
3.st的固件库
4.ALIENTEK的MPU6050例程
5.stm32各种数据手册文档,ucos各种资料
好,开工。
先阅读stm32数据手册了解研究I2C模块原理架构,懵懵懂懂,若有所知的样子,行了不看了。
然后看看ALIENTEK的MPU6050例程。咦?怎么是用软件模拟I2C?stm32集成了I2C控制器都不用,这么浪费,不看了。。。还是再看一下,看看MPU6050大致是怎么操作的。大概就是有个设备地址0x68,有很多寄存器,数据通信通的就是寄存器的数据,每次传输数据都是先发设备地址0x68,然后发寄存器地址,最后收/发数据。
然后复制ALIENTEK例程中操作MPU6050的代码,改写里面所有的函数,用库函数操作STM32硬件I2C重新编制I2C的通信流程。打码完成,测试一下,果然不行。用fprintf打印信息到串口看看吧(没调试器,穷得只剩串口板)。然后开始艰辛的探索(省略一万字)。。。。。。

评论

版权声明:本文为CSDN博主「lalalaxy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/lalalaxy/article/details/86755638  发表于 2023-2-24 23:28
 楼主| 4c1l 发表于 2023-2-24 23:29 | 显示全部楼层
经过串口打印信息、查阅资料、网上搜索,终于成功改写ALIENTEK例程中的MPU_Write_Byte(INT08U reg, INT08U data) 函数如下,
  1. INT08U MPU_Write_Byte(INT08U reg, INT08U data)                                  
  2. {
  3.     while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

  4.     I2C_GenerateSTART(I2C1, ENABLE);
  5.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  6.     I2C_Send7bitAddress(I2C1, (MPU6050_ADDR<<1), I2C_Direction_Transmitter);
  7.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  8.     I2C_SendData(I2C1, reg);
  9.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  10.     I2C_SendData(I2C1, data);
  11.     I2C_GenerateSTOP(I2C1, ENABLE);

  12.     return 1;
  13. }
 楼主| 4c1l 发表于 2023-2-24 23:30 | 显示全部楼层
遇到的主要问题有:
1.设备地址0x68要左移一位,然后后面补上读写位,读是1,写是0。注意,不是0x68+1(或+0),而是(0x68<<1)|0x01(或0x00),也就是0xd1是从MPU6050读数据,发0xd0是向MPU6050写数据。
2.**严格按照st的例程给出的通信流程来编码。**网上各种说stm32硬件I2C有问题,好吧可能是有点问题,但是对于我等渣渣是完全不会遇到的,有问题都是自己的问题。严格按照st的例程来,绝对没问题。不要自己想当然的去编码,也不要觉得自己写的代码跟st的例程中的代码是等效的就坚信自己是对的。我参考的是st的EEPROM的那个例程。

然后改写了MPU_Read_Byte(INT08U reg)函数,OK。
就差MPU_Read_Len(INT08U addr, INT08U reg, INT08U len, INT08U *buf)这条函数就可以读MPU6050的数据了。改完,测试一下,果然不行。果断每行代码后面插一条fprintf。测试一下,电脑蓝屏。重启,测试一下,电脑蓝屏。。。OMG!!!唉12点了躺床吃**睡觉。
 楼主| 4c1l 发表于 2023-2-24 23:30 | 显示全部楼层
第二天
开电脑,测试一下,电脑蓝屏。。。唉还搞什么,放弃吧。。。去掉fprintf看看,不蓝屏,可是我怎么调试程序能?(没调试器,只能靠串口板打印信息)网上搜索一下。。。苦思冥想。。。(省略一万字)
终于,改好了!!!代码如下,
 楼主| 4c1l 发表于 2023-2-24 23:30 | 显示全部楼层
  1. INT08U MPU_Read_Len(INT08U addr, INT08U reg, INT08U len, INT08U *buf)
  2. {
  3.     INT08U rlen = 0;
  4.     CPU_SR_ALLOC();

  5.     while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

  6.     I2C_GenerateSTART(I2C1, ENABLE);
  7.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  8.     I2C_Send7bitAddress(I2C1, (addr<<1), I2C_Direction_Transmitter);
  9.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  10.     I2C_SendData(I2C1, reg);
  11.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  12.     I2C_GenerateSTOP(I2C1, ENABLE);
  13.    
  14.     while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

  15.     I2C_GenerateSTART(I2C1, ENABLE);
  16.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  17.     I2C_Send7bitAddress(I2C1, (addr<<1), I2C_Direction_Receiver);
  18.     while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

  19.     I2C_AcknowledgeConfig(I2C1, ENABLE);
  20.     GPIO_SetBits(GPIOB,GPIO_Pin_7);

  21.     OS_CRITICAL_ENTER();
  22.     for(rlen = 0; rlen < len; rlen++)
  23.     {
  24.         if(len == 1+rlen)
  25.         {
  26.             I2C_AcknowledgeConfig(I2C1, DISABLE);
  27.             (void)I2C1->SR2;
  28.             I2C_GenerateSTOP(I2C1, ENABLE);
  29.         }
  30.         while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
  31.         *buf  = I2C_ReceiveData(I2C1);
  32.         buf++;
  33.     }
  34.     OS_CRITICAL_EXIT();

  35.     return rlen;
  36. }
 楼主| 4c1l 发表于 2023-2-24 23:31 | 显示全部楼层
遇到的主要问题是:
1.接收数据的时候SDA要输出高电平!!!(3个感叹号代表重要的事情说3遍)stm32的SDA脚已选择了GPIO_Mode_AF_OD模拟开漏输出,MPU6050模块的SDA已外接了上拉电阻。如果stm32的SDA输出低电平,那么SDA就拉不高了。
2.网上看到有种做法是
I2C_AcknowledgeConfig(I2C1, DISABLE);
(void)I2C1->SR2;
I2C_GenerateSTOP(I2C1, ENABLE);
这3句要连着写,一是必须读SR2寄存器才能完成某些清寄存器标志的操作(看数据手册),这确实是是stm32做的坑,但不能说它有问题,反正正确流程是怎样就怎样,按正确流程来编码。
3.接收数据阶段我就用OS_CRITICAL_ENTER();关中断好了,保证I2C时序正确,保险一点。(其实这样理解也不对,应该整个I2C通信时序都有因为被打断而发生故障的风险,关键是在哪些地方可以被打断(如等待某些标志位置位的时候),哪些地方一定不能被打断(如等到了某事件后要读写寄存器时))
测试一下,串口打印出加速度、陀螺仪、温度等数据,OK,收工。
咦?怎么LCD显示一卡一卡的。看来I2C读数据太耗时了,还阻止了任务切换。改写一下MPU_Read_Len(INT08U addr, INT08U reg, INT08U len, INT08U *buf)函数吧。把它里面的等待标志位置位的那些while循环,改为pend一个信号量,标志位置位触发中断后再post一个信号量,等待交给中断来做,期间把CPU让给其他任务。
编码编码编码。

 楼主| 4c1l 发表于 2023-2-24 23:32 | 显示全部楼层
第三天
一觉睡到中午饭,下午继续躺床吃**睡觉。晚饭后才编码完成,代码如下,
  1. INT08U MPU6050_Read(INT08U addr, INT08U reg, INT08U len, INT08U *buf)
  2. {
  3.     OS_ERR err;
  4.     CPU_TS ts;
  5.     CPU_SR_ALLOC();
  6.     INT08U rlen = 0;
  7.     INT16U I2CTimeout;
  8.     I2CReadState = I2C_CHECK_BUSY;
  9.     I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
  10.     while(I2C_READ_END > I2CReadState)
  11.     {
  12.         switch(I2CReadState)
  13.         {
  14.             case I2C_CHECK_BUSY:
  15.                 I2CTimeout = I2C_TIMEOUT*((INT16U)(SystemCoreClock/1000000));
  16.                 while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)&&(I2CTimeout--));
  17.                 if(0 == I2CTimeout) delay_ms(fac_ms);
  18.                 else
  19.                 {
  20.                     CPU_CRITICAL_ENTER();
  21.                     if(I2C_CHECK_BUSY == I2CReadState) I2CReadState = I2C_SEND_START;//I2C bus is not busy
  22.                     else I2CReadState = I2C_READ_END;
  23.                     CPU_CRITICAL_EXIT();
  24.                 }
  25.                 break;
  26.             case I2C_SEND_START:
  27.                 I2C_GenerateSTART(I2C1, ENABLE);
  28.                 I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
  29.                 OSSemPend(&MPU6050_SEM, I2C_TIMEOUT*fac_us, OS_OPT_PEND_BLOCKING, &ts, &err);
  30.                 CPU_CRITICAL_ENTER();
  31.                 if((OS_ERR_NONE == err) && (I2C_SEND_START == I2CReadState)) I2CReadState = I2C_SEND_ADDR_SEND;
  32.                 else I2CReadState = I2C_READ_END;
  33.                 CPU_CRITICAL_EXIT();
  34.                 break;
  35.             case I2C_SEND_ADDR_SEND:
  36.                 I2C_Send7bitAddress(I2C1, (addr<<1), I2C_Direction_Transmitter);
  37.                 I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
  38.                 OSSemPend(&MPU6050_SEM, I2C_TIMEOUT*fac_us, OS_OPT_PEND_BLOCKING, &ts, &err);
  39.                 CPU_CRITICAL_ENTER();
  40.                 if((OS_ERR_NONE == err) && (I2C_SEND_ADDR_SEND == I2CReadState)) I2CReadState = I2C_SELECT_REG;
  41.                 else I2CReadState = I2C_READ_END;
  42.                 CPU_CRITICAL_EXIT();
  43.                 break;
  44.             case I2C_SELECT_REG:
  45.                 I2C_SendData(I2C1, reg);
  46.                 I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
  47.                 OSSemPend(&MPU6050_SEM, I2C_TIMEOUT*fac_us, OS_OPT_PEND_BLOCKING, &ts, &err);
  48.                 CPU_CRITICAL_ENTER();
  49.                 if((OS_ERR_NONE == err) && (I2C_SELECT_REG == I2CReadState)) I2CReadState = I2C_CHECK_BUSY_AGAIN;
  50.                 else I2CReadState = I2C_READ_END;
  51.                 CPU_CRITICAL_EXIT();
  52.                 I2C_GenerateSTOP(I2C1, ENABLE);
  53.                 break;
  54.             case I2C_CHECK_BUSY_AGAIN:
  55.                 I2CTimeout = I2C_TIMEOUT*((INT16U)(SystemCoreClock/1000000));
  56.                 while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)&&(I2CTimeout--));
  57.                 if(0 == I2CTimeout) delay_ms(fac_ms);
  58.                 else
  59.                 {
  60.                     CPU_CRITICAL_ENTER();
  61.                     if(I2C_CHECK_BUSY_AGAIN == I2CReadState) I2CReadState = I2C_SEND_START_AGAIN;//I2C bus is not busy
  62.                     else I2CReadState = I2C_READ_END;
  63.                     CPU_CRITICAL_EXIT();
  64.                 }
  65.                 break;
  66.             case I2C_SEND_START_AGAIN:
  67.                 I2C_GenerateSTART(I2C1, ENABLE);
  68.                 I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
  69.                 OSSemPend(&MPU6050_SEM, I2C_TIMEOUT*fac_us, OS_OPT_PEND_BLOCKING, &ts, &err);
  70.                 CPU_CRITICAL_ENTER();
  71.                 if((OS_ERR_NONE == err) && (I2C_SEND_START_AGAIN == I2CReadState)) I2CReadState = I2C_SEND_ADDR_RECV;
  72.                 else I2CReadState = I2C_READ_END;
  73.                 CPU_CRITICAL_EXIT();
  74.                 break;
  75.             case I2C_SEND_ADDR_RECV:
  76.                 I2C_Send7bitAddress(I2C1, (addr<<1), I2C_Direction_Receiver);
  77.                 I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
  78.                 OSSemPend(&MPU6050_SEM, I2C_TIMEOUT*fac_us, OS_OPT_PEND_BLOCKING, &ts, &err);
  79.                 CPU_CRITICAL_ENTER();
  80.                 if((OS_ERR_NONE == err) && (I2C_SEND_ADDR_RECV == I2CReadState)) I2CReadState = I2C_RECV_DATA;
  81.                 else I2CReadState = I2C_READ_END;
  82.                 CPU_CRITICAL_EXIT();
  83.                 I2C_AcknowledgeConfig(I2C1, ENABLE);
  84.                 GPIO_SetBits(GPIOB,GPIO_Pin_7);
  85.                 break;
  86.             case I2C_RECV_DATA:
  87.                 if(len == 1+rlen)
  88.                 {
  89.                     I2C_AcknowledgeConfig(I2C1, DISABLE);
  90.                     (void)I2C1->SR2;
  91.                     I2C_GenerateSTOP(I2C1, ENABLE);
  92.                 }
  93.                 I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
  94.                 OSSemPend(&MPU6050_SEM, I2C_TIMEOUT*fac_us, OS_OPT_PEND_BLOCKING, &ts, &err);
  95.                 CPU_CRITICAL_ENTER();
  96.                 if((OS_ERR_NONE != err) || (I2C_RECV_DATA != I2CReadState)) I2CReadState = I2C_READ_END;
  97.                 CPU_CRITICAL_EXIT();
  98.                 *buf  = I2C_ReceiveData(I2C1);
  99.                 buf++;
  100.                 rlen++;
  101.                 if(len == rlen) I2CReadState = I2C_READ_END;
  102.                 break;
  103.             default:
  104.                 break;
  105.         }
  106.     }
  107.     I2C_ITConfig(I2C1, I2C_IT_ERR, DISABLE);
  108.     return rlen;
  109. }
 楼主| 4c1l 发表于 2023-2-24 23:33 | 显示全部楼层
里面的delay_ms函数在延时时间超过OS时间片时间时可以引起任务切换。
测试一下,OK,串口输出数据,收工。
咦?怎么LCD卡住完全了。研究一下。原来如此:
我获取MPU6050数据的任务代码如下,
while(1)
{
while(0 < sendmpudata)
{
sendmpudata–;
MPU_Get_Accelerometer(&aacx,&aacy,&aacz);
fprintf(UART_OUT, "ax:%5d, ay:%5d, az:%5d ", aacx, aacy, aacz);
res=MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);
fprintf(UART_OUT, "gx:%5d, gy:%5d, gz:%5d ", gyrox, gyroy, gyroz);
temp=MPU_Get_Temperature();
fprintf(UART_OUT, “temp:%5d\n\n”, temp);
}
}
sendmpudata是在OS的定时器中递增的,用来定时一段时间就从MPU6050收数据然后发到串口上。问题是当sendmpudata=0时也就是还没到时间去收发MPU6050数据时,当前任务还在while(1)中跑,没有把CPU让给低优先级的LCD任务。于是我在while(0 < sendmpudata)前面插一条pend等待一个信号量。测试一下,LCD不卡,OK,收工。
不是说I2C通信流程要严格按照st的例程,不要打断吗?其实,当你理解这整个流程,就会很容易地把握哪些地方可以被打断,切换到其它任务,让I2C真正地融入多任务系统中。
 楼主| 4c1l 发表于 2023-2-24 23:33 | 显示全部楼层
突然发现,干嘛要搞那么复杂!!!耗时的步骤都交给中断来做,剩下在任务级完成的步骤不就是读写一下DR寄存器吗?把剩下这些极其简单的步骤也交给中断处理函数来做也可以啊,那任务里面就只需pend等待一个信号量,等中断处理函数处理完I2C通信流程post释放出一个信号量,任务级读写I2C数据函数就可以返回了。再改改代码。。。
 楼主| 4c1l 发表于 2023-2-24 23:34 | 显示全部楼层
第四天
晚上继续改代码。改完如下,
  1. INT08U I2C_Process(INT08U direction, INT08U addr, INT08U len, INT08U *pbuf)
  2. {
  3.     OS_ERR err;
  4.     CPU_TS ts;
  5.     INT08U res;
  6.     INT16U I2CTimeout;

  7.     I2CDirection = direction;
  8.     I2CStage = I2C_DETECT_START;
  9.     I2CError = I2C_SUCCESS;

  10.     I2CAddress = addr;
  11.     I2CLength = len;
  12.     pI2CBuffer = pbuf;

  13.     I2CIndex = 0;

  14.     I2CTimeout = I2C_TIMEOUT*((INT16U)(SystemCoreClock/1000000));
  15.     while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)&&(I2CTimeout--));
  16.     if(0 < I2CTimeout)
  17.     {
  18.         I2C_GenerateSTART(I2C1, ENABLE);
  19.         I2C_ITConfig(I2C1, I2C_IT_EVT|I2C_IT_ERR, ENABLE);
  20.         OSSemPend(&I2C_SEM, I2C_TIMEOUT*fac_us, OS_OPT_PEND_BLOCKING, &ts, &err);
  21.         I2C_ITConfig(I2C1, I2C_IT_EVT|I2C_IT_ERR, DISABLE);
  22.         if(OS_ERR_NONE == err) res = I2C_SUCCESS;
  23.         else if(OS_ERR_TIMEOUT == err)
  24.         {
  25.             if(OS_ERR_NONE == I2CError) res = I2C_OS_TIMEOUT;
  26.             else res = I2CError;
  27.         }
  28.         else res = I2C_OS_ERROR;
  29.     }
  30.     else res = I2C_HW_BUSY;
  31.     return res;
  32. }
 楼主| 4c1l 发表于 2023-2-24 23:34 | 显示全部楼层
  1. static INT08U MPU6050_Write(INT08U addr, INT08U reg, INT08U len, INT08U *pbuf)
  2. {
  3.     INT08U buf[MPU6050_WRITE_MAX], i, res;
  4.     buf[0] = reg;
  5.     for(i = 0; i < len; i++) buf[i+1] = pbuf[i];
  6.     res = I2C_Process(I2C_SEND, addr, len+1, buf);
  7.     return res;
  8. }
 楼主| 4c1l 发表于 2023-2-24 23:34 | 显示全部楼层
  1. static INT08U MPU6050_Read(INT08U addr, INT08U reg, INT08U len, INT08U *pbuf)
  2. {
  3.     INT08U res;
  4.     res = I2C_Process(I2C_SEND, addr, 1, &reg);
  5.     if(I2C_SUCCESS == res) res = I2C_Process(I2C_RECV, addr, len, pbuf);
  6.     return res;
  7. }
 楼主| 4c1l 发表于 2023-2-24 23:34 | 显示全部楼层
  1. void I2C1_EV_IRQHandler(void)
  2. {
  3.     OS_ERR err;
  4.     CPU_SR_ALLOC();
  5.     CPU_CRITICAL_ENTER();
  6.     OSIntEnter();
  7.     CPU_CRITICAL_EXIT();
  8.     switch(I2CStage)
  9.     {
  10.         case I2C_DETECT_START:
  11.             if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  12.             {
  13.                 if(I2C_SEND == I2CDirection) I2C_Send7bitAddress(I2C1, (I2CAddress<<1), I2C_Direction_Transmitter);
  14.                 else I2C_Send7bitAddress(I2C1, (I2CAddress<<1), I2C_Direction_Receiver);
  15.                 I2CStage = I2C_DETECT_ADDR;
  16.             }
  17.             break;
  18.         case I2C_DETECT_ADDR:
  19.             if(I2C_SEND == I2CDirection)
  20.             {
  21.                 if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  22.                 {
  23.                     I2C_SendData(I2C1, *pI2CBuffer);
  24.                     pI2CBuffer++;
  25.                     I2CIndex++;
  26.                     if(I2CLength > I2CIndex) I2CStage = I2C_DETECT_DATA;
  27.                     else
  28.                     {
  29.                         I2C_GenerateSTOP(I2C1, ENABLE);
  30.                         OSSemPost(&I2C_SEM, OS_OPT_POST_1, &err);
  31.                     }
  32.                 }
  33.             }
  34.             else
  35.             {
  36.                 if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
  37.                 {
  38.                     if(I2CLength > I2CIndex+1) I2C_AcknowledgeConfig(I2C1, ENABLE);
  39.                     else
  40.                     {
  41.                         I2C_AcknowledgeConfig(I2C1, DISABLE);
  42.                         (void)I2C1->SR2;
  43.                         I2C_GenerateSTOP(I2C1, ENABLE);
  44.                     }
  45.                     GPIO_SetBits(GPIOB,GPIO_Pin_7);
  46.                     I2CStage = I2C_DETECT_DATA;
  47.                 }
  48.             }
  49.             break;
  50.         case I2C_DETECT_DATA:
  51.             if(I2C_SEND == I2CDirection)
  52.             {
  53.                 if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  54.                 {
  55.                     I2C_SendData(I2C1, *pI2CBuffer);
  56.                     pI2CBuffer++;
  57.                     I2CIndex++;
  58.                     if(I2CLength <= I2CIndex)
  59.                     {
  60.                         I2C_GenerateSTOP(I2C1, ENABLE);
  61.                         OSSemPost(&I2C_SEM, OS_OPT_POST_1, &err);
  62.                     }
  63.                 }
  64.             }
  65.             else
  66.             {
  67.                 if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
  68.                 {
  69.                     *pI2CBuffer  = I2C_ReceiveData(I2C1);
  70.                     pI2CBuffer++;
  71.                     I2CIndex++;
  72.                     if(I2CLength == I2CIndex+1)
  73.                     {
  74.                         I2C_AcknowledgeConfig(I2C1, DISABLE);
  75.                         (void)I2C1->SR2;
  76.                         I2C_GenerateSTOP(I2C1, ENABLE);
  77.                     }
  78.                     else if(I2CLength <= I2CIndex) OSSemPost(&I2C_SEM, OS_OPT_POST_1, &err);
  79.                     else{}
  80.                 }
  81.             }
  82.             break;
  83.         default:
  84.             break;
  85.     }
  86.     OSIntExit();
  87. }
 楼主| 4c1l 发表于 2023-2-24 23:34 | 显示全部楼层
  1. void I2C1_ER_IRQHandler(void)
  2. {
  3.     if(SET == I2C_GetITStatus(I2C1, I2C_IT_BERR)) I2CError = I2C_HW_BERR;
  4.     else if(SET == I2C_GetITStatus(I2C1, I2C_IT_ARLO)) I2CError = I2C_HW_ARLO;
  5.     else if(SET == I2C_GetITStatus(I2C1, I2C_IT_AF)) I2CError = I2C_HW_AF;
  6.     else if(SET == I2C_GetITStatus(I2C1, I2C_IT_OVR)) I2CError = I2C_HW_OVR;
  7.     else if(SET == I2C_GetITStatus(I2C1, I2C_IT_PECERR)) I2CError = I2C_HW_PECERR;
  8.     else if(SET == I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) I2CError = I2C_HW_TIMEOUT;
  9.     else if(SET == I2C_GetITStatus(I2C1, I2C_IT_SMBALERT)) I2CError = I2C_HW_SMBALERT;
  10.     else{}
  11.     I2C_ClearITPendingBit(I2C1, I2C_IT_SMBALERT|I2C_IT_TIMEOUT|I2C_IT_PECERR|I2C_IT_OVR|I2C_IT_AF|I2C_IT_ARLO|I2C_IT_BERR);
  12.     I2C_ITConfig(I2C1, I2C_IT_ERR, DISABLE);
  13. }
 楼主| 4c1l 发表于 2023-2-24 23:35 | 显示全部楼层
上面代码就是最终版本。主要思想是,STM32硬件I2C的读写数据流程大致相同,封装成一个函数,通过传入参数来区分读写,这是I2C层。向MPU6050写数据就是写寄存器地址、写数据。从MPU6050读数据就是写寄存器地址、读数据,分别封装成MPU6050读、写两个函数,供操作MPU6050的其他函数调用,这是MPU6050模块层。任务级调用操作MPU6050的函数,获取想要的数据,这是APP层。
效果如下,
 楼主| 4c1l 发表于 2023-2-24 23:35 | 显示全部楼层
maqianqu 发表于 2023-5-14 20:31 | 显示全部楼层
有硬件IIC,为什么很多应用,还要模拟IIC
MessageRing 发表于 2023-5-14 22:42 | 显示全部楼层
maqianqu 发表于 2023-5-14 20:31
有硬件IIC,为什么很多应用,还要模拟IIC

模拟iic更方便移植
lihuami 发表于 2023-5-18 11:12 | 显示全部楼层
硬件I2C稳定吗               
bartonalfred 发表于 2023-5-18 16:48 | 显示全部楼层
硬件I2C DMA有坑吗              
您需要登录后才可以回帖 登录 | 注册

本版积分规则

65

主题

703

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部