• STM32的I2C主从机通信


    最近一段时间在做I2C通信协议,需要在两块STM32之间做I2C通信,定的是主机用IO口模拟,从机用的是STM32的硬件I2C,我的项目要求是需要主从机之间能够进行一串数据收发而不出错,实验时在主机方面,利用IO口模拟主机,只需要理解时序就够了,同时将速度能够控制在100K(标准)左右,基本的时序理解网上大把的资料,所以主机这一块几个小时就搞定了,而在做从机时,遇到了困难,本来从机也想用IO口模拟的,但是速度达不到那么快,因此只能选择硬件做从机,现就从机用中断方式开说,总结过程中遇到的几点问题:

    1、由于STM32的硬件问题,建议在使用I2C时,将其优先级设为最高。

    2、针对程序中除了I2C数据收发,还有别的中断程序或者指令要执行而导致I2C数据传输堵塞时,可以在执行完该段程序后重新初始化I2C。

    主机程序如下:

      1 #include "Hal_IIC/I2C.h"
      2 #include "Hal_delay/delay.h"
      3 #include "common.h"
      4 #include "gizwits_product.h"
      5 
      6 extern void delayUs(uint32_t nus);
      7 uint8_t b[5];
      8 extern uint8_t Cookr[5];
      9 extern uint8_t WR_flag;
     10 uint8_t Wifi_SET;  //WIFI状态脚
     11 extern uint8_t Power_flag;         //电磁炉开启关闭标志位
     12 uint8_t Give_Up;
     13 /*--------------------------------------------------------------------------------
     14 调用方式:void IIC_Init(void) 
     15 函数说明:私有函数,I2C专用,函数初始化
     16 ---------------------------------------------------------------------------------*/ 
     17 void IIC_Init(void)
     18 {                         
     19     GPIO_InitTypeDef GPIO_InitStructure;
     20     RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOA, ENABLE );    //使能GPIOA时钟
     21        
     22     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;
     23     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
     24     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     25     GPIO_Init(GPIOA, &GPIO_InitStructure);
     26     GPIO_SetBits(GPIOA,GPIO_Pin_11|GPIO_Pin_12);     //PA11,PA12 输出高
     27 }
     28 /*--------------------------------------------------------------------------------
     29 调用方式:void I2CStart(void) 
     30 函数说明:私有函数,I2C专用,开始信号
     31 ---------------------------------------------------------------------------------*/
     32 void IIC_Start(void)
     33 {
     34     SDA_OUT();     //sda线输出
     35     IIC_SDA=1;            
     36     IIC_SCL=1;
     37     delayUs(4);
     38      IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
     39     delayUs(4);
     40     IIC_SCL=0;  //钳住I2C总线,准备发送或接收数据 
     41 }      
     42 /*--------------------------------------------------------------------------------
     43 调用方式:void I2CStop(void) 
     44 函数说明:私有函数,I2C专用,停止信号
     45 ---------------------------------------------------------------------------------*/
     46 void IIC_Stop(void)
     47 {
     48     SDA_OUT();//sda线输出
     49     IIC_SCL=0;
     50     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
     51      delayUs(4);
     52     IIC_SCL=1; 
     53     IIC_SDA=1;//发送I2C总线结束信号
     54     delayUs(4);                                   
     55 }
     56 /*--------------------------------------------------------------------------------
     57 调用方式:I2CAck(void) 
     58 函数说明:私有函数,I2C专用,等待从器件接收方的应答,0表示接受成功,1表示失败
     59 ---------------------------------------------------------------------------------*/
     60 uint8_t IIC_Wait_Ack(void)
     61 {
     62     uint8_t ucErrTime=0;
     63     SDA_IN();      //SDA设置为输入  
     64     IIC_SDA=1;delayUs(1);       
     65     IIC_SCL=1;delayUs(1);     
     66     while(READ_SDA)
     67     {
     68         ucErrTime++;
     69         if(ucErrTime>250)
     70         {
     71             IIC_Stop();
     72             return 1;
     73         }
     74     }
     75     IIC_SCL=0;//时钟输出0        
     76     return 0;  
     77 } 
     78 /*--------------------------------------------------------------------------------
     79 调用方式:void SendAck(void) 
     80 函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,应答信号。
     81 ---------------------------------------------------------------------------------*/
     82 void IIC_Ack(void)
     83 {
     84     IIC_SCL=0;
     85     SDA_OUT();
     86     IIC_SDA=0;
     87     delayUs(2);
     88     IIC_SCL=1;
     89     delayUs(2);
     90     IIC_SCL=0;
     91 }
     92 /*--------------------------------------------------------------------------------
     93 调用方式:void SendAck(void) 
     94 函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,非应答信号。
     95 ---------------------------------------------------------------------------------*/        
     96 void IIC_NAck(void)
     97 {
     98     IIC_SCL=0;
     99     SDA_OUT();
    100     IIC_SDA=1;
    101     delayUs(2);
    102     IIC_SCL=1;
    103     delayUs(2);
    104     IIC_SCL=0;
    105 }                                          
    106 /*--------------------------------------------------------------------------------
    107 调用方式:void IIC_Send_Byte(unsigned char ch) 
    108 函数说明:私有函数,I2C专用
    109 ---------------------------------------------------------------------------------*/      
    110 void IIC_Send_Byte(uint8_t txd)
    111 {                        
    112     uint8_t t;   
    113     SDA_OUT();         
    114     IIC_SCL=0;//拉低时钟开始数据传输
    115     for(t=0;t<8;t++)
    116     {              
    117         //IIC_SDA=(txd&0x80)>>7;
    118         if((txd&0x80)>>7)
    119             IIC_SDA=1;
    120         else
    121             IIC_SDA=0;
    122         txd<<=1;       
    123         delayUs(2);   //对TEA5767这三个延时都是必须的
    124         IIC_SCL=1;
    125         delayUs(2); 
    126         IIC_SCL=0;    
    127         delayUs(2);
    128     }     
    129 }         
    130 /*--------------------------------------------------------------------------------
    131 调用方式:unsigned char IIC_Read_Byte(void) 
    132 函数说明:私有函数,I2C专用
    133 ---------------------------------------------------------------------------------*/
    134 //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
    135 uint8_t IIC_Read_Byte(unsigned char ack)
    136 {
    137     unsigned char i,receive=0;
    138     SDA_IN();//SDA设置为输入
    139     for(i=0;i<8;i++ )
    140     {
    141                 receive<<=1;
    142         IIC_SCL=0; 
    143         delayUs(5);
    144             IIC_SCL=1;
    145                 delayUs(5);
    146         
    147         if(READ_SDA)receive++;   
    148          
    149   }                     
    150     if (!ack)
    151         IIC_NAck();//发送nACK
    152     else
    153         IIC_Ack(); //发送ACK   
    154     return receive;
    155 }
    156 
    157 
    158 //读温度传感器,温度值是由h的高字节和低字节的高四位组成,总共12位,其中负温度值是由补码形式
    159 void T_Read(void)
    160 {
    161             
    162     /***************read start*******************/
    163     if(WR_flag==0x02)
    164     {
    165 
    166     IIC_Start();
    167         IIC_Send_Byte( 0x30|0x01);          //读操作
    168          while(IIC_Wait_Ack());        
    169    //     delayMs(500);                         //等待从机处理一个字节地址位
    170     Give_Up = IIC_Read_Byte(1);        
    171         for(uint8_t i=0;i<4;i++)
    172         {
    173             b[i] = IIC_Read_Byte(1);
    174             printf("%c",b[i]);
    175         }
    176         b[4] = IIC_Read_Byte(0);
    177         printf("%c",b[4]);
    178         
    179         if((b[0]==0xFA)&&(b[4]==0xFB))
    180         {
    181           for(uint8_t i=1;i<6;i++)
    182           {
    183               Cookr[i] = b[i];
    184           }    
    185 
    186         }
    187     }    
    188    
    189     /****************read end********************/
    190   /****************write start*****************/
    191         if(WR_flag==0x01)
    192         {
    193             IIC_Start();
    194             IIC_Send_Byte(0x30);     //写操作
    195             while(IIC_Wait_Ack());
    196             IIC_Send_Byte(0xFA);
    197             while(IIC_Wait_Ack());
    198             delayMs(3);              //延时太低传输数据会出错,因为从机还没处理完数据
    199             IIC_Send_Byte(Cookr[1]);
    200             while(IIC_Wait_Ack());
    201             delayMs(3);
    202             IIC_Send_Byte(0x03);
    203             while(IIC_Wait_Ack());
    204             delayMs(3);
    205             IIC_Send_Byte(Power_flag);
    206             while(IIC_Wait_Ack());
    207             delayMs(3);
    208             IIC_Send_Byte(0xFB);
    209             while(IIC_Wait_Ack());
    210             delayMs(3);
    211             IIC_Stop();
    212           WR_flag=0x02;    
    213         }
    214         /***************write end*****************/
    215      
    216 }

    从机使用中断方式

      1 #include "myiic.h"
      2 #include "delay.h"
      3 #include "led.h"
      4 #include "key.h"
      5 #include "usart.h"
      6 
      7 
      8 #define MY_I2C_ADDRESS    0x30                         //模拟从机地址
      9 unsigned char b[5]={0x00,0x00,0x00,0x00,0x00};         //从机接收操作
     10 uint8_t Wifi_Set=0x00;
     11 extern u8 flag;                                        //电磁炉开关中断位
     12 unsigned char a[5]={0xFA,0x00,0x00,0x00,0xFB};         
     13 //初始化IIC
     14 void I2C1_Init(void)
     15 {
     16     GPIO_InitTypeDef GPIO_InitStructure;
     17     I2C_InitTypeDef I2C_InitStructure;
     18     NVIC_InitTypeDef NVIC_InitStructure;
     19     
     20     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);   // enable APB1 peripheral clock for I2C1
     21     
     22     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // enable clock for SCL and SDA pins
     23     
     24     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
     25     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     26     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;        //I2C必须开漏输出,实现线与逻辑
     27     GPIO_Init(GPIOB, &GPIO_InitStructure);
     28     
     29     
     30     I2C_InitStructure.I2C_ClockSpeed = 100000;             // configure I2C1 
     31     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
     32     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
     33     I2C_InitStructure.I2C_OwnAddress1 = MY_I2C_ADDRESS;
     34     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
     35     I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
     36     I2C_Init(I2C1, &I2C_InitStructure);
     37 
     38     //setup interrupts
     39     I2C_ITConfig(I2C1, I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF, ENABLE);   
     40 
     41     
     42     // Configure the I2C event priority
     43     NVIC_InitStructure.NVIC_IRQChannel                   = I2C1_EV_IRQn;
     44     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;       //抢占优先级1
     45     NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;       //响应优先级0
     46     NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
     47     NVIC_Init(&NVIC_InitStructure);
     48 
     49     // enable I2C1
     50     I2C_Cmd(I2C1, ENABLE);
     51 }
     52 
     53 
     54 //Clear ADDR by reading SR1, then SR2
     55 
     56 void I2C_clear_ADDR(I2C_TypeDef* I2Cx) {
     57     I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR);
     58     ((void)(I2Cx->SR2));
     59 }
     60 
     61 //Clear STOPF by reading SR1, then writing CR1
     62 
     63 void I2C_clear_STOPF(I2C_TypeDef* I2Cx) {
     64     I2C_GetFlagStatus(I2Cx, I2C_FLAG_STOPF);
     65     I2C_Cmd(I2Cx, ENABLE);
     66 }
     67 
     68 /*--------------------------------------------------------------------------------
     69 调用方式:void I2C1_EV_IRQHandler(void) 
     70 函数说明:私有函数,I2C专用,中断按键处理函数,从机中断都在这里面执行
     71 ---------------------------------------------------------------------------------*/
     72 
     73 uint8_t data = 0;
     74 uint8_t S_data=0;
     75 void I2C1_EV_IRQHandler(void) 
     76 {
     77 //        KV1=0;                                 //只是一个测试灯
     78         //Clear AF from slave-transmission end
     79         if(I2C_GetITStatus(I2C1, I2C_IT_AF)) 
     80         {
     81             I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
     82         }
     83         //Big state machine response, since doesn't actually keep state
     84         switch(I2C_GetLastEvent(I2C1)) 
     85             {
     86             //SLAVE
     87             //Receive
     88             case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: //EV1
     89                 I2C_clear_ADDR(I2C1);
     90                 break;
     91             case I2C_EVENT_SLAVE_BYTE_RECEIVED: //EV2
     92                 //Read it, so no one is waiting, clears BTF if necessary
     93                 b[data] = I2C_ReceiveData(I2C1);
     94         //      printf("%c",b[data]);
     95                 data++;
     96                 if(data>=5)
     97                 {
     98                                 data=0;
     99                                 if((b[0]==0xFA)&&(b[4]==0xFB))
    100                                 {
    101                                     a[1]=b[1];
    102                                     Wifi_Set=b[2];
    103                                     flag=b[3];
    104                 //                    printf("%c",a[1]);
    105                                 }
    106 
    107                 }
    108                 if(I2C_GetFlagStatus(I2C1, I2C_FLAG_DUALF)) 
    109                 {//Secondary Receive
    110                 } 
    111                 else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_GENCALL)) 
    112                 {//General Receive
    113                 } 
    114                 else 
    115                 {//Normal
    116                 }
    117                 break;
    118             case I2C_EVENT_SLAVE_STOP_DETECTED: //End of receive, EV4
    119                 I2C_clear_STOPF(I2C1);
    120                 break;
    121 
    122             //Transmit
    123             case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: //EV1
    124                 I2C_clear_ADDR(I2C1);
    125                 //Send first byte
    126                I2C_SendData(I2C1, 0x00);
    127             
    128                 break;
    129             case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //EV3
    130                 //Determine what you want to send
    131                 //data = 5;
    132                 if(I2C_GetFlagStatus(I2C1, I2C_FLAG_DUALF)) 
    133                 {//Secondary Transmit
    134                 } 
    135                 else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_GENCALL)) 
    136                 {//General Transmit
    137                 } 
    138                 else 
    139                 {//Normal
    140                 }
    141                 //Read flag and write next byte to clear BTF if present
    142                 I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF);
    143                 I2C_SendData(I2C1, a[S_data]);
    144                 S_data++;
    145                 if(S_data>=5)
    146                 S_data=0;
    147                 break;
    148             case I2C_EVENT_SLAVE_ACK_FAILURE://End of transmission EV3_2
    149                 //TODO: Doesn't seem to be getting reached, so just
    150                 //check at top-level
    151                 I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
    152                 break;
    153             //Alternative Cases for address match
    154             case I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED:    //EV1
    155                 break;
    156             case I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED: //EV1
    157                 break;
    158             case I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED:        //EV1
    159                 break;
    160 
    161 
    162             //MASTER
    163             case I2C_EVENT_MASTER_MODE_SELECT: //EV5, just sent start bit
    164                 break;
    165             //Receive
    166             case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: //EV6, just sent addr    
    167                 break;
    168             case I2C_EVENT_MASTER_BYTE_RECEIVED: //EV7
    169                 break;
    170             //Transmit
    171             case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: //EV6, just sent addr     
    172                 break;
    173             case I2C_EVENT_MASTER_BYTE_TRANSMITTING: //EV8, about to send data
    174                 break;
    175             case I2C_EVENT_MASTER_BYTE_TRANSMITTED: //EV8_2, just sent data
    176                 break;
    177 
    178             //Alternative addressing stuff, not going to worry about
    179             case I2C_EVENT_MASTER_MODE_ADDRESS10: //EV9
    180                 break;
    181             default:
    182                 //How the FUCK did you get here?
    183                 //I should probably raise some error, but fuck it,
    184                 //it's late
    185                 break;
    186 
    187         }
    188 
    189 
    190 }
    191 
    192 void I2C1_ER_IRQHandler(void) {
    193  //       GPIO_SetBits(GPIOD, RED);
    194 //    LED3=0;
    195         //Can't use nice switch statement, because no fxn available
    196         if(I2C_GetITStatus(I2C1,        I2C_IT_SMBALERT)) {
    197         } else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) {
    198         } else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) {
    199         } else if(I2C_GetITStatus(I2C1, I2C_IT_OVR)) {
    200             //Overrun
    201             //CLK stretch disabled and receiving
    202             //DR has not been read, b4 next byte comes in
    203             //effect: lose byte
    204             //should:clear RxNE and transmitter should retransmit
    205 
    206             //Underrun
    207             //CLK stretch disabled and I2C transmitting
    208             //haven't updated DR since new clock
    209             //effect: same byte resent
    210             //should: make sure discarded, and write next
    211         } else if(I2C_GetITStatus(I2C1, I2C_IT_AF)) {
    212             //Detected NACK
    213             //Transmitter must reset com
    214                 //Slave: lines released
    215                 //Master: Stop or repeated Start must must be generated
    216                 //Master = MSL bit
    217             //Fixup
    218             I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
    219         } else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) {
    220             //Arbitration Lost
    221             //Goes to slave mode, but can't ack slave address in same transfer
    222             //Can after repeat Start though
    223         } else if(I2C_GetITStatus(I2C1, I2C_IT_BERR)) {
    224             //Bus Error
    225             //In slave mode: data discarded, lines released, acts like restart
    226             //In master mode: current transmission continues
    227         }
    228 }
  • 相关阅读:
    Python的一些版本分析
    2006年的长春.NET俱乐部
    大病了一场,不过闲时对AJAX探索时,实现了IE TREE无刷新
    关于AJAX开发
    提供可在WSS上使用的MYTREE
    关于WSS搜索的问题
    转发:使用JavaScript删除ASP.NET生成的HttpCookie
    AJAX(2)
    在将WEBPART打包成*.CAB包和*.MSI安装包后,竟然无法将其安装到指定的WSS网站
    转发:Session研习笔记
  • 原文地址:https://www.cnblogs.com/xiongzongxiong/p/7813526.html
Copyright © 2020-2023  润新知