当前位置: 首页 > news >正文

SPI实验

目录

一、SPI 简介

二、硬件原理

 ECSPI3_SCLK

ECSPI3_MISO和ECSPI3_MOSI

 ECSPI3_SS0

 三、I.MX6U ECSPI 简介

ECSPIx_RXDATA

ECSPIx_TXDATA

ECSPIx_CONREG

ECSPIx_CONFIGREG

 ECSPIx_PERIODREG​编辑

ECSPIx_STATREG

四、ICM-20608 简介

五、代码编写

1、创建文件及文件夹

 2、添加时钟配置

3、编写spi.h

4、编写spi.c

5、编写icm20608.h

6、编写icm20608.c

7、编写main.c

8、修改makefile


同 I2C 一样, SPI 是很常用的通信接口,也可以通过 SPI 来连接众多的传感器。相比 I2C 接
口, SPI 接口的通信速度很快, I2C 最多 400KHz,但是 SPI 可以到达几十 MHz。

一、SPI 简介

和 I2C 一样广泛使用的串行通信: SPI, SPI 全称是 Serial Perripheral Interface,也就是串行外围设备接口。 SPI 是 Motorola 公司推出的一种同步串行接口技术,是一种高速、全双工的同步通信总线, SPI 时钟频率相比 I2C 要高很多,最高可以工作在上百 MHz。 SPI 以主从方式工作,通常是有一个主设备和一个或多个从设备,一般 SPI 需要4 根线,但也可以使用三根线(单向传输)

这四根线如下:
①、 CS/SS, Slave Select/Chip Select,这个是片选信号线,用于选择需要进行通信的从设备。
I2C 主机是通过发送从机设备地址来选择需要进行通信的从机设备的, SPI 主机不需要发送从机
设备,直接将相应的从机设备片选信号拉低即可。
②、 SCK, Serial Clock,串行时钟,和 I2C 的 SCL 一样,为 SPI 通信提供时钟。
③、 MOSI/SDO, Master Out Slave In/Serial Data Output,简称主出从入信号线,这根数据线
只能用于主机向从机发送数据,也就是主机输出,从机输入。
④、 MISO/SDI, Master In Slave Out/Serial Data Input,简称主入从出信号线,这根数据线只能用户从机向主机发送数据,也就是主机输入,从机输出。SPI 通信都是由主机发起的,主机需要提供通信的时钟信号。

SPI 有四种工作模式,通过串行时钟极性(CPOL)和相位(CPHA)的搭配来得到四种工作模式:
①、 CPOL=0,串行时钟空闲状态为低电平。
②、 CPOL=1,串行时钟空闲状态为高电平,可以通过配置时钟相位(CPHA)选择具体的传输议。
③、 CPHA=0,串行时钟的第一个跳变沿(上升沿或下降沿)采集数据。
④、 CPHA=1,串行时钟的第二个跳变沿(上升沿或下降沿)采集数据。
 

二、硬件原理

 看六轴传感器 ICM-20608引脚

 ECSPI3_SCLK

 ECSPI3_SCLK接在 UART2_RXD

ECSPI3_MISO和ECSPI3_MOSI

 ECSPI3_MOSI接在UART2_CTS;ECSPI3_MISO接在UART2_RTS

 ECSPI3_SS0

 

ECSPI3_SS0接在UART2_TXD

这个需要注意,后续会将该引脚复用为上面的GPIO1_IO20(软件片选)

 三、I.MX6U ECSPI 简介

 I.MX6U 自带的 SPI 外设叫做 ECSPI,全称是 Enhanced Configurable Serial Peripheral Interface,别看前面加了个“EC”就以为和标准 SPI 有不同, 其实就是 SPI

I.MX6U 的 ECSPI 可以工作在主模式或从模式,这里使用主模式, I.MX6U 有 4 个ECSPI,每个 ECSPI 支持四个片选信号,因为硬件片选信号只能使用指定的片选 IO,使用硬件片选一个主接口只能接四个从器件;这里用软件片选,人为拉低cs,一个spi主接口就可以支持很多个spi外设,软件片选可以使用任意的 IO

数据手册寄存器如下

ECSPIx_RXDATA

 RXDATA寄存器为接收到的数据

ECSPIx_TXDATA

TXDATA寄存器为发送数据寄存器

ECSPIx_CONREG

 BURST_LENGTH(bit31:24): 突发长度,设置 SPI 的突发传输数据长度,在一次 SPI 发送中最大可以发送 2^12bit 数据。可以设置 0X000~0XFFF,分别对应 1~2^12bit。一般设置突发长度为一个字节,也就是 8bit, BURST_LENGTH=7。
CHANNEL_SELECT(bit19:18): SPI 通道选择,一个 ECSPI 有四个硬件片选信号,每个片选信号是一个硬件通道,虽然本章实验使用的软件片选,但是 SPI 通道还是要选择的。可设置为 0~3,分别对应通道 0~3。开发板上的 ICM-20608 的片选信号接的是ECSPI3_SS0,也就是 ECSPI3 的通道 0,所以实验设置为 0。
DRCTL(bit17:16): SPI 的 SPI_RDY 信号控制位,用于设置 SPI_RDY 信号,为 0 的话不关心 SPI_RDY 信号;为 1 的话 SPI_RDY 信号为边沿触发;为 2 的话 SPI_DRY 是电平触发。
PRE_DIVIDER(bit15:12): SPI 预分频,设置前级分频, ECSPI 时钟频率使用两步来完成分频,此位设置的是第一步,可设置 0~15,分别对应 1~16 分频。
POST_DIVIDER(bit11:8): SPI 分频值,设置2级分频, ECSPI 时钟频率的第二步分频设置,分频值为2^POST_DIVIDER,最大2^n分频,n=0-15
CHANNEL_MODE(bit7:4): SPI 通道主/从模式设置, CHANNEL_MODE[3:0]分别对应 SPI通道 3~0, 为 0 的话就是设置为从模式,如果为 1 的话就是主模式。比如设置为 0X01 的话就是设置通道 0 为主模式。
SMC(bit3):开始模式控制,此位只能在主模式下起作用,为 0 的话通过 XCH 位来开启 SPI突发访问,为 1 的话只要向 TXFIFO 写入数据就开启 SPI 突发访问。
XCH(bit2): 此位只在主模式下起作用,当 SMC 为 0 的话此位用来控制 SPI 突发访问的开启。
HT(bit1): HT 模式使能位, I.MX6ULL 不支持。
EN(bit0): SPI 使能位,为 0 的话关闭 SPI,为 1 的话使能 SPI。

ECSPIx_CONFIGREG

 HT_LENGTH(bit28:24): HT 模式下的消息长度设置, I.MX6ULL 不支持。
SCLK_CTL(bit23:20):设置 SCLK 信号线空闲状态电平, SCLK_CTL[3:0]分别对应通道3~0,为 0 的话 SCLK 空闲状态为低电平,为 1 的话 SCLK 空闲状态为高电平。
DATA_CTL(bit19:16):设置 DATA 信号线空闲状态电平, DATA_CTL[3:0]分别对应通道3~0,为 0 的话 DATA 空闲状态为高电平,为 1 的话 DATA 空闲状态为低电平。
SS_POL(bit15:12): 设置 SPI 片选信号极性设置, SS_POL[3:0]分别对应通道 3~0,为 0 的话片选信号低电平有效,为 1 的话片选信号高电平有效。
SCLK_POL(bit7:4): SPI 时钟信号极性设置,也就是 CPOL, SCLK_POL[3:0]分别对应通道 3~0,为 0 的话 SCLK 高电平有效(空闲的时候为低电平),为 1 的话 SCLK 低电平有效(空闲
的时候为高电平)。
SCLK_PHA(bit3:0): SPI时钟相位设置,也就是CPHA, SCLK_PHA[3:0]分别对应通道3~0,
为 0 的话串行时钟的第一个跳变沿(上升沿或下降沿)采集数据,为 1 的话串行时钟的第二个跳
变沿(上升沿或下降沿)采集数据。
通过 SCLK_POL 和 SCLK_PHA 可以设置 SPI 的工作模式。

 ECSPIx_PERIODREG

CSD_CTL(bit21:16): 片选信号延时控制位,用于设置片选信号和第一个 SPI 时钟信号之
间的时间间隔,范围为 0~63。
CSRC(bit15): SPI 时钟源选择,为 0 的话选择 SPI CLK 为 SPI 的时钟源,为 1 的话选择
32.768KHz 的晶振为 SPI 时钟源。一般选择 SPI CLK 作为 SPI 时钟源,打开时钟树找到eCSPI


  看到eCSPI在粉红色线上,一直对应pll3_sw_clk,也就是480HMZ,从上一直下来到需要”/8“,也就是8分频,也就是480hmz需要除8,就是60mhz;然后到osc选择器,用于选择根时钟源,由寄存器 CSCDR2 的位 ECSPI_CLK_SEL 来控制,下面找到寄存器 CSCDR2的bit18

 为 0 的话选择 pll3_60m 作为 ECSPI 根时钟源。为 1 的话选择 osc_clk 作为 ECSPI 时钟源。本章选择 pll3_60m 作为 ECSPI 根时钟源;时钟树继续往下到1分频,由寄存器 CSCDR2 的位ECSPI_CLK_PODF 来控制,也就是寄存器 CSCDR2的bit24-19,如下

 这里设置为0,表示为1分频;最后进入的eCSPI时钟源为60mhz

ECSPIx_STATREG

 ECSPI 的状态寄存器

TC(bit7):传输完成标志位,为 0 表示正在传输,为 1 表示传输完成。
RO(bit6): RXFIFO 溢出标志位,为 0 表示 RXFIFO 无溢出,为 1 表示 RXFIFO 溢出。
RF(bit5): RXFIFO 空标志位,为 0 表示 RXFIFO 不为空,为 1 表示 RXFIFO 为空。
RDR(bit4): RXFIFO 数据请求标志位,此位为 0 表示 RXFIFO 里面的数据不大于
RX_THRESHOLD,此位为 1 的话表示 RXFIFO 里面的数据大于 RX_THRESHOLD。
RR(bit3): RXFIFO 就绪标志位,为 0 的话 RXFIFO 没有数据,为 1 的话表示 RXFIFO 中
至少有一个字的数据。
TF(bit2): TXFIFO 满标志位,为 0 的话表示 TXFIFO 不为满,为 1 的话表示 TXFIFO 为满。
TDR(bit1): TXFIFO 数据请求标志位,为 0 表示 TXFIFO 中的数据大于 TX_THRESHOLD,
为 1 表示 TXFIFO 中的数据不大于 TX_THRESHOLD。

TE(bit0): TXFIFO 空标志位,为 0 表示 TXFIFO 中至少有一个字的数据,为 1 表示 TXFIFO
为空。
 

四、ICM-20608 简介

ICM-20608 是6 轴 MEMS 传感器,包括 3 轴加速度和 3 轴陀螺仪,并且支持 I2C 和 SPI 两种协议,使用 I2C 接口的话通信速度最高可以达到400KHz,使用 SPI 接口的话通信速度最高可达到 8MHz。

ICM-20608 也是通过读写寄存器来配置和读取传感器数据,使用 SPI 接口读写寄存器需要 16 个时钟或者更多(如果读写操作包括多个字节的话),第一个字节包含要读写的寄存器地址,寄存器地址最高位是读写标志位,如果是读的话寄存器地址最高位要为 1,如果是写的话寄存器地址最高位要为 0,剩下的 7 位才是实际的寄存器地址,寄存器地址后面跟着的就是读写的数据。

在数据手册可以看到

最高频率为8mhz 

注意这个寄存器配置,芯片默认会睡眠,需要关闭 

部分寄存器如下

寄存器
地址
寄存器功能描述
0X19SMLPRT_DIV[7:0]输出速率设置设置输出速率,输出速率计算公式如下:
SAMPLE_RATE=INTERNAL_SAMPLE_RATE/
(1 + SMPLRT_DIV)
0X1ADLPF_CFG[2:0]芯片配置设置陀螺仪低通滤波。可设置 0~7。
0X1BFS_SEL[1:0]陀螺仪量程设置0:±250dps; 1:±500dps; 2:±1000dps
3:±2000dps
0X1CACC_FS_SEL[1:0]加速度计量程设置0:±2g; 1:±4g; 2:±8g; 3:±16g
0X1DA_DLPF_CFG[2:0]加速度计低通滤波设置设置加速度计的低通滤波,可设置 0~7
0X1EGYRO_CYCLE[7]陀螺仪低功耗使能0:关闭陀螺仪的低功耗功能。
1:使能陀螺仪的低功耗功能
0X23TEMP_FIFO_EN[7]FIFO 使能控制1:使能温度传感器 FIFO。
0:关闭温度传感器
XG_FIFO_EN[6]1:使能陀螺仪 X 轴 FIFO。
0:关闭陀螺仪 X 轴 FIFO。
YG_FIFO_EN[5]1:使能陀螺仪 Y 轴 FIFO。
0:关闭陀螺仪 Y 轴 FIFO。
ZG_FIFO_EN[4]1:使能陀螺仪 Z 轴 FIFO。
0:关闭陀螺仪 Z 轴 FIFO。
ACCEL_FIFO_EN[3]1:使能加速度计 FIFO。
0:关闭加速度计 FIFO。
0X3BACCEL_XOUT_H[7:0]数据寄存器加速度 X 轴数据高 8 位
0X3CACCEL_XOUT_L[7:0]加速度 X 轴数据低 8 位        
0X3DACCEL_YOUT_H[7:0]加速度 Y 轴数据高 8 位
0X3EACCEL_YOUT_L[7:0]加速度 Y 轴数据低 8 位
0X3FACCEL_ZOUT_H[7:0]加速度 Z 轴数据高 8 位
0X40ACCEL_ZOUT_L[7:0]加速度 Z 轴数据低 8 位
0X41TEMP_OUT_H[7:0]温度数据高 8 位
0X42TEMP_OUT_L[7:0]温度数据低 8 位
0X43GYRO_XOUT_H[7:0]陀螺仪 X 轴数据高 8 位
0X44GYRO_XOUT_L[7:0]陀螺仪 X 轴数据低 8 位
0X45GYRO_YOUT_H[7:0]陀螺仪 Y 轴数据高 8 位
0X46GYRO_YOUT_L[7:0]陀螺仪 Y 轴数据低 8 位
0X47GYRO_ZOUT_H[7:0]陀螺仪 Z 轴数据高 8 位
0X48GYRO_ZOUT_L[7:0]陀螺仪 Z 轴数据低 8 位
0X6B

DEVICE_RESET[7]

SLEEP[6]

电源管理寄存器 1

1:复位 ICM-20608。

0:退出休眠模式; 1,进入休眠模式

0X6CSTBY_XA[5]电源管理寄存器 20:使能加速度计 X 轴。1:关闭加速度计 X 轴。
STBY_ZA[3]0:使能加速度计 Z 轴。
1:关闭加速度计 Z 轴。
STBY_XG[2]0:使能陀螺仪 X 轴。
1:关闭陀螺仪 X 轴。
STBY_YG[1]0:使能陀螺仪 Y 轴。
1:关闭陀螺仪 Y 轴。
STBY_ZG[0]0:使能陀螺仪 Z 轴。
1:关闭陀螺仪 Z 轴。
0X75WHOAMI[7:0]ID 寄存器, ICM-20608G 的 ID 为 0XAF,ICM-20608D 的 ID 为0XAE。

五、代码编写

1、创建文件及文件夹

 2、添加时钟配置

在时钟配置文件上添加ECSOI的时钟配置

3、编写spi.h

#ifndef __BSP_SPI_H
#define __BSP_SPI_H#include "imx6ul.h"/*函数声明*/
void spi_init(ECSPI_Type *base);
unsigned char spich0_readwrite_byte(ECSPI_Type *base,unsigned char txdata);
#endif 

4、编写spi.c

#include "bsp_spi.h"/*spi初始化*/
void spi_init(ECSPI_Type *base)
{/* 配置CONREG寄存器* bit0 : 		1 	使能ECSPI* bit3 : 		1	当向TXFIFO写入数据以后立即开启SPI突发。* bit[7:4] : 	0001 SPI通道0主模式,根据实际情况选择,*            	   	开发板上的ICM-20608接在SS0上,所以设置通道0为主模式* bit[19:18]:	00 	选中通道0(其实不需要,因为片选信号我们我们自己控制)* bit[31:20]:	0x7	突发长度为8个bit。 */base->CONREG = 0;/*清零*//* 配置CONREG寄存器 */base->CONREG |= (1<<0) | (1<<3) | (1<<4) | (7<<20);/** ECSPI通道0设置,即设置CONFIGREG寄存器* bit0:	0 通道0 PHA为0* bit4:	0 通道0 SCLK高电平有效* bit8: 	0 通道0片选信号 当SMC为1的时候此位无效* bit12:	0 通道0 POL为0* bit16:	0 通道0 数据线空闲时高电平* bit20:	0 通道0 时钟线空闲时低电平*//* 设置通道寄存器 */base->CONFIGREG = 0;/*  * ECSPI通道0设置,设置采样周期* bit[14:0] :	0X2000  采样等待周期,比如当SPI时钟为10MHz的时候*  		    0X2000就等于1/10000 * 0X2000 = 0.8192ms,也就是连续*          	读取数据的时候每次之间间隔0.8ms* bit15	 :  0  采样时钟源为SPI CLK* bit[21:16]:  0  片选延时,可设置为0~63*//* 设置采样周期寄存器 */base->PERIODREG = 0x2000;/** ECSPI的SPI时钟配置,SPI的时钟源来源于pll3_sw_clk/8=480/8=60MHz* 通过设置CONREG寄存器的PER_DIVIDER(bit[11:8])和POST_DIVEDER(bit[15:12])来* 对SPI时钟源分频,获取到我们想要的SPI时钟:* SPI CLK = (SourceCLK / PER_DIVIDER) / (2^POST_DIVEDER)* 比如我们现在要设置SPI时钟为6MHz,那么PER_DIVEIDER和POST_DEIVIDER设置如下:* PER_DIVIDER = 0X9。* POST_DIVIDER = 0X0。* SPI CLK = 60000000/(0X9 + 1) = 60000000=6MHz*//*SPI时钟,ICM20608的SPI最高8mhz将SPI CLK设置为6MHZ*/base->CONREG &= ~((0xF << 12) | (0XF << 8));/*先将bit15:12和bit11:8清理*/base->CONREG |= (9 << 12);/*1级十分频, 60/10 = 6mhz*/
}/*SPI发送、接收函数*/
unsigned char spich0_readwrite_byte(ECSPI_Type *base,unsigned char txdata)
{uint32_t spirxdata = 0;uint32_t spitxdata = txdata;/*选择通道0*/base->CONREG &= ~(3 << 18); /*清零*/base->CONREG |= (0 << 18);/*数据发送*/while((base->STATREG &(1 << 0)) == 0);/* 等待发送FIFO为空 */base->TXDATA = spitxdata;/*数据接收*/while((base->STATREG &(1 << 3)) == 0);/* 等待接收FIFO有数据 */spirxdata = base->RXDATA;return spirxdata;}

5、编写icm20608.h

#ifndef __BSP_ICM20608_H
#define __BSP_ICM20608_H#include "imx6ul.h"
#include "bsp_gpio.h"
#include "bsp_spi.h"
#include "stdio.h"
#include "bsp_delay.h"/*片选宏*/
#define ICM20608_CSN(n) (n ? gpio_pinwrite(GPIO1 , 20 ,1) : gpio_pinwrite(GPIO1 , 20 ,0))/*id值*/
#define ICM20608G_ID (0XAF)
#define ICM20608D_ID (0XAE)/* ICM20608寄存器 *复位后所有寄存器地址都为0,除了*Register 107(0X6B) Power Management 1 	= 0x40*Register 117(0X75) WHO_AM_I 				= 0xAF或0xAE*/
/* 陀螺仪和加速度自测(出产时设置,用于与用户的自检输出值比较) */
#define	ICM20_SELF_TEST_X_GYRO		0x00
#define	ICM20_SELF_TEST_Y_GYRO		0x01
#define	ICM20_SELF_TEST_Z_GYRO		0x02
#define	ICM20_SELF_TEST_X_ACCEL		0x0D
#define	ICM20_SELF_TEST_Y_ACCEL		0x0E
#define	ICM20_SELF_TEST_Z_ACCEL		0x0F/* 陀螺仪静态偏移 */
#define	ICM20_XG_OFFS_USRH			0x13
#define	ICM20_XG_OFFS_USRL			0x14
#define	ICM20_YG_OFFS_USRH			0x15
#define	ICM20_YG_OFFS_USRL			0x16
#define	ICM20_ZG_OFFS_USRH			0x17
#define	ICM20_ZG_OFFS_USRL			0x18#define	ICM20_SMPLRT_DIV			0x19
#define	ICM20_CONFIG				0x1A
#define	ICM20_GYRO_CONFIG			0x1B
#define	ICM20_ACCEL_CONFIG			0x1C
#define	ICM20_ACCEL_CONFIG2			0x1D
#define	ICM20_LP_MODE_CFG			0x1E
#define	ICM20_ACCEL_WOM_THR			0x1F
#define	ICM20_FIFO_EN				0x23
#define	ICM20_FSYNC_INT				0x36
#define	ICM20_INT_PIN_CFG			0x37
#define	ICM20_INT_ENABLE			0x38
#define	ICM20_INT_STATUS			0x3A/* 加速度输出 */
#define	ICM20_ACCEL_XOUT_H			0x3B
#define	ICM20_ACCEL_XOUT_L			0x3C
#define	ICM20_ACCEL_YOUT_H			0x3D
#define	ICM20_ACCEL_YOUT_L			0x3E
#define	ICM20_ACCEL_ZOUT_H			0x3F
#define	ICM20_ACCEL_ZOUT_L			0x40/* 温度输出 */
#define	ICM20_TEMP_OUT_H			0x41
#define	ICM20_TEMP_OUT_L			0x42/* 陀螺仪输出 */
#define	ICM20_GYRO_XOUT_H			0x43
#define	ICM20_GYRO_XOUT_L			0x44
#define	ICM20_GYRO_YOUT_H			0x45
#define	ICM20_GYRO_YOUT_L			0x46
#define	ICM20_GYRO_ZOUT_H			0x47
#define	ICM20_GYRO_ZOUT_L			0x48#define	ICM20_SIGNAL_PATH_RESET		0x68
#define	ICM20_ACCEL_INTEL_CTRL 		0x69
#define	ICM20_USER_CTRL				0x6A
#define	ICM20_PWR_MGMT_1			0x6B
#define	ICM20_PWR_MGMT_2			0x6C
#define	ICM20_FIFO_COUNTH			0x72
#define	ICM20_FIFO_COUNTL			0x73
#define	ICM20_FIFO_R_W				0x74
#define	ICM20_WHO_AM_I 				0x75/* 加速度静态偏移 */
#define	ICM20_XA_OFFSET_H			0x77
#define	ICM20_XA_OFFSET_L			0x78
#define	ICM20_YA_OFFSET_H			0x7A
#define	ICM20_YA_OFFSET_L			0x7B
#define	ICM20_ZA_OFFSET_H			0x7D
#define	ICM20_ZA_OFFSET_L 			0x7E/*icm20608数据结构体*/
struct icm20608_dev_struc
{signed int gyro_x_adc;		/* 陀螺仪X轴原始值 			*/signed int gyro_y_adc;		/* 陀螺仪Y轴原始值 			*/signed int gyro_z_adc;		/* 陀螺仪Z轴原始值 			*/signed int accel_x_adc;		/* 加速度计X轴原始值 			*/signed int accel_y_adc;		/* 加速度计Y轴原始值 			*/signed int accel_z_adc;		/* 加速度计Z轴原始值 			*/signed int temp_adc;		/* 温度原始值 				*//* 下面是计算得到的实际值,扩大100倍方便计算 */signed int gyro_x_act;		/* 陀螺仪X轴实际值 			*/signed int gyro_y_act;		/* 陀螺仪Y轴实际值 			*/signed int gyro_z_act;		/* 陀螺仪Z轴实际值 			*/signed int accel_x_act;		/* 加速度计X轴实际值 			*/signed int accel_y_act;		/* 加速度计Y轴实际值 			*/signed int accel_z_act;		/* 加速度计Z轴实际值 			*/signed int temp_act;		/* 温度实际值 				*/
};
struct icm20608_dev_struc icm20608_dev;	/* icm20608设备 */unsigned char  icm20608_init();
unsigned char icm20608_read_reg(unsigned char reg);
void icm20608_write_reg(unsigned char reg,unsigned char value);
void icm20608_read_len(unsigned char reg ,unsigned char *buf,unsigned char len);
void icm20608_getdata();
float icm20608_gyro_scaleget(void);
unsigned short icm20608_accel_scaleget(void);#endif 

6、编写icm20608.c

#include "bsp_icm20608.h"
#include "bsp_delay.h"
#include "bsp_spi.h"
#include "stdio.h"struct icm20608_dev_struc icm20608_dev;	/* icm20608设备 *//** @description	: 初始化ICM20608* @param		: 无* @return 		: 0 初始化成功,其他值 初始化失败*/
unsigned char icm20608_init(void)
{	unsigned char regvalue;gpio_pin_config_t cs_config;/* 1、ESPI3 IO初始化 * ECSPI3_SCLK 	-> UART2_RXD* ECSPI3_MISO 	-> UART2_RTS* ECSPI3_MOSI	-> UART2_CTS*/IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0);IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0);IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0);/* 配置SPI   SCLK MISO MOSI IO属性	*bit 16: 0 HYS关闭*bit [15:14]: 00 默认100K下拉*bit [13]: 0 keeper功能*bit [12]: 1 pull/keeper使能 *bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 110 驱动能力为R0/6*bit [0]: 1 高转换率*/IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1);IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1);IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1);IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0);IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0X10B0);cs_config.direction = kGPIO_DigitalOutput;cs_config.outputLogic = 0;gpio_init(GPIO1, 20, &cs_config);/* 2、初始化SPI */spi_init(ECSPI3);	icm20608_write_reg(ICM20_PWR_MGMT_1, 0x80);		/* 复位,复位后为0x40,睡眠模式 			*/delayms(50);icm20608_write_reg(ICM20_PWR_MGMT_1, 0x01);		/* 关闭睡眠,自动选择时钟 					*/delayms(50);regvalue = icm20608_read_reg(ICM20_WHO_AM_I);printf("icm20608 id = %#X\r\n", regvalue);if(regvalue != ICM20608G_ID && regvalue != ICM20608D_ID)return 1;icm20608_write_reg(ICM20_SMPLRT_DIV, 0x00); 	/* 输出速率是内部采样率					*/icm20608_write_reg(ICM20_GYRO_CONFIG, 0x18); 	/* 陀螺仪±2000dps量程 				*/icm20608_write_reg(ICM20_ACCEL_CONFIG, 0x18); 	/* 加速度计±16G量程 					*/icm20608_write_reg(ICM20_CONFIG, 0x04); 		/* 陀螺仪低通滤波BW=20Hz 				*/icm20608_write_reg(ICM20_ACCEL_CONFIG2, 0x04); 	/* 加速度计低通滤波BW=21.2Hz 			*/icm20608_write_reg(ICM20_PWR_MGMT_2, 0x00); 	/* 打开加速度计和陀螺仪所有轴 				*/icm20608_write_reg(ICM20_LP_MODE_CFG, 0x00); 	/* 关闭低功耗 						*/icm20608_write_reg(ICM20_FIFO_EN, 0x00);		/* 关闭FIFO						*/return 0;
}/** @description  : 写ICM20608指定寄存器* @param - reg  : 要读取的寄存器地址* @param - value: 要写入的值* @return		 : 无*/
void icm20608_write_reg(unsigned char reg, unsigned char value)
{/* ICM20608在使用SPI接口的时候寄存器地址* 只有低7位有效,寄存器地址最高位是读/写标志位* 读的时候要为1,写的时候要为0。*/reg &= ~0X80;	ICM20608_CSN(0);						/* 使能SPI传输			*/spich0_readwrite_byte(ECSPI3, reg); 	/* 发送寄存器地址		*/ spich0_readwrite_byte(ECSPI3, value);	/* 发送要写入的值			*/ICM20608_CSN(1);						/* 禁止SPI传输			*/
}	/** @description	: 读取ICM20608寄存器值* @param - reg	: 要读取的寄存器地址* @return 		: 读取到的寄存器值*/
unsigned char icm20608_read_reg(unsigned char reg)
{unsigned char reg_val;	   	/* ICM20608在使用SPI接口的时候寄存器地址* 只有低7位有效,寄存器地址最高位是读/写标志位* 读的时候要为1,写的时候要为0。*/reg |= 0x80; 	ICM20608_CSN(0);               					/* 使能SPI传输	 		*/spich0_readwrite_byte(ECSPI3, reg);     		/* 发送寄存器地址  		*/ reg_val = spich0_readwrite_byte(ECSPI3, 0XFF);	/* 读取寄存器的值 			*/ICM20608_CSN(1);                				/* 禁止SPI传输 			*/return(reg_val);               	 				/* 返回读取到的寄存器值 */
}/** @description	: 读取ICM20608连续多个寄存器* @param - reg	: 要读取的寄存器地址* @return 		: 读取到的寄存器值*/
void icm20608_read_len(unsigned char reg, unsigned char *buf, unsigned char len)
{  unsigned char i;/* ICM20608在使用SPI接口的时候寄存器地址,只有低7位有效,* 寄存器地址最高位是读/写标志位读的时候要为1,写的时候要为0。*/reg |= 0x80; ICM20608_CSN(0);               				/* 使能SPI传输	 		*/spich0_readwrite_byte(ECSPI3, reg);			/* 发送寄存器地址  		*/   	   for(i = 0; i < len; i++)					/* 顺序读取寄存器的值 			*/{buf[i] = spich0_readwrite_byte(ECSPI3, 0XFF);	}ICM20608_CSN(1);                			/* 禁止SPI传输 			*/
}/** @description : 获取陀螺仪的分辨率* @param		: 无* @return		: 获取到的分辨率*/
float icm20608_gyro_scaleget(void)
{unsigned char data;float gyroscale;data = (icm20608_read_reg(ICM20_GYRO_CONFIG) >> 3) & 0X3;switch(data) {case 0: gyroscale = 131;break;case 1:gyroscale = 65.5;break;case 2:gyroscale = 32.8;break;case 3:gyroscale = 16.4;break;}return gyroscale;
}/** @description : 获取加速度计的分辨率* @param		: 无* @return		: 获取到的分辨率*/
unsigned short icm20608_accel_scaleget(void)
{unsigned char data;unsigned short accelscale;data = (icm20608_read_reg(ICM20_ACCEL_CONFIG) >> 3) & 0X3;switch(data) {case 0: accelscale = 16384;break;case 1:accelscale = 8192;break;case 2:accelscale = 4096;break;case 3:accelscale = 2048;break;}return accelscale;
}/** @description : 读取ICM20608的加速度、陀螺仪和温度原始值* @param 		: 无* @return		: 无*/
void icm20608_getdata(void)
{float gyroscale;unsigned short accescale;unsigned char data[14];icm20608_read_len(ICM20_ACCEL_XOUT_H, data, 14);gyroscale = icm20608_gyro_scaleget();accescale = icm20608_accel_scaleget();icm20608_dev.accel_x_adc = (signed short)((data[0] << 8) | data[1]); icm20608_dev.accel_y_adc = (signed short)((data[2] << 8) | data[3]); icm20608_dev.accel_z_adc = (signed short)((data[4] << 8) | data[5]); icm20608_dev.temp_adc    = (signed short)((data[6] << 8) | data[7]); icm20608_dev.gyro_x_adc  = (signed short)((data[8] << 8) | data[9]); icm20608_dev.gyro_y_adc  = (signed short)((data[10] << 8) | data[11]);icm20608_dev.gyro_z_adc  = (signed short)((data[12] << 8) | data[13]);/* 计算实际值 */icm20608_dev.gyro_x_act = ((float)(icm20608_dev.gyro_x_adc)  / gyroscale) * 100;icm20608_dev.gyro_y_act = ((float)(icm20608_dev.gyro_y_adc)  / gyroscale) * 100;icm20608_dev.gyro_z_act = ((float)(icm20608_dev.gyro_z_adc)  / gyroscale) * 100;icm20608_dev.accel_x_act = ((float)(icm20608_dev.accel_x_adc) / accescale) * 100;icm20608_dev.accel_y_act = ((float)(icm20608_dev.accel_y_adc) / accescale) * 100;icm20608_dev.accel_z_act = ((float)(icm20608_dev.accel_z_adc) / accescale) * 100;icm20608_dev.temp_act = (((float)(icm20608_dev.temp_adc) - 25 ) / 326.8 + 25) * 100;
}

7、编写main.c


#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"
#include "bsp_rtc.h"
#include "bsp_icm20608.h"
#include "bsp_spi.h"
#include "stdio.h"/** @description	: 指定的位置显示整数数据* @param - x	: X轴位置* @param - y 	: Y轴位置* @param - size: 字体大小* @param - num : 要显示的数据* @return 		: 无*/
void integer_display(unsigned short x, unsigned short y, unsigned char size, signed int num)
{char buf[200];lcd_fill(x, y, x + 50, y + size, tftlcd_dev.backcolor);memset(buf, 0, sizeof(buf));if(num < 0)sprintf(buf, "-%d", -num);else sprintf(buf, "%d", num);lcd_show_string(x, y, 50, size, size, buf); 
}/** @description	: 指定的位置显示小数数据,比如5123,显示为51.23* @param - x	: X轴位置* @param - y 	: Y轴位置* @param - size: 字体大小* @param - num : 要显示的数据,实际小数扩大100倍,* @return 		: 无*/
void decimals_display(unsigned short x, unsigned short y, unsigned char size, signed int num)
{signed int integ; 	/* 整数部分 */signed int fract;	/* 小数部分 */signed int uncomptemp = num; char buf[200];if(num < 0)uncomptemp = -uncomptemp;integ = uncomptemp / 100;fract = uncomptemp % 100;memset(buf, 0, sizeof(buf));if(num < 0)sprintf(buf, "-%d.%d", integ, fract);else sprintf(buf, "%d.%d", integ, fract);lcd_fill(x, y, x + 60, y + size, tftlcd_dev.backcolor);lcd_show_string(x, y, 60, size, size, buf); 
}/** @description	: 使能I.MX6U的硬件NEON和FPU* @param 		: 无* @return 		: 无*/void imx6ul_hardfpu_enable(void)
{uint32_t cpacr;uint32_t fpexc;/* 使能NEON和FPU */cpacr = __get_CPACR();cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk))|  (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);__set_CPACR(cpacr);fpexc = __get_FPEXC();fpexc |= 0x40000000UL;	__set_FPEXC(fpexc);
}/** @description	: main函数* @param 		: 无* @return 		: 无*/
int main(void)
{unsigned char state = OFF;imx6ul_hardfpu_enable();	/* 使能I.MX6U的硬件浮点 			*/int_init(); 				/* 初始化中断(一定要最先调用!) */imx6u_clkinit();			/* 初始化系统时钟 					*/delay_init();				/* 初始化延时 					*/clk_enable();				/* 使能所有的时钟 					*/led_init();					/* 初始化led 					*/beep_init();				/* 初始化beep	 				*/uart_init();				/* 初始化串口,波特率115200 */lcd_init();					/* 初始化LCD 					*/		tftlcd_dev.forecolor = LCD_RED;lcd_show_string(50, 10, 400, 24, 24, (char*)"ALPHA-IMX6UL SPI TEST");    /* 显示字符串 */lcd_show_string(50, 40, 200, 16, 16, (char*)"MY@4384");  lcd_show_string(50, 60, 200, 16, 16, (char*)"2023/2/21");  while(icm20608_init())		/* 初始化ICM20608	 			*/{lcd_show_string(50, 100, 200, 16, 16, (char*)"ICM20608 Check Failed!");delayms(500);lcd_show_string(50, 100, 200, 16, 16, (char*)"Please Check!        ");delayms(500);}	lcd_show_string(50, 100, 200, 16, 16, (char*)"ICM20608 Ready");lcd_show_string(50, 130, 200, 16, 16, (char*)"accel x:");  lcd_show_string(50, 150, 200, 16, 16, (char*)"accel y:");  lcd_show_string(50, 170, 200, 16, 16, (char*)"accel z:");  lcd_show_string(50, 190, 200, 16, 16, (char*)"gyro  x:"); lcd_show_string(50, 210, 200, 16, 16, (char*)"gyro  y:"); lcd_show_string(50, 230, 200, 16, 16, (char*)"gyro  z:"); lcd_show_string(50, 250, 200, 16, 16, (char*)"temp   :"); lcd_show_string(50 + 181, 130, 200, 16, 16, (char*)"g");  lcd_show_string(50 + 181, 150, 200, 16, 16, (char*)"g");  lcd_show_string(50 + 181, 170, 200, 16, 16, (char*)"g");  lcd_show_string(50 + 181, 190, 200, 16, 16, (char*)"o/s"); lcd_show_string(50 + 181, 210, 200, 16, 16, (char*)"o/s"); lcd_show_string(50 + 181, 230, 200, 16, 16, (char*)"o/s"); lcd_show_string(50 + 181, 250, 200, 16, 16, (char*)"C");tftlcd_dev.forecolor = LCD_BLUE;while(1)					{		icm20608_getdata();integer_display(50 + 70, 130, 16, icm20608_dev.accel_x_adc);integer_display(50 + 70, 150, 16, icm20608_dev.accel_y_adc);integer_display(50 + 70, 170, 16, icm20608_dev.accel_z_adc);integer_display(50 + 70, 190, 16, icm20608_dev.gyro_x_adc);integer_display(50 + 70, 210, 16, icm20608_dev.gyro_y_adc);integer_display(50 + 70, 230, 16, icm20608_dev.gyro_z_adc);integer_display(50 + 70, 250, 16, icm20608_dev.temp_adc);decimals_display(50 + 70 + 50, 130, 16, icm20608_dev.accel_x_act);decimals_display(50 + 70 + 50, 150, 16, icm20608_dev.accel_y_act);decimals_display(50 + 70 + 50, 170, 16, icm20608_dev.accel_z_act);decimals_display(50 + 70 + 50, 190, 16, icm20608_dev.gyro_x_act);decimals_display(50 + 70 + 50, 210, 16, icm20608_dev.gyro_y_act);decimals_display(50 + 70 + 50, 230, 16, icm20608_dev.gyro_z_act);decimals_display(50 + 70 + 50, 250, 16, icm20608_dev.temp_act);#if 0		printf("accel x = %d\r\n",icm20608_dev.accel_x_adc);printf("accel y = %d\r\n",icm20608_dev.accel_y_adc);printf("accel z = %d\r\n",icm20608_dev.accel_z_adc);printf("gyrp  x = %d\r\n",icm20608_dev.gyro_x_adc);printf("gyro  y = %d\r\n",icm20608_dev.gyro_y_adc);printf("gyro  z = %d\r\n",icm20608_dev.gyro_z_adc);printf("temp    = %d\r\n",icm20608_dev.temp_adc);
#endifdelayms(120);state = !state;led_switch(LED0,state);	}return 0;
}

在main里面开启了硬件浮点运算,需要在编译文件的时候添加进去

8、修改makefile

添加编译c文件的指令

 $(CC) -Wall -march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ $<

编译后烧写在sd卡插上开发板就能看到屏幕有关6 轴 MEMS传感器的数据了

相关文章:

SPI实验

目录 一、SPI 简介 二、硬件原理 ECSPI3_SCLK ECSPI3_MISO和ECSPI3_MOSI ECSPI3_SS0 三、I.MX6U ECSPI 简介 ECSPIx_RXDATA ECSPIx_TXDATA ECSPIx_CONREG ECSPIx_CONFIGREG ECSPIx_PERIODREG​编辑 ECSPIx_STATREG 四、ICM-20608 简介 五、代码编写 1、创建文件及文…...

去基线处理

目录detrend函数去除基线多项式拟合原函数BEADS 基线处理小波算法经验模态分解&#xff08;EMD&#xff09;参考detrend函数去除基线 detrend函数只能用于去除线性趋势&#xff0c;对于非线性的无能为力。 函数表达式&#xff1a;y scipy.signal.detrend(x): 从信号中删除线…...

模拟信号4-20mA /0-5V/0-75mV/0-100mV转RS-485/232,数据采集A/D转换模块 YL21

特点&#xff1a;● 模拟信号采集&#xff0c;隔离转换 RS-485/232输出● 采用12位AD转换器&#xff0c;测量精度优于0.1%● 通过RS-485/232接口可以程控校准模块精度● 信号输入 / 输出之间隔离耐压3000VDC ● 宽电源供电范围&#xff1a;8 ~ 32VDC● 可靠性高&#xff0c;编程…...

[USB]键盘数据格式以及按键键值

USB键盘数据包含8个字节 BYTE1 – 特殊按键 |–bit0: Left Control是否按下&#xff0c;按下为1 |–bit1: Left Shift 是否按下&#xff0c;按下为1 |–bit2: Left Alt 是否按下&#xff0c;按下为1 |–bit3: Left GUI&#xff08;Windows键&#xff09; 是否按下&#xff0c;…...

web客户端-websocket

1、websocket简介 WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c…...

mysql间隙锁

首先我们这里有一个表t&#xff0c;其中的数据如下图所示 注意哈 update由于操作的最新的值&#xff0c;所以是当前读&#xff01; 另外一个事务插入 8的时候发生锁 而我对id为10的数据进行更新&#xff0c;却不会被锁住 分析&#xff1a;在执行当前读时&#xff0c;由于id7不存…...

华为OD机试 - 计算面积(Java) | 机试题+算法思路+考点+代码解析 【2023】

计算面积 绘图机器的绘图笔初始位i在原点(0.0)。 机器启动后其绘图笔按下面规则绘制直线: 1 )尝试沿着横向坐标轴正向绘制直线,直到给定的终点值E, 2 )期间可通过指令在纵坐标轴方向进行偏移。井同时绘制直线,偏移后按规则1绘制直线;指令的格式为X offsetY。表示在横坐标X…...

Python 之 Pandas 时间戳、通过时间间隔实现 datetime 加减、时间转化、时期频率转换和 shift() 时间频率进行移位)

文章目录一、时间戳1. unit 参数是 s2. year、month、day、hour、minute、second、microsecond 单独设置时间二、通过时间间隔实现 datetime 加减三、时间转化1. 处理各种输入格式2. 将字符串转 datetime3. 除了可以将文本数据转为时间戳外&#xff0c;还可以将 unix 时间转为时…...

一篇文章搞定linux网络模型

网络协议感觉晦涩难懂&#xff1f;什么七层网络模型&#xff1f;又五层网络模型&#xff1f;又四层网络模型&#xff1f;TCP/IP协议是个啥&#xff1f;UDP是啥&#xff1f;什么是三次握手&#xff1f;什么是四次挥手&#xff1f;tcpdump听说是抓包的&#xff0c;怎么用&#xf…...

惠普庆祝在中国40年,强化中国发展战略

中国北京&#xff0c;2023年2月23日 ——今日&#xff0c;“品质信赖向未来” 惠普在中国40年系列活动启动仪式及惠普打印春季新品发布会在北京盛大举行。现场&#xff0c;惠普回顾了40年来与中国经济及产业共同发展的历程&#xff0c;并再次强调了惠普一以贯之的“在中国&…...

C++小作业

前言&#xff1a;long long time ago&#xff0c;老大留了点小作业&#xff0c;一直忘了写…偷偷补上 小作业目录unique_ptr vs shared_ptrunique_ptrshared_ptrpublisher/subscriber 1?boost::bindstd::bindthis? _1&#xff1f;TopicContextPtr?std::moveunique_ptr vs sh…...

Python基础 — lambda匿名函数

1、什么是匿名函数&#xff1f; 匿名函数&#xff0c;顾名思义&#xff0c;就是没有名字的函数&#xff0c;它主要用在那些只使用一次的场景中。如果我们的程序中只需要调用一次某个简单逻辑&#xff0c;把它写成函数还需要先定义、取函数名字等一些列操作&#xff0c;这种场景…...

MongoDB安装和使用过程常见问题

文章目录一、安装过程显示没有相应的权限二、pymongo无法使用&#xff0c;报错一、安装过程显示没有相应的权限 oh我的天&#xff0c;找了网上很多种方法都不行哈哈 不同的电脑对应不同的问题吧~ 我的这个问题是这样解决滴 先直接简述操作路径&#xff0c;不明白的可以看如下图…...

AWS攻略——使用中转网关(Transit Gateway)连接同区域(Region)VPC

文章目录环境准备创建VPC配置中转网关给每个VPC创建Transit Gateway专属挂载子网创建中转网关创建中转网关挂载修改VPC的路由验证创建业务Private子网创建可被外网访问的环境测试子网连通性Public子网到Private子网Private子网到Private子网知识点参考资料在《AWS攻略——Peeri…...

Rouge | 自动文摘及机器翻译评价指标

tag:评价指标,摘要,nlp Rouge(Recall-Oriented Understudy for Gisting Evaluation)&#xff0c;是评估自动文摘以及机器翻译的一组指标。它通过将自动生成的摘要或翻译与一组参考摘要&#xff08;通常是人工生成的&#xff09;进行比较计算&#xff0c;得出相应的分值&#x…...

【Python入门第十五天】Python字典

字典&#xff08;Dictionary&#xff09; 字典是一个无序、可变和有索引的集合。在 Python 中&#xff0c;字典用花括号编写&#xff0c;拥有键和值。 实例 创建并打印字典&#xff1a; thisdict {"brand": "Porsche","model": "911&q…...

java学习思路

基础概念&#xff1a;了解Java的基本概念&#xff0c;如Java虚拟机&#xff08;JVM&#xff09;、Java标准版&#xff08;Java SE&#xff09;、Java企业版&#xff08;Java EE&#xff09;等。了解Java的版本、发展历程以及Java应用场景。可以通过阅读Java官方文档、相关书籍、…...

MySQL操作数据库-------创建数据库

搭建好MySQL环境后&#xff0c;现在我们正式的进入到MySQL的学习当中&#xff0c;这篇文章讲述如何去创建MySQL数据库。 1. 使用CREATE DATABASE创建数据库 语法格式&#xff1a;CREATE DATABASE database_name eg.打开MySQL命令行&#xff0c;查看当前MySQL中存在的数据库 my…...

【十】深入理解redolog,undolog和binlog的底层原理

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…...

高频js手写题之实现数组扁平化、深拷贝、总线模式

前言 古人学问无遗力&#xff0c;少壮工夫老始成。纸上得来终觉浅&#xff0c;绝知此事要躬行。看懂一道算法题很快,但我们必须将这道题的思路理清、手写出来。 三道js手写题的思路和代码实现 数组扁平化 演示效果 将[1, [1, 2], [1, [2]]] 变成 [1, 1, 2, 1, 2] 第一种&…...

HTML介绍

文章目录一. HTML介绍二. 创建三. HTML结构四. 常见的标签五. 链接标签六. 图片标签七. 资源路径八. 列表标签九. 表格标签十. 表单标签十一. 表单提交一. HTML介绍 HTML: 超文本标记语言作用: 书写前端页面前端三大技术(三大标准): HTML: 结构标准 (页面中有什么内容)CSS: 样…...

【C++】string的9道OJ题

要么庸俗&#xff0c;要么孤独… 文章目录一、仅仅反转字母二、字符串中的第一个唯一字符&#xff08;计数排序的思想&#xff09;三、字符串相加&#xff08;做好加进位的工作即可&#xff09;四、把字符串转换成整数五、反转字符串中的单词 III六、字符串相乘&#xff08;高…...

Odoo丨Odoo框架源码研读三:异常处理与定制化开发

Odoo丨Odoo框架源码研读三&#xff1a;异常处理与定制化开发 Odoo源码研读的第三期内容&#xff1a;异常处理与定制化开发。 *异常处理* Odoo中的Exception是对Python内置异常做了继承和封装&#xff0c;设定了自己核心的几个Exception。 而对异常的处理和Python内置异常的…...

Python概述 基础语法 判断 循环

Python概述常用快捷键第二章-Python基础语法01-字面量02-注释03-变量04-数据类型05-数据类型转换06-标识符07-运算符08-字符串的三种定义方式09-字符串的拼接10-字符串格式化11-字符串格式化的精度控制 12-字符串格式化-快速写法13-对表达式进行格式化14-字符串格式化练习题讲解…...

什么是品牌营销?学会正确推广您的业务

什么是品牌营销&#xff1f; 品牌营销涉及长期战略规划&#xff0c;以推广整个品牌&#xff0c;而不是营销单个产品或服务。它分享了一个引人入胜的故事&#xff0c;以在潜在客户中产生品牌知名度并建立声誉。 面向消费者的品牌使用品牌智能软件来了解人们对其品牌的看法&#…...

Golang学习Day1

&#x1f60b; 大家好&#xff0c;我是YAy_17&#xff0c;是一枚爱好网安的小白。本人水平有限&#xff0c;欢迎各位大佬指点&#xff0c;欢迎关注 &#x1f601;&#xff0c;一起学习 &#x1f497; &#xff0c;一起进步 ⭐ 。⭐ 此后如竟没有炬火&#xff0c;我便是唯一的光…...

《设计模式》工厂模式

《设计模式》工厂模式 工厂模式又分为简单工厂&#xff08;Simple Factory&#xff09;、工厂方法&#xff08;Factory Method&#xff09;和抽象工厂&#xff08;Abstract Factory&#xff09;都是常用的创建型设计模式&#xff0c;它们的主要区别如下&#xff1a; 简单工厂…...

JS - 原型对象、原型链是什么

一 阅读掘金 https://juejin.cn/post/7007416743215759373 https://juejin.cn/post/7007416743215759373 二 阅读掘金小册原型知识点 原型 涉及面试题&#xff1a;如何理解原型&#xff1f;如何理解原型链&#xff1f; 当我们创建一个对象时 let obj { age: 25 }&#xff0…...

STM32f103 CubeMX封装 led程序

本文代码使用 HAL 库。 文章目录前言一、LED 原理图二、CubeMX创建工程三、LED 相关函数1. 输出电平函数&#xff1a;2. 延时函数&#xff1a;3. 翻转电平函数&#xff1a;四、详细代码实验现象 &#xff1a;总结代码 源码&#xff1a;前言 从这篇文章开始&#xff0c;我们讲解…...

智慧教室系统--温湿度控制系统

随着科技的不断进步&#xff0c;智能化已经成为了各个行业的发展趋势&#xff0c;智慧教室作为未来教育的主流趋势之一&#xff0c;也将受益于这一趋势。而智慧教室中的温湿度控制系统是其中的重要组成部分&#xff0c;为了创造一个舒适、健康、安全的教学环境&#xff0c;智慧…...