STM32 HAL库F103系列之IIC实验

IIC总线协议

IIC总线协议介绍

IICInter Integrated Circuit,集成电路总线,是一种同步 串行 半双工通信总线。

总线就是传输数据通道

协议就是传输数据的规则

IIC总线结构图

① 由时钟线SCL和数据线SDA组成,并且都接上拉电阻,确保总线空闲状态为高电平

② 总线支持多设备连接,允许多主机存在,每个设备都有一个唯一的地址

③ 连接到总线上的数目受总线的最大电容400pf限制

④ 数据传输速率:标准模式100k bit/s  快速模式400k bit/s 高速模式3.4Mbit/s

 

起始信号

void iic_start(void)
{ /* SCL为高电平期间, SDA从高电平往低电平跳变*/IIC_SDA ( 1 );	IIC_SCL ( 1 );iic_delay( );IIC_SDA ( 0 );	iic_delay( );IIC_SCL ( 0 );	iic_delay( );  /* 钳住总线, 准备发送/接收数据 */
}

停止信号

void iic_stop(void)
{ /* SCL为高电平期间, SDA从低电平往高电平跳变*/IIC_SDA ( 0 );	iic_delay( );IIC_SCL ( 1 );	iic_delay( );IIC_SDA ( 1 ); 	/* 发送总线停止信号*/iic_delay( );
}

检测应答信号

uint8_t iic_wait_ack (void) /* return 1:fail 0:succeed*/
{	IIC_SDA (1);  /* 主机释放SDA线 */iic_delay( );IIC_SCL (1);  /* 从机返回ACK*/ 	iic_delay( );if ( IIC_READ_SDA ) /* SCL高电平读取SDA状态*/ {iic_stop();	    /* SDA高电平表示从机nack */ return 1;}IIC_SCL(0);	 /* SCL低电平表示结束ACK检查 */ iic_delay( );return 0;
}

发送应答信号

void iic_ack(void)
{ IIC_SCL (0);	iic_delay( );IIC_SDA (0);  /* 数据线为低电平,表示应答 */iic_delay( );IIC_SCL (1); 	iic_delay( );
}

发送非应答信号

void iic_nack(void)
{ IIC_SCL (0);	iic_delay( );IIC_SDA (1);  /* 数据线为高电平,表示非应答 */iic_delay( );IIC_SCL (1); 	iic_delay( );
}

发送1字节数据

void iic_send_byte(uint8_t data)
{for (uint8_t t = 0; t < 8; t++){	/* 高位先发 */IIC_SDA((data & 0x80) >> 7);iic_delay( );IIC_SCL ( 1 );	iic_delay( );IIC_SCL ( 0 );data <<= 1; /* 左移1位, 用于下一次发送 */}IIC_SDA ( 1 ); 	/* 发送完成,主机释放SDA线 */ 
}

读取1字节数据

uint8_t iic_read_byte (uint8_t ack) /* 1:ack 0:nack*/
{ uint8_t receive = 0 ;for (uint8_t t = 0; t < 8; t++){	/* 高位先输出,先收到的数据位要左移 */ receive <<= 1;		IIC_SCL ( 1 );	iic_delay( );if ( IIC_READ_SDA ) receive++;IIC_SCL ( 0 );iic_delay( );}if ( !ack ) iic_nack();else iic_ack();return receive; 	
}

 AT24C02

原理图

EEPROM是一种掉电后数据不丢失的储存器,常用来存储一些配置信息,在系统重新上电时就可以加载。

AT24C02是一个2K bitEEPROM存储器,使用IIC通信方式。

AT24C02:写操作地址(0xA0) 读操作地址(0xA1)

AT24C02写时序

AT24C02读时序

IIC配置步骤

1、使能SCLSDA对应时钟

        __HAL_RCC_GPIOB_CLK_ENABLE()

2、设置GPIO工作模式

        SDA开漏/SCL推挽输出模式,使用HAL_GPIO_Init初始化

3、编写基本信号

        起始信号 停止信号 应答信号

4、编写读和写函数

                iic_read_byte、iic_send_byte

为什么IIC总线SDA建议用开漏模式?

开漏输出的特点:不能输出高电平,   必须有外部(或内部)上拉才能输出高电平

IICSDA脚即要作为输出,又要作为输入,用开漏输出模式,很好实现输出输入共用,避免IO模式频繁切换带来的麻烦。

输出时:主机(MCU)输出0,可以拉低信号,来实现低电平发送,主机输出1(实际不起作用),由外部上拉电阻上拉,实现高电平发送。

输入时:主机(MCU)设置输出1状态,此时因为MCU无法输出1,相当于释放了SDA脚,此时外部器件可以主动拉低SDA/释放SDA脚(同样由上拉电阻提供“输出1的功能”),实现SDA脚的高低电平变化。

由于开漏输出模式下,MCU还是可以读取IDR状态寄存器,来获取引脚高低电平,因此MCU读取IDR,即可获得SDA脚的高低电平状态,从而实现输入检测。

AT24C02配置步骤

1、初始化IIC接口

2、编写写入/读取一个字节数据函数        遵循读写时序流程编写

3、编写连续读和连续写函数        在2的基础上进行实现

实验:驱动AT24C02实现读和写1字节数据

myiic.c

#include "./BSP/IIC/myiic.h"
#include "./SYSTEM/delay/delay.h"void iic_init(void)
{GPIO_InitTypeDef gpio_init_struct;IIC_SCL_GPIO_CLK_ENABLE();  /* SCL引脚时钟使能 */IIC_SDA_GPIO_CLK_ENABLE();  /* SDA引脚时钟使能 */gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);    /* SCL */gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;            /* 开漏输出 */HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);    /* SDA *//* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */
}static void iic_delay(void)
{delay_us(2);
}/* 起始信号 */
void iic_start(void)
{/* SCL为高电平期间, SDA从高电平往低电平跳变*/IIC_SDA ( 1 );IIC_SCL ( 1 );iic_delay( );IIC_SDA ( 0 );iic_delay( );IIC_SCL ( 0 );iic_delay( );  /* 钳住总线, 准备发送/接收数据 */
}/* 停止信号 */
void iic_stop(void)
{/* SCL为高电平期间, SDA从低电平往高电平跳变*/IIC_SDA ( 0 );iic_delay( );IIC_SCL ( 1 );iic_delay( );IIC_SDA ( 1 );  /* 发送总线停止信号*/iic_delay( );
}/* 等待应答信号 */
uint8_t iic_wait_ack (void) /* return 1:fail 0:succeed*/
{IIC_SDA (1);    /* 主机释放SDA线 */iic_delay( );IIC_SCL (1);    /* 从机返回ACK*/iic_delay( );if ( IIC_READ_SDA ) /* SCL高电平读取SDA状态*/ {iic_stop();     /* SDA高电平表示从机nack */ return 1;}IIC_SCL(0);         /* SCL低电平表示结束ACK检查 */ iic_delay( );return 0;
}/* 应答信号 */
void iic_ack(void)
{ IIC_SCL (0);iic_delay( );IIC_SDA (0);  /* 数据线为低电平,表示应答 */iic_delay( );IIC_SCL (1);iic_delay( );
}/* 非应答信号 */
void iic_nack(void)
{ IIC_SCL (0);iic_delay( );IIC_SDA (1);  /* 数据线为低电平,表示应答 */iic_delay( );IIC_SCL (1);iic_delay( );
}/* 发送一个字节数据 */
void iic_send_byte(uint8_t data)
{for (uint8_t t = 0; t < 8; t++){/* 高位先发 */IIC_SDA((data & 0x80) >> 7);iic_delay( );IIC_SCL ( 1 );iic_delay( );IIC_SCL ( 0 );data <<= 1;     /* 左移1位, 用于下一次发送 */}IIC_SDA ( 1 );      /* 发送完成,主机释放SDA线 */ 
}/* 读取1字节数据 */
uint8_t iic_read_byte (uint8_t ack)
{ uint8_t receive = 0 ;for (uint8_t t = 0; t < 8; t++){/* 高位先输出,先收到的数据位要左移 */ receive <<= 1;IIC_SCL ( 1 );iic_delay( );if ( IIC_READ_SDA ) receive++;IIC_SCL ( 0 );iic_delay( );}if ( !ack ) iic_nack();else iic_nack();return receive;
}

myiic.h

#ifndef __MYIIC_H
#define __MYIIC_H#include "./SYSTEM/sys/sys.h"/******************************************************************************************/
/* 引脚 定义 */#define IIC_SCL_GPIO_PORT               GPIOB
#define IIC_SCL_GPIO_PIN                GPIO_PIN_6
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */#define IIC_SDA_GPIO_PORT               GPIOB
#define IIC_SDA_GPIO_PIN                GPIO_PIN_7
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 *//******************************************************************************************//* IO操作 */
#define IIC_SCL(x)        do{ x ? \HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* SCL */#define IIC_SDA(x)        do{ x ? \HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* SDA */#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA */void iic_init(void);
void iic_start(void);
void iic_stop(void);
uint8_t iic_wait_ack(void);
void iic_ack(void);
void iic_nack(void);
void iic_send_byte(uint8_t data);
uint8_t iic_read_byte (uint8_t ack);#endif

24cxx.c

#include "./BSP/IIC/myiic.h"
#include "./BSP/24CXX/24cxx.h"
#include "./SYSTEM/delay/delay.h"void at24c02_init(void)
{iic_init();
}void at24c02_write_one_byte(uint8_t addr, uint8_t data)
{/* 1、发送起始信号 */iic_start();/* 2、发送通讯地址(写操作地址) */iic_send_byte(0xA0);/* 3、等待应答信号 */iic_wait_ack();/* 4、发送内存地址 */iic_send_byte(addr);/* 5、等待应答信号 */iic_wait_ack();/* 6、发送写入数据 */iic_send_byte(data);/* 7、等待应答信号 */iic_wait_ack();/* 8、发送停止信号 */iic_stop();/* 等待EEPROM写入完成 */delay_ms(10);
}uint8_t at24c02_read_one_byte(uint8_t addr)
{uint8_t rec = 0;/* 1、发送起始信号 */iic_start();/* 2、发送通讯地址(写操作地址) */iic_send_byte(0xA0);/* 3、等待应答信号 */iic_wait_ack();/* 4、发送内存地址 */iic_send_byte(addr);/* 5、等待应答信号 */iic_wait_ack();/* 6、发送起始信号 */iic_start();/* 7、发送通讯地址(读操作地址) */iic_send_byte(0xA1);/* 8、等待应答信号 */iic_wait_ack();/* 9、等待接收数据 */rec = iic_read_byte(0);/* 10、发送非应答(获取该地址即可) *//* 11、发送停止信号 */iic_stop();return rec;
}

24cxx.h

#ifndef __24CXX_H
#define __24CXX_H#include "./SYSTEM/sys/sys.h"void at24c02_init(void);
void at24c02_write_one_byte(uint8_t addr, uint8_t data);
uint8_t at24c02_read_one_byte(uint8_t addr);#endif

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/24CXX/24cxx.h"int main(void)
{uint8_t key;uint8_t i = 0;uint8_t data = 0;HAL_Init();                                 /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */delay_init(72);                             /* 延时初始化 */usart_init(115200);                         /* 串口初始化为115200 */led_init();                                 /* 初始化LED */key_init();                                 /* 初始化按键 */at24c02_init();while (1){key = key_scan(0);if (key == KEY1_PRES){at24c02_write_one_byte(100, 66);printf("write data \r\n");}if (key == KEY0_PRES){data = at24c02_read_one_byte(100);printf("read data:%d \r\n", data);}i++;if (i % 20 == 0){LED0_TOGGLE();  /* 红灯闪烁 */i = 0;}delay_ms(10);}
}

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

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

相关文章

[华为OD] C卷 5G网络 现需要在某城市进行5G网络建设,已经选取N个地点设置5G基站 200

题目 现需要在某城市进行5G网络建设&#xff0c;已经选取N个地点设置5G基站&#xff0c;编号固定为1到N,接 下来需要各个基站之间使用光纤进行连接以确保基站能互联互通&#xff0c;不同基站之间架设光纤的成 本各不相同&#xff0c;且有些节点之间已经存在光纤相连&#…

python项目入门新手攻略

最近工作需要接手了代码量比较大的python开发的项目&#xff0c;平时写python不多&#xff0c;记录一下如何熟悉项目。 分析调用流程-pycallgraph 因为代码量比较大&#xff0c;所以希望通过工具生成代码调用流程&#xff0c;因此用到了pycallgraph。 pycallgraph&#xff0…

【AIGC调研系列】InternVL开源多模态模型与GPT-4V的性能对比

InternVL和GPT-4V都是多模态模型&#xff0c;但它们在性能、参数量以及应用领域上有所不同。 InternVL是一个开源的多模态模型&#xff0c;其参数量为60亿&#xff0c;覆盖了图像/视频分类、检索等关键任务&#xff0c;并在32个视觉-语言基准测试中展现了卓越性能[2]。InternV…

linux操作系统,进入救援模式的方法

准备好操作系统的 ISO 文件 或 刻录好的U盘启动盘 登录服务器 BMC 管理界面&#xff0c;选择镜像之后&#xff0c;点击 “启动媒体”&#xff08;如果使用U盘启动盘 则跳过这一步骤&#xff0c;直接看下一步&#xff09; 重启服务器&#xff0c;开机界面一般按键盘 “Delete”…

优雅处理枚举值映射和分页

文章目录 引言I pagehelper分页1.1 pagehelper配置1.2 使用方法1.3 SQLServerException: LIMIT 附近有语法错误。II mybatis-plus2.1 多数据源配置2.2 优雅处理枚举值映射@EnumValue2.3 配置枚举扫描包2.4 常见问题引言 分页效果 优雅处理枚举值映射

PotatoPie 4.0 实验教程(34) —— FPGA实现摄像头图像二值化腐蚀效果

链接直达 https://item.taobao.com/item.htm?ftt&id776516984361 图像二值化腐蚀处理有什么作用&#xff1f; 图像二值化腐蚀处理在图像处理中起到了以下作用&#xff1a; 物体分割与提取&#xff1a;在图像二值化之后&#xff0c;通过腐蚀操作可以消除噪声、连接相邻的…

【C语言】动态内存分配

即使行动导致错误&#xff0c;却也带来了学习与成长;不行动则是停滞与萎缩。&#x1f493;&#x1f493;&#x1f493; 目录 •&#x1f319;知识回顾 &#x1f34b;知识点一&#xff1a;为什么要有动态内存分配 &#x1f34b;知识点二&#xff1a;malloc和free • &#x1…

shell脚本,删除30天以前的日志,并将日志推送到nas,但运行出现/bin/bash^M。

删除30天以前的日志 将日志推送到nas中&#xff0c;然后删除pod中的日志 pod挂载到本地 运行出现/bin/bash^M 1、删除30天以前的日志&#xff1a; #! /bin/bash# 定义源日志目录 LOG_DIR/home/log/ # 删除日志 find $LOG_DIR -type f -name "*.log" -mtime 30 -exec…

2024年五一杯高校数学建模竞赛(C题) 建模解析| 冲击地压危险预测 |小鹿学长带队指引全代码文章与思路

我是鹿鹿学长&#xff0c;就读于上海交通大学&#xff0c;截至目前已经帮200人完成了建模与思路的构建的处理了&#xff5e; 本篇文章是鹿鹿学长经过深度思考&#xff0c;独辟蹊径&#xff0c;通过滑动平均法解决冲击地压危险预测问题。实现综合建模。独创复杂系统视角&#xf…

在做题中学习(48):朴素的二分查找

. - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a; 暴力求解 for循环中&#xff0c;从nums[0]枚举到nums[n-1]&#xff0c;依次判断&#xff0c;返回 target的值。 时间复杂度 : O(N) :因为要遍历一遍数组 解法二&#xff1a;二分查找 因为此数组为有序的…

Mybatis进阶(动态SQL)

文章目录 1.动态SQL1.基本介绍1.为什么需要动态SQL2.基本说明3.动态SQL常用标签 2.环境搭建1.新建子模块2.删除不必要的两个文件夹3.创建基本结构4.父模块的pom.xml5.jdbc.properties6.mybatis-config.xml7.MyBatisUtils.java8.MonsterMapper.java9.MonsterMapper.xml10.测试Mo…

如何将安卓手机投屏到Windows 10电脑上

诸神缄默不语-个人CSDN博文目录 我之所以要干这个事是为了用手机直播的时候在电脑上看弹幕…… 文章目录 1. 方法一&#xff1a;直接用Win10内置的投影到此电脑2. 方法二&#xff1a;用AirDroid Cast投屏到电脑上 1. 方法一&#xff1a;直接用Win10内置的投影到此电脑 在设置…

C++ 多态详解

文章目录 1. 多态的概念2. 多态的定义及实现2.1 多态的构成条件2.2 虚函数2.3 虚函数的重写2.3.1 虚函数重写的两个例外 2.4 C11 override 和 final2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 多态的原理3.1 虚函数表3.2多态的原理 4. 单继承和多继承关系的虚函数表4.1 单继…

docker安装【zookeeper】【kafka】【provectuslabs/kafka-ui】记录

目录 1.安装zookeeper:3.9.2-jre-172.安装kafka:3.7.03.安装provectuslabs/kafka-ui &#xff08;选做&#xff09;新环境没有jdk&#xff0c;安装jdk-17.0.10备用 mkdir -p /export/{data,apps,logs,conf,downloads}cd /export/downloadscurl -OLk https://download.oracle.…

新品发布!无人机装调检修实训系统

近年&#xff0c;我国密集出台相关产业政策&#xff0c;推动低空经济从探索走向发展&#xff0c;根据新华网数据&#xff0c;2030年低空经济规模有望达2万亿。无人机专业属于跨学科的综合性专业&#xff0c;其中装调检测技术是无人机教培的重要组成部分。 天途推出无人机装调检…

Apache SeaTunnel k8s 集群模式 Zeta 引擎部署指南

SeaTunnel提供了一种运行Zeta引擎(cluster-mode)的方法&#xff0c;可以让Kubernetes在本地运行Zeta引擎&#xff0c;实现更高效的应用程序部署和管理。在本文中&#xff0c;我们将探索SeaTunnel k8s运行zeta引擎(cluster-mode模式)的更多信息&#xff0c;了解如何更好地利用Ze…

HTML:元素分类

HTML&#xff1a;元素分类 概述块级元素&#xff08;Block-level Elements&#xff09;内联元素&#xff08;Inline Elements&#xff09;替换元素&#xff08;Replaced Elements&#xff09;表单元素&#xff08;Form Elements&#xff09; 概述 HTML&#xff08;HyperText M…

Docker容器:网络模式与资源控制

目录 一、Docker 网络模式 1、Docker 网络实现原理 2、Docker 网络模式概述 2.1 Host 模式 2.2 Container 模式 2.3 None 模式 2.4 Bridge 模式 2.5 自定义网络&#xff08;user-defined network&#xff09; 3、配置 docker 网络模式 3.1 查看网络基础命令 3.1.1 查…

css利用transform:skew()属性画一个大屏的背景斜面四边形特效

在工作工程中需要写一个如下的大屏背景&#xff0c;是由几个斜面做成的效果 使用css transform function中的skew()方法实现画其中一个斜面&#xff0c;然后调整背景色实现 写一个div <div class"skew_container test-2"><div class"skew_container_it…

【python笔记】datafram的时间动态可视化 pyecharts地图

import pandas as pd# 假设DataFrame是这样的&#xff1a; df pd.DataFrame({ year: [2014, 2015, 2016, 2014, 2015, 2016, 2014, 2015, 2016], province: [广东省, 广东省, 河南省, 湖南省, 北京市, 北京市, 上海市, 新疆维吾尔自治区, 上海市], values: [100, 150, 75…