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. 指针寄存器操作

指针寄存器包含一个 8 位的数据字节,低 2 位是其它 4 个寄存器的指针值,高 6 位等于 0 ,见指针寄 存器表格(表 3 )和指针值表格(表 4 )。指针寄存器对于用户来说是不可访问的,但通过将指针数据字节 包含到总线命令中可选择进行读/ 写操作的数据寄存器。

 配置寄存器(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}
}

 最终结果打印:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AJAX--Express速成

一、基本概念 1、AJAX(Asynchronous JavaScript And XML)&#xff0c;即为异步的JavaScript 和 XML。 2、异步的JavaScript 它可以异步地向服务器发送请求&#xff0c;在等待响应的过程中&#xff0c;不会阻塞当前页面。浏览器可以做自己的事情。直到成功获取响应后&#xf…

【Spring MVC】MVC如何浏览器请求(service方法)

文章目录 1. DispatcherServlet 的 service 方法1.1. processRequest 方法1.2. doService 方法 背景&#xff1a;平时我们学习 MVC 重点关注的时DispatcherServlet 的 doDispatcher 方法&#xff0c;但是在 doDispatcher 方法之前 还有请求处理的前置过程&#xff0c;这个过程…

vue 使用 创建二维数组响应数据 渲染 echarts图标

目前我遇到的情况就是用动态的二维数组数据渲染echarts图标&#xff0c;我们从后端收到的接口一般是个一维数组&#xff0c;需要手动构建并且保证响应式。接下来我做了个案例 一、案例总逻辑 1. 先创建一个vue项目 2. 添加 echarts依赖 3. 模拟数据请求&#xff0c;构建二维数组…

Axios post请求出现500错误

笔者在编写前端form表单传后端数据的时候&#xff0c;出现了以下问题 一、问题场景 当我用axios发送post请求的时候&#xff0c;出现了500错误 笔者找了很长时间错误&#xff0c;代码没问题&#xff0c;后端接口也没问题&#xff0c;后来发现问题出在实体类上了 当前端post请…

数据结构: 数组与链表

目录 1 数组 1.1 数组常用操作 1. 初始化数组 2. 访问元素 3. 插入元素 4. 删除元素 5. 遍历数组 6. 查找元素 7. 扩容数组 1.2 数组优点与局限性 1.3 数组典型应用 2 链表 2.1 链表常用操作 1. 初始化链表 2. 插入节点 3. 删除…

10.03

代码 #include <iostream>using namespace std; class cz { private:int num1; //实部int num2; //虚部 public:cz(){}cz(int a,int b):num1(a),num2(b){}cz(const cz &other):num1(other.num1),num2(other.num2){}~cz(){}const cz operator(const cz &othe…

websocket逆向【python实现http/https拦截】

python实现http拦截 前言:为什么要使用http拦截一、技术调研二、技术选择三、使用方法前言:为什么要使用http拦截 大多数爬虫玩家会直接选择API请求数据,但是有的网站需要解决扫码登录、Cookie校验、数字签名等,这种方法实现时间长,难度高。需求里面不需要高并发,有没有…

5月22日比特币披萨日,今天你吃披萨了吗?

比特币披萨日 1. Laszlo Hanyecz2. 最贵披萨诞生记3. 梭哈买披萨4. 未完待续 2010年5月22日&#xff0c;美国佛罗里达州的程序员Laszlo Hanyecz&#xff08;拉兹洛哈涅克斯&#xff09;用10000个比特币购买了棒约翰&#xff08;Papa Johns&#xff09;比萨店一个价值25美元的奶…

C语言:选择+编程(每日一练Day9)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;自除数 思路一&#xff1a; 题二&#xff1a;除自身以外数组的乘积 思路二&#xff1a; 本人实力有限可能对…

C++核心编程--继承篇

4.6、继承 继承是面向对象三大特征之一 有些类与类之间存在特殊的关系&#xff0c;例如下图中&#xff1a; ​ 我们发现&#xff0c;定义这些类的定义时&#xff0c;都拥有上一级的一些共性&#xff0c;还有一些自己的特性。那么我们遇到重复的东西时&#xff0c;就可以考虑使…

OpenCV读取图像时按照BGR的顺序HWC排列,PyTorch按照RGB的顺序CHW排列

OpenCV读取RGB图像 在OpenCV中&#xff0c;读取的图片默认是HWC格式&#xff0c;即按照高度、宽度和通道数的顺序排列图像尺寸的格式。我们看最后一个维度是C&#xff0c;因此最小颗粒度是C。 例如&#xff0c;一张形状为2562563的RGB图像&#xff0c;在OpenCV中读取后的格式…

R | R及Rstudio安装、运行环境变量及RStudio配置

R | R及Rstudio安装、运行环境变量及RStudio配置 一、介绍1.1 R介绍1.2 RStudio介绍 二、R安装2.1 演示电脑系统2.2 R下载2.3 R安装2.4 R语言运行环境设置&#xff08;环境变量&#xff09;2.4.1 目的2.4.2 R-CMD测试2.4.3 设置环境变量 2.5 R安装测试 三、RStudio安装3.1 RStu…

【pwn入门】用gdb实现第1个pwn

声明 本文是B站你想有多PWN学习的笔记&#xff0c;包含一些视频外的扩展知识。 有问题的源码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> char sh[]"/bin/sh"; int func(char *cmd){system(cmd);return 0; }int main(){char …

【操作系统】进程同步与进程互斥

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 进程同步与进程互斥 一、什么是进程同步二、…

redis中list类型的操作

一、特点 Redis列表是简单的字符串列表&#xff0c;按照插入顺序排序。你可以添加一个元素到列表的头部&#xff08;左边&#xff09;或者尾部&#xff08;右边&#xff09;。一个列表最多可以包含 2^32 - 1 个元素 (超过40亿个元素)。 list其底层使用quicklist存储数据 qu…

力扣-383.赎金信

Idea 使用一个hashmap 或者一个int数组存储第二次字符串中每一个字符及其出现的次数 遍历第一个字符串&#xff0c;讲出现的重复字符减1&#xff0c;若该字符次数已经为0&#xff0c;则返回false AC Code class Solution { public:bool canConstruct(string ransomNote, strin…

色彩一致性自动处理方法在遥感图像中的应用

前言 在获取卫星遥感影像时&#xff0c;由于受不均匀的光照、不同的大气条件和不同的传感器设备等因素的影响&#xff0c;遥感影像中会存在局部亮度和色彩分布不均匀的现象&#xff0c;下面是在BigMap地图下载器中收集的几幅谷歌卫星影像&#xff0c;像下面这种都是拼接好的影像…

S32K144 GPIO编程

前面的文章介绍了如何在MDK-Keil下面进行S32K144的开发&#xff0c;下面就使用该工程模板进行GPIO LED的编程试验。 1. 开发环境 S32K144EVB-Q100开发板MDK-Keil Jlink 2. 硬件连接 S32K144EVB-Q100开发板关于LED的原理图如下&#xff1a; 也就是具体连接关系如下&#xf…

键盘上F1至F12键的作用

多年来&#xff0c;我们习惯了最上排的12个按键&#xff0c;从F1到F12&#xff0c;它们被称为“快速功能键”&#xff0c;可以让你更轻松地操作电脑&#xff1b;但是&#xff0c;很多人可能从未使用过它们&#xff0c;也从来不知道它们的用途。那么今天&#xff0c;就向大家科普…

以太网基础学习(二)——ARP协议

一、什么是MAC地址 MAC地址&#xff08;英语&#xff1a;Media Access Control Address&#xff09;&#xff0c;直译为媒体访问控制位址&#xff0c;也称为局域网地址&#xff08;LAN Address&#xff09;&#xff0c;MAC位址&#xff0c;以太网地址&#xff08;Ethernet Addr…