最近实验室需要做一个小项目。stm32来读取ADXL345三轴加速值,原硬件I2C都调好了,但是后来和实验室合作的公司给的板子没有硬件I2C引出端口太难过了。我得重新调整软件I2C,因为我刚接触stm32.我以前从未接触过单片机等编程,所以我花了很多精力,对于网上给的程序,我找了几个都不好用,但是我暂时学会了I2C协议,参考各种在线版本的程序,比较I2C时序图,一点一点写出这个程序,幸好折腾了一天,程序居然好用,心里真的很开心。
I2C代码如下:
azhu_i2c.h:
#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
azhu_i2c.c:
#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); //对TEA五七六七这三个延迟都是必须的 GPIO_SetBits(GPIOA,PIN_SCL); delay_us(5); GPIO_ResetBits(GPIOA,PIN_SCL); delay_us(5); } } ///读一个字节,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, &GPI_InitStruct );
}
void delay_us(u32 m)
{
while(m--)
{
}
}
作者:azhuty 来源:CSDN 原文:https://blog.csdn.net/azhuty/article/details/22264999 版权声明:本文为博主原创文章,转载请附上博文链接!