MCU驱动:模拟IIC

一、Cubemx配置

时钟配置:
大部分配置相同,仅时钟配置部分因芯片系列和外置晶振不同而有所不同。配置界面中的/M中的M数值与外置晶振一样。
STM32F4系列:
在这里插入图片描述
STM32F1系列:
在这里插入图片描述
SDA和SCL引脚配置:
在这里插入图片描述

二、模拟IIC

GPIO配置

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA3 PA4 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_SET);//这句话自己加上,其他都是cubemx配置的	
}

源文件

#include "I2C.h"
#include "GY86.h"
#include "gpio.h"

//IO方向设置
//IO方向设置
//IO操作函数
#define MPU_IIC_SDA_H   HAL_GPIO_WritePin(GPIOA, SDA_Pin, GPIO_PIN_SET)
#define MPU_IIC_SDA_L   HAL_GPIO_WritePin(GPIOA, SDA_Pin, GPIO_PIN_RESET)
#define MPU_IIC_SCL_H   HAL_GPIO_WritePin(GPIOA, SCL_Pin, GPIO_PIN_SET)
#define MPU_IIC_SCL_L   HAL_GPIO_WritePin(GPIOA, SCL_Pin, GPIO_PIN_RESET)

#define MPU_IIC_SDA_Read  HAL_GPIO_ReadPin(GPIOA,SDA_Pin)

#define SDA_Write(XX)    HAL_GPIO_WritePin(GPIOA, SDA_Pin, (XX?GPIO_PIN_SET:GPIO_PIN_RESET))

#define SDA_Pin GPIO_PIN_4
#define SDA_GPIO_Port GPIOA
#define SCL_Pin GPIO_PIN_5
#define SCL_GPIO_Port GPIOA

void MPU_IIC_Delay(uint16_t us)
{
	uint8_t t=1;
	while(t--);
}

void MPU_SDA_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	__HAL_RCC_GPIOA_CLK_ENABLE();
	
	HAL_GPIO_WritePin(GPIOA, SDA_Pin, GPIO_PIN_RESET);
	
  GPIO_InitStruct.Pin = SDA_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
}
void MPU_SDA_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	__HAL_RCC_GPIOA_CLK_ENABLE();
	
	HAL_GPIO_WritePin(GPIOA, SDA_Pin, GPIO_PIN_RESET);
	
  GPIO_InitStruct.Pin = SDA_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}


void MPU_IIC_Start(void)
{
	MPU_SDA_OUT();     //sda线输出
	MPU_IIC_SDA_H;	  	  
	MPU_IIC_SCL_H;
	MPU_IIC_Delay(2);
 	MPU_IIC_SDA_L;//START:when CLK is high,DATA change form high to low 
	MPU_IIC_Delay(2);
	MPU_IIC_SCL_L;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void MPU_IIC_Stop(void)
{
	MPU_SDA_OUT();//sda线输出
	MPU_IIC_SCL_L;
	MPU_IIC_SDA_L;//STOP:when CLK is high DATA change form low to high
 	MPU_IIC_Delay(2);
	MPU_IIC_SCL_H;  
	MPU_IIC_SDA_H;//发送I2C总线结束信号
	MPU_IIC_Delay(2);							   	
}



//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
uint8_t MPU_IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	
	MPU_SDA_IN();      //SDA设置为输入  
	MPU_IIC_SDA_H;
	MPU_IIC_Delay(2);//2us	   
	MPU_IIC_SCL_H;
	MPU_IIC_Delay(2);//2us	 
	while(MPU_IIC_SDA_Read)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			MPU_IIC_Stop();
			return 1;
		}
	}
	MPU_IIC_SCL_L;//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void MPU_IIC_Ack(void)
{
	MPU_IIC_SCL_L;
	MPU_SDA_OUT();
	MPU_IIC_SDA_L;
	MPU_IIC_Delay(2);//2us
	MPU_IIC_SCL_H;
	MPU_IIC_Delay(2);//2us
	MPU_IIC_SCL_L;
}
//不产生ACK应答		    
void MPU_IIC_NAck(void)
{
	MPU_IIC_SCL_L;
	MPU_SDA_OUT();
	MPU_IIC_SDA_H;
	MPU_IIC_Delay(2);//2us
	MPU_IIC_SCL_H;
	MPU_IIC_Delay(2);//2us
	MPU_IIC_SCL_L;
}


//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void MPU_IIC_Send_Byte(uint8_t txd)
{                        
		uint8_t t;   	
		MPU_SDA_OUT(); 	    
		MPU_IIC_SCL_L;//拉低时钟开始数据传输
		for(t=0;t<8;t++)
		{              
			SDA_Write((txd&0x80)>>7);
			txd<<=1; 	  		
			MPU_IIC_Delay(2); 
			MPU_IIC_SCL_H;				
			MPU_IIC_Delay(2);
			MPU_IIC_SCL_L;
			MPU_IIC_Delay(2);
		}	 
} 	    
//1个字节,ack=1时,发送ACK,ack=0,发送nACK   
uint8_t MPU_IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	MPU_SDA_IN();//SDA设置为输入
  for(i=0;i<8;i++ )
	{
			MPU_IIC_SCL_L; 
			MPU_IIC_Delay(2);
			MPU_IIC_SCL_H;
			receive<<=1;
			if(MPU_IIC_SDA_Read)
			receive++;   
			MPU_IIC_Delay(3); 
    }					 
   if (!ack)
      MPU_IIC_NAck();//发送nACK
   else
      MPU_IIC_Ack(); //发送ACK   
   return receive;
}



/******************读寄存器操作,单次与连续*****************/

//IIC写一个字节 
//reg:寄存器地址
//data:数据
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data) 				 
{ 
    MPU_IIC_Start(); 
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令	
	if(MPU_IIC_Wait_Ack())	//等待应答
	{
		MPU_IIC_Stop();		 
		return 1;		
	}
    MPU_IIC_Send_Byte(reg);	//写寄存器地址
    MPU_IIC_Wait_Ack();		//等待应答 
	MPU_IIC_Send_Byte(data);//发送数据
	if(MPU_IIC_Wait_Ack())	//等待ACK
	{
		MPU_IIC_Stop();	 
		return 1;		 
	}		 
    MPU_IIC_Stop();	 
	return 0;
}

//IIC读一个字节 
//reg:寄存器地址 
//返回值:读到的数据
uint8_t MPU_Read_Byte(uint8_t reg)
{
	uint8_t res;
    MPU_IIC_Start(); 
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令	
	while(MPU_IIC_Wait_Ack());		//等待应答 
    MPU_IIC_Send_Byte(reg);	//写寄存器地址
    while(MPU_IIC_Wait_Ack());		//等待应答
    MPU_IIC_Start();
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);//发送器件地址+读命令	
    while(MPU_IIC_Wait_Ack());		//等待应答 
	res=MPU_IIC_Read_Byte(0);//读取数据,发送nACK 
    MPU_IIC_Stop();			//产生一个停止条件 
	return res;		
}

//IIC连续写
//addr:器件地址 
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Write_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{
	uint8_t i; 
    MPU_IIC_Start(); 
	MPU_IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令	
	if(MPU_IIC_Wait_Ack())	//等待应答
	{
		MPU_IIC_Stop();		 
		return 1;		
	}
    MPU_IIC_Send_Byte(reg);	//写寄存器地址
    MPU_IIC_Wait_Ack();		//等待应答
	for(i=0;i<len;i++)
	{
		MPU_IIC_Send_Byte(buf[i]);	//发送数据
		if(MPU_IIC_Wait_Ack())		//等待ACK
		{
			MPU_IIC_Stop();	 
			return 1;		 
		}		
	}    
    MPU_IIC_Stop();	 
	return 0;	
} 
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Read_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{ 
 	MPU_IIC_Start(); 
	MPU_IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令	
	if(MPU_IIC_Wait_Ack())	//等待应答
	{
		MPU_IIC_Stop();		 
		return 1;		
	}
    MPU_IIC_Send_Byte(reg);	//写寄存器地址
    MPU_IIC_Wait_Ack();		//等待应答
    MPU_IIC_Start();
	MPU_IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令	
    MPU_IIC_Wait_Ack();		//等待应答 
	while(len)
	{
		if(len==1)
			*buf=MPU_IIC_Read_Byte(0);//读数据,发送nACK 
		else 
			*buf=MPU_IIC_Read_Byte(1);		//读数据,发送ACK  
		len--;
		buf++; 
	}    
    MPU_IIC_Stop();	//产生一个停止条件 
	return 0;	
}

头文件

#ifndef _I2C_H_
#define _I2C_H_
#include  "stm32f1xx_hal.h"


void MPU_IIC_Start(void);
void MPU_IIC_Stop(void);


uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data) ;
uint8_t MPU_Read_Byte(uint8_t reg);
uint8_t MPU_Write_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf);
uint8_t MPU_Read_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf);
#endif
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值