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…...
讲讲项目里的仪表盘编辑器(三)布局组件
布局容器处理 看完前面两章的讲解,我们对仪表盘系统有了一个大概的理解。接着我们讲讲更深入的应用。 上文讲解的编辑器只是局限于平铺的组件集。而在编辑器中,还会有一种组件是布局容器。它允许其他组件拖拽进入在里面形成自己的一套布局。典型的有分页…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...

