原创 STM32----5----I2C(上)

2011-5-9 11:22 5149 1 1 分类: MCU/ 嵌入式

I2C的协议就不讲了,网上多的很,我们关键在于利用STM32的GPIO模拟出I2C:

I2C.h

#ifndef __IIC_H
#define __IIC_H
#include "stm32f10x_lib.h"
/*********************************************************
 - I2C 宏定义:
 - 软件模拟I2C时的管脚,用PC12模拟CLK,用PC11模拟SDA
 - 所以在应用的时候,要打开GPIOC的时钟   
*********************************************************/
#define IIC_SCL_PORT              GPIOC
#define IIC_SCL_CLK               RCC_APB2Periph_GPIOC 
#define IIC_SCL_PIN               GPIO_Pin_12
#define IIC_SDA_PORT              GPIOC
#define IIC_SDA_CLK               RCC_APB2Periph_GPIOC 
#define IIC_SDA_PIN               GPIO_Pin_11

/*********************************************************
 - I2C宏定义:
 - SDA方向设置:
    - SDA_IN(): 此处是将SDA定义为配置为输入模式
 - SDA_OUT():此处是将SDA_OUT配置为推挽输出模式
 说明:这里是配置的快速写法,当然也可以用库函数初始化,
    因为IIC的SDA线,即要作为输入也要作为输出。       
*********************************************************/
       

#define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}


/*********************************************************
 - I2C宏定义:
 - I2C时钟操作:
    - Set_IIC_SCL: 此处是将SCL拉为高电平
 - Clr_IIC_SCL: 此处是将SCL拉为低电平
 - 说明:通过这两个宏定义就可以模拟IIC的时钟电平SCL的高低变化了    
*********************************************************/
#define Set_IIC_SCL  {GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_PIN);}
#define Clr_IIC_SCL  {GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_PIN);}


/*********************************************************
 - I2C宏定义:
 - I2C数据线操作:
    - Set_IIC_SDA: 此处是将SDA拉为高电平
 - Clr_IIC_SDA: 此处是将SDA拉为低电平
 - READ_SDA  : 此处是读取SDA线上的位数据
 - 说明:通过这两个宏定义就可以模拟IIC的数据线SDA电平的高低变化了    
*********************************************************/
#define Set_IIC_SDA  {GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_PIN);}
#define Clr_IIC_SDA  {GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA_PIN);}
#define READ_SDA    (GPIO_ReadInputDataBit(IIC_SDA_PORT, IIC_SDA_PIN))

 


/*********************************************************
 - I2C模拟操作函数的声明:  
*********************************************************/
//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口    
void IIC_Start(void);    //发送IIC开始信号
void IIC_Stop(void);      //发送IIC停止信号
void IIC_Send_Byte(u8 txd);   //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void);     //IIC等待ACK信号
void IIC_Ack(void);     //IIC发送ACK信号
void IIC_NAck(void);    //IIC不发送ACK信号

/*********************************************************
 - I2C外部操作函数的声明:  
*********************************************************/
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);  
#endif

I2C .c

#include "i2c.h"
#include "delay.h"
/***************************************************************************
    - 功能描述:STM32f103 模拟IIC初始化函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:无
  - 返回说明:无
    - 函数实现步骤:
  (1) 配置好模拟IIC的PC11和PC12的引脚状态
  (2)并打开时钟
  (3)将SCL和SDA拉为高电平,使总线处于空闲状态
***************************************************************************/
void IIC_Init(void)
{         
 GPIO_InitTypeDef GPIO_InitStructure;
 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE ); 
 //打开GPIOC的时钟     
   
 GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
 //配置SCL,也就是PC12为推挽输出模式

 GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
 GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
 //配置SDA,也就是PC11为浮空输入模式


 Set_IIC_SCL;
 Set_IIC_SDA;
 //将SCL和SDA都拉为高电平,表示IIC总线处于高电平
}
/***************************************************************************
    - 功能描述:STM32f103 模拟IIC起始信号函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:无
  - 返回说明:无
    - 函数实现步骤:
  (1)首先将SDA配置为输出
  (2)在SCL为高电平期间,SDA有下降沿的变化
***************************************************************************/
void IIC_Start(void)
{
 SDA_OUT();     //sda线输出
 Set_IIC_SDA;     
 Set_IIC_SCL;
 delay_us(4);
  Clr_IIC_SDA;//START:when CLK is high,DATA change form high to low
 delay_us(4);
 Clr_IIC_SCL;//钳住I2C总线,准备发送或接收数据
}  
/***************************************************************************
    - 功能描述:STM32f103 模拟IIC终止信号函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:无
  - 返回说明:无
    - 函数实现步骤:
  (1)首先将SDA配置为输出
  (2)在SCL为高电平期间,SDA有上升沿的变化
***************************************************************************/
void IIC_Stop(void)
{
 SDA_OUT();//sda线输出
 Clr_IIC_SCL;
 Clr_IIC_SDA;//STOP:when CLK is high DATA change form low to high
  delay_us(4);
 Set_IIC_SCL;
 Set_IIC_SDA;//发送I2C总线结束信号
 delay_us(4);           
}

/***************************************************************************
    - 功能描述:STM32f103 模拟IIC等待应答函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:无  
  - 返回说明:返回值:1,接收应答失败;0,接收应答成功
    - 函数说明:
  (1)首先将SDA配置为输入
  (2)如果返回0,表示接收应答成功;如果为1,接收应答失败
  (3)注意在IIC_STOP()中 ,将SDA置为了输出,所以再满足250条件后,产中IIC停止线号,
    对输出线SDA读SDA输入值是为0的,所以才退出循环。
  (4)此函数为STM32主机等待从机的ACK函数
***************************************************************************/
u8 IIC_Wait_Ack(void)
{
 u8 ucErrTime=0;
 SDA_IN();      //SDA设置为输入 
 Set_IIC_SDA;delay_us(1);   
 Set_IIC_SCL;delay_us(1); 
 while(READ_SDA)
 {
  ucErrTime++;
  if(ucErrTime>250)
  {
   IIC_Stop();
   return 1;
  }
 }
 Clr_IIC_SCL;//时钟输出0    
 return 0; 
}
/***************************************************************************
    - 功能描述:STM32f103 模拟IIC应答信号函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:无
  - 返回说明:无
    - 函数实现步骤:
  (1)首先将SDA配置为输出
  (2)在SCL的一个时钟周期期间,SDA为低
  (3)此函数为STM32主机向从机发送ACK函数
***************************************************************************/
//产生ACK应答
void IIC_Ack(void)
{
 Clr_IIC_SCL;
 SDA_OUT();
 Clr_IIC_SDA;
 delay_us(2);
 Set_IIC_SCL;
 delay_us(2);
 Clr_IIC_SCL;
}
/***************************************************************************
    - 功能描述:STM32f103 模拟IIC不应答信号函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:无
  - 返回说明:无
    - 函数实现步骤:
  (1)首先将SDA配置为输出
  (2)在SCL的一个时钟周期期间,SDA为高电平
  (4)此函数为STM32主机不向从机发送ACK
***************************************************************************/    
void IIC_NAck(void)
{
 Clr_IIC_SCL;
 SDA_OUT();
 Set_IIC_SDA;
 delay_us(2);
 Set_IIC_SCL;
 delay_us(2);
 Clr_IIC_SCL;
}              
/***************************************************************************
    - 功能描述:STM32f103 模拟IIC 发送一个字节函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:无
  - 返回说明:无
    - 函数实现步骤:
  (1)首先将SDA配置为输出
  (2)在SCL为低电平期间,置位SDA的数据为0或者1,延时后拉高SCL,取走数据,循环8次
***************************************************************************/   
void IIC_Send_Byte(u8 txd)
{                       
    u8 t;  
 SDA_OUT();     
    Clr_IIC_SCL;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {             
        //IIC_SDA=(txd&0x80)>>7;
  if ((txd&0x80)>>7)  
   Set_IIC_SDA
  else Clr_IIC_SDA;
         txd<<=1;   
  delay_us(2);  
  Set_IIC_SCL;
  delay_us(2);
  Clr_IIC_SCL; 
  delay_us(2);
    } 
}

/***************************************************************************
    - 功能描述:STM32f103 模拟IIC 发送一个字节函数
    - 隶属模块:STM32 IIC操作
  - 函数属性:外部,使用户使用
  - 参数说明:ack 用于决定是是否回应ACK
  - 返回说明:无
    - 函数实现步骤:
  (1)首先将SDA配置为输入
  (2)在SCL的一个时钟周期后,读SDA的数据,保存在receive中
  (3)读1个字节,ack=1时,发送ACK,ack=0,发送nACK 

***************************************************************************/     
u8 IIC_Read_Byte(unsigned char ack)
{
 unsigned char i,receive=0;
 SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
 {
        Clr_IIC_SCL;
        delay_us(2);
  Set_IIC_SCL;
        receive<<=1;
        if(READ_SDA)receive++;  
  delay_us(1);
    }     
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK  
    return receive;
}

 

 

上面的函数,把STM32作为主机时I2C的功能已经全部描述了出来,至于操作什么I2C器件,那就需要该I2C的驱动函数了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
1
关闭 站长推荐上一条 /3 下一条