时序图:
软件基于STM32 HAL库
IIC–定时器精确延时
软件用涉及到使用定时器做精确延时,可以参考我的文章–“CubeMx 定时器高精度延时”
延时使用的文件:
tim.c
/**
******************************************************************************
* @file tim.c
* @brief This file provides code for the configuration
* of the TIM instances.
******************************************************************************
* @attention
*
* <h2><center>© 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;
已测试使用