聽說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;
}
