最近一段時間在做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>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 }
上一篇:stm32f1xx i2c通訊故障可能原因
下一篇:STM32F030 I2C 從模式中斷編程
推薦閱讀
史海拾趣
ETAL公司成立于XXXX年,由一群富有遠見和熱情的電子工程師創立。他們看到了電子技術在全球范圍內的廣泛應用和巨大潛力,決定投身于這一行業。起初,ETAL主要專注于電子元器件的研發和生產,通過不斷的技術創新和產品優化,逐漸在市場上樹立了良好的口碑。
在產品質量和技術水平得到認可后,ETAL開始積極拓展市場。公司制定了詳細的市場營銷策略,通過參加國際電子展會、與知名企業合作等方式提高品牌知名度。同時,ETAL還注重客戶服務,建立了完善的售后服務體系,確保客戶在使用產品過程中得到及時、專業的支持。這些舉措使得ETAL的市場份額不斷擴大,品牌影響力逐漸增強。
在電子廢棄物處理成為全球關注焦點的背景下,“未來電子”積極倡導綠色生產和循環經濟理念。公司投入大量資源研發環保型電子產品,并建立了完善的電子廢棄物回收處理體系。通過技術創新和科學管理,“未來電子”實現了生產過程中的節能減排和廢棄物的有效回收利用,贏得了社會各界的廣泛贊譽。這一舉措不僅提升了公司的社會形象,還為公司的可持續發展奠定了堅實基礎。
隨著技術的不斷進步和市場需求的不斷變化,CONEC始終堅持產品創新。1985年,D-SUB濾波連接器的推出,是公司技術實力和市場洞察力的體現。這一創新產品不僅滿足了當時市場對高性能連接器的需求,也為公司在電子行業中樹立了良好的口碑。此后,CONEC不斷推出新產品,逐步擴大市場份額,成為全球電子行業的重要參與者。
為了進一步提升公司的競爭力和市場影響力,CONEC開始了國際化布局。1990年,康耐加拿大公司的成立,標志著公司邁出了國際化的重要一步。隨后,CONEC在德國、捷克共和國、美國和波蘭等地設立分公司或生產基地,形成了全球性的生產和銷售網絡。同時,公司還積極尋求與全球領先的電子企業和技術機構的戰略合作,共同推動電子行業的發展。
招聘WAP聯盟運營總監和市場總監 WAP聯盟運營總監和市場總監(2名) 最低學歷:大專以上學歷工作經驗:3年以上薪水范圍:月薪1萬到1萬5千(底薪 + 業績獎金)簡歷請發:mw2009@fly4our.com 聯系電話:13381487182 聯系人:秦小姐 崗位職責: 1. ...… 查看全部問答∨ |
復古磁帶又出現了!這次要介紹的是款磁帶形式的 MP3,沒錯,它看起來很像是一個磁帶,卻是個 MP3。它的特色可是不為人知了,看外形與價格也知道,沒有昂貴的LCD 屏幕,而且它還有一個秘密,就是沒有存儲,底部可以發現個 SD 槽,那就是要點所在,你 ...… 查看全部問答∨ |
ARM上電時把FLASH中的數據LOAD到SDRAM中。 然后程序在SDRAM中運行。 那請問,ARM本身就帶有FLASH的驅動嗎? 要不然怎么能上電就能讀取FLASH呢?… 查看全部問答∨ |
|
小弟也是程序員,不過總聽公司的前輩們說,做MPEG視頻算法啥的都是牛人,不知道是不是指這個領域薪水比較高? 說心里話,既然入了行,當然希望工資高點,挑戰多點沒關系,既然已經選擇了這個職業,也不怕再多吃點苦,多用點腦,只是找不準方向, ...… 查看全部問答∨ |
|
請教一個問題: 我在Platform Builder 建立和模擬器的連接、下載運行時映像時,遇到下面的問題。 the specified ce boot image couldnot be loaded. your virtual machi ...… 查看全部問答∨ |
NMAKE : U1073: don't know how to make WinCE5.0 生成系統時出現: BUILD: [01:0000000913:ERRORE] NMAKE : U1073: don\'t know how to make \'D:\\WINCE500\\platform\\common\\lib\\ARMV4I\\retail\\oal_memory_s3c2440a.lib\' BUILD: [01:0000000915:ERRORE] NMAKE.EXE ...… 查看全部問答∨ |
為何我裝CCS會出現錯誤提示?操作系統64位win7,安裝到最后一個組件前會出現如圖1提示:這個提示是怎么回事?不管,關閉后繼續安裝又會出現圖2提示:取消安裝,刪除安裝文件夾內容,重新安裝,圖2錯誤提示就沒有了,安裝完成。但是圖1的提示還是出 ...… 查看全部問答∨ |