日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32的I2C主从机通信

發布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 high51 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 //初始化IIC14 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 I2C121 22 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // enable clock for SCL and SDA pins23 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 interrupts39 I2C_ITConfig(I2C1, I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF, ENABLE); 40 41 42 // Configure the I2C event priority43 NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;44 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //搶占優先級145 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應優先級046 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;47 NVIC_Init(&NVIC_InitStructure);48 49 // enable I2C150 I2C_Cmd(I2C1, ENABLE);51 }52 53 54 //Clear ADDR by reading SR1, then SR255 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 CR162 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 end79 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 state84 switch(I2C_GetLastEvent(I2C1)) 85 {86 //SLAVE87 //Receive88 case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: //EV189 I2C_clear_ADDR(I2C1);90 break;91 case I2C_EVENT_SLAVE_BYTE_RECEIVED: //EV292 //Read it, so no one is waiting, clears BTF if necessary93 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 }

總結

以上是生活随笔為你收集整理的STM32的I2C主从机通信的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。