文章目录
一、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