STM32——I2C

news2024/11/16 12:06:34

通信协议见(STM32——SPI)

一、I2C协议

1.1 I2C协议介绍;

I2C是(Inter IC Bus)是由Philips公司开发的一种通用数据总线;

有多根通信线;

一根SDA(串行通信线);

一根SCL(串行时钟线);

共地GND;

VCC电源线;

同步半双工;

支持总线挂载多设备(一主多从,多主多从);

带数据应答(主机接收一个数据后,会返回应答位,告诉从机是否接收到了数据);

1.2 I2C协议对硬件的规定;

所有设备的SDA连接在一起,SCL连接在一起,GND连接在一起,如果从设备没有单独供电,还需要外接电源VCC;

主机对SCL时钟线具有绝对的控制权,从机只能输入,不能控制时钟线,此时SCL可以配置为推挽输出;

但是SDA主机和从机即可以输入也可以输出,为了避免主机输出同时,从机也输出,形成短路,I2C设计中是禁止所有设备输出强上拉的高电平;

采样外接弱上拉电阻加开漏输出的模式;(阻值一般为4.7千欧);

结构图如下:

原理:设计为开漏模式,此时输入时,直接经过斯密特触发器整流任何时刻都可以输入,输出时,经过开漏设计,低电平导通,为拉下状态低电平,高电平截至处于浮空状态,引脚电平外接上拉电阻弱上拉为高电平;

设计的优点:

作用:

1.避免电路出现短路现象;

2.避免频繁切换引脚模式;

3.线与:一个或者多个输出低电平,呈现低电平,只有全部都输出高电平才输出高电平;执行多主机下的时钟同步和总线仲裁;

过程:当I2C处于空闲状态时,SCL和SDA均由外挂的电阻,拉高至高电平;总线处于高电平状态;当总线需要传输数据时候,SCL保持不变,将SDA从高电平转换为低电平,产生一个下降沿,当从机检测到SCL高电平,SDA下降沿时候,会复位,进入就绪状态;在SDA下降沿后,SCL也从高电平到低电平,一方面占用这个总线,同时拼接单元,完成后传输后,SCL回弹到高电平,产生上升沿后,SDA也回弹到高电平,从机检测后,进入终止;终止后俩个都处于高电平,恢复到平静状态;

1.3 I2C协议对软件的规定;

1.3.1时序单元:

由起始条件,传输字节,应答位,终止条件组成;

起始条件:标志着一个数据帧的开始,SCL高电平的时候,SDA由高电平变成低电平产生下降沿;

终止条件:标志着一个数据帧的间隔,SLC高电平的时候,SDA由低电平转换为高电平产生上升沿;

传输字节:发送一个字节,接收一个字节;

发送一个字节;

分析:SCL高电平期间,SDA由高电平变成低电平,产生下降沿,触发起始条件,之后再SCL低电平时,主机将数据首位放在SDA上,在SCL高电平时,从机从SDA进行采样(读取数据),所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节;

接收一个字节时序:

分析:SCL高电平期间,SDA由高电平变成低电平,产生下降沿,触发起始条件,之后再SCL低电平时,从机机将数据首位放在SDA上,在SCL高电平时,主机从SDA进行采样(读取数据),所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节;主机在接受前,需要先释放总线(需要先使总线恢复到空闲状态,然后从机才能拿到掌控权);

发送和接收一个应答位时序:

分析:

发送一个应答位:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答;

接收一个应答位:主机发送完数据后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA);

一个完整的时序过程:

I2C一主多从的模型,主机可以访问总线上的任何一个设备,通过地址来确定是哪个设备,首先将每个从机确定一个唯一的设备地址,主机在起始条件后,发送一个字节,从机匹配,响应主机,在同一个I2C总线上,从机的地址必须不同;

从机地址在I2C中分为7位和10位地址;

每个芯片在出厂时候,都会设置一个同类型芯片相同,不同类型芯片不同的7位地址;如果在一个I2C总线上接相同的芯片,此时可以根据芯片的最后几位地址,即可变地址,

根据引脚改变,例如高电平则位1101 0000 低电平位1010 0000;

1.3.2示波器时序分析:

时序1:指定地址写

对于指定设备(从机地址),在指定地址(设备内部寄存器地址)下,写入指定数据;

首先产生起始条件,然后发送一个地址字节(七位或者十位基地址,如果是十位需要发送两个字节第一个字节由5位表示十位基地址的标识+3位地址位,第二字节为剩余7位地址位+一位读写标志位,选择从设备和读写方式),发送一位应答位,之后发送设备内部寄存器地址,然后一位应答位,之后发送有效数据位,如果要连续发送数据位,在指定地址下,连续依次向后写入,就依次发送数据,直到数据位发送完毕后,发送一位应答位,最后发送终止条件;

(因为寄存器是在线系空间连续存放的,通过指针进行操作,所以每次读写后,指针自动++,指向下一位地址,要连续操作几位,就可以找到指定地址后,通过连续写入字节即可)

过程:首先处于平稳状态下,SCL和SDA都是处于高电平,主机需要给从机写入数据时候,在SLC高电平期间,拉低SDA,产生起始条件,随后紧跟的时序,必须是发送一个字节的时序,内容必须是7位从机地址加1位读写位;拉低SCL,产生下降沿,主机开始输出数据,SCL低电平时候,主机将数据位依次放在SDA上(高位先行),然后SCL拉高,从机读取SDA上的数据位,读取过程中即SCL高电平期间,SDA不允许改变,循环八次得到的结果是:从机地址:1101 000 写操作: 0(读操作1),数据时序结束后,紧跟着是应答时序,主机需要释放SDA,根据协议规定,从机需要在此时立刻拉低SDA,产生一个信号,给主机,主机判断从机是否应答(根据线与的关系主机释放SDA后,从机立刻下拉SDA,所以SDA依旧保持低电平,这个过程就表示了应答);SCL为高电平时,主机读取数据,判断结果;从机发送完成后,结束对SDA控制,SDA回调至高电平,因为从机要在低电平尽快变化数据,所以SCL下降沿和SDA上升沿同步发送;读写为给的0为写入操作,所以在应答时序完成后,我们立刻要写入一个字节,类似地址发送的方法重复八次(从机可以自己定义第二个字节的用途),重复应答时序,然后在重新重复写入时序,进行应答时序,直到主机结束发送时候,产生停止条件,即先拉带SDA,为后续SDA上升沿做准备,释放SCL,最后释放SDA;形成一个完整的数据帧;

时序2:指定地址读:当前地址读 对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data));

首先产生起始条件,之后发送一个地址字节(设备内部地址(7)+读写标志位(1)),之后读出当前指针指示的地址下的数据;

时序3:指定地址读 对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

首先首先产生起始条件,然后发送一个地址字节(七位地址,一位写标志位,选择从设备),发送一位应答位,之后发送设备内部寄存器地址,然后一位应答位,之后重新起始位,再次发送地址字节(七位地址,一位读标志位,选择从设备),在指定地址下,连续依次向后读出;

二、I2C外设;

2.1I2C外设介绍:

I2C外设是STM32内部集成的硬件电路,可以自动执行时钟生成和数据时序的收发,减轻CPU的负担;

硬件自动实现时序,软件只需要写入控制寄存器CR(产生起始条件等),数据寄存器DR(写入读取数据),读取状态寄存器SR(通过标志位判断当前状态);

支持多主机模式;分为固定多主机和可变多主机;

固定多主机即为主机个数固定,从机个数固定,主机掌控数据总线,从机只能通过主机允许才可以短暂的掌控数据总线,当多个主机同时控制总线使用权时,总线进行仲裁,胜利的一方获得总线使用权;

可变多主机,I2C总线上挂在多个设备,没有固定的主机和从机,任何一个设备都可以在总线空闲的时候作为主机,然后指定其他设备进行通信,当通信完成后,主机又变成从机,当多个设备同时申请时,总线进行仲裁,胜利的一方获得总线使用权;

支持7位/10位地址模式;

   A.7位地址,起始条件后,第一个时序是必须是寻址+读写位,主机想要通信的从机的七位地址+一位读写位;

        B.十位地址则为起始条件后,第一、二个时序是必须是寻址+读写位,是主机想要通信的从机的十位地址+一位读写位,此时俩个时序为15位+读写位共16位,15位由5位的十位地址标志位帧头11110+十位地址组成;

*并且同一个厂商生成的同一种芯片的I2C外挂地址是相同的,如果要在一条I2C总线上挂载俩个相同地址的芯片,可以通过配置芯片的可变地址,即地址的最低位,来配置不同的地址,在一条I2C总线上,不能有相同的地址;

支持不同的通信速度,标准速度(高达100khz),快速(400KHZ);

作为同步时序,只需要不超过最大值即可;

支持DMA

在多字节操作时候,可以提高效率;

兼容SMbus(系统管理总线)协议;包括CRC码的生成和校验、SMBus(系统管理总线—System Management Bus)和PMBus(电源管理总线—Power Management Bus)主要用于电源管理系统中;。

2.2 I2C外设的结构图;

分析:I2C外设引脚都是通过复用GPIO实现的,具体参考映射表;

数据接收与发送:

数据控制:通过数据控制,控制数据的接收发送,

接收一个数据:当接收一个数据时候,数据一位一位的从SDA输入到移位寄存器中,低位先行

,一位一位的放入数据寄存器中,当一个字节数据接收完毕后,移位寄存器的值会被移入RDR

数据寄存器中,并置标志位RXNE为1,接收寄存器非空,此时可以读取寄存器,获取寄存器中的值;

发送一个数据:把要发送的数据写入数据寄存器TDR中,当移位寄存器为空时,数据寄存器的值会被立刻移入移位寄存器中,并置标志位TXE为1,发送寄存器空,此时新的数据可以存放在数据寄存器中;

 

比较器,自身地址寄存器和双地址寄存器作用是,当STM32作为从机的时候,即可变多主机模式下,STM32也是可以作为从机与其他主机通信,此时STM32的从机地址通过自身的地址寄存器来配置,当主机通信时,通过比较器判断是否相同,选择是否响应通信;并且支持同时响应俩个从机地址;

帧错误校验计算:I2C自带数据校验;

时钟控制:通过配置时钟控制寄存器,控制时钟控制电路,控制SCL输出的时钟频率;

控制逻辑电路:

中断:当内部某些标志位置1时,可以开启中断执行一些事件;

DMA:可以开启DMA通道转运数据;

通过配置控制寄存器CR1和CR2,实现控制;

通过读取状态寄存器SR1和SR2读取状态,例如TXE,RXNE位;

SMBALERT:

 总功能图:

2.3 I2C外设的实现过程;

配置过程:

1.RCC开始GPIO和SPI时钟;

2.初始化GPIO,配置为开漏输出和上拉输入模式;

3.初始化SPI,配置SPI;

4.使能CMDSPI;

2.4 时序图

主机发送:

过程分析:

起始条件S+寻址+读写标志+数据1+数据2+....+数据N+终止条件p(数据后包括A响应);

首先:初始化后,总线处于空闲状态,STM32默认为从模式,产生起始条件,写入控制寄存器,STM32又从模式转换为主模式,发送EV5事件,即是否产生标志位,产生标志位后即起始条件产生完成,在数据寄存器中写入一个字节的从机地址,数据寄存器转到移位寄存器中,再把这个字节发送到I2C总线上,并硬件自动判断是否应答,可以产生中断标志位,寻址完成后,发送EV6事件,表示地址发送结束,EV6结束,发生EV8_1事件,TXE移位寄存器空,数据寄存器空,此时可以写入数据,写入数据可以因为移位寄存器也为空,此时数据寄存器立马转移数据到移位寄存器,并产生事件EV8,数据寄存器空,移位寄存器非空,TXE=1,数据1时序产生,写入DR清除该事件,接收应答为结束后,然后移位寄存器空,数据寄存器立马转移数据到移位寄存器,并产生事件EV8,一直重复上述过程,直达没有新的数据发送,此时当前移位寄存器完成时,数据寄存器空,移位寄存器也为空,此时事件为EV8_2,标志位TXE1,BTF字节发送结束;

主机接收:

过程:

首先写入控制寄存器DR,S位,产生起始条件S,然后进入EV5事件,表示起始条件已发送,之后寻址,应答,产生EV6事件,代表寻址已完成,数据1代表数据正通过移位寄存器进行输入,EV6_1事件,只适用于接收一个字节接收,接收后,硬件自动发送应答位,当时序结束后,表示移入的一个字节已转移到数据寄存器了,产生EV7事件,即收到了数据,当把数据读走后,该位清除,从重复进行,当不需要接收时候,需要在最后一个时序单元发送时,提前把应答位控制寄存器ACK置0,并设置终止条件请求,即EV7_1事件,完成后给出非应答,产生终止事件P;

五、API实现;

5.1软件模拟I2C实现对MPU的控制;

5.1.1程序规划:
首先明确想实现的功能:通过封装GPIO通信引脚,模拟I2C时序,实现读写MPU;根据功能将程序主要分为三部分:通信层(底层),驱动层(上层),应用层(main)

5.1.1.1建立I2C通信层模块(底层):
1.主要对通信引脚的封装,初始化(GPIO初始化,引脚电平变化封装);

2.以及I2C的三个时序组成部分:起始,终止,交换字节;

5.1.1.2硬件驱动层(上层)
基于I2C通信层模块建立MPU6050模块,在这个模块里调用底层的拼图,组成完整的时序(写使能,擦除,页编程,读数据等)

5.1.1.3应用层
mian函数里调用驱动层函数,实现功能;

5.1.2模块封装

首先建立模块,MYI2C,MPU6050模块对应.c,.h文件,并且包含在文件中,完成基础配置(参考STM32_程序建立)

首先编写第一个模块,I2C底层通信:主要实现功能,初始化GPIO,配置GPIO引脚为开漏输出模式,封装通信引脚,配置时序单元(拼图);

功能:RCC开启GPIOB时钟,初始化GPIOB,配置PB10,11为开漏输出模式,模拟I2C输出,空闲状态下SDA和SCL为高电平(外接电阻上拉至高电平);

参数:无:

返回值:无:

封装通信引脚:

功能:将PB10引脚封装成通信引脚SCL,通过改变PB10的电平,实现模拟I2C输出;

说明:在SMT32主频高,变化快,要求在SCL电平变化时,立刻读走数据,I2C对读取速率有要求,太快无法读取,所以加入延时函数;

参数:高低电平0/1;

返回值:无

功能:将PB11引脚封装成通信引脚SDA,通过改变PB11的电平,实现模拟I2C输出;

参数:高低电平0/1;

返回值:

功能:将PB11引脚封装成通信引脚SDA,通过读取PB11的电平,实现模拟接收从机输入;

参数:无;

返回值:接收到的值;

时序单元:起始条件,终止条件,发送应答位,接收应答位,发送一个字节的数据,接收一个字节的数据; 

功能:产生起始条件(空闲条件下,SCL和SDA均为高电平,在SCL高电平时候,SDA由高电平转变为低电平,之后在拉低SCL),标志着时序的开始;

说明:*先将释放SDA,在释放SCL,确保在重复起始条件时,不出错;如果先置SCL高电平,在置SDA高电平,会判断为终止条件;

参数:无 

返回值:无

终止条件时序

功能:标志着数据帧的结束/间隔;

说明:(发送数据或者接受数据的最后一位是SCL低电平的时候放在SDA上,高电平时从SDA上读出,之后发送完毕,SCL变为低电平,但是SDA不确定,在此之前需要将SDA先置低电平,能够产生上升沿,之后在SCL高电平时候,SDA由低电平转变为高电平),标志着时序的开始;

参数:无;

返回值:无;

发送一个字节时序

功能:实现主机发送一个字节;

说明:在SCL低电平的时,主机把字节的一位放在SDA上,在SCL高电平时候,从机读取SDA上的数据,起始条件后,SDA为低电平,所以直接放入数据,之后拉高SCL,从机从SDA上读取数据,之后拉低SCL主机放入下一位数据;

参数:要发送的字节;

返回值:无;

接收一个字节的时序: 

功能:接收一个字节的时序;

说明:先将释放SDA相当于切换为输入模式,通过低电平写,高电平读,实现读写分离,进来之后SCL是低电平,主机释放SDA,从机把数据放在SDA上,SCL切换为高电平,主机从SDA上读取数据,之后拉低SCL,从机放入下一位数据;

参数:无;

返回值:接收到的数据;

发送应答位

功能:主机发送应答位;

说明:SCL低电平时,主机写入SDA,SCL高电平时,从机接收SDA上的数据,开始SCL低电平,主机放入数据SDA上,随后拉低SCL,从机读取SDA,之后在拉低SCL,写入下一个数据;

参数:发送的应答位;

返回值:无;

接收应答位

功能:从机发送应答位

说明:首先释放SDA,SCL低电平时,从机写入SDA,SCL高电平时,主机接收SDA上的数据,开始SCL低电平,从机放入数据SDA上,随后拉低SCL,主机读取SDA,之后在拉低SCL,写入下一个数据;

参数:无;

返回值:接收的值;

在.H文件中声明:

第一个模块底层通信层封装完成;

下面封装第二个模块硬件驱动层(上层),将底层的时序单元,拼接成一个完整的时序,实现功能;

指定地址写:

功能:对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data);

说明:首先是产生起始条件,触发起始条件后,主机发送的第一个字节是寻址(发送从设地址,选择通信的目标),第二个字节是从设置的寄存器地址,第三个字节是要发送的数据,每次发送后,接收从机的应答位,最后终止条件,时序接收;

参数:1.从设备的寄存器地址;

2.发送的数据;

返回值:无;

指定地址读:

功能:对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)(Data)

说明:在通过指针对指定地址进行读写操作的,所以先通过在指定地址写,将指针指向我们需要的地址,所以先重复在指定地址写的,首先是产生起始条件,触发起始条件后,主机发送的第一个字节是寻址(发送从设地址,选择通信的目标),第二个字节是从设置的寄存器地址,之后重复起始条件,寻址时,将在指定地址写,改为在指定地址读,通过|,修改最后一位为读;然后直接读取数据,再把发送应答位为1,表示非应答,从机将不会在发送数据;

如果要进阶连续读取多个数据,则将重复读取数据,发送应答位写0,直到最后一位不再需要读取,发送应答位写1;

参数:1.从设备的寄存器地址;

返回值:读到的数据;

 如果要进阶连续读取多个数据,则将重复读取数据,发送应答位写0,直到最后一位不再需要读取,发送应答位写1;

读取寄存器不同的位置,获取的内容,参考手册;

 要想写入寄存器,首先要解除芯片的睡眠模式,通过写入电源管理寄存器1;

初始化MPU6050

功能:初始化

说明:在初始化之后,要写入一些寄存器,对MP6050硬件电路进行初始化配置;初始化完成后,MPU内部就会进行连续不断的数据转换,输出的数据保存在数据寄存器中;

参数:无;

功能:无;

(使用宏定义修改,这样不用频繁的查看手册,而且直接写入数字,可读性不高)

获取数据寄存器的值:

功能:获取数据寄存器的值,获取XYZ对应的加速度值和陀螺仪值;

说明:定义俩个变量,先读取陀螺仪X轴的高八位,在读取陀螺仪x轴的低八位,再把他们|在一起,的、得到16位数据后,在用指针传递进来的地址,把读到的数据,通过指针返回回去;

参数:无;

功能:返回6个16位的值,分别代表XYZ的加速度值和陀螺仪值;

*因为函数正常只能返回一个返回值,这里需要六个返回值,多返回值的方法:1在函数外定义六个全局变量,子函数读到的数据直接写道全局变量里,六个全局变量在主函数中共享,相当于返回六个值;

2.用指针,进行变量的地址传递,来实现多返回值;

3.用结构体对多个变量进行打包;

使用第二种方法:定义六个指针变量,之后在主函数中定义变量;通过指针,把主函数变量的地址传递到子函数来,子函数通过传递过来的地址,操作主函数的变量,这样子函数结束后,主函数里的变量的值就是子函数想要返回的值;

为什么读取的值是16位——>因为是通过ADC采集电压值,所以是16位(详细可见MPU6050;)

因为接收值是16的,所以八位数据会进行自动强制类型转换,所以左移八位不会出错

因为这些寄存器是连续的,我们可以通过连续读取多个字节,一次性读取14个字节加速度,陀螺仪XYZ数据+两位温度;

在.H文件中声明

 

测试显示:

根据在MPU6050介绍的模型:1943/32768=x/16g;x大约为1g,测得Z轴加速度值为1g

加速度计模型,我们选择最大量程16g,测得数据是1945,1945/32768

陀螺仪:测得数据/32768=x/16(满量程);

5.2硬件SPI实现对MPU的控制;

将软件改成硬件实现,只需要更改底层通信层代码的操作,驱动层不需要修改,因为他们是调用底层通信函数来实现功能的,这就是代码隔离封装的好处;

主要实现步骤:1.RCC开启GPIO和I2C的时钟;

2.初始化GPIO,将引脚配置成开漏输出;

3.初始化I2C外设;

4.生成时序单元;

5.使能12C;

首先查看库函数:

通过结构体初始化12C; 

 生成时序:起始条件:查看手册通过配置CR1寄存器的START位;

产生终止条件:

 

 产生应答位:

 

发送一个字节:

 

接收一个字节:

发送7位地址:

如果不是写入操作,就把Address最低为置0,否则就置1;(可以用代替函数代替) 

查看标志位状态监控:

分为三种:1基本状态监控,同时判断一个或者多个标志位,确定那几个EVEN发生;

2高级状态监控;(把SR1和SR2两个状态寄存器拼接为16的值输出)

3.基于标志位的监控状态;判断某一个标志位;

 读取标志位,清除标志位,读取中断标志位,清除中断标志位;

1.RCC开始GPIO和I2C时钟;

2.初始化GPIO,配置输出模式为,AF_OD复用开漏输出,选择引脚PB11和PB10;

 3.初始化I2C,配置IC2的应答位,时钟频率,时钟占空比,响应地址位数,I2C作为从设备时的响应地址;

4.使能I2C

因为I2C是低电平,产生下降沿的时候,是强下拉,所以下降沿变化很快,但是输出高电平,是释放,外部上拉电阻产生弱上拉,所以上升沿有一个缓冲,随着时钟频率越来越大,缓冲影响越大,大于100Khz时,我们通过改变占空比,使低电平时间逐渐增多,原因是因为,低电平改变数据,高电平读取数据,数据变化需要一定的时间来翻转波形,所以在快速模式下要给低电平更多的时间,要不低电平来不及数据变化,高电平读取也无效,所以在小于100kHz时,占空比是1:1,大于100kHz时,低电平占空比越来越大;

这就是为什么频率过高的时候,I2C的传输速度会收到限制的原因;

5.时序单元

起始条件:

功能:产生一个起始条件;

参数:无;

返回值:无;

//软件配置我们通过Delay,进行阻塞式的流程,函数运行完后,对于的波形也发送完成,但是硬件生成时,是直接把寄存器对于位进行修改,波形是否完成需要进行标志位判断,根据时序图,进行判断;

 参数是指定要检查哪个事件,返回值是SUCCESS表示最后一次事件等于我们指定的事件,ERROR表示不等于;

停止条件:

发送一个字节:

接收一个字节:

不需要应答位,因为在我们发送一个字节和接收一个字节后,硬件会自动产生应答位;

六、实际应用;

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

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

相关文章

如何用Docker+jenkins 运行 python 自动化?

1.在 Linux 服务器安装 docker 2.创建 jenkins 容器 3.根据自动化项目依赖包构建 python 镜像(构建自动化 python 环境) 4.运行新的 python 容器,执行 jenkins 从仓库中拉下来的自动化项目 5.执行完成之后删除容器 前言 环境准备 Linux 服务器一台(我的是 CentOS7)…

解析Go语言中HTTP代理的请求和响应过程

在Go语言中,构建一个HTTP代理服务器其实非常简单。那么,当你发送一个请求给代理服务器时,代理服务器到底做了哪些事情呢? 首先,当你向代理服务器发送一个HTTP请求时,代理服务器会先接收到这个请求。这个请…

Android中属性property_get和property_set的详细用法介绍

1,property_get和property_set的作用说明 在Android操作系统中,property_get和property_set是用于获取和设置系统属性的函数。这些属性通常用于存储和读取配置信息,例如设备配置、网络设置、系统参数等。 property_get函数用于获取指定属性…

spring-bus消息总线的使用

文章目录 依赖bus应用接口用到的封装参数类 接收的应用监听器定义的事件类 使用bus定义bus远程调用A应用数据更新后通过bus数据同步给B应用 依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp…

51单片机通过级联74HC595实现倒计时秒表Protues仿真设计

一、设计背景 近年来随着科技的飞速发展&#xff0c;单片机的应用正在不断的走向深入。本文阐述了51单片机通过级联74HC595实现倒计时秒表设计&#xff0c;倒计时精度达0.05s&#xff0c;解决了传统的由于倒计时精度不够造成的误差和不公平性&#xff0c;是各种体育竞赛的必备设…

一家企业需要CRM,通常有以下这些迹象

CRM软件是一个集成的套件——通常是——云应用程序&#xff0c;例如营销云、销售云和服务云&#xff0c;用于收集和存储客户数据。它为销售团队提供了一个集中的平台来管理客户交互并确定活动的优先级&#xff0c;这样客户就不会感到被忽视&#xff0c;从而提升了他们的客户体验…

Flask使用Jinja2渲染模版使用变量实战

前言&#xff1a; Flask 使用 Jinja2 作为其默认模板引擎&#xff0c;这意味着您可以直接在 Flask 应用程序中使用 Jinja2 模板。您可以创建模板文件&#xff0c;然后在视图函数中渲染这些模板&#xff0c;将动态数据传递给模板进行渲染&#xff0c;并最终生成最终的 HTML 页面…

mcu专用看门狗复位芯片(如MAX706)

mcu专用看门狗复位芯片&#xff08;如MAX706&#xff09; 为什么要使用电压复位芯片RESET引脚WDO引脚MR引脚WDI引脚 国产替代型号应用电路1 推荐电路&#xff08;用一个跳线帽使能/关闭看门狗功能&#xff0c;调试MCU时防止看门狗芯片随便触发复位功能&#xff09;&#xff0c;…

ChatGPT PLUS升级步骤--支付宝、微信

AI伴随着我们已经有一年多了&#xff0c;这一年多里我使用ChatGPT做ppt、生成绘画、写文案、做旅游攻略&#xff0c;还有一些医学知识&#xff0c;医学知识我感觉没有回答的很好&#xff0c;对比于医生给的建议我个人觉得还是医生的比较好&#xff0c;Chat GPT回答的比较官方 …

【极数系列】Flink集成DataSource读取文件数据(08)

文章目录 01 引言02 简介概述03 基于文件读取数据3.1 readTextFile(path)3.2 readFile(fileInputFormat, path)3.3 readFile(fileInputFormat, path, watchType, interval, pathFilter, typeInfo)3.4 实现原理3.5 注意事项3.6 支持读取的文件形式 04 源码实战demo4.1 pom.xml依…

ROS学习笔记11——ROS中的重名问题

一、ros功能包重名——ros工作空间覆盖 功能包重名时&#xff0c;会按照 ROS_PACKAGE_PATH 查找&#xff0c;在前的会优先执行。ROS 会解析 .bashrc 文件&#xff0c;并生成 ROS_PACKAGE_PATH ROS包路径&#xff0c;即调用功能包的顺序&#xff0c;该变量中按照 .bashrc 中配置…

leetcode—跳跃游戏—贪心算法

1 跳跃游戏1 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&a…

图像畸变校正(2)

畸变校正是一种用于矫正图像或视频中的失真或畸变的技术。这种失真通常是由摄像头镜头的特性或角度造成的&#xff0c;可能会导致图像中的对象形状、大小或位置不准确。以下是畸变校正的一般方法&#xff1a; 摄像头模型建立&#xff1a; 首先&#xff0c;需要建立摄像头的模型…

【React教程】(1) React简介、React核心概念、React初始化

目录 ReactReact 介绍React 特点React 的发展历史React 与 Vue 的对比技术层面开发团队社区Native APP 开发 相关资源链接 EcmaScript 6 补充React 核心概念组件化虚拟 DOM 起步初始化及安装依赖Hello World React React 介绍 React 是一个用于构建用户界面的渐进式 JavaScrip…

海外云手机为什么吸引用户?

近年来&#xff0c;随着全球化的飞速发展&#xff0c;海外云手机逐渐成为各行各业关注的焦点。那么&#xff0c;究竟是什么让海外云手机如此吸引用户呢&#xff1f;本文将深入探讨海外云手机的三大吸引力&#xff0c;揭示海外云手机的优势所在。 1. 高效的社交媒体运营 海外云…

Android 13以上版本读写SD卡权限适配

如题&#xff0c;最近工作上处理的问题&#xff0c;把解决方案简单逻列出来&#xff0c;供有需要的朋友参考之 解决方案&#xff1a; 1、配置权限 <uses-permission android:name"android.permission.READ_MEDIA_IMAGES" /><uses-permission android:name&q…

PyQt5零基础入门(八)——按钮控件(QPushButton、QToolButton)

前言 按钮控件是图形用户界面(GUI)中常用的交互元素&#xff0c;用于触发特定的事件或行为。在Qt框架中&#xff0c;QPushButton和QToolButton是两种常用的按钮控件。 后边我们将以test.png为按钮图标&#xff0c;对比使用两种按钮控件。 普通按钮控件(QPushButton) QPushB…

禁止 ios H5 中 bounces 滑动回弹效果

在开发面向 iOS 设备的 HTML5 应用时&#xff0c;控制页面的滚动行为至关重要&#xff0c;特别是禁用在 Safari 中默认的滑动回弹效果。本文旨在提供一个简洁明了的解决方案&#xff0c;帮助开发者在特定的 Web 应用中禁用这一效果。 1. 什么是滑动回弹效果&#xff1f; 在 iO…

编写交互式 Shell 脚本

在日常的系统管理和自动化任务中&#xff0c;使用 Shell 脚本可以为我们节省大量时间和精力。 文章将以输入 IP 为例&#xff0c;通过几个版本逐步完善一个案例。 原始需求 编写一个交互式的 Shell 脚本&#xff0c;运行时让用户可以输入IP地址&#xff0c;并且脚本会将输入…

【高效开发工具系列】Wolfram Alpha

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…