聽說STM32的IIC硬件做的很雞肋,所以在這里通過模擬的方式實現IIC協議。此程序能成功對AT24C02操作。
程序中的帶參數宏 IIC_DELAY(time)的功能是延時time us,在實際中具體場合具體分析。
宏定義文件--IIC.h
#ifndef _IIC_ #define _IIC_ #include "SysTick.h" #include "stm32f10x.h" #include "SystemConfig.h" /* 配置IIC的SDA、SCL兩個端口 */ #define IIC_SCL_IO GPIO_Pin_6 #define IIC_SDA_IO GPIO_Pin_7 /* SDA端口動態改變輸入輸出狀態定義 */ #define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X80000000;} //配置上拉輸入 #define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X30000000;} //配置推挽輸出 /* IIC 操作定義 */ #define IIC_SDA PBOUT(7) //定義的STM32位操作 #define READ_SDA PBIN(7) #define IIC_SCL PBOUT(6) #define IIC_DELAY(time) delay(time) /* 定義的函數原型 */ void IIC_IOInit(void); void IIC_Start(void); void IIC_Stop(void); unsigned char IIC_Wait_Ack(void); void IIC_NoAck(void); void IIC_Ack(void); void IIC_Send_Byte(unsigned char txd); unsigned char IIC_Read_Byte(unsigned char ack); #endif
程序源文件IIC.c文件
#include "IIC.h" /********************************************************************* ** STM32模擬IIC通信 ** 文件編碼: GBK2312 **********************************************************************/ /***************************** ** 初始化IIC的IO口 ** ******************************/ void IIC_IOInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE ); //使能IO口時鍾 GPIO_InitStructure.GPIO_Pin = IIC_SCL_IO | IIC_SDA_IO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB,IIC_SCL_IO | IIC_SDA_IO); //置位SDA,SCL } /***************************** ** 起始信號 ** ******************************/ void IIC_Start(void) { SDA_OUT(); //sda 線輸出 IIC_SDA=1; IIC_SCL=1; IIC_DELAY(4); IIC_SDA=0;//當時鍾線為高時,SDA拉低則起始信號才有效 IIC_DELAY(4); IIC_SCL=0;//鉗住 I2C 總線,准備發送或接收數據 } /***************************** ** 停止信號 ** ******************************/ void IIC_Stop(void) { SDA_OUT();//sda 線輸出 IIC_SCL=0; IIC_SDA=0;//STOP:when CLK is high DATA change form low to high IIC_DELAY(4); IIC_SCL=1; IIC_DELAY(1); IIC_SDA=1;//發送 I2C 總線結束信號 IIC_DELAY(4); } /***************************** ** 等待應答信號 ** 返回值: 1-接收應答失敗, 0-為接收成功 ******************************/ unsigned char IIC_Wait_Ack(void) { unsigned char ucErrTime=0; SDA_IN(); //SDA 設置為輸入 IIC_SDA=1;IIC_DELAY(1); IIC_SCL=1;IIC_DELAY(1); while(READ_SDA) //判斷SDA上是否有低電平發生 { ucErrTime++; if(ucErrTime>250) //如果在一段時間內沒有接收到應答信號,則發送停止信號 { IIC_Stop(); return 1; } } IIC_SCL=0;//時鍾輸出 0 return 0; } /***************************** ** 產生應答信號 ** ******************************/ void IIC_Ack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; IIC_DELAY(2); //數據改變有效 IIC_SCL=1; IIC_DELAY(2); IIC_SCL=0; } /***************************** ** 不產生應答信號 ** ******************************/ void IIC_NoAck(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=1; IIC_DELAY(2); IIC_SCL=1; IIC_DELAY(2); IIC_SCL=0; } /***************************** ** 發送一個字節的數據 ** ******************************/ void IIC_Send_Byte(unsigned char txd) { unsigned char t; SDA_OUT(); IIC_SCL=0;//拉低時鍾開始數據傳輸,時SDA上的數據改變有效 for(t=0;t<8;t++) { IIC_SDA=(txd&0x80)>>7; txd<<=1; IIC_DELAY(2); //對 TEA5767 這三個延時都是必須的 IIC_SCL=1; IIC_DELAY(2); //保持數據一段時間 IIC_SCL=0; IIC_DELAY(2); } } /***************************** ** 讀一個字節的數據 ** 形式參數:ack=1,發送ACK, ack=0,發送NACK ******************************/ unsigned char IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN();//SDA 設置為輸入 for(i=0;i<8;i++ ) { IIC_SCL=0; IIC_DELAY(2); IIC_SCL=1; receive<<=1; if(READ_SDA)receive++; IIC_DELAY(1); } if (!ack) IIC_NoAck();//發送 nACK else IIC_Ack(); //發送 ACK return receive; }