GD32F103x IIC通信
1. IIC通信
1.IIC的介绍
IIC总线有两条串行线,其一是时钟线SCK(同步),其二是数据线SDA。只有一条数据线属于半双工。应用中,单片机常常作为主机,外围器件可以挂载多个。(当然主机也可以有多个。多个主机都要访问从机需要仲裁机制。)每一个从机器件都拥有唯一的一个地址。 这样才能区分主机与哪个从机通信。如下图:
有两个从机与一个主机。
由于在设置SDA,SCL两个串行时GPIO时都会设置成开漏模式。开漏模式需要通过上拉电阻拉到高电平。
那么为什么不用复用推挽呢?都知道推挽能输出稳定的高低电平。当某一主机SDA为高,某一从机SDA为低。那么很可能短路。如果是开漏带上拉电阻的。就直接上拉电阻流向从机SDA低。这样是比较安全的。开漏模式组成线与的关系,任何一个器件都可以拉低电平。
2. IIC的时序图
分为起始信号,数据传输,应答信号,停止信号。
1. 起始信号 ,停止信号
2. 数据传输信号
在SCL高电平时SDA必须稳定不变。等待从机读取。所以在SCL低电平时才可以改变。
3.应答信号。
总结:我们在起始信号之后,主机开始发送传输的数据;在串行时钟线 SCL 为低电平状态时,SDA 允许改变传输的数据位(1 为高电平,0 为低电平),在SCL 为高电平状态时,SDA 要求保持稳定,相当于一个时钟周期传输 1bit 数据,经过8 个时钟周期后,传输了 8bit 数据,即一个字节。第8 个时钟周期末,主机释放SDA 以使从机应答,在第 9 个时钟周期,从机将 SDA 拉低以应答;如果第 9 个时钟周期,SCL 为高电平时,SDA 未被检测到为低电,视为非应答,表明此次数据传输失败。第 9 个时钟周期末,从机释放 SDA 以使主机继续传输数据,如果主机发送停止信号,此次传输结束。我们要注意的是数据以8bit 即一个字节为单位串行发出,其最先发送的是字节的最高位。
3.IIC具体详细的数据帧格式
具体注意主机给从机呢还是从机给主机发送。看颜色的不同。
4. IIC 实现的方式
对于有些51单片机可能没有IIC的硬件驱动。要用模拟GPIO的方式来实现。但现在的单片机都会有
硬件的IIC驱动。直接用就好了。
2. LM75温度传感器
1.LM75的概述
1. LM75的AD转换原理
内部的温度传感器感知一个模拟信号。
2. LM75框图
内部有一个温度传感器。通过操作指针寄存器读取温度传感器的值。
3. 温度怎么保存及怎么计算。
4. LM75寄存器介绍。
1. 配置寄存器
总结:具体详细的看LM75的手册。
3. doem (IIC 读取LM75温度)
用模拟IIC的方式来获取LM75的温度。通过串口打印出来。
硬件电路:用PB6,PB7GPIO口来模拟。
1. LM75的唯一地址(查手册)
1001 A0 = 1 A1 = 1 A2 =1 = 0x9E
2. 指针寄存器操作
配置寄存器(01):
3. 读温度寄存器的流程
4. 写配置寄存器的流程
总结:代码都是按流程来的。配合流程一起看。
my_i2c_soft.h
#ifndef MY_I2C_SOFT_H
#define MY_I2C_SOFT_H
/**
@brief: 软件I2C的实现
*/#include "gd32f10x.h"#define I2C_SOFT_RCU RCU_GPIOB
#define I2C_SOFT_PORT GPIOB
#define I2C_SOFT_SCL_PIN GPIO_PIN_6
#define I2C_SOFT_SDA_PIN GPIO_PIN_7void my_i2c_init(void); /* i2c的初始化 */void my_i2c_start(void); /* i2c的起始 */
void my_i2c_stop(void); /* i2c的结束 */void my_i2c_send_byte(uint8_t byte_to_send); /* SDA发送一个byte */
uint8_t my_i2c_read_byte(void); /* SDA读取一个byte */void my_i2c_ack(void); /* 主机应答 */
void my_i2c_nack(void); /* 主机非应答 */
uint8_t my_i2c_read_ack(void); /* 从机应答 */#endif
my_i2c_soft.c
#include "my_i2c_soft.h"
#include "systick.h"void my_i2c_w_SDA(uint8_t bit_value)
{gpio_bit_write(I2C_SOFT_PORT, I2C_SOFT_SDA_PIN, (bit_status)bit_value);delay_1us(10);
}void my_i2c_w_SCL(uint8_t bit_value)
{gpio_bit_write(I2C_SOFT_PORT, I2C_SOFT_SCL_PIN, (bit_status)bit_value);delay_1us(10);
}uint8_t my_i2c_r_SDA(void){return gpio_input_bit_get(I2C_SOFT_PORT, I2C_SOFT_SDA_PIN);
}//初始化函数
void my_i2c_init(void){rcu_periph_clock_enable(I2C_SOFT_RCU);/* 开漏模式 */gpio_init(I2C_SOFT_PORT, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, I2C_SOFT_SCL_PIN|I2C_SOFT_SDA_PIN);gpio_bit_set(I2C_SOFT_PORT, I2C_SOFT_SCL_PIN|I2C_SOFT_SDA_PIN);
}//i2c的起始
void my_i2c_start(void){//SDA高,SCL高,SDA低,SCL低; my_i2c_w_SDA(1);my_i2c_w_SCL(1);my_i2c_w_SDA(0);my_i2c_w_SCL(0); /* 为传输数据做准备,只有SCL才可以改变数据 */
}//i2c的结束
void my_i2c_stop(void){my_i2c_w_SDA(0);my_i2c_w_SCL(1);my_i2c_w_SDA(1);
}//SDA发送一个byte
void my_i2c_send_byte(uint8_t byte_to_send){uint8_t i;for(i = 0; i < 8; i++){my_i2c_w_SDA(byte_to_send & (0x80>>i));my_i2c_w_SCL(1); /* 从机来读 */my_i2c_w_SCL(0);}
}//SDA读一个byte
uint8_t my_i2c_read_byte(void){uint8_t result = 0x00;my_i2c_w_SDA(1); /* 主机释放 */uint8_t i;for(i = 0; i < 8; i++){my_i2c_w_SCL(1);if(my_i2c_r_SDA())result = result | (0x80 >> i);//读SDA的bit值my_i2c_w_SCL(0);}return result;
}//主机应答
void my_i2c_ack(void){my_i2c_w_SCL(0);my_i2c_w_SDA(0);my_i2c_w_SCL(1);my_i2c_w_SCL(0);
}//主机非应答
void my_i2c_nack(void){my_i2c_w_SCL(0);my_i2c_w_SDA(1);my_i2c_w_SCL(1);my_i2c_w_SCL(0);
}//主机读应答
uint8_t my_i2c_read_ack(void){uint8_t ack_result;my_i2c_w_SDA(1); /* 主机释放 */my_i2c_w_SCL(1);ack_result = my_i2c_r_SDA();my_i2c_w_SCL(0);return ack_result;
}
lm75a_temp.h
#ifndef __LM75A_TEMP_H
#define __LM75A_TEMP_H#include "gd32f10x.h"
#include "my_i2c_soft.h"#define LM75A_I2C_ADDR 0x9E /* LM75A的从机地址 */#define LM75A_TEMP_REG 0x00 /* 温度寄存器的指针地址 */
#define LM75A_CONF_REG 0x01 /* 配置寄存器(Conf)*/
#define LM75A_THYST_REG 0x10 /* 滞后寄存器(Thyst) */
#define LM75A_TOS_REG 0x11 /* 过热关断寄存器(Tos) */#define IIC_WRITE 0
#define IIC_READ 1void lm75a_init(void);float lm75a_get_temp(void); //获取温度传感器的温度值void lm75a_poweroff(uint8_t id_rw,uint8_t reg_addr,uint8_t data); //关断温度传感器void lm75a_read_reg(uint8_t lm75a_id, uint8_t reg, uint8_t *p, uint8_t len); //读温度寄存器的值
uint8_t lm75a_write_addr(uint8_t id_rw, uint8_t reg_addr);#endif
lm75a_temp.c
#include "lm75a_temp.h"
#include "systick.h"void lm75a_init(void){my_i2c_init();
}// 读温度传感器的温度寄存器的值并转换为温度值
float lm75a_get_temp(void){float temp_result;//读温度寄存器值uint8_t byte_data[2];lm75a_poweroff(LM75A_I2C_ADDR | IIC_WRITE, LM75A_CONF_REG,0x00); /* 开启LM75 */lm75a_read_reg(LM75A_I2C_ADDR, LM75A_TEMP_REG, byte_data, 2);delay_1ms(100); /* 需要延时100ms */lm75a_poweroff(LM75A_I2C_ADDR | IIC_WRITE, LM75A_CONF_REG,0x01); /* 关闭LM75 *///将温度寄存器值转为温度值uint16_t temp_reg = byte_data[0]<<3 | byte_data[1]>>5;/* 判断D10是正负还是负数 0:正 1::负数 */if((temp_reg & 0x0400) == 0){temp_result = temp_reg * 0.125;}else{temp_reg = (~((temp_reg&0x03ff)-1)) & 0x03ff; //补码到原码转换temp_result = temp_reg * (-0.125);}return temp_result;
}/***
功能:读温度寄存器的值
输入:uint8_t lm75a_id: lm75a的iic从机地址uint8_t reg:要操作的寄存器的指针uint8_t *p:读取结果存放的位置uint8_t len:寄存器的字节长度(1 or 2)
返回:无
*****/
void lm75a_read_reg(uint8_t lm75a_id, uint8_t reg, uint8_t *p, uint8_t len){//向iic总线上写入器件地址、指针字节lm75a_write_addr(lm75a_id|IIC_WRITE, reg);my_i2c_start();my_i2c_send_byte(lm75a_id|IIC_READ);my_i2c_read_ack();uint8_t i;for(i = 0; i < len; i++){*p++ = my_i2c_read_byte();if(i != (len-1))my_i2c_ack();}my_i2c_nack();my_i2c_stop();
}/***
输入:uint8_t id_rw:从机地址|读写标识
**/
uint8_t lm75a_write_addr(uint8_t id_rw, uint8_t reg_addr){my_i2c_start();my_i2c_send_byte(id_rw);my_i2c_read_ack();my_i2c_send_byte(reg_addr);my_i2c_read_ack();return 0;
}void lm75a_poweroff(uint8_t id_rw,uint8_t reg_addr,uint8_t data) //关断温度传感器
{lm75a_write_addr(id_rw, reg_addr);my_i2c_send_byte(data);my_i2c_read_ack();my_i2c_stop();}
main.c
#include <stdio.h>
#include "systick.h"
#include "usart_comm.h"
#include "lm75a_temp.h"int main(){systick_config();usart0_init(9600);float temp_result;char temp_string[80];lm75a_init();while(1){temp_result = lm75a_get_temp();sprintf(temp_string, "temperature is: %.3f C.\n", temp_result); /* 把浮点转成字符 */usart0_send_string((uint8_t *)temp_string); /* 打印温度 */delay_1ms(1000); //等待1s}
}
最终结果打印:
相关文章:

GD32F103x IIC通信
1. IIC通信 1.IIC的介绍 IIC总线有两条串行线,其一是时钟线SCK(同步),其二是数据线SDA。只有一条数据线属于半双工。应用中,单片机常常作为主机,外围器件可以挂载多个。(当然主机也可以有多个。…...

什么是FOSS
FOSS 是指 自由和开放源码软件(Free and Open Source Software)。这并不意味着软件是免费的。它意味着软件的源代码是开放的,任何人都可以自由使用、研究和修改代码。这个原则允许人们像一个社区一样为软件的开发和改进做出贡献。...

C++语言GDAL批量裁剪多波段栅格图像:基于像元个数裁剪
本文介绍基于C 语言的GDAL模块,按照给定的像元行数与列数,批量裁剪大量多波段栅格遥感影像文件,并将所得到的裁剪后新的多波段遥感影像文件保存在指定路径中的方法。 在之前的文章中,我们多次介绍了在不同平台,或基于不…...

简单丝的tab切换栏(html/CSS)
#html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>CSS实现左右滑动选项卡效果</title><link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/meyer-res…...

LabVIEW开发带式谱感测技术
LabVIEW开发带式谱感测技术 如今,通过无线网络传输的数据量正在迅速增加,并导致频谱稀缺。超过数十亿的无线设备将被连接起来,并需要互联网接入。因此,无线电频谱管理方案的效率不足以授予对所有设备的访问权限。在频谱分配中&am…...

认识柔性数组
在C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员 限制条件是: 结构体中最后一个成员未知大小的数组 1.柔性数组的形式 那么我们怎样写一个柔性数组呢 typedef struct st_type {int i;int a[0];//柔性数组成员 }ty…...

熔断、限流、降级 —— SpringCloud Alibaba Sentinel
Sentinel 简介 Sentinel 是阿里中间件团队开源的,面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性 Sentinel 提供了两个服务组件…...
python经典百题之反向输出数字
题目:输入一个整数,并将其反转后输出。 程序分析 我们需要对输入的整数进行反转,即将整数的数字反向排列。 方法1:使用字符串反转 解题思路 将整数转换为字符串,然后对字符串进行反转。 代码实现 def reverse_integer_usin…...
复习Day08:哈希表part01:242.有效的字母异位词、349. 两个数组的交集、1. 两数之和、160. 相交链表
之前的blog:https://blog.csdn.net/weixin_43303286/article/details/131765317 我用的方法是在leetcode再过一遍例题,明显会的就复制粘贴,之前没写出来就重写,然后从拓展题目中找题目来写。辅以Labuladong的文章看。然后刷题不用…...

用 Pytest+Allure 生成漂亮的 HTML 图形化测试报告
本篇文章将介绍如何使用开源的测试报告生成框架 Allure 生成规范、格式统一、美观的测试报告。 通过这篇文章的介绍,你将能够: 将 Allure 与 Pytest 测试框架相结合; 如何定制化测试报告内容 执行测试之后,生成 Allure 格式的测…...

Python字符串索引解码乱码谜题
输入数行“数字字母”字符组成的乱码字符串,根据谜题规则解码出乱码字符串中隐藏的单词信息。 (本笔记适合熟悉python字符串索引操作的 coder 翻阅) 【学习的细节是欢悦的历程】 Python 官网:https://www.python.org/ Free:大咖免费“圣经”…...

协议栈——收发数据(拼接网络包,自动重发,滑动窗口机制)
目录 协议栈何时发送数据~ 数据长度 IP模块的分片功能 发送频率 网络包序号~利用syn拼接网络包ack确认网络包完整 确定偏移量 服务器ack确定收到数据总长度 序号作用 双端告知各自序号 协议栈自动重发机制 大致流程 ack等待时间如何调整 是…...

传输层协议——TCP、UDP
目录 1、UDP 协议(用户数据报协议) 协议特点 报文首部格式 2、TCP 协议(传输控制协议) 协议特点 报文首部格式 TCP连接建立时的三次握手 TCP拆除连接的四次挥手 TCP的流量控制 TCP的拥塞控制 3、传输层端口号 三类端口…...
优化您的Spring应用程序:缓存注解的精要指南
优化您的Spring应用程序:缓存注解的精要指南 前言详细说明1. Cacheable:2. CacheEvict:3. CachePut:4. Caching:5. CacheConfig: 项目中的实现前提使用 前言 当我们构建和运行Spring应用程序时,…...
Java之原子性问题的解决
2. 原子性 2.1 volatile-问题 代码分析 : package com.itheima.myvolatile; public class Demo {public static void main(String[] args) {MyThread1 t1 new MyThread1();t1.setName("小路同学");t1.start(); MyThread2 t2 new MyThread2();t2.setName(&q…...

实时目标检测:基于YOLOv3和OpenCV的摄像头应用
一、前言 随着人工智能和计算机视觉技术的不断发展,目标检测成为了智能监控、自动驾驶、机器人等领域的关键技术之一。实时目标检测更是对系统的反应速度和准确度提出了更高的要求。本文介绍使用OpenCV和YOLOv3实现实时目标检测的方法,演示如何使用OpenCV调用YOLOv3模型进行…...

【软考】4.2 关系代数
《 关系代数 》 表和表之间的逻辑运算 笛卡尔积:S1 x S2 投影:π;选择某一列(属性);一个关系R的投影操作结果也是一个关系,记作Πa,它由从关系R中选出的A列元素构成;选择…...

STM32F4学习笔记读取芯片UID和MAC地址
一、简介 在嵌入式设备开发过程中有时会需要为设备设置唯一的ID用以标识设备唯一,比如要求同一总线上的所有设备ID不能重复,要求设备具体唯一的MAC地址等等。每个STM32微控制器都自带一个96位的唯一ID,这个ID在任何情况下都是唯一且不允许修…...
webpack优化策略
这三点是webpack优化策略的一部分,具体解释如下: 优化正则匹配(Test):在webpack的配置中,test属性是一个正则表达式,用于匹配需要应用该loader的文件的扩展名。在您提供的代码中,te…...

讲讲项目里的仪表盘编辑器(三)布局组件
布局容器处理 看完前面两章的讲解,我们对仪表盘系统有了一个大概的理解。接着我们讲讲更深入的应用。 上文讲解的编辑器只是局限于平铺的组件集。而在编辑器中,还会有一种组件是布局容器。它允许其他组件拖拽进入在里面形成自己的一套布局。典型的有分页…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...

Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...

qt+vs Generated File下的moc_和ui_文件丢失导致 error LNK2001
qt 5.9.7 vs2013 qt add-in 2.3.2 起因是添加一个新的控件类,直接把源文件拖进VS的项目里,然后VS卡住十秒,然后编译就报一堆 error LNK2001 一看项目的Generated Files下的moc_和ui_文件丢失了一部分,导致编译的时候找不到了。因…...
背包问题双雄:01 背包与完全背包详解(Java 实现)
一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...
使用python进行图像处理—图像滤波(5)
图像滤波是图像处理中最基本和最重要的操作之一。它的目的是在空间域上修改图像的像素值,以达到平滑(去噪)、锐化、边缘检测等效果。滤波通常通过卷积操作实现。 5.1卷积(Convolution)原理 卷积是滤波的核心。它是一种数学运算,…...

Linux入门课的思维导图
耗时两周,终于把慕课网上的Linux的基础入门课实操、总结完了! 第一次以Blog的形式做学习记录,过程很有意思,但也很耗时。 课程时长5h,涉及到很多专有名词,要去逐个查找,以前接触过的概念因为时…...