一种基于STM32标准库简易多端口IIC配置方式

一种基于STM32标准库简易多端口IIC配置方式


以下是具体代码:仅供参考
//= .c文件=============
#include “IIC.h”
#include “delay.h”
/*
by lewis-- 2019.8
*/
SOFT_I2C_TypeDef IIC_1 =
{
GPIOB, GPIO_Pin_6,//SCL
GPIOB, GPIO_Pin_7,//SDA
};

int Log2(int data)
{
unsigned char x=0;
while(data>1)
{
data=/2;
x++;
}
return x;
}

void IIC_Init(SOFT_I2C_TypeDef* IIC)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//

GPIO_InitStructure.GPIO_Pin = IIC->SCL_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(IIC->SCL_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = IIC->SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//
GPIO_Init(IIC->SDA_PORT, &GPIO_InitStructure);//

IIC_SCL(1,IIC);
IIC_SDA(1,IIC);

}

void IIC_Start(SOFT_I2C_TypeDef* IIC)
{
SDA_OUT(IIC); //
IIC_SDA(1,IIC);
IIC_SCL(1,IIC);
Delay_1us(4);
IIC_SDA(0,IIC);//
Delay_1us(4);
IIC_SCL(0,IIC);//
}
//产生IIC停止信号
void IIC_Stop(SOFT_I2C_TypeDef* IIC)
{
SDA_OUT(IIC);//
IIC_SCL(0,IIC);
IIC_SDA(0,IIC);//
Delay_1us(2);
IIC_SCL(1,IIC);
Delay_1us(2);
IIC_SDA(1,IIC);//
Delay_1us(2);
}

u8 IIC_Wait_Ack(SOFT_I2C_TypeDef* IIC)
{
u8 Timeout=0;
SDA_IN(IIC); //SDA设置为输入
IIC_SDA(1,IIC);
Delay_1us(1);
IIC_SCL(1,IIC);
Delay_1us(1);
while(READ_SDA(IIC))
{
Timeout++;
if(Timeout>250)
{
IIC_Stop(IIC);
return 1;
}
}
IIC_SCL(0,IIC);//时钟输出0
return 0;
}

void IIC_Ack(SOFT_I2C_TypeDef* IIC)
{
IIC_SCL(0,IIC);
SDA_OUT(IIC);
IIC_SDA(0,IIC);
Delay_1us(1);
IIC_SCL(1,IIC);
Delay_1us(1);
IIC_SCL(0,IIC);
}

void IIC_NAck(SOFT_I2C_TypeDef* IIC)
{
IIC_SCL(0,IIC);
SDA_OUT(IIC);
IIC_SDA(1,IIC);
Delay_1us(1);
IIC_SCL(1,IIC);
Delay_1us(1);
IIC_SCL(0,IIC);
}

void IIC_Send_Byte(SOFT_I2C_TypeDef* IIC,u8 data)
{
u8 t;
SDA_OUT(IIC);
IIC_SCL(0,IIC);//
for(t=0;t<8;t++)
{
if(((data&0x80)>>7) == 1)
IIC_SDA(1,IIC);
else
IIC_SDA(0,IIC);
data<<= 1;
Delay_1us(2); //
IIC_SCL(1,IIC);
Delay_1us(2);
IIC_SCL(0,IIC);
Delay_1us(2);
}
}
int IIC_Send_Nbyte(SOFT_I2C_TypeDef* IIC,uint8_t addr,uint8_t* wrbuf,uint8_t cmd)
{
uint8_t i ;
uint8_t wrbuf_len;
wrbuf_len=strlen((char*)wrbuf); //
IIC_Start(IIC);
IIC_Send_Byte(IIC,addr|0x00);
if((IIC_Wait_Ack(IIC))) return 0;
IIC_Send_Byte(IIC,cmd);
if((IIC_Wait_Ack(IIC))) return 0;
for(i=0;i<wrbuf_len;i++)
{
IIC_Send_Byte(IIC,wrbuf[i]);
if((IIC_Wait_Ack(IIC))) return 0;
}
IIC_Stop(IIC);
return 1;
}

u8 IIC_Read_Byte(SOFT_I2C_TypeDef* IIC,uint8_t ACk)
{
unsigned char i,receive=0;
SDA_IN(IIC);
for(i=0;i<8;i++ )
{
IIC_SCL(0,IIC);
Delay_1us(2);
IIC_SCL(1,IIC);
receive<<=1;
if(READ_SDA(IIC))receive++;
Delay_1us(1);
}
if (!ACk)
IIC_NAck(IIC);
else
IIC_Ack(IIC);
return receive;
}

int IIC_Read_Nbyte(SOFT_I2C_TypeDef* IIC,uint8_t addr,uint8_t cmd,uint8_t rbuf,int ACK)
{
uint8_t i;
IIC_Start(IIC);
IIC_Send_Byte(IIC,addr|0x00);
if((IIC_Wait_Ack(IIC))) return 0;
IIC_Send_Byte(IIC,cmd);
if((IIC_Wait_Ack(IIC))) return 0;
IIC_Start(IIC);
IIC_Send_Byte(IIC,addr|0x01);
if((IIC_Wait_Ack(IIC))) return 0;
for(i=0;ACK>0;i++)
{
rbuf[i]=IIC_Read_Byte(IIC,ACK–);
}
IIC_Stop(IIC);
return 1;
}
//.h文件=======
#include “stm32f4xx.h”
#include “stm32f4xx_gpio.h”
#include “math.h”
/

by lewis-- 2019.8
*/
//IO方向设置
//系统log()耗时太长,导致只能读取一个字节数据
//#define SDA_IN(IIC) {IIC->SDA_PORT->MODER&=~(3<<((uint8_t)(log2(IIC->SDA_PIN))*2));IIC->SDA_PORT->MODER|=0<<((uint8_t)(log2(IIC->SDA_PIN))*2);} //
//#define SDA_OUT(IIC) {IIC->SDA_PORT->MODER&=~(3<<((uint8_t)(log2(IIC->SDA_PIN))*2));IIC->SDA_PORT->MODER|=1<<((uint8_t)(log2(IIC->SDA_PIN))*2);} //
//#define SCL_OUT(IIC) {IIC->SCL_PORT->MODER&=~(3<<((uint8_t)(log2(IIC->SCL_PIN))*2));IIC->SCL_PORT->MODER|=1<<((uint8_t)(log2(IIC->SCL_PIN))*2);} //

#define SDA_IN(IIC) {IIC->SDA_PORT->MODER&=~(3<<((uint8_t)(Log2(IIC->SDA_PIN))*2));IIC->SDA_PORT->MODER|=0<<((uint8_t)(Log2(IIC->SDA_PIN))*2);} //
#define SDA_OUT(IIC) {IIC->SDA_PORT->MODER&=~(3<<((uint8_t)(Log2(IIC->SDA_PIN))*2));IIC->SDA_PORT->MODER|=1<<((uint8_t)(Log2(IIC->SDA_PIN))*2);} //
#define SCL_OUT(IIC) {IIC->SCL_PORT->MODER&=~(3<<((uint8_t)(Log2(IIC->SCL_PIN))*2));IIC->SCL_PORT->MODER|=1<<((uint8_t)(Log2(IIC->SCL_PIN))*2);} //

#define IIC_SCL(x,IIC) (x ? GPIO_SetBits(IIC->SCL_PORT, IIC->SCL_PIN): GPIO_ResetBits(IIC->SCL_PORT, IIC->SCL_PIN))
#define IIC_SDA(x,IIC) (x ? GPIO_SetBits(IIC->SDA_PORT, IIC->SDA_PIN): GPIO_ResetBits(IIC->SDA_PORT, IIC->SDA_PIN))

#define READ_SDA(IIC) GPIO_ReadInputDataBit(IIC->SDA_PORT, IIC->SDA_PIN)

typedef struct SoftIIC
{
GPIO_TypeDef* SCL_PORT;
uint16_t SCL_PIN;
GPIO_TypeDef* SDA_PORT;
uint16_t SDA_PIN;
}SOFT_I2C_TypeDef;

int Log2(int data);

extern SOFT_I2C_TypeDef IIC_1 ;

void IIC_Init(SOFT_I2C_TypeDef* IIC);
void IIC_Start(SOFT_I2C_TypeDef* IIC);
void IIC_Stop(SOFT_I2C_TypeDef* IIC);
u8 IIC_Wait_Ack(SOFT_I2C_TypeDef* IIC);
void IIC_Ack(SOFT_I2C_TypeDef* IIC);
void IIC_NAck(SOFT_I2C_TypeDef* IIC);
void IIC_Send_Byte(SOFT_I2C_TypeDef* IIC,u8 txd);
int IIC_Send_Nbyte(SOFT_I2C_TypeDef* IIC,uint8_t addr,uint8_t* wrbuf,uint8_t cmd);
u8 IIC_Read_Byte(SOFT_I2C_TypeDef* IIC,unsigned char ack);
int IIC_Read_Nbyte(SOFT_I2C_TypeDef* IIC,uint8_t addr,uint8_t cmd,uint8_t *rbuf,int ACK);

#endif

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IIC是一种串行通信协议,通常用于连接微控制器和各种外设,如传感器和存储器。在STM32中,可以使用硬件IIC接口来进行通信,但是有时候可能需要在没有硬件IIC接口的情况下进行IIC通信,这时候可以使用软件模拟IIC。 在STM32HAL中,可以使用GPIO模块来模拟IIC通信。具体实现步骤如下: 1. 定义IIC的GPIO引脚 首先需要定义IIC的GPIO引脚,包括SCL和SDA引脚。可以使用STM32的GPIO模块来定义这些引脚。 ```c #define SCL_PIN GPIO_PIN_10 #define SCL_PORT GPIOB #define SDA_PIN GPIO_PIN_11 #define SDA_PORT GPIOB ``` 2. 初始化GPIO引脚 在使用GPIO引脚之前,需要进行初始化。可以使用HAL提供的GPIO初始化函数来初始化引脚。 ```c GPIO_InitTypeDef GPIO_InitStruct = {0}; /*Configure GPIO pins : SCL_PIN SDA_PIN */ GPIO_InitStruct.Pin = SCL_PIN|SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 设置为开漏输出模式 GPIO_InitStruct.Pull = GPIO_NOPULL; // 不使用上拉或下拉电阻 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // GPIO时钟频率 HAL_GPIO_Init(SCL_PORT, &GPIO_InitStruct); ``` 3. 定义IIC操作函数 定义IIC的操作函数,包括发送数据、接收数据和等待应答等。 ```c void IIC_Start(void) { SDA_HIGH(); SCL_HIGH(); HAL_Delay(1); SDA_LOW(); HAL_Delay(1); SCL_LOW(); } void IIC_Stop(void) { SDA_LOW(); SCL_HIGH(); HAL_Delay(1); SDA_HIGH(); HAL_Delay(1); } void IIC_SendByte(uint8_t byte) { uint8_t i; for (i = 0; i < 8; i++) { if ((byte & 0x80) == 0x80) SDA_HIGH(); else SDA_LOW(); HAL_Delay(1); SCL_HIGH(); HAL_Delay(1); SCL_LOW(); byte <<= 1; } SDA_HIGH(); HAL_Delay(1); SCL_HIGH(); HAL_Delay(1); SCL_LOW(); } uint8_t IIC_RecvByte(void) { uint8_t i; uint8_t byte = 0; SDA_HIGH(); HAL_Delay(1); for (i = 0; i < 8; i++) { byte <<= 1; SCL_HIGH(); HAL_Delay(1); if (SDA_READ()) byte++; SCL_LOW(); HAL_Delay(1); } return byte; } uint8_t IIC_WaitAck(void) { uint8_t ack; SDA_HIGH(); HAL_Delay(1); SCL_HIGH(); HAL_Delay(1); if (SDA_READ()) ack = 1; else ack = 0; SCL_LOW(); HAL_Delay(1); return ack; } void IIC_SendAck(uint8_t ack) { if (ack) SDA_HIGH(); else SDA_LOW(); HAL_Delay(1); SCL_HIGH(); HAL_Delay(1); SCL_LOW(); HAL_Delay(1); } ``` 4. 定义宏函数 定义宏函数来简化IIC操作函数的调用。例如,可以定义宏函数`SDA_HIGH()`来调用`HAL_GPIO_WritePin()`函数来设置SDA引脚为高电平。 ```c #define SDA_HIGH() HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET) #define SDA_LOW() HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_RESET) #define SDA_READ() HAL_GPIO_ReadPin(SDA_PORT, SDA_PIN) #define SCL_HIGH() HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET) #define SCL_LOW() HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET) ``` 5. 调用IIC操作函数 使用定义的宏函数和IIC操作函数来进行IIC通信。例如,可以使用以下代码来发送一个字节。 ```c IIC_Start(); IIC_SendByte(0xA0); IIC_WaitAck(); IIC_SendByte(0x01); IIC_WaitAck(); IIC_Stop(); ``` 以上就是基于STM32HAL的软件模拟IIC的实现步骤。需要注意的是,在实现过程中需要根据具体的硬件和需求进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值