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

news/2024/11/24 19:21:49/

一、用完软件模拟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.ppmy.cn/news/1548797.html

相关文章

【Linux学习】【Ubuntu入门】1-8 ubuntu下压缩与解压缩

1.Linux系统下常用的压缩格式 常用的压缩扩展名&#xff1a;.tar、.tar.bz2、.tar.gz 2.Windows下7ZIP软件安装 Linux系统下很多文件是.bz2&#xff0c;.gz结尾的压缩文件。 3.Linux系统下gzip压缩工具 gzip工具负责压缩和解压缩.gz格式的压缩包。 gzip对单个文件进行…

lua脚本使用redis

1 安装工具包 luarocks install redis-lua 2 使用lua语言连接redis local MyFirstHandler {-- 插件的优先级&#xff0c;决定了插件的执行顺序&#xff1b;数字越大&#xff0c;优先级越高&#xff0c;越早执行PRIORITY 1101,-- 插件的版本号VERSION "0.1.0-1"…

MIT协议:保留原始版权声明的自由开源协议

MIT协议&#xff0c;最近因为网络热点&#xff0c;变得火热起来了。 它的全名是Massachusetts Institute of Technology License&#xff0c;来自麻省理工学院。 上世纪80年代末&#xff0c;互联网刚刚起步&#xff0c;MIT协议就在那个时候诞生了。 它的目的很简单&#xff1…

利用uniapp开发鸿蒙:运行到鸿蒙模拟器—踩坑合集

从uniapp运行到鸿蒙模拟器上这一步&#xff0c;就有非常多的坑&#xff0c;一些常见的坑&#xff0c;官网都有介绍&#xff0c;就不再拿出来了&#xff0c;这里记录一下官网未记录的大坑 1.运行路径从hbuilderx启动鸿蒙模拟器 解决方法&#xff1a; Windows系统&#xff0c;官…

redis:主从复制

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言主从模式复制拓扑结构主从节点建立复制流程数据同步 psyncpsync运行流程全量复制流程部分复制流程实时复制总结 前言 分布式系统&#x…

slf4j 基于 logback 单独打印性能日志到另外一个文件

logback.xml 添加性能日志 <appender name"PERF" class"ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_HOME}/perf.log</file><append>true</append><rollingPolicy class"ch.qos.logback.core.r…

MySQL初学之旅(3)约束

目录 1.前言 2.正文 2.1约束类型 2.2NULL约束 2.3UNIQUE约束 2.4DEFAULT约束 2.5PRIMARY KEY主键约束 2.6FOREIGN KEY外键约束 2.7CHECK约束 3.小结 1.前言 哈喽大家好啊&#xff0c;今儿来继续给大家分享最近学习的MySQL和约束相关的知识点&#xff0c;希望大家一起…

【AIGC】破解ChatGPT!如何使用高价值提示词Prompt提升响应质量

文章目录 为什么高价值提示词如此重要&#xff1f;&#x1f50d;1.1 提升响应的相关性和准确性1.2 节省时间与资源1.3 增强用户体验 了解ChatGPT的工作原理&#x1f9e0;2.1 语言模型的训练过程2.2 上下文理解与生成2.3 限制与挑战 高价值提示词的核心要素✍️3.1 清晰明确的指…