【GD32】08 - IIC(以SHT20为例)

news2024/12/23 19:21:27

GD32中的IIC

今天来了解一下GD32中的硬件IIC,其实我个人是觉得软件IIC比较方便的,不过之前文章里用的都是软件IIC,今天就算是走出自己的舒适圈,我们来了解了解GD32中的硬件IIC。

我这里用的型号是GD32F407,不同型号的只需要看准自己板子的资源引脚即可。

关于IIC以及本文中演示的SHT20,在之前的文章里都有,并且也不是本文的重点,因此这里就不介绍了,不了解且感兴趣的小伙伴可以去看看之前的文章。

【STM32F103】I2C通信协议&SHT20温湿度传感器_sht20通信方式-CSDN博客文章浏览阅读2.3k次,点赞29次,收藏33次。I2C是Inter IC BUS=IIC=I²C=I2C,一般我们读作“挨方C”。简述一下I2C,是只需要两根通信线就能实现多主多从半双工的串行通信协议。传输速度会偏慢一点点,一般是100Kbps,是属于标准模式。另外还有快速模式,400Kbps;高速模式3.4Mbps;超快速模式5Mbps(后两种没接触过)。分别是SCL和SDA。SCL是Serial Clock,也就是统一时间的。SDA是Serial Data,也就是传输数据的。_sht20通信方式https://blog.csdn.net/m0_63235356/article/details/135734887?spm=1001.2014.3001.5501

接下来我们来看看GD32的IIC。

GD32F407一共有三个IIC资源,挂载在了APB1上面。

硬件IIC0的数据线在GPIOB的8和9号引脚上。因此我们首先就是要打开GPIOB的外设时钟,以及初始化一下这俩引脚,因为我们用的是硬件资源,因此要设置为复用模式。

    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_af_set(GPIOB, GPIO_AF_4,GPIO_PIN_8|GPIO_PIN_9);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8|GPIO_PIN_9);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_8|GPIO_PIN_9);

引脚复用我们选择4号复用。

不同型号需要查阅自己型号的固件库手册,比如说GD32E230的I2C就是0号复用。

上一篇文章写串口的在这方面是直接跳过了,现在在这边补充一下。

包括输出模式设置成什么上一篇好像也是跳过的,其实这一点我们可以查阅手册。

甚至我们可以直接参考STM32的手册,因为STM32里在GPIO章节里直接有个表格方便我们查阅,而GD32里可能也有但是我没有找到。

关于GPIO的设置我们就说到这边,其实我们使用到硬件资源的时候初始化GPIO都是这一套流程,具体细节在文档中都能找到。

接下来就是关于IIC的固件库函数了。

i2c_deinit(I2C0);

首先一样是复位函数,在设置IIC之前我们最好都调用一遍。

i2c_clock_config(I2C0, 100000, I2C_DTCY_2);

设置IIC的时钟,参数二理论上我们可以随便填入一个32bit大小的值,但是我们最好还是按照IIC常见的速率来设置,例如100k,400k这样。

i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0X80);

接下来是设置IIC通信的模式与地址,模式我们自然是选择I2C模式的,而地址可以选择7位或者是10位的(10位的参数截图没截上,因为卡在手册的下一页了),这个根据我们通信的模块的从机地址而定。

我们今天示范的SHT20是7位从机地址,是100 000,对应到十六进制就是0x80。

i2c_ack_config(I2C0, I2C_ACK_ENABLE);

设置发送应答,我们一般都设置为发送,当发送我们结束IIC通信的上一个时序的时候我们再关闭应答。

i2c_master_addressing(I2C0,0x80,I2C_TRANSMITTER);

发送从机地址,在IIC中我们开始时序发送之后第一个要发送的数据就是从机地址。我们知道从机地址是7位,剩下一位就是读写位了,0为写,1为读,我们不用手动去修改,直接调用这个函数就可以达到设置收发状态的从机地址并发送了。

不嫌麻烦的话,调用发送时序的函数再手动修改从机地址也是一样的效果。

i2c_enable(I2C0);

使能IIC,设置完IIC后使能,我们就可以使用IIC了。

IIC时序其实不多,就是开始,结束,发送,接收。应答的话硬件IIC会自动帮我们发送接收可以不用管。接下来我们就来看看这些时序对应的固件库函数是哪一些。

i2c_start_on_bus(I2C0);

这个就是起始时序了。起始时序就是在SCL高电平的时候,SDA从高电平切换到低电平。

i2c_stop_on_bus(I2C0);

发送结束时序。结束时序就是在SCL高电平的时候,SDA从低电平切换到高电平。

i2c_data_transmit(I2C0,data);

发送时序,在SCL低电平的时候,主机将数据放置到SDA(1为高电平,0为低电平) 主机拉高SCL的时候,在SCL高电平时,从机读取SDA的数据。可以一次发送8位数据。

i2c_data_receive(I2C0)

接收时序,一次收8bit。

至此我们就集齐了IIC的时序了,可以开始IIC了……吗?

硬件IIC麻烦的地方来了。那就是每个时序我们都需要等待标志位以及清除标志位。

获取标志位的函数在上面,我们讲过的时序用到的标志位参数我用红框框出来了。

获取完之后还得清除,传入的参数和上面获取的函数基本一样,我就不贴出来了。不过有些标志位是不用我们手动清除的,这个具体要查看手册,手册中没有对应的标志位参数就代表我们不用手动清除。

那么接下来我们就可以进行IIC通信了,时序都凑齐了,我们每发完一个时序都需要等待标志位置位(获取标志位)并且清除。

接下来我直接贴出代码(GD32F407),我会尽量写出注释,关于SHT20的看不懂的部分可以回顾一下开头链接的文章。

串口部分可以参考上一篇文章。

#include "board.h"
#include <stdio.h>
#include "Z_UART.h"

float SHT20_GetData(uint8_t command){
    uint16_t res = 0;

    i2c_start_on_bus(I2C0);                             //起始时序
    while(!i2c_flag_get(I2C0,I2C_FLAG_SBSEND) );        //等待起始位发送完. 这个不用手动清除标志位
    
    i2c_master_addressing(I2C0, 0x80, I2C_TRANSMITTER); //发送从机地址(0x80)+写命令(0)
    while(!i2c_flag_get(I2C0,I2C_FLAG_ADDSEND) );       //等待从机发送完毕之后得到回应(即从机地址正确)
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);              //清除标志位
    
    while(!i2c_flag_get(I2C0,I2C_FLAG_TBE));            //等待发送缓冲区空
    
    if(command == 'w')  i2c_data_transmit(I2C0,0xF3);   //发送数据,发送SHT20的指令,F3为获取温度,F5为获取湿度
    else    i2c_data_transmit(I2C0,0xF5);
    
    while(!i2c_flag_get(I2C0,I2C_FLAG_BTC) );           //等待字节传输完毕

    i2c_stop_on_bus(I2C0);                              //发送结束时序
    
    uint8_t count = 0;                                  //计数,因为SHT20采集数据需要时间,我们设置个超时时间
    do{
        i2c_start_on_bus(I2C0);                         //起始时序
        while(!i2c_flag_get(I2C0,I2C_FLAG_SBSEND));     //等待起始位发送完毕
     
        i2c_master_addressing(I2C0, 0x80, I2C_RECEIVER);//发送从机地址(0x80)+读命令(1)
        
        delay_ms(10);                                   //延时10ms
        if(++count >= 10) return 0;                     //超过100ms我们就算读取失败
    }while(!i2c_flag_get(I2C0,I2C_FLAG_ADDSEND));       //等待回应

    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);              //清除标志位

    i2c_ack_config(I2C0, I2C_ACK_ENABLE);               //开启应答

    while(!i2c_flag_get(I2C0,I2C_FLAG_RBNE) );          //等待接收缓冲区不为空

    res = i2c_data_receive (I2C0);                      //读取SHT传来的数据的高8位
    res <<= 8;

    i2c_ack_config(I2C0, I2C_ACK_DISABLE);              //关闭应答,因为我们就获取俩8bit数据

    while(!i2c_flag_get(I2C0,I2C_FLAG_RBNE) );          //等待接收缓冲区不为空

    res |= i2c_data_receive (I2C0);                     //读取SHT传来的数据的低8位
    
    i2c_stop_on_bus(I2C0);                              //结束时序

    res &= 0xFFFC;                                      //清除最后两位,这是SHT20要求的
    
    //根据指令的不同(获取温度/湿度)来计算数据
    if(command == 'w') return ((res / 65536.0) * 175.72 - 46.85);
    return (( res / 65536.0) * 125 - 6);
}

int main(void){
    board_init();
    //初始化串口,为了将结果打印到串口助手上,不懂怎么操作的小伙伴可以看看上一篇文章
    Z_UART_Init();
    //开启时钟
    rcu_periph_clock_enable(RCU_I2C0);
    rcu_periph_clock_enable(RCU_GPIOB);
    //初始化硬件IIC的引脚
    gpio_af_set(GPIOB, GPIO_AF_4,GPIO_PIN_8|GPIO_PIN_9);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8|GPIO_PIN_9);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_8|GPIO_PIN_9);
       
    i2c_deinit(I2C0);                                           //复位IIC0
    i2c_clock_config(I2C0, 100000, I2C_DTCY_2);                 //设置IIC速率为100k
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0X80);  //设置SHT20的七位地址
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);                       //使能应答
    i2c_enable(I2C0);                                           //使能IIC
    
    printf("hello world!\r\n");
    while (1){
        printf("%f\t%f\r\n",SHT20_GetData('w'),SHT20_GetData('s'));
        delay_ms(1000);
    }
}

 可以正常接收数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1870569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多路h265监控录放开发-(14)通过PaintCell自定义日历控件继承QCalendarWidget的XCalendar类

首先创建一个新类XCalendar继承QCalendarWidget类&#xff0c;然后在UI视图设计器中把日历提升为XCalendar&#xff0c;通过这个函数自己设置日历的样式 xcalendar.h #pragma once #include <QCalendarWidget> class XCalendar :public QCalendarWidget { public:XCal…

Java基础(四)——字符串、StringBuffer、StringBuilder、StringJoiner

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 ⚡开源项目&#xff1a; rich-vue3 &#xff08;基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL&#xff09; &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1…

C++编程(四)this指针 常函数 常对象 静态成员

文章目录 一、this指针&#xff08;一&#xff09;概念&#xff08;二&#xff09;显式使用this指针的场景1. 当形参和成员变量名一致时2. 返回对象自身的时候必须要使用this指针3. 在类中销毁一个对象 二、常函数和常对象&#xff08;一&#xff09;常函数1. 概念2. 语法格式 …

Linux Static calls机制

文章目录 前言一、简介二、Background: indirect calls, Spectre, and retpolines2.1 Indirect calls2.2 Spectre (v2)2.3 RetpolinesConsequences 2.4 Static callsHow it works 三、其他参考资料 前言 Linux内核5.10内核版本引入新特性&#xff1a;Static calls。 Static c…

关于摄像头模组中滤光片的介绍

1、问题背景 红外截止滤光片&#xff08;IR CUT Filter&#xff09;是应用在摄像头模组中非常重要的一个器件&#xff0c;因人眼与 coms sensor 对光线各波长的响应不同&#xff0c; 人眼看不到红外光&#xff0c;但 sensor 能感应到&#xff08;如下图是某sensor在各波长下的…

【设计模式-04】原型模式

【设计模式-04】原型模式 1. 概述2. 结构3. 实现4. 案例5. 使用场景6. 优缺点6.1 原型模式的优点6.2 原型模式的缺点 7. 实现深克隆(深拷贝) 1. 概述 原型模式: 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 2. 结构 原型…

策略模式和状态模式

策略模式 在上下文中携带策略接口作为成员变量&#xff0c;在使用上下文之前需要设置策略setStrategy&#xff08;&#xff09;&#xff0c;然后使用策略接口成员变量来进行策略的执行。 步骤1&#xff1a;定义策略接口 // 策略接口 public interface Strategy {int execut…

面试突击:ArrayList源码详解

本文已收录于&#xff1a;https://github.com/danmuking/all-in-one&#xff08;持续更新&#xff09; 前言 哈喽&#xff0c;大家好&#xff0c;我是 DanMu。ArrayList 是我们日常开发中不可避免要使用到的一个类&#xff0c;并且在面试过程中也是一个非常高频的知识点&#…

酷睿Ultra 200V系CPU全阵容规格、跑分出炉:拉了坨大的

从最近几个月 12 代酷睿 CPU 大面积降价清库存&#xff0c;到 13、14 代高端 U 大范围翻车问题迟迟得不到解决。 这就很难不让人生出一种 Intel 似乎真无暇顾及老款 U&#xff0c;而是将有限精力通通放在了接下来酷睿 Ultra 处理器上的感觉。 当然&#xff0c;作为新工艺、新架…

【编译原理必考大题】 推导构建语法树,写出语法树的短语,简单短语和句柄

写在最前 本文为编译原理重点考察大题之一&#xff0c;理论基础见专栏文章&#xff0c;0基础直接使用也可食用 文章目录 推导构造语法树1.语法树的概念2. 子树&#xff0c;短语&#xff0c;简单短语&#xff0c;句柄2.1 子树2.2 短语2.3 简单短语与句柄2.4 真题实战 推导构造语…

Discourse OpenAI 生成图片

正如一些讨论的&#xff0c;生成图片是比较贵的。 差不多到了 1 元 一张图了。 就 OpenAI 生成了上面 4 张图&#xff0c;费用 0.4 美元。 Discourse OpenAI 生成图片 - Discourse - iSharkFly

AI 开发平台(Coze)搭建《AI女友(多功能版本)》

前言 本文讲解如何从零开始&#xff0c;使用扣子平台去搭建《AI女友&#xff08;多功能版本&#xff09;》 bot直达&#xff1a;AI女友&#xff08;多功能版&#xff09; - 扣子 AI Bot (coze.cn) 欢迎大家前去体验&#xff01;&#xff01;&#xff01; 正文 功能介绍 …

分别使用netty和apache.plc4x测试读取modbus协议的设备信号

记录一下常见的工业协议数据读取方法 目录 前言Modbus协议说明Netty 读取测试使用plc4x 读取测试结束语 前言 Modbus 是一种通讯协议&#xff0c;用于在工业控制系统中进行数据通信和控制。Modbus 协议主要分为两种常用的变体&#xff1a;Modbus RTU 和 Modbus TCP/IP Modbus …

平面点云格网过程及可视化介绍(python)

1、背景介绍 实际人工构造物中&#xff0c;很多物体表面为平面结构&#xff0c;因此将点云投影在二维平面上进行处理&#xff0c;如进行点云面积计算、点云边缘提取等。 具体案例可以参考博客&#xff1a;详解基于格网法统计平面点云面积_点云格网法计算xy投影面积-CSDN博客、点…

分页处理封装+分页查询题目列表

文章目录 1.sun-club-common封装分页1.com/sunxiansheng/subject/common/eneity/PageInfo.java2.com/sunxiansheng/subject/common/eneity/PageResult.java 2.sun-club-application-controller1.SubjectInfoDTO.java 继承PageInfo并新增字段2.SubjectController.java 3.sun-clu…

8个Unity开发高手都在用的秘密技巧!

1. 不要重新发明轮子&#xff0c;使用内置的引擎工具 在使用任何引擎时&#xff0c;比如Unity或Unreal Engine&#xff0c;一些开发者&#xff0c;主要是来自计算机科学领域的开发者&#xff0c;可能会倾向于从头开始开发大型算法或结构&#xff0c;而不去了解引擎中是否已经存…

三角洲行动卡顿严重?这样快速解决三角洲行动国服卡顿问题

三角洲行动官方精心设计的游戏地图和敌人布局&#xff0c;加上“曼德尔砖”等目标导向性道具的引入&#xff0c;更是为玩家之间的竞技和争夺增添了无数的变数。每一次的争夺都如同是一场智慧与勇气的较量&#xff0c;让人热血沸腾&#xff0c;无法自拔。在这个战场上&#xff0…

免费可视化工具如何提升工作效率?

免费可视化工具能为我们的工作带来什么好处&#xff1f;在如今数据密集的工作环境中&#xff0c;如何高效地处理和展示数据成为了每个行业的重要任务。传统的工具如Excel虽然强大&#xff0c;但在处理复杂数据和创建高级图表时往往显得力不从心。而免费可视化工具的出现&#x…

Arduino - 光敏传感器

Arduino - Light Sensor Arduino - 光传感器 In this tutorial, we are going to learn: 在本教程中&#xff0c;我们将学习&#xff1a; How light sensor works 光传感器的工作原理How to connect the light sensor to Arduino 如何将光传感器连接到ArduinoHow to progra…

C#udpClient组播

一、0udpClient 控件&#xff1a; button&#xff08;打开&#xff0c;关闭&#xff0c;发送&#xff09;&#xff0c;textbox&#xff0c;richTextBox 打开UDP&#xff1a; UdpClient udp: namespace _01udpClient {public partial class Form1 : Form{public Form1(){Initi…