STM32 硬件I2C的使用:中断方式 无DMA 无最高优先级

2019-07-21 08:56发布

STM32的硬件I2C和RTC一样,一直以来都是STM32的一大败笔,我也曾经在想,这么好的片子I2C是这个样子。。。真想骂两句。。。呵呵! 不过对其有了深入了解之后,哪怕不用勘误手册上的办法(DMA或优先级最高)也是可以的。估计有很多人是知道办法的,我在这里就当是把问题重新提一下,大家讨论一下,共同学习了!
关于STM32乃至STM8的I2C,估计应该是专利的问题,所以故意做的不同,其不同点就在于无论是发送还是接收,都多了一个缓存寄存器,发送时先写缓存,缓存复制到移位寄存器,缓冲空了,可以再写一个字节,也就是当第一个字节还没发完的时候就可以再写一个字节,可以视作一次性写了2个字节;接收的时候移位寄存器先收到一个字节,复制到缓冲,移位寄存器空,然后可以接收下一个字节,可以视作一次性可接2个字节。这样的结构看似美好,其实问题就出在这里,具体的错误过程我就不在这里分析了(其实我也搞得不是很清楚,希望清楚的同志赐教),如何克服这一缺点呢。
具体做法:只使能事件中断 而不使能缓冲区中断,这样做的目的是把发送或接收的2个寄存器当成一个来用,一次只发或接一个字节,当BTF中断来临时去判断是RXE还是TXE,这样一来STM32的I2C结构就和其他单片机一样了。
这样就能做到硬件I2C中断方式 无DMA 无最高优先级了!
呵呵!分享,快乐!

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
20条回答
whjambo
1楼-- · 2019-07-21 13:46
自己顶一下自己,呵呵!
欢迎讨论!
正点原子
2楼-- · 2019-07-21 15:41
 精彩回答 2  元偷偷看……
whjambo
3楼-- · 2019-07-21 17:28
感谢原子兄的祝愿,我觉得还是脚踏实地比较好,一路顺风的话,代码容易飞啊,哈哈!
rgzdb
4楼-- · 2019-07-21 19:16
具体程序我原来倒是写过一个24c02的,这一时半会也找不到,读写一点问题没有,但是有时会出现从机死掉的情况(很少很少,除非不断24c02的电直接复位stm32),呵呵,其实模拟I2C也会出现这样的情况,这个就要另外处理了,关闭硬件I2C,用硬I2C的引脚io连续模拟产生9个以上的SCL,在保证SDA为高电平的情况下软复位I2C总线,以上的处理方法应在I2C错误中断里完成,具体做法我给个链接,我也是从这个地方学到的,希望能给大家帮助,当然也希望高手指正。
http://racede.me/talk_about_stm32_i2c_peripheral.html
whjambo
5楼-- · 2019-07-21 22:28
STM32的I2C还有一个设置比较扯淡的地方,参考手册上说“ 要求FPCLK1应当是10 MHz的整数倍,这样可以正确地产生400KHz的快速时钟”,这个我已经验证是无关紧要的。手册上这样说是因为设定了在快速模式下只能:DUTY=1,Tlow/Thigh = 16/9,一个周期就是25,但是FPCLK1我们一般都是36M在用,这样我们能得到的最快速度也就是360KHz,用不到最快速度就是纠结(呵呵,这是一种病)。其实完全可以忽视这个设定,就让DUTY=0,Tlow/Thigh = 2/1,这样周期就是3了,呵呵可以整除了。其实大家看看16/9和2/1能差多少。。。很不理解手册为何如此忽悠。我反倒觉得DUTY=0这个设置就是让I2C在36M的时候也能到400KHz!还有24c02手册上说可以到2MHz,我把STM32的I2C设成2MHz也试过,跑来一天,当然只是读,一切正常,但是我还是不建议这么干,平时玩玩可以,做产品就算了,还是400K靠谱!
whjambo
6楼-- · 2019-07-22 03:04
昨天晚上回去翻箱倒柜终于找到了代码,贴出部分代码跟大家分享,欢迎指正:
void i2c_init(void)
{
 I2C_InitTypeDef I2C_InitStructure;
 I2C_DeInit(I2C2);
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
 I2C_InitStructure.I2C_OwnAddress1 = 0x0002;
 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
 I2C_InitStructure.I2C_ClockSpeed = 400000;
 I2C_Init(I2C2, &I2C_InitStructure);
 //研究库代码发现I2C_Init函数执行后I2C就已经使能了,所以无需I2C_Cmd(I2C2, ENABLE)
 
 I2C_ITConfig(I2C2, I2C_IT_EVT|I2C_IT_ERR, ENABLE);
}

void c02_write_data(u8 address, u8 data0,u8 data1,u8 data2,u8 data3,u8 data4,u8 data5,u8 data6,u8 data7)
{
 while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
 
 c02_direction = c02_write;
 c02_address = address;
 c02_data_w[0]=data0; c02_data_w[1]=data1; c02_data_w[2]=data2; c02_data_w[3]=data3;
 c02_data_w[4]=data4; c02_data_w[5]=data5; c02_data_w[6]=data6; c02_data_w[7]=data7;
 i2c_plan = 0;
 I2C_GenerateSTART(I2C2, ENABLE);
 
 while(i2c_plan!=20);
 while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
 delay_ms(5);
}

void c02_read_data(u8 address)
{
 while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
 
 c02_direction = c02_read;
 c02_address = address;
 i2c_plan = 0;
 I2C_GenerateSTART(I2C2, ENABLE);
 
}


void I2C2_EV_IRQHandler(void)
{
 
 switch(i2c_plan)
 {
  case  0:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_SB))//ev5
          {
           I2C_Send7bitAddress(I2C2, 0xA0, I2C_Direction_Transmitter); i2c_plan=1;//address+w
          }
          break;
  case  1:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_ADDR))//ev6
          {
           if(I2C_GetFlagStatus(I2C2, I2C_FLAG_TRA)){I2C_SendData(I2C2, c02_address); i2c_plan=2;}
          }
          break;
  case  2:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           if(c02_direction==c02_write){I2C_SendData(I2C2, c02_data_w[0]); i2c_plan=3;}//write data0
           else{I2C_GenerateSTART(I2C2, ENABLE); i2c_plan=11;}
          }
          break;
/******************************************************************************/
  case  3:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           I2C_SendData(I2C2, c02_data_w[1]); i2c_plan=4;//write data1
          }
          break;
  case  4:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           I2C_SendData(I2C2, c02_data_w[2]); i2c_plan=5;//write data2
          }
          break;
  case  5:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           I2C_SendData(I2C2, c02_data_w[3]); i2c_plan=6;//write data3
          }
          break;
  case  6:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           I2C_SendData(I2C2, c02_data_w[4]); i2c_plan=7;//write data4
          }
          break;
  case  7:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           I2C_SendData(I2C2, c02_data_w[5]); i2c_plan=8;//write data5
          }
          break;
  case  8:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           I2C_SendData(I2C2, c02_data_w[6]); i2c_plan=9;//write data6
          }
          break;
  case  9:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8
          {
           I2C_SendData(I2C2, c02_data_w[7]); i2c_plan=10;//write data7
          }
          break;
  case 10:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev8_2
          {
           I2C_GenerateSTOP(I2C2, ENABLE);
           i2c_plan=20;
          }
          break;
/******************************************************************************/
  case 11:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_SB))//ev5
          {
           I2C_Send7bitAddress(I2C2, 0xA0, I2C_Direction_Receiver); i2c_plan=12;//address+r
          }
          break;
  case 12:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_ADDR))//ev6
          {
           if(!I2C_GetFlagStatus(I2C2, I2C_FLAG_TRA)) i2c_plan=13;
          }
          break;
  case 13:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev7
          {
           c02_data_r[0] = I2C_ReceiveData(I2C2); i2c_plan=14;//read data0
          }
          break;
  case 14:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev7
          {
           c02_data_r[1] = I2C_ReceiveData(I2C2); i2c_plan=15;//read data1
          }
          break;
  case 15:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev7
          {
           c02_data_r[2] = I2C_ReceiveData(I2C2); i2c_plan=16;//read data2
          }
          break;
  case 16:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev7
          {
           c02_data_r[3] = I2C_ReceiveData(I2C2); i2c_plan=17;//read data3
          }
          break;
  case 17:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev7
          {
           c02_data_r[4] = I2C_ReceiveData(I2C2); i2c_plan=18;//read data4
          }
          break;
  case 18:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev7
          {
           I2C_AcknowledgeConfig(I2C2, DISABLE);
           
           c02_data_r[5] = I2C_ReceiveData(I2C2); i2c_plan=19;//read data5
          }
          break;
  case 19:if(I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))//ev7
          {
           I2C_AcknowledgeConfig(I2C2, ENABLE);
           I2C_GenerateSTOP(I2C2, ENABLE);
           c02_data_r[6] = I2C_ReceiveData(I2C2);//read data6
           while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_RXNE));
           c02_data_r[7] = I2C_ReceiveData(I2C2);//read data7
           i2c_plan=21;
          }
          break;
  
 }
 
}

当然main函数里面会调用24c02读或写函数去发送start信号

一周热门 更多>