14、IIC主机控制--引脚软件模拟

news2024/11/23 0:42:31

时序图:
在这里插入图片描述
软件基于STM32 HAL库

IIC–定时器精确延时

软件用涉及到使用定时器做精确延时,可以参考我的文章–“CubeMx 定时器高精度延时”
延时使用的文件:
tim.c

/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

TIM_HandleTypeDef htim17;

/* TIM17 init function */
void MX_TIM17_Init(void)
{

  /* USER CODE BEGIN TIM17_Init 0 */

  /* USER CODE END TIM17_Init 0 */

  /* USER CODE BEGIN TIM17_Init 1 */

  /* USER CODE END TIM17_Init 1 */
  htim17.Instance = TIM17;
  htim17.Init.Prescaler = 24-1;
  htim17.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim17.Init.Period = 65535;
  htim17.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim17.Init.RepetitionCounter = 0;
  htim17.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim17) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM17_Init 2 */

  /* USER CODE END TIM17_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM17)
  {
  /* USER CODE BEGIN TIM17_MspInit 0 */

  /* USER CODE END TIM17_MspInit 0 */
    /* TIM17 clock enable */
    __HAL_RCC_TIM17_CLK_ENABLE();
  /* USER CODE BEGIN TIM17_MspInit 1 */

  /* USER CODE END TIM17_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM17)
  {
  /* USER CODE BEGIN TIM17_MspDeInit 0 */

  /* USER CODE END TIM17_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM17_CLK_DISABLE();
  /* USER CODE BEGIN TIM17_MspDeInit 1 */

  /* USER CODE END TIM17_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Delay_Driver.c

/**********************************************************************
*file:定时器高精度延时
*author:残梦
*date:2022.9.26
*note:注:用户禁止使用、更改
    该定时器配置:
	分频系数 -- 24,周期 -- 65535
	无需开启中断
**********************************************************************/
#include "Delay_Driver.h"

/******************************
@function:us延时
@param:us--待延时的时间
@return:void
@date:2022.9.26
@remark:
******************************/
void Delay_us(unsigned int us)
{
    if(!us){return;}
    us = (us > 6553)?6553:us;
    us *= 10;//基础是100ns
    _DelayTIM_Handle.Instance->CNT = 0;
	HAL_TIM_Base_Start(&_DelayTIM_Handle);
	while(_DelayTIM_Handle.Instance->CNT < us);
	HAL_TIM_Base_Stop(&_DelayTIM_Handle);
}

/******************************
@function:ms延时
@param:ms--待延时的时间
@return:void
@date:2022.9.26
@remark:
******************************/
void Delay_ms(unsigned int ms)
{
    unsigned int i = 0;
    if(!ms){return;}
    while(ms)
    {
        i = (ms < 6)?(ms):6;
        Delay_us(i*1000);
        ms -= i;
    }
}

/******************************
@function:s延时
@param:s--待延时的时间
@return:void
@date:2022.9.26
@remark:
******************************/
void Delay_s(unsigned int s)
{
    unsigned int i = 0;
    if(!s){return;}
    while(s)
    {
        i = (s < 60)?(s):60;
        Delay_ms(i*1000);
        s -= i;
    }
}

Delay_Driver.h

#ifndef _Delay_Driver_H_
#define _Delay_Driver_H_
#include "tim.h"

#define _DelayTIM_Handle htim17

extern void Delay_us(unsigned int us);
extern void Delay_ms(unsigned int ms);
extern void Delay_s(unsigned int s);

#endif

模拟IIC主机:版本一

此版本SDA引脚,SCK引脚使用宏定义
IIC_simulate.c

/**********************************************************************
*file:模拟IIC文件
*author:残梦
*date:2023.5.20
*note:V1.0
**********************************************************************/
#include "IIC_simulate.h"
#include "stdio.h"
#include "gpio.h"
#include "Delay_Driver.h"

#define _SET_PIN(GPIOx,Pin) GPIOx->BSRR = Pin //pin set 1
#define _RESET_PIN(GPIOx,Pin) GPIOx->BSRR =  ((uint32_t)Pin << 16u) //pin set 0
#define _READ_PIN(GPIOx,Pin) (GPIOx->IDR & Pin)?1:0

#define dIIC_DELAY() Delay_us(1)//IIC延时函数,设置IIC通信速度:500KHz
#define dIIC_SDA_CLOCK  __HAL_RCC_GPIOB_CLK_ENABLE()
#define dIIC_SDA_PORT   GPIOB
#define dIIC_SDA_PIN    GPIO_PIN_3
#define dIIC_SCK_CLOCK  __HAL_RCC_GPIOB_CLK_ENABLE()
#define dIIC_SCK_PORT   GPIOB
#define dIIC_SCK_PIN    GPIO_PIN_4

#define dIIC_SDA(x) if(x){_SET_PIN(dIIC_SDA_PORT,dIIC_SDA_PIN);}else _RESET_PIN(dIIC_SDA_PORT,dIIC_SDA_PIN)
#define dIIC_SCL(x) if(x){_SET_PIN(dIIC_SCK_PORT,dIIC_SCK_PIN);}else _RESET_PIN(dIIC_SCK_PORT,dIIC_SCK_PIN)

//IO 方向设置
#define dIIC_SDA_IN     {GPIOB->MODER &= ~(3<<(dIIC_SDA_PIN*2));GPIOB->MODER |= 0<<(dIIC_SDA_PIN*2);}//输入模式
#define dIIC_SDA_OUT    {GPIOB->MODER &= ~(3<<(dIIC_SDA_PIN*2));GPIOB->MODER |= 1<<(dIIC_SDA_PIN*2);}//输出模式
#define dIIC_SDA_READ   _READ_PIN(dIIC_SDA_PORT,dIIC_SDA_PIN)
#define dIIC_SCK_READ   _READ_PIN(dIIC_SCK_PORT,dIIC_SCK_PIN)

/******************************
@function:模拟IIC初始化
@param:void
@return:void
@note:
******************************/
void simIIC_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    dIIC_SDA_CLOCK;dIIC_SCK_CLOCK;

    GPIO_InitStruct.Pin = dIIC_SDA_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(dIIC_SDA_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = dIIC_SCK_PIN;
    HAL_GPIO_Init(dIIC_SCK_PORT, &GPIO_InitStruct);
    dIIC_SCL(1);
    dIIC_SDA(1);
}

/******************************
@function:IIC起始信号
@param:void
@return:void
@note:
******************************/
void simIIC_Start(void)
{
    dIIC_SDA_OUT;
    dIIC_SDA(1);
    dIIC_SCL(1);
    dIIC_DELAY();

    dIIC_SDA(0);
    dIIC_DELAY();
    dIIC_SCL(0);
}

/******************************
@function:IIC结束信号
@param:void
@return:void
@note:
******************************/
void simIIC_Stop(void)
{
    dIIC_SCL(0);    
    dIIC_SDA(0);
    dIIC_DELAY();

    dIIC_SCL(1);
    dIIC_DELAY();
    dIIC_SDA(1);
    dIIC_DELAY();
}

/******************************
@function:IIC写数据(请勿其他使用)
@param: data--待发送的数据
@return:0--写成功,-1--写失败(从机地址不存在)
@note:不含IIC起始,IIC结束
******************************/
signed int simIIC_WriteOneByte(unsigned char data)
{
    unsigned char ack = 0,mask = 0;

    dIIC_SDA_OUT;
    for(mask=0x80;mask != 0;mask >>= 1)
    {
        dIIC_SDA(((mask & data) ? 1 : 0));
        dIIC_DELAY();
        dIIC_SCL(1);
        dIIC_DELAY();
        dIIC_SCL(0);
    }
    dIIC_SDA(1);
    dIIC_SDA_IN;
    dIIC_DELAY();
    dIIC_SCL(1);
    dIIC_DELAY();
    ack = dIIC_SDA_READ;
    dIIC_SCL(0);
    dIIC_SDA_OUT;

    return (ack?-1:0);
}

/******************************
@function:IIC读数据(请勿其他使用)
@param: ack:0--应答,1--不应答
@return:读取的数据
@note:不含IIC起始,IIC结束
******************************/
unsigned char simIIC_ReadOneByte(unsigned char ack)
{
    unsigned char mask = 0,data = 0;

    dIIC_SDA(1);
    dIIC_SDA_IN;
    for(mask=0x80;mask != 0;mask >>= 1)
    {
        dIIC_DELAY();
        dIIC_SCL(1);
        dIIC_DELAY();
        data |= ((dIIC_SDA_READ)?mask:0);
        dIIC_SCL(0);
    }
    dIIC_SDA_OUT;
    dIIC_SDA((ack?1:0));
    dIIC_DELAY();
    dIIC_SCL(1);
    dIIC_DELAY();
    dIIC_SCL(0);

    return data;
}

/******************************
@function:IIC写数据
@param: data--待发送的数据
        byteNum--数据字节数,不含地址字节
        address--从机地址
@return:0--写成功,-1--写失败(从机地址不存在|数据字节数0)
@note:
******************************/
signed int simIIC_Write(unsigned char *data,unsigned int byteNum,unsigned char address)
{
    unsigned int pos = 0;
    if(byteNum == 0)return -1;

    simIIC_Start();
    if(simIIC_WriteOneByte(address << 1) < 0){simIIC_Stop();return -1;}//地址访问:写
    for(pos=0;pos < byteNum;pos++){if(simIIC_WriteOneByte(data[pos]) < 0){simIIC_Stop();return -1;}}
    simIIC_Stop();
    return 0;
}

/******************************
@function:IIC读数据
@param: data--读取到的数据
        byteNum--待读取数据字节数,不含地址字节
        address--从机地址
@return:0--读成功,-1--读失败(从机地址不存在|读取错误)
@note:
******************************/
signed int simIIC_Read(unsigned char *data,unsigned int byteNum,unsigned char address)
{
    unsigned int pos = 0;
    if(byteNum == 0)return -1;
    address = (address << 1) | 0x01;

    simIIC_Start();
    if(simIIC_WriteOneByte(address) < 0){simIIC_Stop();return -1;}//地址访问:读
    for(pos=0;pos < byteNum;pos++){data[pos] = simIIC_ReadOneByte((pos == (byteNum-1))?1:0);}
    simIIC_Stop();
    return 0;
}

IIC_simulate.h

#ifndef _IIC_simulate_H_
#define _IIC_simulate_H_

void simIIC_Init(void);
void simIIC_Start(void);
void simIIC_Stop(void);
signed int simIIC_WriteOneByte(unsigned char data);
unsigned char simIIC_ReadOneByte(unsigned char ack);
signed int simIIC_Write(unsigned char *data,unsigned int byteNum,unsigned char address);
signed int simIIC_Read(unsigned char *data,unsigned int byteNum,unsigned char address);

#endif

简易示例

/******************************
@function:发送两个字节数据
@param:MSB 高8位;LSB 低8位
@return:-1--写失败,0--成功
@note:
******************************/
int SHT3x_WriteByte(uint8_t MSB,uint8_t LSB)
{
  uint8_t data[2] = {0};
  data[0] = MSB;data[1] = LSB;
  return (simIIC_Write(data,2,dSHT3X_IIC_ADDRESS) < 0) ? -1 : 0;
}

uint8_t data[6] = {0};
if(simIIC_Read(data,6,dSHT3X_IIC_ADDRESS) < 0)return -1;

已测试使用
在这里插入图片描述

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

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

相关文章

Linux基础内容(21)—— 进程消息队列和信号量

Linux基础内容&#xff08;20&#xff09;—— 共享内存_哈里沃克的博客-CSDN博客 目录 1.消息队列 1.定义 2.操作 2.信号量 1.定义 2.细节 3.延申 4.操作 3.IPC的特点共性 1.消息队列 1.定义 定义&#xff1a;是操作系统提供的内核级队列 2.操作 msgget&#xff1a;…

Java实现MQTT传输协议通信

Java实现MQTT传输协议通信 1. MQTT1.1 概述1.2 发布和订阅模型1.3 客户端1.4 服务器1.5 订阅、主题、会话1.6 协议中的方法2. Java使用MQTT2.1 添加 pom 依赖2.3 订阅方2.4 发布方2.4 MQTT 连接创建方式2.4.1 普通 TCP 连接2.4.2 TLS/SSL 连接1. MQTT

java_day01_单元测试_配置文件

一、软件的生命周期 **软件的可行性分析:**分析该软件是否值的研发,会消耗多少成本,能带来多少的利益等分析 **需求分析:**分析该软件具体该具备有那些功能,产品经理与客户一起讨论 **软件设计:**该软件应该使用什么样的架构,用什么样的数据库,每个模块的具体功能 **程序编…

2023年8大黑客编程语言

以下是2023年最适合黑客攻击的8种编程语言的列表。 道德黑客被定义为合法进入各种网络的做法&#xff0c;目的是识别黑客可能利用的潜在弱点来访问网络。此类黑客攻击旨在在任何漏洞进入危险攻击者手中之前发现它们&#xff0c;然后及时修复它们以防止攻击。让我们进入文章&am…

【数字通信】PAM基带信号的功率谱原理推导详解

PAM信号可以说是最简单的数字通信信号,很多理论最初都是由该信号的表达式推导得到并进行拓展的,纵观各类数字信号的表达式,或多或少都有PAM信号的“影子”,也就是说PAM信号相关的理论知识是最基本的,很有必要搞清楚,本博客主要讨论PAM基带信号的功率谱的原理及推导过程,…

我干了8年测试,告诉你现在软件测试还能不能找到工作!

观点&#xff1a;如果你还是以前的思维来学习测试&#xff0c;那你肯定是找不到工作&#xff01; 我做测试工作有将近8年的时间&#xff0c;蚂蚁金服做过2年&#xff0c;因为加班太多离职了。目前在一家国企上市公司&#xff0c;一年能拿三四十个左右&#xff0c;对比头部互联…

系统集成项目管理工程师 下午 真题 及考点(2018年下半年)

文章目录 一&#xff1a;第4章 项目管理一般知识&#xff0c;项目管理办公室的职责。第6章 项目整体管理二&#xff1a;第5章 项目立项管理。第14章 项目采购管理&#xff0c;采购文件。第13章 项目合同管理&#xff0c;按项目 付款方式 划分的合同分类三&#xff1a;第9章 项目…

GB/T28181-2022针对H.265编码细化及技术实现

技术背景 新版国家标准GB/T28181-2022《公共安全视频监控联网系统信息传输、交换、控制技术要求》已于2022年12月30日发布&#xff0c;并将于2023年7月1日正式实施。 国家标准GB/T28181-2022《公共安全视频监控联网系统信息传输、交换、控制技术要求》规定了公共安全视频监控…

RocketMQ学习

各MQ 并发性能比较 吞吐量 kafka 17.3w/s rocketMQ 11.6w/s RabbitMQ 5.96w/s RocketMQ组件 broker 核心业务组件 nameServe 保存broker 的ip、端口、上下线信息等。 类似注册中心 启动nameServe 时会调用 runserver 启动broker &#xff0c;会默认读取/conf/broker.conf …

第3章“程序的机器级表示”:程序编码 和 数据格式

文章目录 3.2 程序编码3.2.1 机器级代码3.2.2 代码示例3.2.3 关于格式的注解 3.3 数据格式 3.2 程序编码 假设写一个 C 程序&#xff0c;有两个文件 p1.c 和 p2.c。然后用 Unix 命令行编译这段代码&#xff1a; unix> gcc -O2 -o p p1.c p2.c命令 gcc 表明的就是 GNU C 编…

嵌入式 Linux 入门(十一、make 和 MakeFile)

嵌入式 Linux 入门第十一课&#xff0c;Make 工具和 Makefile 的引入...... 矜辰所致目录 前言一、Linux 下多文件编译二、make 工具和 Makefile2.1 make 和 Makefile 是什么?2.2 通过 STM32 提前熟悉 Makefile2.3 GCC 与 make 的关系/区别&#xff1f; 三、一个简单的 Makefi…

〖Python网络爬虫实战㉙〗- Selenium案例实战(三)

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

OpenGL之着色器

文章目录 什么是着色器数据类型输入与输出Uniform三角形渐变色例子从文件中读取 什么是着色器 着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的&#xff0c;它包含一些针对向量和矩阵操作的有用特性。着色器的开头总是要声明版本&#xff0c;接着是输入和输…

攻击面管理有多重要?从一个社工钓鱼的仿冒网站说起

2023年4月中旬&#xff0c;A企业紧锣密鼓地展开了重保前期的筹备。A企业是一家集团公司&#xff0c;业务范围广&#xff0c;资产众多&#xff0c;为了提前了解自身安全情况&#xff0c;探知未知风险&#xff0c;公司通过自身资产清单及配套手段对自身资产暴露情况进行了梳理。 …

总结springboot项目中一些后端接收前端传参的方法

文章目录 1、java方法入参里面什么注解都没有2、不使用&#xff1f;&来拼接参数&#xff0c;在参数中添加PathVariable注解3、RequestBody 先创建一个springboot项目&#xff0c;并在pom文件中添加web依赖&#xff1a; <dependency><groupId>org.springframewo…

Linux:LVM动态磁盘管理

Linux中的LVM是什么 LVM&#xff08;Logical Volume Manager&#xff09;是Linux系统中的一种动态分区技术&#xff0c;它允许将多个物理硬盘上的存储空间组合成一个或多个逻辑卷&#xff08;Logical Volume&#xff09;&#xff0c;并且可以在运行时对逻辑卷进行调整。LVM的设…

Unity UI -- (7) 创建世界空间UI

目前为止&#xff0c;我们已经设计了一个屏幕空间UI&#xff08;Screen Space UI&#xff09;。一个屏幕空间UI会在屏幕上平坦放置&#xff0c;它会被渲染到环境中所有东西的上面&#xff0c;无论相机位置在哪里。 而一个世界空间UI&#xff08;World Space UI&#xff09;能够…

什么是半实物仿真平台自动驾驶半实物仿真平台有哪些?

文章目录 半实物仿真平台介绍自动驾驶半实物仿真平台介绍1.CARLA2.AirSim3.LGSVL Simulator 半实物仿真平台介绍 半实物仿真平台是一种综合利用虚拟仿真和实际硬件设备的仿真系统。它将虚拟环境和真实硬件设备结合起来&#xff0c;旨在提供更真实、更准确的仿真体验。 在半实…

Hack The Box真实靶机环境搭建教程

Hack The Box真实靶机环境搭建教程 1.开启测试靶机的方法2.Windows连接HTB3.Kali连接HTB 1.开启测试靶机的方法 在机器列表中选择一台主机&#xff1a; 选择加盟主机&#xff1a; 靶机开启成功&#xff1a; 2.Windows连接HTB 下载安装OpenVPN&#xff1a; 下载VPN&#xff08…

Linux---文本处理命令(grep、wc、管道符 |)

1. grep命令 grep命令能够在一个或多个文件中&#xff0c;搜索某一特定的字符模式&#xff08;也就是正则表达式&#xff09;&#xff0c;此模式可以 是单一的字符、字符串、单词或句子。 注意&#xff1a;在基本正则表达式中&#xff0c;如通配符 *、、{、|、( 和 )等&#…