新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32 I2C AT24C02驅動

        STM32 I2C AT24C02驅動

        作者: 時間:2016-11-25 來源:網絡 收藏
        如果搞過51的I2C的同志,再來看看STM32的I2C驅動,一定有相見恨晚的感覺。STM32自帶I2C硬件模塊,再配合ST的官方庫函數,I2C在STM32這里可以玩得如火的地步。這里的這個I2C驅動算是很完整了的,可以直接拿來用到項目開發中去。好,不廢話,上圖:

        工程結構圖:

        本文引用地址:http://www.104case.com/article/201611/321301.htm

        1、main.c

        #include"stm32f10x.h"
        #include"usart1.h"
        #include"led.h"
        #include"i2c_at24c02.h"
        #include



        struct Contact{
        u8 Name[15]; //姓名
        u8 Phone[11];//電話
        u8 BirthDay[10];//生日
        }WgchnlnContact[3],NewContact;
        struct Contact WgchnlnContact[3]={
        {
        "wgchnln",
        "18682101373",
        "1987-02-19",
        },
        {
        "hezepan",
        "18528473728",
        "1987-10-28",
        },
        {
        "lixiaowei",
        "13527492729",
        "1988-12-02",
        }};


        #ifdef Test

        void I2C_Test(void)
        {
        u16 i;
        u8 I2c_Buf[256];

        printf("寫入的數據");

        //填充緩沖
        for(i=0;i<=255;i++)
        {
        I2c_Buf[i]=i;
        printf("0x%x ",I2c_Buf[i]);
        if(i == 9)
        {
        printf("");
        }
        }
        printf("");

        I2C_AT24Cx_Writes(0,I2c_Buf,256);//將I2C_Buf中順序遞增的數據寫入EERPOM中


        //清緩沖
        for(i=0;i<=255;i++)
        {
        I2c_Buf[i]=0;
        }

        printf("讀出的數據");
        I2C_AT24Cx_Reads(0,I2c_Buf,256);//將EEPROM讀出數據順序保持到I2C_Buf中

        //將I2C_Buf中的數據通過串口打印
        for(i=0;i<256;i++)
        {
        if(I2c_Buf[i]!=i)
        {
        printf("錯誤:I2C EEPROM寫入與讀出的數據不一致");
        while(1);
        }
        printf("0x%X ", I2c_Buf[i]);
        if(i == 9)
        {
        printf("");
        }
        }
        }
        #endif

        int main(void)
        {
        u8 ReadBuffer[36];
        u8 i=0;
        u8 j=0;
        USART_Config(); //串口1初始化
        printf("這是一個I2C-EEPROM-AT24C02演示實驗");

        //Led_Init(); //LED初始化

        I2C_AT24Cx_Init(); //I2C初始化

        #ifdef Test
        I2C_Test();
        #endif


        printf("寫入聯系人");
        for(j=0;j<3;j++)
        {
        I2C_AT24Cx_Writes(0+j*36,WgchnlnContact[j].Name,15);
        I2C_AT24Cx_Writes(15+j*36,WgchnlnContact[j].Phone,11);
        I2C_AT24Cx_Writes(26+j*36,WgchnlnContact[j].BirthDay,10);
        }
        j=0;

        printf("讀出聯系人");
        for(j=0;j<3;j++)
        {
        I2C_AT24Cx_Reads(j*36,ReadBuffer,36);

        for(i=0;i<15;i++)
        {
        NewContact.Name[i]=ReadBuffer[i];
        }
        i=0;
        printf("姓名:%s",NewContact.Name);

        for(i=0;i<11;i++)
        {
        NewContact.Phone[i]=ReadBuffer[i+15];
        }
        i=0;
        printf("電話:%s",NewContact.Phone);//為什么打印第二個聯系人的號碼電話會把第一個聯系人的生日一同打印出來

        for(i=0;i<10;i++)
        {
        NewContact.BirthDay[i]=ReadBuffer[i+26];
        }
        i=0;
        printf("生日:%s",NewContact.BirthDay);

        }
        while(1);
        }

        2、今天的主角:i2c_at24c02.c

        #include"stm32f10x.h"
        #include"i2c_at24c02.h"


        #define AT24Cx_Address 0xa0 //I2C芯片地址 EEPROM
        #define AT24Cx_PageSize 8 //芯片內部一頁容量


        static void I2C_ATC24x_GPIO_Config(void)
        {
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(I2C_SCL_GPIO_RCC,ENABLE); //沒有外部中斷,沒有重映射,所以不需要開啟復用功能


        GPIO_InitStructure.GPIO_Pin =I2C_SCL_Pin|I2C_SDA_Pin;
        GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_OD; //設置管腳為復用功能開漏輸出 SDA是輸入輸出引腳

        GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);
        }



        static void I2C_Config(void)
        {
        I2C_InitTypeDef I2C_InitStructure;


        RCC_APB1PeriphClockCmd(I2C_RCC,ENABLE);


        I2C_DeInit(I2C);

        I2C_InitStructure.I2C_ClockSpeed =100000; //100KHz I2C時鐘頻率
        I2C_InitStructure.I2C_Mode =I2C_Mode_I2C; //I2C模式
        I2C_InitStructure.I2C_DutyCycle =I2C_DutyCycle_2; //時鐘占空比
        I2C_InitStructure.I2C_OwnAddress1 =0x30; //主機地址 可以任意的
        I2C_InitStructure.I2C_Ack =I2C_Ack_Enable; //開啟ACK應答響應
        I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit;//7位地址模式 非10為地址模式


        I2C_Init(I2C,&I2C_InitStructure);


        I2C_Cmd(I2C,ENABLE);


        I2C_AcknowledgeConfig(I2C,ENABLE);
        }



        void I2C_AT24Cx_Init(void)
        {
        I2C_ATC24x_GPIO_Config();

        I2C_Config();
        }


        void I2C_AT24Cx_Reads(u8 Address,u8 *ReadBuffer,u16 ReadNumber)
        {
        if(ReadNumber==0) //沒有需要讀取的數據
        return;


        while(I2C_GetFlagStatus(I2C,I2C_FLAG_BUSY));


        I2C_AcknowledgeConfig(I2C, ENABLE);


        I2C_GenerateSTART(I2C,ENABLE);
        while(!I2C_CheckEvent(I2C,I2C_EVENT_MASTER_MODE_SELECT)); //檢查是不是主模式與起始位已經發送 備注:這樣做的目的就是為了清空該事件


        I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
        while (!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//檢查數據是不是已經發送地址完成


        I2C_SendData(I2C, Address);
        while (!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //檢查數據是不是已經發送完成

        //需要讀取數據,這個時候需要變換數據傳輸方向,就要主機重新發送起始位
        I2C_GenerateSTART(I2C, ENABLE);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));


        I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Receiver); //再一次發送EEPROM地址
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));


        while(ReadNumber)
        {

        if(ReadNumber==1)
        {
        I2C_AcknowledgeConfig(I2C, DISABLE);//關閉應答
        I2C_GenerateSTOP(I2C,ENABLE);//使能停止功能
        }

        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)); //檢查是不是接受到了數據
        *ReadBuffer=I2C_ReceiveData(I2C);
        ReadBuffer++;
        ReadNumber--;
        }
        I2C_AcknowledgeConfig(I2C, ENABLE);//允許應答模式
        }



        static void I2C_AT24Cx_WaitForComplete(void)
        {
        vu16 SR1_Tmp;
        do
        {

        I2C_GenerateSTART(I2C1, ENABLE); //一旦發送起始位,主機等待讀取SR1,然后發送地址

        SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1); //也是為了清除該事件

        I2C_Send7bitAddress(I2C1,AT24Cx_Address, I2C_Direction_Transmitter);
        }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002)); //直到地址發送完成


        I2C_ClearFlag(I2C, I2C_FLAG_AF); //前面如果出現過忙碌 就會出現應答錯誤現象

        I2C_GenerateSTOP(I2C, ENABLE);
        }



        void I2C_AT24Cx_WriteByte(u8 Address,u8 WriteData)
        {

        I2C_GenerateSTART(I2C, ENABLE);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));


        I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //實際就是等待收到EEPROM的ACK應答信號(收到ACK后,硬件會做相應的置位)


        I2C_SendData(I2C, Address);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));


        I2C_SendData(I2C, WriteData);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));


        I2C_GenerateSTOP(I2C, ENABLE); //這里的設置停止為與接收時不同 這里是寫入最后一個數據之后設置停止位

        I2C_AT24Cx_WaitForComplete();
        }



        void I2C_AT24Cx_WritePage(u8 Address,u8 *WriteData,u16 WriteNumber)
        {
        while(I2C_GetFlagStatus(I2C, I2C_FLAG_BUSY));


        I2C_GenerateSTART(I2C, ENABLE);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));


        I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));


        I2C_SendData(I2C,Address);
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        while(WriteNumber--)
        {
        I2C_SendData(I2C,*WriteData);
        WriteData++;
        while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
        }


        I2C_GenerateSTOP(I2C, ENABLE);
        }



        void I2C_AT24Cx_Writes(u8 Address,u8 *WriteData,u16 WriteNumber)
        {
        u8 Temp;


        Temp=Address%AT24Cx_PageSize;
        if(Temp)//存在頁不對齊的現象
        {
        Temp=AT24Cx_PageSize-Temp;//求出頁不對齊的數量
        I2C_AT24Cx_WritePage(Address,WriteData,Temp);
        Address+=Temp;
        WriteData+=Temp;
        WriteNumber-=Temp;
        I2C_AT24Cx_WaitForComplete();
        }

        while(WriteNumber)
        {

        if(WriteNumber>=AT24Cx_PageSize)
        {
        I2C_AT24Cx_WritePage(Address,WriteData,AT24Cx_PageSize);
        Address+=AT24Cx_PageSize;
        WriteData+=AT24Cx_PageSize;
        WriteNumber-=AT24Cx_PageSize;
        I2C_AT24Cx_WaitForComplete();
        }

        else
        {
        I2C_AT24Cx_WritePage(Address,WriteData,WriteNumber);
        WriteNumber=0;
        I2C_AT24Cx_WaitForComplete();
        }
        }
        }

        i2c_at24c02.h


        #ifndef _I2C_AT24C02_H
        #define _I2C_AT24C02_H

        #include"stm32f10x.h"


        #define I2C I2C1
        #define I2C_RCC RCC_APB1Periph_I2C1

        #define I2C_SCL_GPIO_RCC RCC_APB2Periph_GPIOB
        #define I2C_SCL_GPIO GPIOB
        #define I2C_SCL_Pin GPIO_Pin_6

        #define I2C_SDA_GPIO_RCC RCC_APB2Periph_GPIOB
        #define I2C_SDA_GPIO GPIOB
        #define I2C_SDA_Pin GPIO_Pin_7

        void I2C_AT24Cx_Init(void); //I2C外設與AT24C02初始化

        void I2C_AT24Cx_Reads(u8 Address,u8 *ReadBuffer,u16 ReadNumber); //從AT24C02中讀取數據 EEPROM

        void I2C_AT24Cx_WriteByte(u8 Address,u8 WriteData); //寫入一字節數據

        void I2C_AT24Cx_WritePage(u8 Address,u8 *WriteData,u16 WriteNumber); //寫入一頁之內數據

        void I2C_AT24Cx_Writes(u8 Address,u8 *WriteData,u16 WriteNumber); //寫入任意數量的數據 流程:寫入也不對齊部分--寫入整頁部分(假如需要)--寫入最后不足一頁的
        #endif

        剩下的串口驅動與LED驅動分別見:《STM32 串口例程之查詢收發》、《STM32 基于庫函數控制按鍵 蜂鳴器 LED顯示》完全一樣的。這里就不在重復上代碼了。

        以上,結束。



        關鍵詞: STM32I2CAT24C02驅

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 襄垣县| 新丰县| 基隆市| 山东省| 清水河县| 东乡| 赣州市| 龙里县| 宕昌县| 社会| 正定县| 东乡| 马边| 鲁甸县| 米脂县| 平凉市| 平原县| 安福县| 东山县| 栖霞市| 凤台县| 涿州市| 贡嘎县| 松江区| 张掖市| 阳朔县| 望江县| 金川县| 兴城市| 得荣县| 鄂托克旗| 瑞丽市| 金华市| 阳山县| 玛纳斯县| 怀远县| 漳平市| 峡江县| 临武县| 新野县| 开江县|