赞
踩
关于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信号
-
- }
即无论前面做了啥,只要发送了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
- }
这里数据手册没讲
我们根据逻辑来
当接收了芯片发来的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
- }
以下内容编排中,待定
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。