<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                iic協議是比較簡單的雙線協議,時鐘線CLK和數據線SDA。 一般我們常見的還有spi總線,這種總線可以可以根據需要擴展,還有單總線等等 這次還以at240c2為例進行操作! ![](https://box.kancloud.cn/2016-06-21_576915ba02866.jpg) PS:這就是傳說中的iic時序圖 硬件構造我們不過多的分析,今天用到庫了!我們先從庫函數硬件iic初始化說起! PB6 ? -- ? CLK PB7 ? -- ? SDA ~~~ void i2c_init(u8 addr,u32 clock) { I2C_InitTypeDef i2c; RCC->APB2ENR |= 1<<3; GPIOB->CRL |= (u32)0xff<<(6*4); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); i2c.I2C_Ack = I2C_Ack_Enable; i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; i2c.I2C_ClockSpeed = clock*1000; i2c.I2C_DutyCycle = I2C_DutyCycle_2; i2c.I2C_Mode = I2C_Mode_I2C; i2c.I2C_OwnAddress1 = addr; I2C_Cmd(I2C1,ENABLE); I2C_Init(I2C1,&i2c); } ~~~ 在配置管腳方面,我還是喜歡用寄存器配置,因為我的兩行代碼可以解決庫函數的N多行代碼的問題! 還有在結構體變量命名方面也是屬于我自己的獨創吧,這樣反正我覺得是既容易識別,也少打幾個字! ~~~ typedef struct { uint32_t I2C_ClockSpeed; //I2C時鐘頻率設置 uint16_t I2C_Mode; ? ? ? ? ? ? //I2C模式設置 uint16_t I2C_DutyCycle; ? ? //高低電平時間之比 uint16_t I2C_OwnAddress1; ? ? ?//主設備地址設置,也就是自己的地址 uint16_t I2C_Ack; ? ? ? ? ? ? ? ? //Check uint16_t I2C_AcknowledgedAddress; //地址長度,可以為7bit的也可以為10bit的 }I2C_InitTypeDef; ~~~ IIC初始化完之后,我們開始來研究eeprom ![](https://box.kancloud.cn/2016-06-21_576915ba166b1.jpg) 看完這個寫一個字節的協議之后,我們應該對這個寫已經沒有什么問題了,很簡單的。 ![](https://box.kancloud.cn/2016-06-21_576915ba2ce96.jpg) 這個是寫一個page 注:在eeprom里面寫數據時,一次最多只能寫一個page,一個page為8byte,同時這個也有字節對齊的要求! ![](https://box.kancloud.cn/2016-06-21_576915ba40592.jpg) 比如我們從Address = 4開始寫,那么我們最多一次性可寫4個byte,如果我們從8開始寫的話,我們就可以8個byte,最后偏移到15。 ~~~ void eeprom_write_byte(u8 wt_addr,u8 data) { I2C_GenerateSTART(I2C1,ENABLE);delay(5); I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1,wt_addr);delay(5); I2C_SendData(I2C1,data);delay(5); I2C_GenerateSTOP(I2C1, ENABLE); delay(20); } ~~~ 由于stm32的i2c確實做的不怎么樣,標著寄存器太多,也不容易識別,我們就不要檢測這些標志寄存器,用延時了把他們隔離了。不過在把地址發送出去之后,要檢測設備是否被選中,這個在我們的模擬的i2c里面也是必須檢測的!可以認為是必不可少的! ~~~ void eeprom_write_page(u8 wt_addr,u8 *buff,u32 length) { int i = 0; I2C_GenerateSTART(I2C1,ENABLE);delay(5); I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1,wt_addr);delay(5); for(i=0; i<length; i++) { I2C_SendData(I2C1,buff[i]);delay(5); } I2C_GenerateSTOP(I2C1, ENABLE); } ~~~ 這個是寫一個page的函數,如果大家想看比較靈活的寫函數,去我看我前面發表的博客里面找找,那個無論你寫幾個都無所謂,只要不超過eeprom的大小! ![](https://box.kancloud.cn/2016-06-21_576915ba57e04.jpg) 讀數據是稍稍復雜一點點的,我們首先要選中設備,然后選擇我們要操作的地址,這時候不要stop,如果stop信號一發出,總線就被釋放掉了,設備也就跟處理器斷開,所以這里需要一個RSTART,跟START不一樣,多了個R,這個可以理解為重新開始,這個信號不會選中其他設備,也不會丟失當前設備。 然后還有個注意點是,在讀完第N個字節后,不要返回回應,直接stop,不然設備會以為你沒有結束,會一直占據總線,等待下一個數據的發送,這樣等你下一次來訪問他的時候,他就不讓你訪問了,因為他還停留在給你傳數據的狀態,所以這里一定不要返回acK直接stop信號發出哦! ~~~ unsigned char eeprom_read_byte(u8 rd_addr) { u8 temp = 0; I2C_GenerateSTART(I2C1,ENABLE);delay(5); I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_Cmd(I2C1, ENABLE); I2C_SendData(I2C1,rd_addr);delay(10); I2C_GenerateSTART(I2C1,ENABLE);delay(5); I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); I2C_AcknowledgeConfig(I2C1, DISABLE); while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))); temp = I2C_ReceiveData(I2C1);delay(5); I2C_GenerateSTOP(I2C1, ENABLE); delay(20); I2C_AcknowledgeConfig(I2C1, ENABLE); return temp; } ~~~ 還是有幾個信號是必須確認的,設備地址發送出去,看設備是否有回應! 這里最后一個NOACK必須在發送最后一個字節前使能,在stop信號發出后,記得吧ACK信號重新使能,因為我們剛剛開始是需要ack的,只是最后有時候不需要! ![](https://box.kancloud.cn/2016-06-21_576915ba70026.jpg) 對于數據的讀,在所讀數據長度上,是沒有要求的,也沒有page限制,想讀多少,讀多少! ~~~ void eeprom_read(u8 rd_addr,u8 *buff,u32 length) { int i = 0; I2C_GenerateSTART(I2C1,ENABLE);delay(5); I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_Cmd(I2C1, ENABLE); I2C_SendData(I2C1,rd_addr);delay(20); I2C_GenerateSTART(I2C1,ENABLE);delay(5); I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); for(i=0; i<length; i++) { if(i == length-1) I2C_AcknowledgeConfig(I2C1, DISABLE); while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))); buff[i] = I2C_ReceiveData(I2C1);delay(5); } I2C_GenerateSTOP(I2C1, ENABLE); I2C_AcknowledgeConfig(I2C1, ENABLE); } ~~~ PS:在提一下,在接收最后一個數據之前,必須關閉ACK,不然,。。。后果很嚴重!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看