【开源】六足机器人2.0之软件IIC

前言

         所用芯片STM32H750VBT6,采用hal库实现。

1.IIC简介

        在 I2C 总线中,每个设备都必须有一个唯一的地址,用于识别该设备。地址位的数目由总线规范给出。在数据传输过程中,发送主机先将设备地址发送到总线上,接收设备会检测该地址并发送应答信号。若该设备在总线上没有被发现,则总线会终止数据传输。

I2C 数据传输格式包括写操作和读操作两种。在写操作中,发送主机会先向设备发送一个字节的控制信息,然后跟随数据字节。在读操作中,发送主机先向设备发送控制信息,并向设备发出读地址,接着由设备向发送主机返回数据。具体的数据传输格式会随着不同的设备而有所不同。

        在软件实现 I2C 总线时,需要使用相应的 I2C 库函数,通过开启 I2C 模块并设置 I2C 总线参数来实现数据传输。而在硬件实现中,需要使用 I2C 接口芯片或 MCU 的硬件 I2C 模块来实现数据传输。软件 I2C 适用于资源受限的嵌入式系统,硬件 I2C 适用于需要高速、高可靠性和高精度的应用。

2.代码(可移植) 

        myiic.c文件

#include "i2c_2.h"
#include "tim.h"
#include "sys.h"

#define DELAY_TIME 20

void SCCB_Init(void)
{				
  GPIO_InitTypeDef  GPIO_InitStructure;
  __HAL_RCC_GPIOB_CLK_ENABLE();//使能GPIOB时钟
  //PB8,PB9初始化设置
  GPIO_InitStructure.Pin = GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;  //PB8、PB9 推挽输出
  GPIO_InitStructure.Pull = GPIO_PULLUP;
  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8|GPIO_PIN_9,GPIO_PIN_SET);	   
}		

//配置SDA引脚为输入模式
void SDA_Input_Mode2(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = SDA2;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
//配置SDA引脚为输出模式
void SDA_Output_Mode2(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = SDA2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
//SDA引脚输出
void SDA_Output2(uint16_t val )
{
	if(val)
		HAL_GPIO_WritePin(GPIOB, SDA2, GPIO_PIN_SET);    
	else
        HAL_GPIO_WritePin(GPIOB, SDA2, GPIO_PIN_RESET);
        
}
//SCL引脚输出
void SCL_Output2( uint16_t val )
{
	if(val)
		HAL_GPIO_WritePin(GPIOB, SCL2, GPIO_PIN_SET);
	else
		 HAL_GPIO_WritePin(GPIOB, SCL2, GPIO_PIN_RESET);
}
//读取SDA引脚状态
uint8_t SDA_Input2(void)
{
	return HAL_GPIO_ReadPin(GPIOB, SDA2);
}

//I2C总线启动信号
void SCCB_Start(void)
{
    SDA_Output2(1);
    delay_us(DELAY_TIME);
    SCL_Output2(1);
    delay_us(DELAY_TIME);
    SDA_Output2(0);
    delay_us(DELAY_TIME);
    SCL_Output2(0);
    delay_us(DELAY_TIME);
}

//I2C总线停止信号
void SCCB_Stop(void)
{
    SCL_Output2(0);
    delay_us(DELAY_TIME);
    SDA_Output2(0);
    delay_us(DELAY_TIME);
    SCL_Output2(1);
    delay_us(DELAY_TIME);
    SDA_Output2(1);
    delay_us(DELAY_TIME);

}

//等待应答
unsigned char I2CWaitAck2(void)
{
    unsigned short cErrTime = 5;
    SDA_Input_Mode2();
    delay_us(DELAY_TIME);
    SCL_Output2(1);
    delay_us(DELAY_TIME);
    while(SDA_Input2())
    {
        cErrTime--;
        delay_us(DELAY_TIME);
        if (0 == cErrTime)
        {
            SDA_Output_Mode2();
            SCCB_Stop();
            return ERROR;
        }
    }
    SCL_Output2(0);
    SDA_Output_Mode2();
    delay_us(DELAY_TIME);
    return SUCCESS;
}

//发送应答
void I2CSendAck2(void)
{
    SDA_Output2(0);
    delay_us(DELAY_TIME);
    delay_us(DELAY_TIME);
    SCL_Output2(1);
    delay_us(DELAY_TIME);
    SCL_Output2(0);
    delay_us(DELAY_TIME);

}

//发送非应答
void SCCB_No_Ack(void)
{
    SDA_Output2(1);
    delay_us(DELAY_TIME);
    delay_us(DELAY_TIME);
    SCL_Output2(1);
    delay_us(DELAY_TIME);
    SCL_Output2(0);
    delay_us(DELAY_TIME);

}

//发送一个字节数据
u8 SCCB_WR_Byte(u8 cSendByte)
{
    unsigned char  i = 8;
    while (i--)
    {
        SCL_Output2(0);
        delay_us(DELAY_TIME);
        SDA_Output2(cSendByte & 0x80);
        delay_us(DELAY_TIME);
        cSendByte += cSendByte;
        delay_us(DELAY_TIME);
        SCL_Output2(1);
        delay_us(DELAY_TIME);
    }
    SCL_Output2(0);
    delay_us(DELAY_TIME);
    return 0;
}

//接收一个字节数据
unsigned char SCCB_RD_Byte(void)
{
    unsigned char i = 8;
    unsigned char cR_Byte = 0;
    SDA_Input_Mode2();
    while (i--)
    {
        cR_Byte += cR_Byte;
        SCL_Output2(0);
        delay_us(DELAY_TIME);
        delay_us(DELAY_TIME);
        SCL_Output2(1);
        delay_us(DELAY_TIME);
        cR_Byte |=  SDA_Input2();
    }
    SCL_Output2(0);
    delay_us(DELAY_TIME);
    SDA_Output_Mode2();
    return cR_Byte;
}

//写寄存器
//返回值:0,成功;1,失败.
u8 SCCB_WR_Reg(u8 reg,u8 data)
{
	// u8 res=0;
	// SCCB_Start(); 					//启动SCCB传输
	// if(SCCB_WR_Byte(SCCB_ID))res=1;	//写器件ID	  
	// delay_us(100);
  	// if(SCCB_WR_Byte(reg))res=1;		//写寄存器地址	  
	// delay_us(100);
  	// if(SCCB_WR_Byte(data))res=1; 	//写数据	 
  	// SCCB_Stop();	  
  	// return	res;
    u8 res=0;
	SCCB_Start(); 					//启动SCCB传输
	if(SCCB_WR_Byte(SCCB_ID))res=1;	//写器件ID	  
	I2CWaitAck2();
  	if(SCCB_WR_Byte(reg))res=1;		//写寄存器地址	  
	I2CWaitAck2();
  	if(SCCB_WR_Byte(data))res=1; 	//写数据
    I2CWaitAck2();	 
  	SCCB_Stop();	  
  	return	res;
}		  					    
//读寄存器
//返回值:读到的寄存器值
u8 SCCB_RD_Reg(u8 reg)
{
	// u8 val=0;
	// SCCB_Start(); 				//启动SCCB传输
	// SCCB_WR_Byte(SCCB_ID);		//写器件ID	  
	// delay_us(4);	 
  	// SCCB_WR_Byte(reg);			//写寄存器地址	  
	// delay_us(100);	  
	// SCCB_Stop();   
	// delay_us(100);	   
	// //设置寄存器地址后,才是读
	// SCCB_Start();
	// SCCB_WR_Byte(SCCB_ID|0X01);	//发送读命令	  
	// delay_us(100);
  	// val=SCCB_RD_Byte();		 	//读取数据
  	// SCCB_No_Ack();
  	// SCCB_Stop();
  	// return val;
    u8 val=0;
	SCCB_Start(); 				//启动SCCB传输
	SCCB_WR_Byte(SCCB_ID);		//写器件ID	  
	I2CWaitAck2();
  	SCCB_WR_Byte(reg);			//写寄存器地址	  
	I2CWaitAck2();	  
	SCCB_Stop(); 

	delay_us(100);	   

	//设置寄存器地址后,才是读
	SCCB_Start();
	SCCB_WR_Byte(SCCB_ID|0X01);	//发送读命令	  
	I2CWaitAck2();
  	val=SCCB_RD_Byte();		 	//读取数据
  	SCCB_No_Ack();
  	SCCB_Stop();
  	return val;
}

        myiic.h文件

#ifndef __I2C_2_H
#define __I2C_2_H

#include "main.h"
#include "sys.h"
//I2C总线引脚定义
#define SCL2	GPIO_PIN_8
#define SDA2	GPIO_PIN_9

//接口函数


#define SCCB_ID   			0X60  			//OV2640的ID

///
void SCCB_Init(void);
void SCCB_Start(void);
void SCCB_Stop(void);
void SCCB_No_Ack(void);
u8 SCCB_WR_Byte(u8 cSendByte);
u8 SCCB_RD_Byte(void);
u8 SCCB_WR_Reg(u8 reg,u8 data);
u8 SCCB_RD_Reg(u8 reg);

unsigned char I2CWaitAck2(void);
void I2CSendAck2(void);


#endif

PS.调试有问题可以留言,不同型号的芯片可能操作上有小变化。 

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gui林

你的热爱是我更新的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值