stm32之软件模拟IIC

news2024/11/19 6:18:47

        在之前的文章中分析过在52上的IIC时序,也测试过stm32的自带IIC功能,这里大致写下如何模拟stm32上的IIC。实验硬件基于stm32f103c8t6

废话不多说,先直接上代码。

一、源码

头文件


#include "stdint.h"
#include "gpio.h"

#ifndef __IIC_H__
#define	__IIC_H__


/*********************引脚和主频根据情况更换*****************************/
#define CPU_FREQUENCY_MHZ  72		 			 // STM32时钟主频

#define IIC_GPIO_PORT	GPIOB			    	 // GPIO端口 
#define IIC_SCL_PIN		GPIO_PIN_9			 // 连接到SCL时钟线的GPIO引脚
#define IIC_SDA_PIN		GPIO_PIN_8			 // 连接到SDA数据线的GPIO引脚
 
#define IIC_SCL_1()  IIC_GPIO_PORT->BSRR = IIC_SCL_PIN											// SCL = 1 
#define IIC_SCL_0()  IIC_GPIO_PORT->BSRR = (uint32_t)IIC_SCL_PIN << 16U  		// SCL = 0 
 
#define IIC_SDA_1()  IIC_GPIO_PORT->BSRR = IIC_SDA_PIN   										// SDA = 1 
#define IIC_SDA_0()  IIC_GPIO_PORT->BSRR = (uint32_t)IIC_SDA_PIN << 16U  		// SDA = 0 
 
#define IIC_SDA_READ()  (IIC_GPIO_PORT->IDR & IIC_SDA_PIN)									// 读SDA引脚 
#define IIC_SCL_READ()  (IIC_GPIO_PORT->IDR & IIC_SCL_PIN)									// 读SCL引脚
 
 
void iic_start(void); //开始信号

void iic_stop(void); //停止信号

void iic_send_byte(uint8_t _ucByte); //发送一个字节

void iic_ack(void); //应答信号

uint8_t iic_read_byte(void); //读取一个字节

uint8_t iic_wait_ack(void); //等待应答信号


#endif

.m文件

#include "iic.h"
 
 void delay_us(__IO uint32_t delay) {
    int last, curr, val;
    int temp;

    while (delay != 0) { 
        temp = delay > 900 ? 900 : delay;
        last = SysTick->VAL;
        curr = last - CPU_FREQUENCY_MHZ * temp;
        if (curr >= 0){
            do{
                val = SysTick->VAL;
            }
            while ((val < last) && (val >= curr));
        } else{
            curr += CPU_FREQUENCY_MHZ * 1000;
            do{
                val = SysTick->VAL;
            }
            while ((val <= last) || (val > curr));
        }
        delay -= temp;
    }
}
 
// IIC 至少0.6us,1us即可
void iic_delay_1us(void) {
	delay_us(1);
}

// SCL保持高电平期间,SDA由高电平变成低电平,产生一个下降沿。
void iic_start(void) {
	IIC_SDA_1();
	IIC_SCL_1();
	iic_delay_1us();
	IIC_SDA_0();
	iic_delay_1us();
}
  
// SCL保持高电平期间,SDA由低电平变成高电平,产生一个上升沿。
void iic_stop(void){
	IIC_SDA_0();
	IIC_SCL_1();
	iic_delay_1us();
	IIC_SDA_1();
	iic_delay_1us();
}

void iic_send_byte(uint8_t _ucByte){
	uint8_t i;
	for (i = 0; i < 8; i++) {
		IIC_SCL_0();
		if (_ucByte & 0x80){
			IIC_SDA_1();
		} else{
			IIC_SDA_0();
		}
		iic_delay_1us();
		IIC_SCL_1();
		iic_delay_1us();
		IIC_SCL_0();
		// 发送最后一位
		if (i == 7) {
			 IIC_SDA_1(); 	// 释放总线
		}
		_ucByte <<= 1;		// 左移一个bit 
		iic_delay_1us();
	}
}

uint8_t iic_read_byte(void){
	uint8_t i;
	uint8_t value = 0;
	for (i = 0; i < 8; i++) {
		value <<= 1;
		IIC_SCL_1();
		iic_delay_1us();
		if (IIC_SDA_READ()) {
			value++;
		}
		IIC_SCL_0();
		iic_delay_1us();
	}
	return value;
}

uint8_t iic_wait_ack(void){
	uint8_t result;

	IIC_SCL_1();	
	iic_delay_1us();
	result = IIC_SDA_READ() ? 1 :0;
	IIC_SCL_0();
	iic_delay_1us();
	return result;
}

void iic_ack(void){
	IIC_SDA_0();	
	iic_delay_1us();
	IIC_SCL_1();	
	iic_delay_1us();
	IIC_SCL_0();
	iic_delay_1us();
	IIC_SDA_1();	
}
 
 
uint8_t iic_CheckDevice(uint8_t _Address){
	uint8_t ucAck;
 
	if (IIC_SDA_READ() && IIC_SCL_READ()){
		iic_start();		/* 发送启动信号 */
 
		/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
		iic_send_byte(_Address | 0);
		ucAck = iic_wait_ack();	
 
		iic_stop();			
 
		return ucAck;
	}
	return 1;	
}
 
 
void Device_WriteData(uint8_t DeciveAddr,uint8_t *Data,int size){
    int count=size;
		uint8_t *pData=Data;
		//起始信号
    iic_start();    
    //发送器件地址                         
    iic_send_byte(DeciveAddr);       
    //等待应答
    iic_wait_ack();                          
    while(count--)
		{
			//发送数据
			iic_send_byte(*pData++);                     
			//等待应答
			iic_wait_ack();   
		}			 
                       
    //结束信号
    iic_stop();     
}



二、CubeMX配置

 实验用了PB8和PB9,设置的都是开漏输出式,因为在这个模式下有如下说明:

在配置成开漏输出时,可以读IDR寄存器。 

三、源码分析

整个源码的格式写法和之前手撸51中的IIC的类似,包括start,stop, ack等的时序。

这里是直接操作的寄存器来输出/输入数据。输出时比如SDA,设置BSRR,读取状态时,比如SDA中的ack,直接读取IDR寄存器。

#define IIC_SCL_1()  IIC_GPIO_PORT->BSRR = IIC_SCL_PIN											// SCL = 1 
#define IIC_SCL_0()  IIC_GPIO_PORT->BSRR = (uint32_t)IIC_SCL_PIN << 16U  		// SCL = 0 
 
#define IIC_SDA_1()  IIC_GPIO_PORT->BSRR = IIC_SDA_PIN   										// SDA = 1 
#define IIC_SDA_0()  IIC_GPIO_PORT->BSRR = (uint32_t)IIC_SDA_PIN << 16U  		// SDA = 0 
 
#define IIC_SDA_READ()  (IIC_GPIO_PORT->IDR & IIC_SDA_PIN)									// 读SDA引脚 
#define IIC_SCL_READ()  (IIC_GPIO_PORT->IDR & IIC_SCL_PIN)									// 读SCL引脚

其它地方就没什么分析的了,和51的代码都一致,O(∩_∩)O哈哈~

完整代码

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

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

相关文章

编译u-boot的过程中遇到的问题

我使用的是uboot-2016.tar.bz2这个压缩包&#xff0c;将其解压之后进入这个文件夹&#xff0c;里面所包含的文件如下图所示。 这个文件夹下包含着三个Shell脚本文件&#xff0c;都是可执行的&#xff0c;打开其中一个其内容如下。 根据自己的开发板类型决定执行哪一个Shell脚…

基于Python实现的快递管理系统源码+数据库,采用PyQt6实现GUI界面

快递管理系统 完整代码下载地址&#xff1a;快递管理系统 介绍 通过对传统的快递收发流程进行分析&#xff0c;完成网上快递管理系统的分析设计与开发&#xff0c;使客户能方便在网站上查询自己的快件信息以及网上寄件&#xff0c;同时管理员又能对每天的收到快件进行登记和…

一步步教你如何搭建K8S集群

一、环境配置 三台CentOS7虚拟机&#xff0c;默认配置&#xff0c;内存2GB、处理器2核心。 先更新下系统 1 sudo yum update 2 sudo yum upgrade 二、安装并启动 docker 1 yum -y install wget 2 wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo …

Unity中Shader需要了解的点与向量

文章目录 前言一、点和向量的区别二、向量加法减法1、向量加法2、向量减法(可以把向量减法转化为向量加法) 三、向量的模四、标量![在这里插入图片描述](https://img-blog.csdnimg.cn/03df81df3cdf47989a11605d5f5e7da5.png)1、向量与标量的乘法 前言 Unity中Shader了解使用的…

3个变化3秒区别MT4和MT5

自从mt5上市以来&#xff0c;很多投资者无法快速区别MT4和MT5&#xff0c;其实很简单&#xff0c;通过3个变化anzo capital昂首资本3秒一眼区别。 外观区别 很难从视觉上定义MT4和MT5的区别。在新的平台版本中&#xff0c;开发者专注于平台功能的升级&#xff0c;几乎没有改变…

node 解决多版本配置 error:03000086:digital 引起的问题 已解决

在日常后端工作中&#xff0c;难免会安装前端的项目&#xff0c;今天有旧项目需要维护&#xff0c;但是 提示 node版本过高&#xff0c;或者不是长维护版本&#xff0c;部分分享说&#xff0c;加 opensll 过滤能解决&#xff0c;但是 还是不行&#xff0c;索性来这个 底朝天的找…

阿里云服务器共享型和企业级独享有什么区别?

阿里云ECS云服务器共享型和企业级有什么区别&#xff1f;企业级就是独享型&#xff0c;共享型和企业级云的主要区别CPU调度模式&#xff0c;共享型是非绑定CPU调度模式&#xff0c;企业级是固定CPU调度模式&#xff0c;共享型云服务器在高负载时计算性能可能出现波动不稳定&…

XC1336 高侧过压保护器 30V过压保护IC 可做OVP、高压开关

XC1336是一个高压30V过电压保护器&#xff08;OVP&#xff09;&#xff0c;其电阻较低&#xff0c;只需改变外部连接。它可以用作OVP设备或高压开关。 XC1336由一个电荷泵、一个可配置的功率MOSFET、一个电压参考、一个栅极驱动器和一些逻辑和保护模块组成。 XC1336可以对输入浪…

Linux发行版X华为鲲鹏openEuler

前言 作为硬件和软件之间的桥梁&#xff0c;我接触的最多的就是Windows和Centos&#xff0c;还记得最初的鸟哥的Linux私房菜&#xff0c;而Centos即将停止维护更新&#xff08;Centos7维护到2024&#xff09;&#xff0c;对于个人学习来说没有任何影响&#xff0c;但是对于企业…

算法通过村第十关-快排|白银笔记|快排实战

一个程序员一生中可能会邂逅各种各样的算法&#xff0c;但总有那么几种&#xff0c;是作为一个程序员一定会遇见且大概率需要掌握的算法。今天就来聊聊这些十分重要的“必抓&#xff01;”算法吧~ 文章目录 前言数组第K大总结 前言 这是快排中的经典算法题&#xff0c;但是很多…

C语言 Cortex-A7核 SPI 实验

1 实验目的 1、数码管显示相同的值0000 1111 2222 .... 9999 2、数码管不同的值1234 2 代码 include/spi.h #ifndef __SPI_H__ #define __SPI_H__ #includ…

ROS2 从头开始​​:第 2 部分 - 包、发布者和订阅者

一、说明 在这篇文章中,我们将重点关注 ROS 2 包、发布者和订阅者。具体来说,我们将涵盖以下主题:1. 什么是 ROS 2 包以及为什么它很重要?2.如何使用ros2 pkg create命令创建ROS 2包? 3. 如何使用该rclcpp库在ROS 2中创建发布者和订阅者? 让我们开始吧! 二、套…

世界第一ERP厂商SAP,推出类ChatGPT产品—Joule

9月27日&#xff0c;世界排名第一ERP厂商SAP在官网宣布&#xff0c;推出生成式AI助手Joule&#xff0c;并将其集成在采购、供应链、销售、人力资源、营销、数据分析等产品矩阵中&#xff0c;帮助客户实现降本增效。 据悉&#xff0c;Joule是一款功能类似ChatGPT的产品&#xf…

HONEYWELL 05704-A-0144 端子模块

HONEYWELL 05704-A-0144 端子模块用于连接电缆、导线或连接器&#xff0c;以便将电信号或电源引出到不同的部件或设备中。这些模块在各种工业和电子应用中都有广泛的用途&#xff0c;通常具有以下特点&#xff1a; 连接性&#xff1a;HONEYWELL 05704-A-0144 端子模块提供可靠的…

[C++ 网络协议] I/O流分离所带来的半关闭问题

1.问题和解决方法 根据所学内容&#xff0c;I/O流分离现如今有如下2种方法&#xff1a; 1.调用进程fork函数&#xff0c;分离出子进程&#xff0c;主进程和子进程分别进行输入流的读和输出流的写。 2.用FILE指针按读模式和写模式将输入流和输出流进行区分。 第一种方法&#…

【word密码】为什么word设置只读模式之后,还能编辑?

Word文档设置了只读模式&#xff0c;是可以编辑的&#xff0c;但是当我们进行保存的时候就会发现&#xff0c;word提示需要重命名并选择新路径才能够保存。 这种操作&#xff0c;即使可以编辑文字&#xff0c;但是原文件是不会受到影响的&#xff0c;编辑之后的word文件会保存到…

外汇天眼:Patrick Wonsey挪用340万美元!涉嫌外汇和二元期权欺诈

美国衍生品市场监管机构商品期货交易委员会&#xff08;CFTC&#xff09;宣布&#xff0c;已在佛罗里达州中区地区法院对佛罗里达州里维尤(Riverview)的Patrick Wonsey提起民事执法诉讼。 诉状指控Wonsey涉嫌欺诈和挪用资金&#xff0c;与一项涉及杠杆或保证金的零售外汇&…

变电站无人值守方案:提升效率与增强安全性

随着信息技术、人工智能、大数据的发展进步&#xff0c;电力行业正逐步向智能化转型。其中&#xff0c;无人值守变电站成为了现代电力系统的明显趋势。这种新型的运营模式不仅提高了效率&#xff0c;还极大地增强了电力系统的安全性。 无人值守变电站的核心概念是在没有人类现场…

探索UML类图:软件建模的关键概念和Visual Paradigm的优势

引言&#xff1a; 在软件开发领域&#xff0c;UML&#xff08;统一建模语言&#xff09;是一种广泛使用的建模语言&#xff0c;用于可视化和描述软件系统的结构和行为。其中&#xff0c;UML类图是最常用的一种图表类型之一&#xff0c;用于表示系统中的类、对象和它们之间的关系…

SI3262—高度集成的低功耗SOC芯片

Si3262是一款高度集成的低功耗SOC芯片&#xff0c;其集成了基于RISC-V核的低功耗MCU和工作在13.56MHz的非接触式读写器模块。 MCU模块具有低功耗、Low Pin Count、宽电压工作范围&#xff0c;集成了13/14/15/16位精度的ADC、LVD、UART、SPI、I2C、TIMER、WUP、IWDG、RTC、TSC等…