45 STM32 IIC主机、从机通信实例(ma51t12b触摸按键芯片)

基于STM32的IIC slave代码实现 此文档是基于STM32单片机编写的I2C 从机通信的代码实现过程 阅读详情

45.1引言

最近在研究触摸按键板的通信,按键板主要用到的通信协议为IIC,事实上IIC的例子有很多,但大都都是模拟IIC的主机(引用某网友的评论),从机这边的内容还是比较少。

早在两三年前就跟着原子哥的学习资料,学习并操作过IIC的eeprom器件,但是依葫芦画瓢,虽然看了IIC的协议,但是还不算很透!!!只能说熟悉。最近接到这个项目,用到IIC通信,原本很快就搞定了,但是遇到了一些问题,发现是从机地址写错了(感觉是芯片厂商故意在文档里面写错的),不过换算挺好的,借此机会算是把IIC较为透彻的跑一遍。

 

45.2 实验环境

本次IIC实验环境使用了两块stm32f103C8t6最小开发板,一个做IIC主机,一个做IIC从机,使用的是标准库完成。

硬件环境:

IIC主机:使用了模拟IIC;

IIC从机:使用STM32自带的标准库;

还有逻辑分析仪!!(因为IIC学会了使用这家伙,感觉还不错)

45.3 IIC知识

(0)IIC支持一主多从,属于半双工,

 

主机跟从机通信,由直接先发目标从机的地址,目标从机匹配好自己地址后会回复主机一个ACK,然后根据从机定义的读写协议进行通信。

(1)IIC总线在空闲状态SDA和SCL都是高电平;

(2)IIC的起始信号和结束信号;

在使用模拟IIC的时候,按照时序图来就好,延时us级延时,根据原子哥那个延时应该没啥问题。

 

(3)IIC应答信号

 

应答信号,是数据传输第8位完成后,第九位需要应答,如果SDA在第九个时钟被拉低,表示发生了应答信号,否则没有应答。

(4)数据时序

传输数据的时候,在时钟跳变的时候,SDA必须保持稳定,否则数据错乱。

(7)IIC主从交互的时候,从机如何判断主机是要写?还是要读呢?

本来以前我没怎么关注这个问题,因为一些外设器件已经设计好了,提供了相关的驱动demo,在用的时候不会深究每一个细节,但当这次用stm32模拟从机的时候,我就遇到了这个问题,因为我要读取从机的数据。

好了,从机如何判断主机要读?还是写?是基于主机发送从机地址的第1位,是高还是低,来判断的!!!如下图所示。

主机写时序:

主机读时序:

结合上面两张图,就可以看到就是从机地址的第1位,是否为0或1来判断的。

注:上述的IIC从机设备的地址只有高7个字节,所以第1位是用来判断,主机到底是要写还是要读的。如果地址是其它位数的,地址的第1位,作用也是一样的功能,就是用来判断是否读写!!

(6)IIC完整的数据时序示例

 

45.4 STM32F103C8T6 IIC模拟主机代码

IIC头文件代码:

#ifndef __MYIIC_H
#define __MYIIC_H

#include "sys.h"
#include "stm32f10x.h"

//IO操作函数	 
#define IIC_SCL    PBout(8) //SCL
#define IIC_SDA    PBout(9) //SDA	 
#define READ_SDA   PBin(9)  //输入SDA 

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif

IIC源文件代码:

#include "myiic.h"
#include "delay.h"


//////////////////////////////////////////////////////////////////
//初始化IIC
void IIC_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); // 使能PB端口时钟	

	////////////////////////////////////////////////////////////////////////////////////
	//PB8-SCL  PB9-SDA
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;	//选择对应的引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);	//初始化PC端口
	GPIO_SetBits(GPIOB, GPIO_Pin_8);   // 关闭所有LED
	GPIO_SetBits(GPIOB, GPIO_Pin_9);   // 关闭所有LED

	////////////////////////////////////////////////////////////////////////////////////
}

//IO方向设置
void SDA_IN(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//PB9-SDA
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	//选择对应的引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	   
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void SDA_OUT(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//PB9-SDA
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	//选择对应的引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	   
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}


//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  

//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL=1;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;//发送I2C总线结束信号
	delay_us(4);							   	
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA=1;delay_us(1);	   
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 

//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
}

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

 

45.5 STM32F103C8T6 IIC硬件从机代码

说到IIC的从机代码,网上找了挺多的,但好像标准库的比较少,导致要自己翻了 较多的博客才搞定,现在共享出来,为了大伙更好的学习吧。

 

IIC头文件代码:

#ifndef __MYIIC_H
#define __MYIIC_H

#include "sys.h"
#include "stm32f10x.h"

void I2C1_Init(void);


#endif

 

IIC源文件代码:

#include <stdio.h>
#include <stdint.h>
#include "myiic.h"
#include "delay.h"


/*---------IIC1---------------*/
u8 I2C1_ADDRESS = 0x68; //7 位 I2C 地址


vu8 I2C_Status = 0;

vu8 I2C1_Buffer_Tx[8] = {0};
vu8 I2C1_Buffer_Rx[8] = {0};

vu32 Tx_Counter = 0;
vu32 Rx_Counter = 0;
//////////////////////////////////////

void I2C1_Init(void)
{
	GPIO_InitTypeDef  	GPIO_InitStructure;
	I2C_InitTypeDef 	I2C_InitStructure;
	NVIC_InitTypeDef 	NVIC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);


	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

	I2C_DeInit(I2C1);
	I2C_InitStructure.I2C_Mode 			= I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle 	= I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 	= I2C1_ADDRESS; 	//从机地址,一定要设置正确
	I2C_InitStructure.I2C_Ack 			= I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed 	= 100000;
	I2C_Init(I2C1, &I2C_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel 						= I2C1_EV_IRQn;//事件中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 	= 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority 			= 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd					= ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel 						= I2C1_ER_IRQn;//错误中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 	= 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority 			= 1;				   
	NVIC_InitStructure.NVIC_IRQChannelCmd					= ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);   
	I2C_Cmd(I2C1, ENABLE);	 
	/*允许1字节1应答模式*/
    I2C_AcknowledgeConfig(I2C1, ENABLE);    
	
}


// I2C1 作为从机,用于中断接收从机数据
void I2C1_EV_IRQHandler(void)
{
	uint8_t ch = 0;

	switch(I2C_GetLastEvent(I2C1))
	{
		// 收到匹配的地址数据
		case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
		{
			I2C_Status = 1;
			//I2C_GenerateSTOP(I2C1, DISABLE);
			break;
		}
		// 收到一个字节数据
		case I2C_EVENT_SLAVE_BYTE_RECEIVED:
		{
			I2C_Status = 2;
			
			//I2C_ClearITPendingBit(I2C1, I2C_IT_RXNE);		  
			ch = I2C_ReceiveData(I2C1);
			I2C1_Buffer_Rx[2] = ch;
			break;
		}
		case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: //发送数据
		{
			I2C_Status = 3;
			
			I2C_SendData(I2C1, 0x77);
			//I2C_ClearITPendingBit(I2C1, I2C_IT_TXE);		  
			break;
		}
		//发送数据,要发送,不然锁死,不过 master 没收到
		case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
		{
			I2C_Status = 4;

			I2C_SendData(I2C1, 0x66);
			//I2C_ClearITPendingBit(I2C1, I2C_IT_TXE);		  

			break;
		}
		case I2C_EVENT_SLAVE_STOP_DETECTED: //收到结束条件
		{
			I2C_Status = 5;
			//I2C_GenerateSTOP(I2C1, ENABLE);			
			I2C_Cmd(I2C1, ENABLE); 
			break;
		}
		default: 
			break;
	}

	
}


void  I2C1_ER_IRQHandler(void)
{
	/* Check on I2C1 AF flag and clear it */ 
	if (I2C_GetITStatus(I2C1, I2C_IT_AF)) 
	{ 
		I2C_ClearITPendingBit(I2C1, I2C_IT_AF); 
	} 

	/* Check on I2C1 AF flag and clear it */ 
	if (I2C_GetITStatus(I2C1, I2C_IT_BERR))  
	{ 
		I2C_ClearITPendingBit(I2C1, I2C_IT_BERR);
	}
}

45.6 ma51t12b触摸按键芯片IIC通信实例

 

本次实验刚好用到这块ma51t12b触摸芯片,这里要吐槽一下他们的datasheet,从机的地址跟文档写的是不一样的,搞的我浪费了一天时间找问题,最后他们联系上厂商,他们发了一个51单片机的IIC读取demo,也不是stm32的,然后一对比,发现地址居然跟文档写的不一样,真的好气啊。

不过现在搞定了就好了,按照下面的时序进行读写操作。

废话不多说,还是上代码把,因为我现在要吃午饭了。

ma51t12b.h 头文件

#ifndef __MA51T12B_H__
#define __MA51T12B_H__

#define 	MA51T12B_DEVICE_ADDR			0xD0

#define		MA51T12B_MID_SENS_VALUE			((1<<7)|(8<<4)|(1<<3)|(8<<0))



/////////////////////register addr//////////////////////////////
#define 	MA51T12B_CH1_2_SEN_ADDR			0x02
#define 	MA51T12B_CH3_4_SEN_ADDR			0x03
#define 	MA51T12B_CH5_6_SEN_ADDR			0x04
#define 	MA51T12B_CH7_8_SEN_ADDR			0x05
#define 	MA51T12B_CH9_10_SEN_ADDR		0x06
#define 	MA51T12B_CH11_12_SEN_ADDR		0x07

#define 	MA51T12B_INT_MOD_ADDR			0x08
#define 	MA51T12B_SYS_CON_ADDR			0x09
#define 	MA51T12B_CH1_8_PD_ADDR			0x0C
#define 	MA51T12B_CH9_12_PD_ADDR			0x0D

#define 	MA51T12B_CH1_4_OUT_ADDR			0x10
#define 	MA51T12B_CH5_8_OUT_ADDR			0x11
#define 	MA51T12B_CH9_12_OUT_ADDR		0x12
///////////////////////////////////////////////////////////////

void MA51TXX_WriteOneByte(uint8_t addr, uint8_t nByte);
uint8_t MA51TXX_ReadOneByte(uint8_t addr);

void MA51TXX_Init(void);

#endif

ma51t12b.c源文件

#include <stdio.h>
#include <stdint.h>
#include "sys.h"
#include "stm32f10x.h"
#include "ma51t12b.h"
#include "myiic.h"


uint8_t		keyNumValue 	= 0xff;
uint8_t		keyASCIIValue 	= 'N';
uint8_t		nCnt = 0;


void MA51TXX_WriteOneByte(uint8_t addr, uint8_t nByte)
{
	uint8_t res = 0;
	
	//起始信号
	IIC_Start();
	
	//写从机地址
	IIC_Send_Byte(MA51T12B_DEVICE_ADDR);
	
	//等待应答
	res = IIC_Wait_Ack();
	if(res ==1)
	{
		printf("===>falied at (%d) line\r\n",__LINE__);
		return;
	}
	
	//写寄存器地址
	IIC_Send_Byte(addr);
	
	//等待应答
	res = IIC_Wait_Ack();
	if(res ==1)
	{
		printf("===>falied at (%d) line\r\n",__LINE__);
		return;
	}
	
	//写数据
	IIC_Send_Byte(nByte);
	
	//等待应答
	res = IIC_Wait_Ack();
	if(res ==1)
	{
		printf("===>falied at (%d) line\r\n",__LINE__);
		return;
	}

	//t
	IIC_Stop();

	delay_ms(10);
}

uint8_t MA51TXX_ReadOneByte(uint8_t addr)
{
	uint8_t res = 0x0;
	
	//起始信号
	IIC_Start();
	
	//写从机地址
	IIC_Send_Byte(MA51T12B_DEVICE_ADDR);
	
	//等待应答
	res = IIC_Wait_Ack();
	if(res ==1)
	{
		printf("===>falied at (%d) line\r\n",__LINE__);
		return;
	}
	
	//写寄存器地址
	IIC_Send_Byte(addr);
	
	//等待应答
	res = IIC_Wait_Ack();
	if(res ==1)
	{
		printf("===>falied at (%d) line\r\n",__LINE__);
		return;
	}
	IIC_Stop();

	delay_us(50);
	
	//起始信号
	IIC_Start();

	//写从机地址
	IIC_Send_Byte(MA51T12B_DEVICE_ADDR | 0x01);

	//等待应答
	res = IIC_Wait_Ack();
	if(res ==1)
	{
		printf("===>falied at (%d) line\r\n",__LINE__);
		return;
	}

	res = IIC_Read_Byte(0);

	IIC_Stop();

	delay_ms(10);

	return res;
}

//初始化硬件
void MA51TXX_Init(void)
{	
	IIC_Init();
	delay_ms(500);

	//配置工作模式 0-正常模式 1-低功耗模式
	MA51TXX_WriteOneByte(MA51T12B_SYS_CON_ADDR,0x03);

	//配置中断输出-中灵敏度-低灵敏度值
	MA51TXX_WriteOneByte(MA51T12B_INT_MOD_ADDR,0x10);

	//设置按键灵敏度
	MA51TXX_WriteOneByte(MA51T12B_CH1_2_SEN_ADDR,MA51T12B_MID_SENS_VALUE);
	MA51TXX_WriteOneByte(MA51T12B_CH3_4_SEN_ADDR,MA51T12B_MID_SENS_VALUE);
	MA51TXX_WriteOneByte(MA51T12B_CH5_6_SEN_ADDR,MA51T12B_MID_SENS_VALUE);
	MA51TXX_WriteOneByte(MA51T12B_CH7_8_SEN_ADDR,MA51T12B_MID_SENS_VALUE);
	MA51TXX_WriteOneByte(MA51T12B_CH9_10_SEN_ADDR,MA51T12B_MID_SENS_VALUE);
	MA51TXX_WriteOneByte(MA51T12B_CH11_12_SEN_ADDR,MA51T12B_MID_SENS_VALUE);

	//使能1-12按键
	MA51TXX_WriteOneByte(MA51T12B_CH1_8_PD_ADDR,0x00);
	MA51TXX_WriteOneByte(MA51T12B_CH9_12_PD_ADDR,0x00);
	
}

 好了,到此结束了!通过本次实验,算是较为完整的熟悉了IIC,估计还差时序调节的问题吧。

 

两片STM32之间I2C通信 硬件平台:master:stm32f401re slave:stm32f401ce 开发平台:keil 5.18 操作系统:win7 如上篇所讲,将401CE配置为I2C从机,并设置为从发送模式。 主机的I2C与从机相同,同样配置即可。同时增加uart设置,方便将接收到的数据打印出来。 主机的设置为主接收: printf("\n\rStart....\n\r"); ... 阅读详情

相关推荐

【IoT】STM32 IIC 详解 之 stm32 IIC 从机模式(中断方式收发数据)

1、IIC简介 第二节代码会用到该部分内容,对于IIC来说,从机是不能主动发送数据的,开始条件都是由主机生成。 1.1、主机发送数据流程 1) 主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始 2) 主机接着发送一个命令字节。该字节由 7 位的外围器件地址和 1 位读写控制位 R/W组成(此时 R/W=0) 3...

产品线负责人 4万+

STM32设置为I2C从机模式

STM32的I2C作为主机的情况相信很多同学都用过,网上也有很多教程,但是作为从设备使用的例子应该不多,本文通过硬件和软件的层面,介绍如何把STM32设置为一个I2C从机。

ShenZhen_zixian的博客 2万+

嵌入式工程师成长之路(2)——电路设计

为什么你的电源模块总是发热炸机?DC/DC和LDO选型的“潜规则”你踩坑了吗? LM2596降压芯片用错电容导致输出振荡?LED恒流驱动设计让灯珠寿命缩水50%?24V转12V方案成本超预算被老板狂喷?——这些血泪教训,谁能懂得!

云轩阁 13万+

STM32硬件I2C双机通信

在本次实验中需要用到两块STM32单片机,其中一块的I2C1做主机,另一块的I2C2做从机,分别进行I2C1写I2C2实验、I2C1读I2C2实验,两次实验I2C1均为主机。

wuyanboplus的博客 1万+

【Agent】多智能体框架MetaGPT入门教程

创建一个 Action 类的子类 SimpleWriteCode,子类中定义好 prompt,并解析返回结果。在 MetaGPT 中,

酒酿小圆子呀~ 3137

iSLIP算法实战:如何用Python模拟交换机优先级匹配(附完整代码)

本文详细介绍了如何使用Python实现iSLIP算法,模拟交换机优先级匹配过程。通过核心的指针滑动逻辑和迭代循环策略,构建了一个完整的iSLIP算法模拟器,并加入可视化模块以直观展示匹配过程。文章还提供了完整的代码框架和性能优化建议,适合网络工程师和Python开发者直接集成到测试环境中。

weixin_29313239的博客 251

stm32之IIC通讯(详细图解附代码)

目录 I2C硬件实现协议: 硬件I2C: 引脚选择:PB6 --SCL ;PB7 --SDA I2C 初始化结构体: I2C配置代码: I2C作为主设备发送数据: I2C发送(写)数据代码: I2C软件模拟协议: I2C软件通信: 1、空闲状态: 2、开始信号: 3、停止信号: 4、应答信号: 5、数据的有效性: 各个信号产生的时间间隔: 起始信号: 停止信号: 应答信号ACK: 等待应答: I2C写字节: I2C硬件实现协议: 由STM32的IIC片上外..

qq_54402650的博客 3万+

STM32实战:5分钟搞定MXL90614红外测温模块的I2C驱动(附完整代码)

本文提供了一份快速集成MLX90614红外测温模块的STM32实战指南。通过详细的软件I2C驱动代码,重点解析了SMBus通信协议、CRC校验及温度数据转换,帮助开发者避开常见陷阱,实现5分钟内完成模块驱动并读取准确温度值。

wasm7browser的博客 353

14 玩转STM32之IIC通信详解(软件模拟篇)看这篇就够了

根据上图我们分开进行分析:当SCL为高电平的时候。SDA从高电平到低电平,这就是开始信号(中间会有极小的延时这点要注意,具体的请参考数据手册),如下图:当SCL为高电平的时候。

南山府的博客 1万+

Ardupilot环境搭建

Ardpilot介绍:ArduPilot通过多种传感器的数据(GPS、加速度计、气压计、磁场计)等来估计飞行器的姿态,从而使飞行器能够保持稳定。

weixin_62387234的博客 2637

第 9 篇:TMC2240 速度调节实战|STEP 信号生成 + 平滑调速算法(无抖动)

摘要:本文详细介绍了TMC2240电机调速方案,重点解决调速时电机抖动、丢步等问题。核心原理是通过STEP信号频率控制转速,结合平滑加减速算法避免电流冲击。文章从速度与STEP频率的数学关系入手,提供了定时器生成固定频率STEP信号的实现代码,并给出不同转速下的频率参数表。针对42步进电机+256微步细分场景,详细讲解了定时器初始化、中断处理及固定转速设置方法,帮助开发者实现稳定调速。全文包含可直接复用的代码片段,适合嵌入式开发者快速实现电机平滑调速功能。

BackCatK Chen的博客 1035

STM32的I2C主从机通信

最近一段时间在做I2C通信协议,需要在两块STM32之间做I2C通信,定的是主机用IO口模拟,从机用的是STM32的硬件I2C,我的项目要求是需要主从机之间能够进行一串数据收发而不出错,实验时在主机方面,利用IO口模拟主机,只需要理解时序就够了,同时将速度能够控制在100K(标准)左右,基本的时序理解网上大把的资料,所以主机这一块几个小时就搞定了,而在做从机时,遇到了困难,本来从机也想用IO口模拟...

weixin_30703911的博客 2536

PLC凸轮开关指令编程应用——控制算法

凸轮开关指令的作用是在PLC程序中根据凸轮开关(Cam Switch)的状态执行不同的操作。凸轮开关通常是机械式的开关装置,它的位置会随着机械运动的变化而改变。凸轮开关的状态可以用来检测机器的位置、角度或其他相关信息,从而触发相应的控制动作。总结起来,凸轮开关指令是PLC编程中常用的一种控制算法,通过检测凸轮开关的状态来触发相应的操作。本文将介绍凸轮开关指令的应用和相应的控制算法,并提供相关的源代码示例。在这个示例中,凸轮开关状态的值代表不同的位置,根据凸轮开关状态的不同,执行相应的动作。

LiJavascript的博客 1034

STM32F103使用硬件i2c作为从机模式

一、简单说明 本例子参考了ST官方历程,官方历程的链接如下 http://www.st.com/content/st_com/zh/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32094.

酱油师兄的博客 4万+

华为OD机试 - 项目规划 - 深度优先搜索dfs(Java 2024 C卷 100分)

每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天优快云在线答疑。

学Java,找哪吒 1153

独家改进|基于YOLO26的轻量级检测网络:参数量减半,精度不降反升

不要全层替换深度可分离卷积:P5深层对语义特征要求高,用标准卷积效果更好,只在P2、P3浅层用DWConv性价比最高注意力不是越多越好:每个阶段加一个就够,加在模块输出端,不要插在模块中间,否则部署容易出现算子不兼容问题轻量模型训练别贪快:初始学习率一定要调低,不然很容易前期震荡,后期收敛不上,精度卡在瓶颈小目标场景优先保留P2分支:如果对速度要求不是极致,保留P2检测头,小目标收益远大于速度损失。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 221

如何判断I2C从机的设备地址?

大家在使用Ginkgo USB-I2C适配器,有个非常重要的信息就是所控制的从机地址必须要知道,否则就无法正确的和I2C从机进行通信,一般来说,在I2C设备的数据手册中都会明确提出这个设备的I2C地址是多少,不过在有的时候,可能手边没有这个设备的地址信息,但是也想和它建立通信,这种情况怎么办呢?下面我们就可以用我们的适配器并配合我们提供的一个小工具来找到这个设备的地址。实现的基本原理,我们先假设这...

viewtoolsz的博客 5818

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

stm32入门学习之IIC

MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度。

weixin_62127790的博客 1091

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

STM32 IIC双机通信—— HAL库硬件IIC版

1,stm32的I2C总线既可以作为主模式也可以作为从模式 作为主模式和作为从模式在CUBE中的配置是一样的,只是i2c设备的地址不一样 Timing是时序,是在配置的时候生成的,不需要修改 当总线的频率设置为100KHZ的时候,rise time 和fall time 要设置为100ns ownAddress就是指的i2c总线的设备地址,该地址可以选择7bit 或者10bit 2,测试的时候使用两块开发板,一块作为master另一块作为slave,主机向从机发送"I2C",当..

晴树的专栏 8372

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

STM32——IIC(I2C)附代码

介绍IIC(I2C)的原理及应用,代码部分包括:软件模拟IIC与IIC硬件外设。利用IIC实现stm32与MPU6050姿态传感器的通信的代码。

m0_60503814的博客 1万+

(六)STM32学习笔记——如何进行IIC通讯

这里采用型号为【AT24C02】的EEPROM掉电存储模块。

lhyriver的博客 561

STM32——硬件IIC从机通信

前言:   根据网上的资料,大部分网友表示STM32自带的硬件IIC存在bug,读写时很容易卡死。自己在调试的时候也出现卡死的情况,最后一点一点调试,也还是调通了。本文将记录自己调试STM32硬件IIC从机的一些心得体会。硬件IIC主机通信见另一篇文章:传送门 。 硬件平台:STM32F205 软件平台:keil v5 函数库:标准库 硬件IIC从机初始化 下面看下STM32中IIC的...

夜风的博客 3万+

STM32设置为I2C从机模式(HAL库版本)

STM32的I2C作为主机的情况相信很多同学都用过,网上也有很多教程,但是作为从设备使用的例子应该不多,本文通过硬件和软件的层面,介绍如何把STM32设置为一个I2C从机。

ShenZhen_zixian的博客 1万+

STM32硬件IIC 主从(一、CubeMx快速实现)

目的 通过HAL库实现STM32F103C8T6两块板之间的IIC主从相互通信,串口打印接收数据。 环境搭建 /**I2C1 GPIO Configuration PB6 ------> I2C1_SCL PB7 ------> I2C1_SDA 注意通信线记得接上拉电阻4.7k。 CubeMx配置 配置sys 串行调试 配置外部高速时钟 配置串口,默认值 配置IIC,默认值,从机地址0x01,左移1位=0x02 开启IIC的事件中断与错误中断 代码 1

qq_36561846的博客 1万+

STM32IIC通信详解(硬件实现IIC通信详解II 基于HAL库编程)

目录STM32硬件框架介绍IIC初始化 STM32硬件框架介绍 首先我们来看IIC通信的硬件架构 可以看出,可以分为以上4部分。 第一部分:通信接口 SDA信号和SCL信号由此产生或输入 第二部分:时钟部分 时钟信号由此产生或由此读取 第三部分:数据部分 通信时,数据从缓冲区放入DR寄存器,再由SR寄存器将其一位一位移出到SDA发送。这个过程持续直到数据发送完毕。 第四部分:控制部分 控制部分和初始化密切相关,控制部分设置IIC的工作模式和使能等各种内部配置 我们主要需要理解的部分为1、3部分。内部的时钟

蓝狐桑的博客 1万+

STM32——I2C通信

STM32——I2C通信

NRWHF的博客 6934
上一篇: 44 RT-Thread Nano移植到stm32F103CBT6 (STD标准库)
下一篇: 46 合泰BS8116A-3触摸按键踩过的坑
Chasing_Chasing
博客等级 码龄10年 233粉丝 87原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值