关于学习炸鸡佬智能手表 应用硬件IIC1来取代原来软件模拟的IIC

一、用完软件模拟IIC,虽然实现了一个通用接口,只要是IO口都可以用,但是既然引脚用到了PB6和PB7,这俩都是自带硬件外设IIC的,不用白不用。这里我也给出硬件IIC的实现,不得不说HAL库封装的真好

1.硬件IIC

这里我加入一个编译宏,在main.h中,实现可以切换软硬件IIC

硬件IIC速度不要太快,我开始跳到400000的时候触摸是无效的。

其他的配置都在CubeMx生成的iic文件中。这里利用句柄的形式也可以切换不同的iic。

因为我只使用了IIC1 这里也可以再添加一个参数指明使用的是IIC几。

#include "iic_hal_hard.h"
#include "main.h"
#if IICSOFT  == 0/* I2C1 init function */
void MX_I2C1_Init(I2C_HandleTypeDef *hi2cx)
{hi2cx->Instance = I2C1;hi2cx->Init.ClockSpeed = 100000;hi2cx->Init.DutyCycle = I2C_DUTYCYCLE_2;hi2cx->Init.OwnAddress1 = 0;hi2cx->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;hi2cx->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;hi2cx->Init.OwnAddress2 = 0;hi2cx->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;hi2cx->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;if (HAL_I2C_Init(hi2cx) != HAL_OK){Error_Handler();}}
void IICInit(I2C_HandleTypeDef *hi2cx)
{MX_I2C1_Init(hi2cx);
}uint8_t IIC_Write_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t data)
{HAL_StatusTypeDef status;status = HAL_I2C_Mem_Write(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, &data, 1, 1000);if (status == HAL_OK){return SUCCESS;}else{return ERROR;}
}
uint8_t IIC_Write_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[])
{HAL_StatusTypeDef status;status = HAL_I2C_Mem_Write(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, buff, length, 1000);if (status == HAL_OK){return SUCCESS;// 数据写入寄存器成功}else{return ERROR;// 数据写入失败,可能是从机无应答、通信错误等原因}
}
uint8_t IIC_Read_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg)
{HAL_StatusTypeDef status;uint8_t RxBuff;status = HAL_I2C_Mem_Read(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, &RxBuff, 1, 1000);if (status == HAL_OK){return RxBuff;}else{return ERROR;}}
uint8_t IIC_Read_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[])
{HAL_StatusTypeDef status;status = HAL_I2C_Mem_Read(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, buff, length, 1000);if (status == HAL_OK){return SUCCESS;}else{return ERROR;}
}#endif

HAL库封装的,我觉得没有这个中间IIC接口层也可以实现触摸IC的驱动编写。

2 硬件IIC头文件

#ifndef __IIC_HAL_HARD_H
#define __IIC_HAL_HARD_H#include "stm32f4xx_hal.h"
#include "main.h"//PB6 PB7 IIC1外设
#if IICSOFT == 0 extern I2C_HandleTypeDef hi2c1;void IICInit(I2C_HandleTypeDef *hi2cx);uint8_t IIC_Write_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t data);
uint8_t IIC_Write_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[]);
uint8_t IIC_Read_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg);
uint8_t IIC_Read_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[]);
#endif#endif

3 修改后的软件IIC

#include "iic_hal.h"
#include "delay.h"
#if IICSOFT == 1//SCL 低电平期间 SDA可以任意改变电位 高电平不允许改动 因为要采样
// SDA输入模式
void SDA_Input_Mode(iic_bus_t* bus)
{GPIO_InitTypeDef GPIO_InitStructure = {0};GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;GPIO_InitStructure.Pull = GPIO_MODE_INPUT;GPIO_InitStructure.Pull = GPIO_PULLUP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(bus->IIC_SDA_PORT,&GPIO_InitStructure);
}
// SDA输出模式
void SDA_Output_Mode(iic_bus_t* bus)
{GPIO_InitTypeDef GPIO_InitStructure = {0};GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;//下次不要这样搞,还是用MX来配置后复制,不然容易错GPIO_InitStructure.Pull = GPIO_NOPULL;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(bus->IIC_SDA_PORT,&GPIO_InitStructure);
}//SDA输出一个位
void SDA_Output(iic_bus_t *bus, uint8_t val)
{if(val)HAL_GPIO_WritePin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN,GPIO_PIN_SET);elseHAL_GPIO_WritePin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN,GPIO_PIN_RESET);}//SCL输出一个位
void SCL_Output(iic_bus_t *bus, uint8_t val)
{if(val)HAL_GPIO_WritePin(bus->IIC_SCL_PORT,bus->IIC_SCL_PIN,GPIO_PIN_SET);elseHAL_GPIO_WritePin(bus->IIC_SCL_PORT,bus->IIC_SCL_PIN,GPIO_PIN_RESET);
}//SDA输入一位 读一位
uint8_t SDA_Input(iic_bus_t *bus)
{//我觉得这里可以直接返回读到得值 不用判断了return (uint8_t)HAL_GPIO_ReadPin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN) ;}//从这个严格定义的角度来说,最后将 SCL 拉低这一步不属于起始信号本身的部分
//将 SCL 拉低是为了按照 I2C 通信的正确时序,
//把总线状态调整到适合后续数据传输的起始位置
void IICStart(iic_bus_t *bus)
{//当 SCL 为高电平时,SDA 从高电平向低电平跳变SDA_Output(bus,1);delay_us(2);SCL_Output(bus,1);delay_us(1);SDA_Output(bus,0);delay_us(1);SCL_Output(bus,0);delay_us(1); //}
//严格来说,I2C 协议中定义的停止信号是当 SCL 为高电平时,
//SDA 从低电平向高电平跳变
//为了确保正确的时序过渡:在 I2C 通信中,
//数据的传输和各种信号的产生都是按照严格的时序进行的
void IICStop(iic_bus_t *bus)
{//当 SCL 为高电平时,SDA 从低电平向高电平跳变SCL_Output(bus,0);delay_us(2);SDA_Output(bus,0);delay_us(1);SCL_Output(bus,1);delay_us(1); //释放总线SDA_Output(bus,1);delay_us(1);}
uint8_t IICWaitAck(iic_bus_t *bus)
{	uint8_t cErrTime = 5;SDA_Input_Mode(bus);//将数据线变成输入模式 接受从机的应答SCL_Output(bus,1);// 拉高时钟线while(SDA_Input(bus))//读到的数一直是1的话就是没有应答{cErrTime--;//读5次都没有结果就是没有应答 表示接受结束delay_us(1);if(0 == cErrTime){SDA_Output_Mode(bus);IICStop(bus);return ERROR;}}//如果给了应答 就是读到了0SDA_Output_Mode(bus);//转换成输出模式SCL_Output(bus,0);//拉低时钟线 为下一个时序做准备delay_us(2);return SUCCESS;
}
void IICSendAck(iic_bus_t *bus)
{SDA_Output(bus,0);//我记得是低电平放上数据delay_us(1);SCL_Output(bus,1);delay_us(1);SCL_Output(bus,0);delay_us(2);
}
void IICSendNotAck(iic_bus_t *bus)
{//我记得是低电平放上数据等时钟线高电平稳定采样 且此时不允许修改数据SDA_Output(bus,1);delay_us(1);SCL_Output(bus,1);delay_us(1);SCL_Output(bus,0);delay_us(2);
}void IICSendByte(iic_bus_t *bus, uint8_t cSendByte)
{uint8_t i;for(i=0;i<8;i++){SCL_Output(bus,0);delay_us(2);SDA_Output(bus,((cSendByte >> (7 - i)) & 0x01));delay_us(1);SCL_Output(bus,1);delay_us(1);}SCL_Output(bus,0);delay_us(2);
}uint8_t IICReceiveByte(iic_bus_t *bus)
{uint8_t i, cR_Byte=0;uint8_t bit=0;SDA_Input_Mode(bus);//接受字节 改成输入模式for(i=0;i<8;i++){SCL_Output(bus,0); //拉低时钟线 等待从机放数据delay_us(2);SCL_Output(bus,1);//拉高时钟线 可以采样了delay_us(1);bit = SDA_Input(bus);cR_Byte |= bit << (7-i);}SCL_Output(bus,0);//拉低时钟线SDA_Output_Mode(bus);//改变为输出模式 只有读数据才是输入模式return cR_Byte;
}
void IICInit(iic_bus_t *bus)
{GPIO_InitTypeDef GPIO_InitStructure = {0};//bus->CLK_ENABLE();GPIO_InitStructure.Pin = bus->IIC_SDA_PIN ;//上面给的是开漏 这里变成推挽搞不懂 ,推挽就不用变输入模式了GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Pull = GPIO_NOPULL;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(bus->IIC_SDA_PORT, &GPIO_InitStructure);GPIO_InitStructure.Pin = bus->IIC_SCL_PIN ;HAL_GPIO_Init(bus->IIC_SCL_PORT, &GPIO_InitStructure);
}
//返回1表示失败
uint8_t IIC_Write_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t data)
{IICStart(bus);//开始信号IICSendByte(bus,(daddr << 1));//写从机地址if(IICWaitAck(bus)) //无应答停止传输{IICStop(bus);//printf("%d\r\n",IICWaitAck(bus)); 第一次初始化器件的时候会非应答return 1;}IICSendByte(bus,reg);IICWaitAck(bus);IICSendByte(bus,data);IICWaitAck(bus);IICStop(bus);delay_us(1);return 0;}uint8_t IIC_Write_Multi_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[])
{uint8_t i;uint8_t* dataPtr = buff;IICStart(bus);//开始信号IICSendByte(bus,(daddr << 1));//写从机地址if(IICWaitAck(bus)) //无应答停止传输{IICStop(bus);return 1;}IICSendByte(bus,reg);IICWaitAck(bus);for(i=0;i<length;i++){//IICSendByte(bus,buff[i]);     	IICSendByte(bus,*dataPtr++);//利用指针指向缓存区 先解引用给首个元素赋值 再指向下一个字节IICWaitAck(bus);}IICStop(bus);delay_us(1);return 0;
}
uint8_t IIC_Read_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg)
{uint8_t cR_Byte=0;IICStart(bus);//开始信号IICSendByte(bus,(daddr << 1));//写从机地址IICWaitAck(bus);IICSendByte(bus,reg);IICWaitAck(bus);IICStart(bus);//开始信号IICSendByte(bus,(daddr << 1)| 1);//读操作IICWaitAck(bus);cR_Byte = IICReceiveByte(bus);IICSendNotAck(bus);IICStop(bus);return cR_Byte;
}
uint8_t IIC_Read_Multi_Byte(iic_bus_t *bus, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[])
{uint8_t i;uint8_t* dataPtr = buff;IICStart(bus);//开始信号IICSendByte(bus,(daddr << 1)&0xFE );//写从机地址IICWaitAck(bus);IICSendByte(bus,reg);IICWaitAck(bus);IICStart(bus);//开始信号IICSendByte(bus,(daddr << 1)| 1);//读操作IICWaitAck(bus);for(i=0;i<length;i++){//buff[i] = IICReceiveByte(bus);*dataPtr++ = IICReceiveByte(bus);//右++ 先操作后自加if(i<length-1)IICSendAck(bus);elseIICSendNotAck(bus);}IICStop(bus);return 0;
}
#endif

4 修改后的软件IIC头文件 (就是加了个宏编译)

#ifndef __IIC_HAL_H
#define __IIC_HAL_H#include "stm32f4xx_hal.h"
#include "main.h"#if IICSOFT == 1typedef struct
{GPIO_TypeDef* IIC_SDA_PORT;GPIO_TypeDef* IIC_SCL_PORT;uint32_t IIC_SDA_PIN;uint32_t IIC_SCL_PIN;// void (*CLK_ENABLE)(void);
}iic_bus_t;//IIC控制器void IICStart(iic_bus_t *bus);
void IICStop(iic_bus_t *bus);
uint8_t IICWaitAck(iic_bus_t *bus);
void IICSendAck(iic_bus_t *bus);
void IICSendNotAck(iic_bus_t *bus);
void IICSendByte(iic_bus_t *bus, uint8_t cSendByte);
uint8_t IICReceiveByte(iic_bus_t *bus);
void IICInit(iic_bus_t *bus);uint8_t IIC_Write_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t data);
uint8_t IIC_Write_Multi_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[]);
uint8_t IIC_Read_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg);
uint8_t IIC_Read_Multi_Byte(iic_bus_t *bus, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[]);
#endif#endif

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

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

相关文章

用 Python 从零开始创建神经网络(三):添加层级(Adding Layers)

添加层级&#xff08;Adding Layers&#xff09; 引言1. Training Data2. Dense Layer Class 引言 我们构建的神经网络变得越来越受人尊敬&#xff0c;但目前我们只有一层。当神经网络具有两层或更多隐藏层时&#xff0c;它们变成了“深度”网络。目前我们只有一层&#xff0c…

MFC工控项目实例三十实现一个简单的流程

启动按钮夹紧 密闭&#xff0c;时间0到平衡 进气&#xff0c;时间1到进气关&#xff0c;时间2到平衡关 检测&#xff0c;时间3到平衡 排气&#xff0c;时间4到夹紧开、密闭开、排气关。 相关代码 void CSEAL_PRESSUREDlg::OnTimer_2(UINT nIDEvent_2) {// if (nIDEvent_21 &am…

Java I/O(输入/输出)——针对实习面试

目录 Java I/O&#xff08;输入/输出&#xff09;什么是Java I/O流&#xff1f;字节流和字符流有什么区别&#xff1f;什么是缓冲流&#xff1f;为什么要使用缓冲流&#xff1f;Java I/O中的设计模式有哪些&#xff1f;什么是BIO&#xff1f;什么是NIO&#xff1f;什么是AIO&am…

Exploring Defeasible Reasoning in Large Language Models: A Chain-of-Thought A

文章目录 题目摘要简介准备工作数据集生成方法实验结论 题目 探索大型语言模型中的可废止推理&#xff1a;思路链 论文地址&#xff1a;http://collegepublications.co.uk/downloads/LNGAI00004.pdf#page136 摘要 许多大型语言模型 (LLM) 经过大量高质量数据语料库的训练&…

数据结构--数组

一.线性和非线性 线性&#xff1a;除首尾外只有一个唯一的前驱和后继。eg&#xff1a;数组&#xff0c;链表等。 非线性&#xff1a;不是线性的就是非线性。 二.数组是什么&#xff1f; 数组是一个固定长度的存储相同数据类型的数据结构&#xff0c;数组中的元素被存储在一…

MySQL技巧之跨服务器数据查询:基础篇-更新语句如何写

MySQL技巧之跨服务器数据查询&#xff1a;基础篇-更新语句如何写 上一篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的连接名: MY_ODBC_MYSQL 以及用同样的…

Unity教程(十八)战斗系统 攻击逻辑

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

前端学习八股资料CSS(二)

更多详情&#xff1a;爱米的前端小笔记&#xff0c;更多前端内容&#xff0c;等你来看&#xff01;这些都是利用下班时间整理的&#xff0c;整理不易&#xff0c;大家多多&#x1f44d;&#x1f49b;➕&#x1f914;哦&#xff01;你们的支持才是我不断更新的动力&#xff01;找…

云计算研究实训室建设方案

一、引言 随着云计算技术的迅速发展和广泛应用&#xff0c;职业院校面临着培养云计算领域专业人才的迫切需求。本方案旨在构建一个先进的云计算研究实训室&#xff0c;为学生提供一个集理论学习、实践操作、技术研发与创新于一体的综合性学习平台&#xff0c;以促进云计算技术…

通过Python 调整Excel行高、列宽

在Excel中&#xff0c;默认的行高和列宽可能不足以完全显示某些单元格中的内容&#xff0c;特别是当内容较长时。通过调整行高和列宽&#xff0c;可以确保所有数据都能完整显示&#xff0c;避免内容被截断。合理的行高和列宽可以使表格看起来更加整洁和专业&#xff0c;尤其是在…

【代码审计】常见漏洞专项审计-业务逻辑漏洞审计

❤️博客主页&#xff1a; iknow181 &#x1f525;系列专栏&#xff1a; 网络安全、 Python、JavaSE、JavaWeb、CCNP &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐评论✍ 0x01 漏洞介绍 1、 原理 业务逻辑漏洞是一类特殊的安全漏洞&#xff0c;业务逻辑漏洞属于设计漏洞而非实…

Wordpress常用配置,包括看板娘跨域等

一个Wordpress的博客已经搭建完成了&#xff0c;那么为了让它看起来更有人间烟火气一点&#xff0c;有一些常用的初始配置&#xff0c;这里整理一下。 修改页脚 页脚这里默认会显示Powered by Wordpress&#xff0c;还有一个原因是这里要加上备案信息。在主题里找到页脚&…

数据库范式、MySQL 架构、算法与树的深入解析

一、数据库范式 在数据库设计中&#xff0c;范式是一系列规则&#xff0c;用于确保数据的组织和存储具有良好的结构、完整性以及最小化的数据冗余。如果不遵循范式设计&#xff0c;数据可能会以平铺式罗列&#xff0c;仅使用冒号、分号等简单分隔。这种方式存在诸多弊端&#…

Taro React-Native IOS 打包发布

http网络请求不到 配置 fix react-native facebook::flipper::SocketCertificateProvider‘ (aka ‘int‘) is not a function or func_rn运行debug提示flipper-CSDN博客 Xcode 15&#xff08;iOS17&#xff09;编译适配报错_no template named function in namespace std-CS…

基于yolov8、yolov5的车型检测识别系统(含UI界面、训练好的模型、Python代码、数据集)

摘要&#xff1a;车型识别在交通管理、智能监控和车辆管理中起着至关重要的作用&#xff0c;不仅能帮助相关部门快速识别车辆类型&#xff0c;还为自动化交通监控提供了可靠的数据支撑。本文介绍了一款基于YOLOv8、YOLOv5等深度学习框架的车型识别模型&#xff0c;该模型使用了…

从python源码到可自动更新软件

相关阅读 标题链接如何打包python程序为exebczl【auto-py-to-exe 可视化打包python到exe】51CTO ZATA 1. python源码 打包时需要特别注意的源码编写规范 除了基本的 Python 编码规范之外,在准备程序进行打包时,还需要特别注意以下几点: 1.1 依赖管理 确保 requirements.t…

javaWeb小白项目--学生宿舍管理系统

目录 一、检查并关闭占用端口的进程 二、修改 Tomcat 的端口配置 三、重新启动 Tomcat 一、javaw.exe的作用 二、结束javaw.exe任务的影响 三、如何判断是否可以结束 结尾&#xff1a; 这个错误提示表明在本地启动 Tomcat v9.0 服务器时遇到了问题&#xff0c;原因是所需…

k8s笔记——核心概念

什么是K8s Kubernetes 也称为 K8s&#xff0c;是用于自动部署、扩缩和管理容器化应用程序的开源系统。 Kubernetes 最初是由 Google 工程师作为 Borg 项目开发和设计的&#xff0c;后于 2015 年捐赠给 云原生计算基金会&#xff08;CNCF&#xff09;。 什么是 Kubernetes 集群…

SkyWalking-安装

SkyWalking-简单介绍 是一个开源的分布式追踪系统&#xff0c;用于检测、诊断和优化分布式系统的功能。 支持 ElasticSearch、H2、MySQL、PostgreSql 等数据库 基于 ElasticSearch 的情况 ElasticSearch&#xff08;ES&#xff09; 安装 1、下载并解压 https://www.elastic…

怎么样绑定域名到AWS(亚马逊云)服务器

1&#xff0c;拿着你买的域名去亚马逊申请一个证书。申请证书分两种&#xff0c;一种是去亚马逊后台填域名手动申请 &#xff0c;另一种是通过API来申请&#xff0c;类似如下代码&#xff1a; 2、证验证书。有两种方式&#xff1a;一种是通过邮件&#xff0c;另一种去到域名提供…