[应用相关] STM32软件模拟IIC

[复制链接]
969|15
八层楼 发表于 2025-9-8 15:22 | 显示全部楼层 |阅读模式
模拟IIC
SCL = PB6
SDA = PB7

.c文件


#include "MCU_DRV_Soft_IIC.h"

/************************************************************************
函数名称:IIC_1_Init
函数功能:IIC初始化
输入参数:
返回参数:
其他说明:
************************************************************************/
void IIC_1_Init(void)
{
        GPIO_InitTypeDef GPIO_Initure;

        __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
        // PB6,7初始化设置
        GPIO_Initure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;                // 推挽输出
        GPIO_Initure.Pull = GPIO_PULLUP;                                // 上拉
        GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; // 快速
        HAL_GPIO_Init(GPIOB, &GPIO_Initure);

        IIC_1_SDA = 1;
        IIC_1_SCL = 1;
}
/************************************************************************
函数名称:IIC_1_Start
函数功能:产生IIC_1起始信号
输入参数:
返回参数:
其他说明:
************************************************************************/
void IIC_1_Start(void)
{
        // START:当CLK为高电平时,DATA从高电平变为低电平
        IIC_1_SDA_OUT(); // sda线输出
        IIC_1_SDA = 1;
        IIC_1_SCL = 1;
        delay_us(4);
        IIC_1_SDA = 0;
        delay_us(4);
        IIC_1_SCL = 0; // 钳住I2C总线,准备发送或接收数据
}
/************************************************************************
函数名称:IIC_1_Stop
函数功能:产生IIC_1停止信号
输入参数:
返回参数:
其他说明:
************************************************************************/
void IIC_1_Stop(void)
{
        // STOP:当CLK为高电平时,DATA从低电平变为高电平
        IIC_1_SDA_OUT(); // sda线输出
        IIC_1_SCL = 0;
        IIC_1_SDA = 0;
        delay_us(4);
        IIC_1_SCL = 1;
        delay_us(4);
        IIC_1_SDA = 1; // 发送I2C总线结束信号
}
/************************************************************************
函数名称:IIC_1_Wait_Ack
函数功能:等待应答信号到来
输入参数:
返回参数:1,接收应答失败 0,接收应答成功
其他说明:
************************************************************************/
u8 IIC_1_Wait_Ack(void)
{
        u8 ucErrTime = 0;
        IIC_1_SDA_IN(); // SDA设置为输入
        IIC_1_SDA = 1;
        delay_us(1);
        IIC_1_SCL = 1;
        delay_us(1);
        while (IIC_1_READ_SDA)
        {
                ucErrTime++;
                if (ucErrTime > 250)
                {
                        IIC_1_Stop();
                        return 1;
                }
        }
        IIC_1_SCL = 0; // 时钟输出0
        return 0;
}

/************************************************************************
函数名称:IIC_1_Ack
函数功能:产生ACK应答
输入参数:
返回参数:
其他说明:
************************************************************************/
void IIC_1_Ack(void)
{
        IIC_1_SCL = 0;
        IIC_1_SDA_OUT();
        IIC_1_SDA = 0;
        delay_us(2);
        IIC_1_SCL = 1;
        delay_us(2);
        IIC_1_SCL = 0;
}
/************************************************************************
函数名称:IIC_1_NAck
函数功能:不产生ACK应答
输入参数:
返回参数:
其他说明:
************************************************************************/
void IIC_1_NAck(void)
{
        IIC_1_SCL = 0;
        IIC_1_SDA_OUT();
        IIC_1_SDA = 1;
        delay_us(2);
        IIC_1_SCL = 1;
        delay_us(2);
        IIC_1_SCL = 0;
}
/************************************************************************
函数名称:IIC_1_Send_Byte
函数功能:IIC_1发送一个字节
输入参数:
返回参数:返回从机有无应答 1,有应答 0,无应答
其他说明:
************************************************************************/
void IIC_1_Send_Byte(u8 txd)
{
        u8 t;
        IIC_1_SDA_OUT();
        IIC_1_SCL = 0; // 拉低时钟开始数据传输
        for (t = 0; t < 8; t++)
        {
                IIC_1_SDA = (txd & 0x80) >> 7;
                txd <<= 1;
                delay_us(2); // 对TEA5767这三个延时都是必须的
                IIC_1_SCL = 1;
                delay_us(2);
                IIC_1_SCL = 0;
                delay_us(2);
        }
}
/************************************************************************
函数名称:IIC_1_Read_Byte
函数功能:读1个字节,ack=1时,发送ACK,ack=0,发送nACK
输入参数:
返回参数:
其他说明:
************************************************************************/
u8 IIC_1_Read_Byte(unsigned char ack)
{
        unsigned char i, receive = 0;
        IIC_1_SDA_IN(); // SDA设置为输入
        for (i = 0; i < 8; i++)
        {
                IIC_1_SCL = 0;
                delay_us(2);
                IIC_1_SCL = 1;
                receive <<= 1;
                if (IIC_1_READ_SDA)
                        receive++;
                delay_us(1);
        }
        if (!ack)
                IIC_1_NAck(); // 发送nACK
        else
                IIC_1_Ack(); // 发送ACK
        return receive;
}






.h文件

#ifndef _MCU_DRV_SOFT_IIC_H
#define _MCU_DRV_SOFT_IIC_H
#include "sys.h"        // 数据类型、位带操作的头文件,位带操作:https://blog.csdn.net/dxjlg/article/details/150262542?spm=1001.2014.3001.5501
#include "delay.h"        // 延时相关函数的头文件

//IO方向设置
#define IIC_1_SDA_IN()  {GPIOB->MODER&=~(3<<(7*2));GPIOB->MODER|=0<<7*2;}        //输入模式
#define IIC_1_SDA_OUT() {GPIOB->MODER&=~(3<<(7*2));GPIOB->MODER|=1<<7*2;}        //输出模式

//IO操作
#define IIC_1_SCL           PBout(6) //SCL
#define IIC_1_SDA           PBout(7) //SDA
#define IIC_1_READ_SDA  PBin(7)  //输入SDA

//IIC所有操作函数
void IIC_1_Init(void);                                        //初始化IIC的IO口
void IIC_1_Start(void);                                        //发送IIC开始信号
void IIC_1_Stop(void);                                        //发送IIC停止信号
void IIC_1_Send_Byte(u8 txd);                        //IIC发送一个字节
u8 IIC_1_Read_Byte(unsigned char ack);        //IIC读取一个字节
u8 IIC_1_Wait_Ack(void);                                //IIC等待ACK信号
void IIC_1_Ack(void);                                        //IIC发送ACK信号
void IIC_1_NAck(void);                                        //IIC不发送ACK信号

#endif





————————————————
版权声明:本文为CSDN博主「冲动的老飞鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dxjlg/article/details/150422844

qiufengsd 发表于 2025-9-9 11:29 | 显示全部楼层
用高效的延时函数和GPIO操作函数
mickit 发表于 2025-9-10 12:26 | 显示全部楼层
SCL频率≤100kHz              
timfordlare 发表于 2025-9-10 14:18 | 显示全部楼层
在SCL/SDA引脚附近添加100nF去耦电容,滤除高频噪声
wwppd 发表于 2025-9-10 20:32 | 显示全部楼层
上拉电阻不可少              
fengm 发表于 2025-9-13 11:29 | 显示全部楼层
在SCL和SDA线上添加上拉电阻
earlmax 发表于 2025-9-13 14:52 | 显示全部楼层
软件模拟I²C可在STM32上稳定运行
pentruman 发表于 2025-9-13 16:17 | 显示全部楼层
IIC协议对时序有严格要求              
maudlu 发表于 2025-9-13 21:14 | 显示全部楼层

​​必须添加外部上拉电阻              
sdlls 发表于 2025-9-14 07:26 | 显示全部楼层
核心函数:I2C_Start()、I2C_Stop()、I2C_WriteByte()、I2C_ReadByte()、I2C_Ack()、I2C_Nack()。
1988020566 发表于 2025-9-14 08:12 | 显示全部楼层
软件模拟I2C需要严格遵守I2C协议的时序要求
robincotton 发表于 2025-9-14 10:20 | 显示全部楼层
将IIC的起始信号、停止信号、数据发送和接收等功能封装成独立函数
uiint 发表于 2025-9-14 11:04 | 显示全部楼层
上拉电阻 通常 4.7kΩ~10kΩ
dspmana 发表于 2025-9-14 12:10 | 显示全部楼层
在等待应答信号或读取数据时,设置超时机制,防止无限等待。
hudi008 发表于 2025-9-14 19:20 | 显示全部楼层
SDA必须配置为开漏输出              
beacherblack 发表于 2025-9-14 20:13 | 显示全部楼层
标准模式下建议不超过 1m,高速模式需更短以减少容性负载影响。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

125

主题

4370

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部