最近做一个实验室里的小项目,需要用stm32来读取ADXL345三轴加速度的值,本来硬件I2C都调好了,可是后来和实验室合作的一个公司给的板子却没把硬件I2C的端口给引出来,太伤心了,我又得重新调一下软件I2C,因为我才刚刚接触stm32,以前也从未接触过单片机之类的编程,所以费了很大的劲,对于网上给的程序,我找了几个都不好用,无奈之下又临时学了I2C协议,参考着网上各个版本的程序,对照着I2C的时序图,一点点的写出来了这个程序,幸好折腾一天后,程序居然好用,心中实在是高兴的很。
I2C代码如下::
#ifndef __AZHU_I2C_H
#define __AZHU_I2C_H
#include "stm32f10x.h"
#define PIN_SCL GPIO_Pin_6
#define PIN_SDA GPIO_Pin_5
#define I2C_PORT GPIOA
//SDA的方向设置
void SDA_IN(void);
void SDA_OUT(void);
//I2C所有操作函数
void I2C_Init(void); //初始化I2C的IO口
void I2C_Start(void); //发送I2C开始信号
void I2C_Stop(void); //发送I2C停止信号
void I2C_Send_Byte(u8 txd); //I2C发送一个字节
u8 I2C_Read_Byte(unsigned char ack); //I2C读取一个字节
u8 I2C_Wait_Ack(void); //I2C等待ACK信号
void I2C_Ack(void); //I2C发送ACK信号
void I2C_NAck(void); //I2C不发送ACK信号
void I2C_Write_One_Byte(u8 daddr,u8 addr,u8 data); //写一个字节
u8 I2C_Read_One_Byte(u8 daddr,u8 addr); //读一个字节
void delay_us(u32 m); //延时函数
#endif
#include "azhu_i2c.h"
void I2C_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); //使能A口时钟
GPIO_InitStructure.GPIO_Pin = PIN_SCL | PIN_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_PORT, &GPIO_InitStructure);
}
//产生I2C开始信号
void I2C_Start(void)
{
SDA_OUT(); //sda线输出
GPIO_SetBits(GPIOA,PIN_SDA); //SDA =1
delay_us(10);
GPIO_SetBits(GPIOA,PIN_SCL); //SCL=1
delay_us(10);
GPIO_ResetBits(GPIOA,PIN_SDA);//SDA=0
delay_us(10);
GPIO_ResetBits(GPIOA,PIN_SCL);//SCL=0
}
//产生I2C停止信号
void I2C_Stop(void)
{
SDA_OUT(); //sda线输出
GPIO_ResetBits(GPIOA,PIN_SDA);
delay_us(10);
GPIO_SetBits(GPIOA,PIN_SCL);
delay_us(10);
GPIO_SetBits(GPIOA,PIN_SDA);
delay_us(10);
GPIO_ResetBits(GPIOA, PIN_SCL);//SCL=0;
delay_us(10);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 I2C_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
GPIO_SetBits(GPIOA,PIN_SDA);
delay_us(5);
GPIO_SetBits(GPIOA,PIN_SCL);
delay_us(5);
while(GPIO_ReadInputDataBit(GPIOA,PIN_SDA))
{
ucErrTime++;
if(ucErrTime>250)
{
I2C_Stop();
return 1;
}
}
GPIO_ResetBits(GPIOA, PIN_SCL);
return 0;
}
//产生ACK应答
void I2C_Ack(void)
{
GPIO_ResetBits(GPIOA,PIN_SCL);
SDA_OUT();
GPIO_ResetBits(GPIOA,PIN_SDA);
delay_us(5);
GPIO_SetBits(GPIOA,PIN_SCL);
delay_us(5);
GPIO_ResetBits(GPIOA,PIN_SCL);
}
//不产生ACK应答
void I2C_NAck(void)
{
GPIO_ResetBits(GPIOA,PIN_SCL);
SDA_OUT();
GPIO_SetBits(GPIOA,PIN_SDA);
delay_us(5);
GPIO_SetBits(GPIOA,PIN_SCL);
delay_us(5);
GPIO_ResetBits(GPIOA,PIN_SCL);
}
//I2C发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void I2C_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
GPIO_ResetBits(GPIOA,PIN_SCL);//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
if((txd&0x80)==0x80)
{GPIO_SetBits(GPIOA, PIN_SDA);}//SDA=1,写 1
else
{GPIO_ResetBits(GPIOA, PIN_SDA);}//SDA=0,写 0
txd<<=1;
delay_us(5); //对TEA5767这三个延时都是必须的
GPIO_SetBits(GPIOA,PIN_SCL);
delay_us(5);
GPIO_ResetBits(GPIOA,PIN_SCL);
delay_us(5);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 I2C_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
GPIO_ResetBits(GPIOA,PIN_SCL);
delay_us(5);
GPIO_SetBits(GPIOA,PIN_SCL);
receive<<=1;
if(GPIO_ReadInputDataBit(GPIOA,PIN_SDA))receive++;
delay_us(5);
}
if (!ack)
I2C_NAck();//发送nACK
else
I2C_Ack(); //发送ACK
return receive;
}
void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = PIN_SDA;
GPIO_Init(GPIOA, &GPIO_InitStruct );
}
void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = PIN_SDA;
GPIO_Init(GPIOA, &GPIO_InitStruct );
}
void delay_us(u32 m)
{
while(m--)
{
}
}
作者:azhuty
来源:CSDN
原文:https://blog.csdn.net/azhuty/article/details/22264999
版权声明:本文为博主原创文章,转载请附上博文链接!