正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-23.3,4,5,6 讲 I2C驱动-读取AP3216C传感器​

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第23讲 I2C驱动。本节将参考正点原子的视频教程第23讲和配套的正点原子开发指南文档进行学习。

0. 概述

I2C 是最常用的通信接口,众多的传感器都会提供 I2C 接口来和主控相连,比如陀螺仪、加速度计、触摸屏等等。所以 I2C 是做嵌入式开发必须掌握的, I.MX6U 有 4 个 I2C 接口,可以通过这 4 个 I2C 接口来连接一些 I2C 外设。 I.MX6U-ALPHA 使用 I2C1 接口连接了一个距离传感器 AP3216C,本章我们就来学习如何使用 I.MX6U 的 I2C 接口来驱动 AP3216C,读取AP3216C 的传感器数据。

1. I.MX6U 硬件I2C接口产生I2C Start,Stop,Repeated-Stop信号

1.1 产生I2C Start 信号

根据I2C总线协议,在I2C读/写时需要先发出一个Start信号,在SCL为高电平时,SDA出现下降沿从高电平变为低电平指示Start信号。然后是7比特的sub-address从机地址先传输高位在前地位在后(MSB-LSB),然后是1比特的方向(读写)指示位,1表示读0表示写,每发送8个数据位之后需要从机回复ACK/NAK,所以在第9个时钟周期,I2C主机释放SDA总线让从机来通过SDA拉低或拉高来回复ACK/NACK,I2C寻址匹配的从机再第9个时钟周期高电平期间拉低SDA回复ACK,保持SDA高电平表示回复NAK。

NACK信号出现的情况有如下几种:

  • 1-无:I2C主机寻址时没有匹配的从机
  • 2-忙:I2C从机忙,无法回复
  • 3-错:I2C从机检测到数据错误或者处理错误
  • 4-停:I2C主机 Master-Receiver 模式下通知从机停止发送

对于产生I2C Start信号I.MX6ULL手册中说:

After completion of the initialization procedure, serial data can be transmitted by selecting the Master Transmit mode. On a multimaster bus system, the busy bus (I2C_I2SR[IBB]) must be tested to determine whether the serial bus is free. If the bus is free (IBB = 0), the Start signal and the first byte (the slave address) can be sent. The data written to the data register comprises the address of the desired slave and the LSB indicates the transfer direction.

I.MX6U 参考手册中说I2C硬件接口的 Start 信号产生条件为:I2C选择Master-Transmit模式,等待I2C总线不忙时(busy=0),开始信号和第一字节(Slave-Address,从机地址+R/W方向位)可以被发送。写到I2Cx->I2DR数据寄存器的值包括呼叫的从机地址(7bit MSB优先)和读写方向位(1bit, R:1/W:0)。发送Start信号+7bit sub-address+R/W 这8位数据之后,在第9个时钟周期需要等待子设备回复ACK。

如下图片1,是正点原子示例源码和视频教程里提供的 I.MX6U I2C 硬件接口发起 Start 信号,并在I2Cx->I2DR数据加上i2c子设备呼叫地址的示例源码,通过此正点原子提供的I2C示例源码可以正确读取出来 AP3216C 红外/接近/环境光传感器的i2c数据。

但是根据I2C协议,在I2C Master主机发送Start信号+子设备地址呼叫之后,需要等待并确认是否有子设备被回复ACK信号表示有子设备被正确寻址。正点原理的示例源码里缺少了则一部分。

下面是我自己根据I.MX6U 参考手册里提供的 Polling Routine 模式下编程框图在正点原子示例源码的基础上,在 i2c_start() 函数做增强发出 start + sub-address 之后,等待并检查ACK回复。

下图是我自己在正点原子I.MX6U I2C 硬件接口 start 信号产生函数的基础上修改的源码,新增了发送Start+Sub-address+R/W 8位数据之后等待并检查从机ACK信号的步骤。

  • I2C主机发送Start信号和Sub-address子设备地址+R/W读写方向 8位数据之后,需要检查子设备寻址是否正确,通过检查子设备回复的ACK信号来确认子设备地址呼叫成功。因为可能地址错误在I2C总线上并不存在被呼叫的字设备地址。
  • I.MX6ULL 手册 I2C 硬件接口的指导文档说明,在关闭I2C接口中断的时候软件程序需要通过 Polling循环检测 IIF 标志位的方式等待数据传输(发送/接收)完成,然后检查ICF标志位来确认IIF被置位的原因(区分是传输完成IIF置1,还是仲裁丢失IIF置1)。
  • 等待IFF,ICF被置1 数据传输完成之后,就可以检查ACK标志位了,ACK=1表示收到了子设备的ACK信号,地址呼叫成功。ACK=0表示收到了NACK信号,地址寻址失败。

1.2 I.MX6U I2C 硬件发送/接收之后的软件处理流程

如下图是I.MX6U 手册中说明的“Post-Transer software response” ,也就是在 I.MX6U I2C 硬件家口发送(Transmit)或者接收(Recive)一个字节之后软件需要进行的处理步骤。

  1. 这里说,在发送或者接收一个字节完成之后,I2Cx->I2SR 的 ICF 就会被设置为1
    在完成之后 IIF 中断标志位也会别设置位1
  2. 必须在软件里清除 IIF 中断标志位
  3. ICF标志位,在I2C Master Tx模式时写 I2DR写清除或者 I2C Master Rx模式时读清零
  4. 在从Address-Cycle周期结束之后,必须Toggle翻转I2C_L2CR[MTX]位,并且做一个 假读 dummy-read 来触发接收数据
  5. 手册同时指出在I.MX6U I2C 硬件接口的中断关闭之后,软件需要轮询检查(Polling)检查IIF标志位来确认传输是否完成,当IIF标志位置1时再检查ICF标志位来用来区分其他IIF中断的情况,例如,Arbitration-Lost 仲裁丢失。

I.MX6U 参考手册给出的I2C硬件中断关闭时Polling轮询模式编程代码框图。

  • I.MX6ULL 参考手册的流程框图说,需要循环检测polling IIF 标志位来检查传输是否完成。
  • 并且在Address-Cycle结束之后需要toggle(翻转)MTX方向并且加一个 dummy -read 假读来触发Rx接收数据。

1.3 产生I2C Stop 信号

在I2C数据传输(读/写)结束之后需要I2C主机发送一个 STOP 标志位,I.MX6U I2C硬件接口产生STOP信号的方式是:

通过清除I2Cx->I2CR寄存器的 MSTA bit[5] 标志位来产生一个 I2C STOP 信号。

  • Master主机模式,通过MSTA从1修改0,触发一个STOP信号
  • Slave从机模式,通过MSTA从0修改为1,触发一个Start信号并且选择为Master模式

这里I.MX6ULL 手册说在主机接收模式 Master-Received模式,再倒数第二个字节,I2C主机应该发送NAK信号给从机,并且在最后一个字节被读取之前需要触发一个Stop信号。

A data transfer ends when the master signals a Stop, which can occur after all data is sent.
For a master receiver to terminate a data transfer, it must inform the slave transmitter by
not acknowledging the last data byte. This is done by setting the transmit acknowledge
bit (I2C_I2CR[TXAK]) before reading the next-to-last byte. Before the last byte is read,
a Stop signal must be generated.

1.4 产生Repeated-Start信号

在I2C读时序中在发送Restat+从机地址+W+ACK+寄存器地址+ACK之后,需要重新发送一次Restart+从机地址+R。

I.MX6U I2C硬件接口产生Repeast-Start信号的方法如下:

2. I.MX6U I2C硬件接口为什么需要Dummy Read 

在正点原子的视频教程里,左盟主说参考的NXP提供的I.MX6U I2C SDK源码发现在读取I2C硬件接口之前需要先做一次假读 Dummy-Read,为什么需要做 dummy-read 假读哪?

In Master Receive mode, reading the data register allows a read to occur and initiates the next byte to be received.

在I2C主机Master-Receive模式,read动作读取一个数据并且指示I2C接口开始接收下一个数据。

When an interrupt occurs at the end of the address cycle, the master is always in Transmit
mode; that is, the address is sent. If Master Receive mode is required, then I2C_I2CR[MTX] should be toggled and a dummy read of the I2C_I2DR register must be executed to trigger receive data.
 在寻址周期结束的时候,I2C主机一定是在Master-Transmit模式,此时如果需要读取从机数据就必须先翻转 I2C-I2CR[MTX]位为Rx模式,并且做一次假读 dummy-read 触发I2C接口来读取数据。

  • I.MX6ULL 参考手册的流程框图说,需要循环检测polling IIF 标志位来检查传输是否完成。
  • 并且在Address-Cycle结束之后需要toggle(翻转)MTX方向并且加一个 dummy -read 假读来触发Rx接收数据。

2.1 I2C 读取数据

I.MX6U I2C硬件接口读取数据的部分如下,这里需要注意的是按照I.MX6U I2C 硬件接口的指导说明按照规定的时序回复 NAK 信号给从机,并且发送STOP信号给从机。

这里容易理解错误,并且源码编写错位的地方是 I.MX6ULL 手册要求 I2C Master Received 模式下 读 Rx 数据的时候,要求在倒数第二个读设置发送发送 NAK信号,在最后一次读时设置发送 STOP 信号。

如下源码,读I2Cx->I2DR寄存器动作本身的结果有两个:第一个是读取到当前已经接收到的Rx数据,第二个是read动作触发I2C接口进行下一个数据的接收。

		/* 读取当前已接收数据,并触发下一次接收 */*buf++ = base->I2DR;

如上分析读I2Cx->I2DR寄存器读动作本身不进可以读取当前已经接收的数据还同时触发I2C接口进行下一个数据的Rx接收。按照这个分析,我们可以指导 “假读 Dummy-Read” 触发I.MX6U I2C 硬件接口开始接收数据,这也是I.MX6U 手册中明确要求的。

	/* dummy read */dummy = base->I2DR;

2.2 I2C 发送数据

I.MX6U I2C硬件接口发送数据的部分如下,

3. I2C驱动源码编写

完整的驱动源码见如下我的Gitee链接,源码参考了正点的原子的示例源码和NXP提供I2C SDK示例源码:

imx6ull_mini: 基于正点原子I.MX6ULL Mini 视频教程的Linux ARM开发学习笔记,这里记录各个实验中所写的源码。 - Gitee.comicon-default.png?t=N7T8https://gitee.com/iPickCan/imx6ull_mini/tree/master/17_i2c

bsp/bsp_i2c.c

#include "bsp_i2c.h"
#include "bsp_gpio.h"
#include "bsp_delay.h"
#include "stdio.h"/* 初始化I2C */
void i2c_init(I2C_Type *base)
{base->I2CR &= ~(1 << 7);		/* 关闭I2C *//* 设置I2C时钟 */base->IFDR = 0x15 << 0;			/* 640分频,IPG_CLK=66MHZ/640=103.125KHz */base->I2CR |= (1 << 7);			/* 使能I2C */
}// /* I2C 等待ACK回复 */
// void i2c_wait_ACK(I2C_Type *base){
// 		/* 参考NXP的SDK驱动, bit[1]中断标志位 */
// 		while(!(base->I2SR & (1 << 1)));
// 		base->I2SR &= ~(1 << 1);
// }/* I2C Start 信号产生以及从机地址 */
unsigned char i2c_master_start(I2C_Type *base, unsigned char address, enum i2c_direction direction)
{uint8_t ack;/* 判断是否为忙 */if((base->I2SR & (1 << 5))){/* 当前I2C忙 */return 1;}/* 设置为主机模式 */// base->I2CR |= (1 << 5);			/* bit[5]主机模式 Master */// base->I2CR |= (1 << 4);			/* bit[4]主机发送模式 Tx*/base->I2CR |= (1 << 5) | (1 << 4);//清除IIF中断标志I2C1->I2SR &= ~(1 << 1);/* 产生Start 信号 *//* I2C从设备地址(bit[7:1]) *//* bit[0] 0 表示写,1表示read */base->I2DR = ((unsigned int)address) << 1 | ((direction == kI2C_Write)? 0 : 1);/* 检查I2C address calling 地址呼叫是否成功 */while(!(I2C1->I2SR & (1 << 1)));					/* 检查IIF */if((I2C1->I2SR & (1 << 7))){						/* 检查ICF *//* 检查Start信号后面的sub-address calling 地址呼叫是否收到ACK */if((ack = i2c_check_and_clear_error(I2C1, I2C1->I2SR))){if(I2C_STATUS_NAK == ack){printf("I2C calling failed\r\n");return I2C_STATUS_ADDRNAK;}else{printf("I2C Arbitration lost error\r\n");return I2C_STATUS_ARBITRATIONLOST;}}}return 0;
}/* I2C Stop信号 */
unsigned char i2c_master_stop(I2C_Type *base)
{unsigned short timeout = 0xFFFF;/* bit[3] Transmit acknowledge enable, *//* bit[4] Transmit/Receive mode select, *//* bit[5] master/slave mode select, 软件清0产生一个stop信号 *///base->I2CR &= ~(1 << _I2C_I2CR_TXAK_SHIFT) | ~(1 << _I2C_I2CR_MTX_SHIFT) | ~(1 << _I2C_I2CR_MSTA_SHIFT);base->I2CR &= ~((1 << 3) | (1 << 4) | (1 << 5));/* 检查busy */while(base->I2SR & (1 << _I2C_I2SR_IBB_SHIFT)){timeout--;if(timeout == 0){return I2C_STATUS_TIMEOUT;}}return I2C_STATUS_OK;
}/* repeat-restart 信号*/
unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address, enum i2c_direction direction)
{/* 判断是否为忙并且工作在从机模式下*/if((base->I2SR & (1 << 5)) && ((base->I2CR & (1 << 5)) == 0)){/* 判断是否为忙并且工作在从机模式下*/return 1;}/* bit[2] 写1生成一个repeat-start信号 *//* bit[5] 写1 master模式 *//* bit[4] 写1 tx模式 */base->I2CR |=  (1 << 4) | (1 << 2);/* 写从机地址 */base->I2DR = ((unsigned int)address) << 1 | ((direction == kI2C_Write)? 0 : 1);return 0;
}/* 错误检查和清除函数 */
unsigned char  i2c_check_and_clear_error(I2C_Type *base, unsigned int state)
{/* 先检查是否为仲裁丢失错误 *//* 仲裁丢失 */if(state & (1 << 4)){base->I2SR &= ~(1 << 4); 	/* 先清除标志位 */base->I2CR  &= ~(1 << 7);		/* 关闭I2C*/base->I2CR  |= (1 << 7);		/* 重新打开I2C, 关闭打开复位I2C */return I2C_STATUS_ARBITRATIONLOST;}/* 收到NACK信号 */else if(state & (1 << 0)){return I2C_STATUS_NAK;}return I2C_STATUS_OK;
}/* 发送数据函数 */
void i2c_master_write(I2C_Type *base, const unsigned char *buf, unsigned int size)
{//等待上一个发送传输完成while(!(base->I2SR & (1 << 7)));//清除中断标记位base->I2SR &= ~(1 << 1);/* 发送模式 */base->I2CR |= (1 << 4);while(size--){base->I2DR = *buf++;/* 参考NXP的SDK驱动, bit[1]中断标志位,等待数据发送完成 */while(!(base->I2SR & (1 << 1)));base->I2SR &= ~(1 << 1);/* 每发送8bit 检查ACK *///if(i2c_check_and_clear_error(base, base->I2SR) != I2C_STATUS_OK){if(i2c_check_and_clear_error(base, base->I2SR)){/* 有错误发生 */break;}}/* bit[1]中断标志位  */base->I2SR &= ~(1 << 1);/* Stop 停止位 */i2c_master_stop(base);
}/* 读数据函数 */
void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size)
{volatile uint8_t dummy = 0;		/* 假读 *//* clean compile warning */dummy++;//等待上一个发送传输完成while((base->I2SR & (1 << 7)) == 0);/* bit[1]中断标志位  */base->I2SR = ~(1 << 1);base->I2CR &= ~( 1<< 4);	/* bit[4] MTX Select, 选择Rx */base->I2CR &= ~(1 << 3);	/* bit[3] TXAK 发送ACK */if(size == 1){/* 参考NXP的SDK驱动, 发送NACK信号 */base->I2CR |= (1 << 3);}/* dummy read */dummy = base->I2DR;while(size--){/* 等待数据接收完成 */while(!(base->I2SR & (1 << 1)));		/* 等待数据传输完成 *//* bit[1]中断标志位  */base->I2SR = ~(1 << 1);if(size == 1){/* 参考NXP的SDK驱动, 发送NACK信号 */base->I2CR |= (1 << 3);}if(size == 0){/* 数据发送完成 */i2c_master_stop(base);}/* 读取当前已接收数据,并触发下一次接收 */*buf++ = base->I2DR;}
}/** @description	: I2C数据传输,包括读和写* @param - base: 要使用的IIC* @param - xfer: 传输结构体* @return 		: 传输结果,0 成功,其他值 失败;*/
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer)
{unsigned char ret = 0;enum i2c_direction direction = xfer->direction;	base->I2SR &= ~((1 << 1) | (1 << 4));			/* 清除标志位,中断标志位和仲裁丢失标志位 *//* 等待传输完成 */while(!((base->I2SR >> 7) & 0X1)){}; /* 如果是读的话,要先发送寄存器地址,所以要先将方向改为写 */if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read)){direction = kI2C_Write;}ret = i2c_master_start(base, xfer->slaveAddress, direction); /* 发送开始信号 */if(ret){	return ret;}while(!(base->I2SR & (1 << 1))){};			/* 等待传输完成 */ret = i2c_check_and_clear_error(base, base->I2SR);	/* 检查是否出现传输错误 */if(ret){i2c_master_stop(base); 						/* 发送出错,发送停止信号 */return ret;}/* 发送寄存器地址 */if(xfer->subaddressSize){do{base->I2SR &= ~(1 << 1);			/* 清除标志位 */xfer->subaddressSize--;				/* 地址长度减一 */base->I2DR =  ((xfer->subaddress) >> (8 * xfer->subaddressSize)); //向I2DR寄存器写入子地址while(!(base->I2SR & (1 << 1)));  	/* 等待传输完成 *//* 检查是否有错误发生 */ret = i2c_check_and_clear_error(base, base->I2SR);if(ret){i2c_master_stop(base); 				/* 发送停止信号 */return ret;}  } while ((xfer->subaddressSize > 0) && (ret == I2C_STATUS_OK));if(xfer->direction == kI2C_Read) 		/* 读取数据 */{base->I2SR &= ~(1 << 1);			/* 清除中断挂起位 */i2c_master_repeated_start(base, xfer->slaveAddress, kI2C_Read); /* 发送重复开始信号和从机地址 */while(!(base->I2SR & (1 << 1))){};/* 等待传输完成 *//* 检查是否有错误发生 */ret = i2c_check_and_clear_error(base, base->I2SR);if(ret){ret = I2C_STATUS_ADDRNAK;i2c_master_stop(base); 		/* 发送停止信号 */return ret;  }}}	/* 发送数据 */if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0)){i2c_master_write(base, xfer->data, xfer->dataSize);}/* 读取数据 */if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0)){i2c_master_read(base, xfer->data, xfer->dataSize);}return 0;	
}

4. 编译烧写SD卡验证结果

编译源码烧录SD卡验证本节的 I.MX6U I2C驱动实验。预期烧录SD卡后正点原子I.MX6ULL ALPHA/Mini 开发板后,可以通过I2C总线读取到AP3216C 红外/接近/环境光 IR/PS/ALS传感器的采集值。

我本地验证的结果是烧录SD卡后,在串口里可以打印出通过I2C总线读取到AP3216C 红外/接近/环境光 IR/PS/ALS传感器的采集值。

5. 总结和实验遇到问题记录

5.1 错误1: if 判断条件里将运算符 "&" 错误的写成了 "&=",这样寄存器的值就完全给搞错了

错误1: if 判断条件里将运算符 "&" 错误的写成了 "&=",这样寄存器的值就完全给搞错了,这样的错误写法最重要的是将 I2Cx->CR 的 bit[7] 给设置为了0关闭了 I2C 接口

5.2 错误2:将运算符 “&” 错误的写成了“<<"运算符,if条件执行的结果完全不同并且把寄存器状态给搞错乱了。

错误2:将运算符 “&” 错误的写成了“<<"运算符,if条件执行的结果完全不同并且把寄存器状态给搞错乱了。

5.3 错误3:将运算符“&=”,错写成了 “=” 运算符,本来是清除一个bit位,结果却成了赋值,寄存器的状态完全错了

错误3:将运算符“&=”,错写成了 “=” 运算符,本来是清除一个bit位,结果却成了赋值,寄存器的状态完全错了

 

6. 结束

本文至此结束。

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

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

相关文章

什么是知识中台?为什么企业需要知识中台?

如今市面上的企业数不胜数&#xff0c;企业的任何一个小细节都会产生很大的影响。近几年来一直很热门的知识中台备受企业关注。关于如何高效地管理、整合和运用知识&#xff0c;成为了每一家企业都在重点关注的问题。而知识中台&#xff0c;就是为了解决这一问题而诞生的一个全…

豪赌?远见?浙江东方的量子冒险

今年4月16日&#xff0c;量子通信概念异动&#xff0c;浙江东方&#xff08;600120&#xff09;拉升涨停。 量子和浙江东方&#xff0c;要把这两个词联系起来似乎并不太容易。 浙江东方&#xff0c;即浙江东方金融控股集团股份有限公司&#xff0c;系浙江省国资委下属浙江省国…

地下18米的科技守护:旗晟综合管廊巡检机器人

近日&#xff0c;安徽某业主的地下18米深的地下管廊处&#xff0c;一种先进的巡检机器人正活跃在管廊轨道上&#xff0c;执行着重要的巡检任务&#xff0c;只见机器人在管廊轨道上平稳前行&#xff0c;它搭载着先进的检测设备&#xff0c;对地下管廊内的各种设施进行监测巡检&a…

java -- jar打包成exe -- 携带jre环境

java的项目一般都是以jar发布&#xff0c;很少打包为可执行程序&#xff0c;因此常见的打包方式也不多&#xff0c;且即使打包之后也需要jre环境才能运行&#xff0c;大部分打包都不会携带jre&#xff0c;需要手动添加jre。这里介绍几种我用过的打包方案。 exe4j(不推荐) jpac…

关于已配好java环境但双击无法打开jar包的解决方案

如果你已经装好了 java 环境直接跳到最后看解决方法即可 先说一下你安装的 java 环境&#xff0c;如果完全是默认选项安装&#xff0c;则会安装 jdk 和 jre&#xff0c;并且在安装 jre 时还需要安装目录下为空&#xff0c;其实 jre 的安装是多余的&#xff0c;因为安装的 jdk 里…

Teamcenter 查询包含Assembly的ItemRevision

问题描述 需要得到所有包含Assembly的ItemRevision。 TC OOTB的查询方式没有可用的&#xff0c;需要在Query Builder中进行自定义。 进一步分析&#xff0c;如果ItemRevision包含Assembly&#xff0c;其必定包含BOMViewRevision。 解决方案 自定义如下查下。 注意&#xff1…

vue 微信公众号定时发送模版消息

目录 第一步&#xff1a;公众号设置 网页授权第二步&#xff1a;引导用户去授权页面并获取code第三步&#xff1a;通过code换取网页授权access_token&openid第四步&#xff1a;后端处理绑定用户和发送消息 相关文档链接&#xff1a; 1、微信开发文档 2、订阅号/服务号/企业…

英语四级翻译练习笔记③——大学英语四级考试2023年12月真题(第三套)

目录 引言&#xff08;必看&#xff09; 四级翻译评分标准分析及真题解析 四级翻译评分标准 四级翻译真题 学生作答 1. 评分 2. 修正翻译中的错误 错误标记&#xff1a; 3. 改正句子 4. 标出错误单词 5. 标准答案 6. 常考万能句子 7.重点单词的中文意思 引言&…

远程抄表及预付费管理系统:智能管理的新篇章

1.系统简述 远程抄表及预付费管理系统是现代能源管理方面的一项重要自主创新&#xff0c;它将传统手动式抄水表方式转变为自动化技术、智能化管理模式&#xff0c;大大提高了高效率并减少了经营成本。该系统搭载了前沿的通讯技术、数据分析技术和财务管理系统核心理念&#xf…

RedHat9 | DNS剖析-配置转发DNS服务器

一、实验环境 1、转发DNS服务器 转发服务器&#xff08;Forwarding Server&#xff09;接受查询请求&#xff0c;但不直接提供DNS解析&#xff0c;而是将所有查询请求发送到另外一台DNS服务器&#xff0c;查询到结果后保存在本地缓存中。如果没有指定转发服务器&#xff0c;D…

性能测试(一)—— 性能测试理论+jmeter的使用

1.性能测试介绍 定义&#xff1a;软件的性能是软件的一种非功能特性&#xff0c;它关注的不是软件是否能够完成特定的功能&#xff0c;而是在完成该功能时展示出来的及时性。 由定义可知性能关注的是软件的非功能特性&#xff0c;所以一般来说性能测试介入的时机是在功能测试完…

Python | Leetcode Python题解之第103题二叉树的锯齿形层序遍历

题目&#xff1a; 题解&#xff1a; class Solution:def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:if not root: return []res, deque [], collections.deque()deque.append(root)while deque:tmp []# 打印奇数层for _ in range(len(deque)…

春秋云境CVE-2020-26048

简介 CuppaCMS是一套内容管理系统&#xff08;CMS&#xff09;。 CuppaCMS 2019-11-12之前版本存在安全漏洞&#xff0c;攻击者可利用该漏洞在图像扩展内上传恶意文件&#xff0c;通过使用文件管理器提供的重命名函数的自定义请求&#xff0c;可以将图像扩展修改为PHP&#xf…

SpringBoot之@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder注解

前言 SpringBoot通过AutoConfigureOrder、AutoConfigureBefore、AutoConfigureAfter注解&#xff0c;控制自动配置类的实例化顺序。 Spring中控制Bean的实例化顺序 Spring中默认实例化顺序 创建实体类A、B、C Component public class A {public A() {System.out.println(&…

编程中的模块迷宫:区分与正确使用

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、模块混淆的陷阱 二、碳模块与探母模块的区别 三、如何正确使用模块 四、代码示例 五…

CR渲染噪点严重怎么办?常见噪点来源+排查方法

使用Corona渲染器进行渲染时&#xff0c;画面出现噪点是常见现象&#xff0c;尤其是在渲染初期。轻微的高频噪点通常是正常的&#xff0c;但如果经过多次渲染或长时间渲染后噪点依然明显&#xff0c;就可能意味着渲染设置或场景本身存在问题。虽然我们可以利用降噪功能模糊噪点…

NameSilo + Cloudflare 给网站加个域名(附 NameSilo 购买域名优惠码)

网站做好了之后,下一步就是买域名 在国内买域名的话,还需要备案,个人名下备案好像是还有限制,我就去 NameSilo 上面买的 在买之前,对比过几家 比如: godaddy/namecheap/cloudflare 本来是倾向于在 godaddy 上面买的,因为它支持支付宝支付,但是在详细看的时候,发现如果购买一年…

文心一言 VS 讯飞星火 VS chatgpt (269)-- 算法导论20.2 4题

四、修改 proto-vEB 结构&#xff0c;以支持重复关键字。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 在原始的 van Emde Boas 树&#xff08;vEB tree&#xff09;结构中&#xff0c;关键字&#xff08;key&#xff09;是唯一的&#xff0c;不允许有重复的关…

DL/ML/RL/TL/FL机器学习框架总结

前言 本文总结了DL/深度学习、ML/机器学习、DML/分布式机器学习、AutoML/自动化机器学习、RL/强化学习、MLaaS/机器学习及服务、SR/语音识别领域的机器学习框架&#xff0c;可作为学习、研究、研发的参考资料。 1.DL/深度学习框架 PyTorch PyTorch是一个开源的Python机器学…

git的使用之筛选文件上传到远程服务器仓库

.gitignore 让本地文件有选择上传到远程服务器仓库 下面是linux内核的.gitignore # # NOTE! Dont add files that are generated in specific # subdirectories here. Add them in the ".gitignore" file # in that subdirectory instead. # # NOTE! Please use gi…