stm32的hal库软件模拟iic通信学习(以M24C02/AT24C02为例) 从数据手册到配置到代码看这一个就够啦

关于iic的概念我就不多说了,csdn很多资料。

我将讲述英语不会的情况下如何查看英文的手册

从原理到代码一步一步记录如何与芯片进行通信。

在阅读本篇文章时,请去学习iic的通信规范,不然比较难懂

开篇:

不废话,电脑安装一个有道词典并且启动就行

首先:

我用的是蓝桥杯嵌入式的stm32g431开发板,使用的M24C02芯片,接线图如下

可以看出,

PB6   接的是     SCL

PB7   接的是     SDA

并且还外接了两个上拉电阻,在通信时起到上拉的作用

这两个引脚并没有硬件iic功能,所以只能软件iic通信。

由于iic支持一主多从,图中还有一个MCP4017芯片,这个芯片不做讲解,没有影响。

引脚配置

现在知道了两个引脚了,那就配置两个引脚

打开cubemx

找到pb6,pb7,设置为gpio_output模式,即引脚输出模式

选择好后,进入system core->gpio

点开pb6,和pb7,配置成如下的代码

释义:

GPIO output level:High
引脚默认输出电平,这里选择high,在开漏模式下属于高阻态,电平取决于外部电路


GPIO mode:Output Open Drain
引脚的输出模式,这里是开漏输出,只有高阻态和下拉


GPIO Pull-up/Pull-down:No pull-up and no pull-down
这个是是否配置上拉,我选择的是无上下拉,如果上面的原理图中没有上拉电阻,那这里就要配置成上拉电阻,即GPIO Pull-up/Pull-down:pull-up


Maximum output speed:Low
输出速度,默认,慢
Fast Mode:Disable
快速模式,默认,不启动

User Label:

用户重命名,默认空,不动。

pb6和pb7都按这个配置配置完后生成代码

驱动部分

芯片的规范

首先在工程中配置好两个空白的myiic.c和.h文件

不会的看这个链接
http://t.csdnimg.cn/6lkJx
 

之后会参考数据手册,

m24c02数据手册获取

链接:https://pan.baidu.com/s/1hE7OGJWPdsbPWSUG9vwXYg 
提取码:8888

打开数据手册,看第一页

没什么好看的,就是参数介绍,继续往下看

目录,非常明显,我们需要参考的地方就在红色的框框里面

图中标记的数据大概就是SDA或者SCL电平保持的时间不能低于多少时间,因为我们使用软件iic模拟,所以基本上不会出现时间过短导致传输失败,不做过多解释,往下一大半

这里讲了大概的引脚规范,其中提到了芯片的两个引脚是开漏输出模式。与我们的stm32的两个引脚配置的引脚是开漏输出相呼应,并且建议使用上拉电阻,对应了iic的协议规范。

这里提到了本芯片的iic寻址是的7位地址,而且是高位起始,意思是数据从高位开始往地位发送,并且第八位是命令位,代表读或者写。

通过查看原理图和手册,E1,E2,E3都接地,即0.

所以本芯片的ip地址是1010000(),最后一位是命令位

这个就很重要了,讲述了iic通信中的各组标志。
起始信号:SCL为高电平期间,SDA信号线由高电平向低电平的变化表示起始信号;
终止信号:SCL为高电平期间,SDA由低电平向高电平的变化表示终止信号。

即在SCL拉高时
SDA:由低到高 – 起始信号
SDA:由高到低 – 终止信号

起始与终止的代码撰写

回到开头的引脚原理图部分

进行启动和停止代码的描写

首先,我们将pb6和pb7进行封装

打开myiic.h

#ifndef _MY_IIC_H
#define _MY_IIC_H
//scl的端口
#define MYSCL_PORT  GPIOB
#define MYSCL_PIN   GPIO_PIN_6
//sda的端口
#define MYSDA_PORT  GPIOB
#define MYSDA_PIN   GPIO_PIN_7






#endif

然后加入4个函数用来封装SDA与SCL的控制

#ifndef _MY_IIC_H
#define _MY_IIC_H
//scl的端口
#define MYSCL_PORT  GPIOB
#define MYSCL_PIN   GPIO_PIN_6
//sda的端口
#define MYSDA_PORT  GPIOB
#define MYSDA_PIN   GPIO_PIN_7


void            MYIIC_W_SCL(unsigned char x);//控制scl电平
void            MYIIC_W_SDA(unsigned char x);//控制sda电平
unsigned char   MYIIC_R_SDA(void);//读取sda电平
void            delay_us(unsigned int delay);//微妙级延迟


#endif

对应的.c代码是:

#include "myiic.h"


#define WAIT_TIME 50
static void delay1(unsigned int n)
{
    uint32_t i;
    for ( i = 0; i < n; ++i);
}

void MYIIC_W_SCL(unsigned char x)
{
    HAL_GPIO_WritePin(MYSCL_PORT, MYSCL_PIN,(GPIO_PinState)x);
    delay1(WAIT_TIME);
    
}
void MYIIC_W_SDA(unsigned char x)
{
    HAL_GPIO_WritePin(MYSDA_PORT, MYSDA_PIN,(GPIO_PinState)x);
    delay1(WAIT_TIME);
}

unsigned char MYIIC_R_SDA(void)
{
    unsigned char u8;
    
    u8 = HAL_GPIO_ReadPin(MYSDA_PORT, MYSDA_PIN);
    delay1(WAIT_TIME);
    return u8; 
    
}

其中有一个小tip,当引脚配置为开漏输出时,在高阻态的情况下是可以读取引脚的真实电平的,所以这里读取SDA电平直接readpin就行

为了降低篇幅,之后的代码就不放出.h中的函数声明,下面出现的函数都可以在头文件中声明。

好了,引脚控制有了,可以开始起始与终止的代码

起始位:
参考数据手册

即:在SCL为高电平期间将SDA拉低,随后SCL拉低

void MYIIC_Start(void)
{
    MYIIC_W_SDA(1); // 一定要先拉高SDA再拉高SCL
    MYIIC_W_SCL(1);
    
    MYIIC_W_SDA(0);//在SCL拉高的时候拉低SDA
    MYIIC_W_SCL(0);//随后拉低SCL
   
}
终止位:
参考数据手册

即SCL为高电平期间,SDA由低电平向高电平的变化表示终止信号。

void MYIIC_Stop(void)
{
    MYIIC_W_SCL(0);//先拉低SCL,控制
    MYIIC_W_SDA(0);//拉低SDA
    
    MYIIC_W_SCL(1);//拉高SCL
    MYIIC_W_SDA(1);//拉高的SCL期间拉高SDA。将iic总线释放,表示stop信号

}

发送ACK与接收ACK代码的撰写

接收ACK

即无论前面做了啥,只要发送了8位的数据且是有效的,芯片就会在下一个SCL拉高前将SDA拉低,表示ACK(收到)

//代码比较复杂,加了循环是为了防止在数据传输出错后不会卡在等待ack的循环里面
unsigned char MYIIC_WaitAck(void)
{
    unsigned short cErrTime = 10;//设置错误循环为10次
    MYIIC_W_SDA(1);//拉高SDA,即释放SDA的控制
    MYIIC_W_SCL(1);//拉高SCL
    while(MYIIC_R_SDA())//读取SDA,如果为0,则跳出循环
    {
        cErrTime--;
        if (0 == cErrTime)//错误处理
        {
            MYIIC_Stop();
            return ERROR;
        }
    }
    MYIIC_W_SCL(0);//读取完毕,重新拉低SCL
    return SUCCESS;//代码执行到这里说明接收ACK成功,返回success,即0
}
发送ACK(在进行读操作时需要)

这里数据手册没讲

我们根据逻辑来

当接收了芯片发来的8位数据时,如果还需要继续接收下一位地址,我们则需要发送ACK(0)给芯片,芯片就会自动发送下一个地址的数据。否则发送非ACK(1)。

void MYIIC_SentAck(unsigned char bit)
{
    if(bit == 0)//判断要ACK还是非ACK
    MYIIC_W_SDA(0);
    else
    MYIIC_W_SDA(1);

    MYIIC_W_SCL(1);//拉高SCL,从机读取SDA判断是否ACK
    MYIIC_W_SCL(0);//拉低SCL
}

以下内容编排中,待定

写数据的的撰写

指定地址写

读数据的的撰写

当前地址读
指定地址读
指定地址多次读

应用层的理解与代码

M24C02关于存储的描述与控制

芯片信息
芯片控制参数
芯片控制代码

总源代码

  • 9
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值