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的驱动函数了。
文章评论(0条评论)
登录后参与讨论