STM32标准库通用软件模拟IIC

2023-05-16

STM32标准库通用软件模拟IIC

继上次通用可移植的矩阵键盘之后,便继续寻找着下一个能够拿来只需改改引脚就可以使用的通用方案。

恰好最近在研究PCA9685,这是一片能够产生最多十六路PWM信号的芯片,通过IIC总线接口控制,只需要SCL+SDA,外加一根GND,就可以控制多达16路舵机,这属实减少了开发难度。也正是因此,博主产生了写一下通用IIC总线的想法,以下是代码

具体IIC时序在网上一搜一大把,这里就不再多说了。

博主使用的是STM32F103ZET6开发板测试,测试有效,引脚输出速度可以根据你的板子再做修改。

#ifndef _IIC_H
#define _IIC_H

#include "stm32f10x.h"
#include "delay.h"
// 只需要修改下方需要使用的端口,以及时钟即可,注意一定要全部修改好,
#define SCLPort GPIOE		//SCL引脚端口
#define SCLPin GPIO_Pin_15			//SCL引脚
#define SCLPinCLK RCC_APB2Periph_GPIOE
#define SDAPort GPIOE   //SDA引脚端口
#define SDAPin GPIO_Pin_13			//SDA引脚
#define SDAPinCLK RCC_APB2Periph_GPIOE


void IIC_Init(void);	// IIC初始化
// 这里,因为SDA需要实现写和读的功能,因此写了两个,需要读的时候就调用in,需要写的时候调用out,默认out
void IIC_SDA_In(void);
void IIC_SDA_Out(void);

void IIC_Start(void);	// IIC起始
void IIC_Stop(void);	// IIC结束

uint8_t IIC_Wait_Ack(void);

void IIC_Ack(void);		//IICAck
void IIC_NAck(void);  //IICNAck

// 写一个字节
void IIC_Write_One_Byte(uint8_t byte);
// 读一个字节
uint8_t IIC_Read_One_Byte(uint8_t ack);

#endif
#include "stm32f10x.h"
#include "iic.h"

void IIC_Init(void)	// IIC初始化
{
	GPIO_InitTypeDef GPIO_InitStructure;
    // 这一句保留着,不要删掉,禁用掉JTAG
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); 
	RCC_APB2PeriphClockCmd(SCLPinCLK,ENABLE);
	RCC_APB2PeriphClockCmd(SDAPinCLK,ENABLE);
	
	// 初始化SCL引脚
	GPIO_InitStructure.GPIO_Pin = SCLPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SCLPort, &GPIO_InitStructure);
	
	// 初始化SDA引脚
	GPIO_InitStructure.GPIO_Pin = SDAPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SDAPort, &GPIO_InitStructure);
	
	GPIO_SetBits(SCLPort,SCLPin);
	GPIO_SetBits(SDAPort,SDAPin); 	

}
//
void IIC_SDA_In(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin = SDAPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SDAPort, &GPIO_InitStructure);
}
void IIC_SDA_Out(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin = SDAPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SDAPort, &GPIO_InitStructure);
}

void IIC_Start(void)	// IIC起始
{
	IIC_SDA_Out();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(4);
	GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
	delay_us(4);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
}
void IIC_Stop(void)	// IIC结束
{
	IIC_SDA_Out();
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
	delay_us(4);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	delay_us(4);
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)		//等待Ack
{
	u8 ucErrTime=0;
	IIC_SDA_In();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	delay_us(1);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(1);
	while(GPIO_ReadInputDataBit(SDAPort,SDAPin))
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	return 0;
	
}

void IIC_Ack(void)	//IICAck
{
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	IIC_SDA_Out();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
}
void IIC_NAck(void)  //IICNAck
{
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	IIC_SDA_Out();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
}

// 写一个字节
void IIC_Write_One_Byte(uint8_t byte)
{
	uint8_t t;
	IIC_SDA_Out();
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	for(t=0;t<8;t++)
  {              
		if((byte&0x80)>>7)
			GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
		else
			GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
		byte<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
		delay_us(2); 
		GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
		delay_us(2);
  }
}
// 读一个字节
uint8_t IIC_Read_One_Byte(uint8_t ack)
{
	unsigned char i,receive=0;
	IIC_SDA_In();//SDA设置为输入
   for(i=0;i<8;i++ )
	{
		GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
		delay_us(2);
		GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
		receive<<=1;
        if(GPIO_ReadInputDataBit(SDAPort,SDAPin))receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

代码中使用的延时函数取自正点原子官方例程提供的delay.c,delay.h,这里也一并放到了压缩包里。

网盘链接
提取码:1111
博主个人网站,欢迎访问,发现更多有趣的东西,欢迎交流。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32标准库通用软件模拟IIC 的相关文章

随机推荐

  • cmake 常用变量、常用环境变量、常用语法总结

    一 cmake 变量引用的方式 前面我们已经提到了 使用 进行变量的引用 在 IF 等语句中 是直接使用变量名而不通过 取值 二 cmake 自定义变量的方式 主要有隐式定义和显式定义两种 隐式定义的例子 xff1a PROJECT 指令
  • Java基础篇:Iterator迭代器

    一 什么是Iterator xff1a 迭代器 Iterator 是一个对象 xff0c 它的工作是遍历并目标序列中的对象 xff0c 它提供了一种访问一个容器 container 对象中的各个元素的方法 xff0c 把访问逻辑从不同类型的
  • 2022-2-19 ros环境变量

    学习时间及标题 xff1a 2022 2 19 ros环境变量 学习内容 xff1a 1 添加环境变量 xff1a source span class token operator span span class token operato
  • EGO-Planner: An ESDF-free Gradient-based Local Planner for Quadrotors(论文学习)

    EGO规划器 xff1a 一种基于ESDF自由梯度的四转子局部规划器 摘要 ESDF地图被广泛运用在局部地图的梯度方向和大小估计之中 xff0c 但是由于我们在进行轨迹优化的过程中 xff0c 只用到了ESDF地图中很小的一部分 xff0c
  • cmake "undefined reference to"

    main函数在调用其他 c或 cpp文件的函数时 xff0c 有以下几种情况 函数名写错 没有将其他 c或 cpp文件链接到main o xff0c 导致main函数在执行时找不到需要调用的函数 的解决方法 修改CMakeLists txt
  • STM32串口详解

    实验一 xff1a 简单的利用串口接收中断回调函数实现数据的返回 关于串口调试助手 xff0c 还应知道 xff1a 发送英文字符需要用一个字符即8位 xff0c 发送汉字需要两个字符即16位 xff0c 如上图 xff0c 发送汉字 姜
  • RLException: [xx.launch] is neither a launch file in package [x] nor is [x] a launch file name的解决方法

    ROS学习过程中 xff0c 遇到问题 xff1a RLException xx launch is neither a launch file in package x nor is x a launch file name 出现的问题
  • numpy 中 shape 与 size 属性

    因为需要生成一个和现有矩阵大小相等的矩阵 xff0c 故查找了相关资料 span class token operator gt gt span span class token operator gt span span class to
  • Ubtuntu+C语言实现网络通信附源代码

    下面这个案例是我用C在ubtuntu上面写的网络编程案例 2 网络编程 xff08 1 xff09 OSI七层模型理想化 应用层 xff1a app xff0c 应用程序 表示层 xff1a 对数据进行加工 会话层 xff1a 建立会话 x
  • Jetson Nano的GPIO口学习

    1 配置GPIO库 https github com NVIDIA jetson gpio 1 安装pip工具 sudo apt get update sudo apt get install python3 pip sudo apt ge
  • 22.11.22 TCP与UDP 客户端与服务器 协议搭建

    ubuntu 64 ubuntu yuyu yu 11 cat Tcp Cli c 客户端 include lt stdio h gt include lt sys types h gt include lt sys socket h gt
  • cmake交叉编译配置

    cmake交叉编译配置 很多时候 xff0c 我们在开发的时候是面对嵌入式平台 xff0c 因此由于资源的限制需要用到相关的交叉编译 即在你host宿主机上要生成target目标机的程序 里面牵扯到相关头文件的切换和编译器的选择以及环境变量
  • OS——gcc、g++、gdb、vim、vs code的基本使用

    文章目录 g 43 43 的使用gdb的使用vim的使用vscode的使用vs code的安装vs code中C 43 43 的编译运行配置 如果想要学习如何在CentOS 7中安装配置gcc g 43 43 gdb zhs和oh my z
  • make和cmake

    编程人员已经使用CMake和Make很长一段时间了 当你加入一家大公司或者开始在一个具有大量代码的工程上开展工作时 xff0c 你需要注意所有的构建 你需要看到处跳转的 CMakeLists txt 文件 你应该会在终端使用 cmake 和
  • ubuntu自带python与anaconda python环境的切换

    ubuntu的python可分为三大类 xff1a 1 ubuntu自带的python环境 一般安装在 usr bin 中python2和python3可以共存 2 anaconda自带的base环境 3 在anaconda中创建的虚拟py
  • 详细介绍如何在ubuntu20.04中安装ROS系统,以及安装过程中出现的常见错误的解决方法,填坑!!!

    本篇文章写于2020 10 xff0c 经过很多小伙伴的验证 xff0c 文章所介绍的步骤是可以正常完成安装的 xff0c 现在是2021 10 xff0c 经过近期的探索 xff0c 我将安装步骤进行了进一步的优化 xff0c 使安装变得
  • VScode进行python开发出现 No module named “XXX“的解决方法

    VScode进行python开发出现 No module named 34 XXX 34 的解决方法 最近从pycharm转向vscode的时候 xff0c 遇到了如下问题 span class token keyword import s
  • CM3寄存器简介

    Cortex M3基础 寄存器组 通用目的寄存器组R0 R7 也被称为低组寄存器 xff0c 所有指令都能访问字长32位 通用目的寄存器组R8 R12 高组寄存器 32位寄存器 复位后的初始值不可预料 堆栈指针R13 CM3中共有两个堆栈指
  • 基于亚博K210开发板的学习之旅(一)

    本文参考亚博智能官方K210开源课程 五月份购买了亚博的K210开发板 xff0c 但由于课程压力就搁置了 xff0c 最近暑假得空又恰逢电赛清单里有这个 芯片 xff0c 就抽空学习一下 xff0c 特写下这些 xff0c 以作记录 按照
  • STM32标准库通用软件模拟IIC

    STM32标准库通用软件模拟IIC 继上次通用可移植的矩阵键盘之后 xff0c 便继续寻找着下一个能够拿来只需改改引脚就可以使用的通用方案 恰好最近在研究PCA9685 xff0c 这是一片能够产生最多十六路PWM信号的芯片 xff0c 通