CH341的I2C接口编程说明

news2024/10/1 3:36:26

 CH341的I2C接口特性:

1、支持I2C速度20K/100K/400K/750K;

2、默认不支持设备的ACK应答监测,即忽略ACK状态;强制支持需修改软件;

引脚序号功能说明
24SCL
23SDA

 Windows系统SPI通讯接口函数

HANDLE	WINAPI	CH341OpenDevice(  // 打开CH341设备,返回句柄,出错则无效
	ULONG			iIndex );  // 指定CH341设备序号,0对应第一个设备


VOID	WINAPI	CH341CloseDevice(  // 关闭CH341设备
	ULONG			iIndex );  // 指定CH341设备序号

BOOL	WINAPI	CH341SetStream(  // 设置串口流模式
	ULONG			iIndex,  // 指定CH341设备序号
	ULONG			iMode );  // 指定模式,见下行
// 位1-位0: I2C接口速度/SCL频率, 00=低速/20KHz,01=标准/100KHz(默认值),10=快速/400KHz,11=高速/750KHz
// 位2:     SPI的I/O数/IO引脚, 0=单入单出(D3时钟/D5出/D7入)(默认值),1=双入双出(D3时钟/D5出D4出/D7入D6入)
// 位7:     SPI字节中的位顺序, 0=低位在前, 1=高位在前
// 其它保留,必须为0

BOOL	WINAPI	CH341ReadI2C(  // 从I2C接口读取一个字节数据
	ULONG			iIndex,  // 指定CH341设备序号
	UCHAR			iDevice,  // 低7位指定I2C设备地址
	UCHAR			iAddr,  // 指定数据单元的地址
	PUCHAR			oByte );  // 指向一个字节单元,用于保存读取的字节数据


BOOL	WINAPI	CH341WriteI2C(  // 向I2C接口写入一个字节数据
	ULONG			iIndex,  // 指定CH341设备序号
	UCHAR			iDevice,  // 低7位指定I2C设备地址
	UCHAR			iAddr,  // 指定数据单元的地址
	UCHAR			iByte );  // 待写入的字节数据

BOOL	WINAPI	CH341StreamI2C(  // 处理I2C数据流,2线接口,时钟线为SCL引脚,数据线为SDA引脚(准双向I/O),速度约56K字节
	ULONG			iIndex,  // 指定CH341设备序号
	ULONG			iWriteLength,  // 准备写出的数据字节数
	PVOID			iWriteBuffer,  // 指向一个缓冲区,放置准备写出的数据,首字节通常是I2C设备地址及读写方向位
	ULONG			iReadLength,  // 准备读取的数据字节数
	PVOID			oReadBuffer );  // 指向一个缓冲区,返回后是读入的数据

BOOL	WINAPI	CH341ReadEEPROM(  // 从EEPROM中读取数据块,速度约56K字节
	ULONG			iIndex,  // 指定CH341设备序号
	EEPROM_TYPE		iEepromID,  // 指定EEPROM型号
	ULONG			iAddr,  // 指定数据单元的地址
	ULONG			iLength,  // 准备读取的数据字节数
	PUCHAR			oBuffer );  // 指向一个缓冲区,返回后是读入的数据


BOOL	WINAPI	CH341WriteEEPROM(  // 向EEPROM中写入数据块
	ULONG			iIndex,  // 指定CH341设备序号
	EEPROM_TYPE		iEepromID,  // 指定EEPROM型号
	ULONG			iAddr,  // 指定数据单元的地址
	ULONG			iLength,  // 准备写出的数据字节数
	PUCHAR			iBuffer );  // 指向一个缓冲区,放置准备写出的数据

如上API接口函数,根据不通的业务场景可以选用不同的函数。

CH341ReadI2C,CH341WriteI2C: 适用于I2C设备地址固定7位,单次读写1个字节。

CH341StreamI2C: 适用于多字节的设备地址,或设备地址后紧跟寄存器地址,或连续的多字节读写。

CH341ReadIEEPROM,CH341WriteEEPROM: 适用于直接操作EEPROM存储器件。

操作流程:

CH341StreamI2C 函数说明

iWriteLength:I2C Write的字节长度

iWriteBuffer:I2C Write的缓冲区内容,该缓冲区内容会经过SDA信号线对外输出首字节地址通常是设备地址及读写位。如设备地址是0x50,I2C写操作时首字节为:0x50 << 1 = 0xA0,I2C读操作时首字节为:0x50 << 1 | BIT(0) = 0xA1。

iReadLength:I2C Read的字节长度

oReadBuffer:API成功返回后,其内容是从SDA信号线上采集的数据

示例1:EEPROM 24C256的设备地址是:0x50, 从其3200H开始的地址读取256字节的数据。

UCHAR OutBuf[3] = {0xA1, 0x32, 0x00};
UCHAR InBuf[256];

CH341StreamI2C(0, 3, OutBuf, 256, inBuf);

示例2:EEPROM 24C256的设备地址是:0x50, 从其3200H开始的地址写入2个字节的数据,内容0x11,0x22。

UCHAR OutBuf[5];

OutBuf[0] = 0xA0;
OutBuf[1] = 0x32;
OutBuf[2] = 0x00;
OutBuf[3] = 0x11;
OutBuf[4] = 0x22;

CH341StreamI2C(0, 5, OutBuf, 0, NULL);

对应I2C总线时序如下:(未连接真正的EEPROM器件,忽略红色NACK标识)

升级的I2C接口函数

默认库函数提供的I2C函数不支持设备ACK的应答检测,此外有些外设需要在I2C的地址和数据或数据和数据之间插入一定的延迟delay,来满足时序上的要求。此类需求,可参考如下 API的实现。

I2C Start 和 I2C Stop

BOOL	WINAPI	IIC_IssueStart(
	ULONG			iIndex )  // 指定CH341设备序号
{
	UCHAR	mBuffer[ mCH341_PACKET_LENGTH ];
	ULONG	mLength;
	mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM;  // 命令码
	mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_STA;  // 产生起始位
	mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束
	mLength = 3;
	return( CH341WriteData( iIndex, mBuffer, &mLength ) );  // 写出数据块
}

BOOL	WINAPI	IIC_IssueStop(
	ULONG			iIndex )  // 指定CH341设备序号
{
	UCHAR	mBuffer[ mCH341_PACKET_LENGTH ];
	ULONG	mLength;
	mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM;  // 命令码
	mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_STO;  // 产生停止位
	mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束
	mLength = 3;
	return( CH341WriteData( iIndex, mBuffer, &mLength ) );  // 写出数据块
}

I2C Write 1个字节并检查应答

BOOL	WINAPI	IIC_OutByteCheckAck(  // 输出一字节数据并检查应答是否有效
	ULONG			iIndex,  // 指定CH341设备序号
	UCHAR			iOutByte )  // 准备写出的数据
{
	UCHAR	mBuffer[ mCH341_PACKET_LENGTH ];
	ULONG	mLength, mInLen;
	mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM;  // 命令码
	mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_OUT;  // 输出数据,位5-位0为长度,0长度则只发送一个字节并返回应答
	mBuffer[ 2 ] = iOutByte;  // 数据
	mBuffer[ 3 ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束
	mLength = 4;
	mInLen = 0;
	if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) {  // 执行数据流命令,先输出再输入
		if ( mInLen && ( mBuffer[ mInLen - 1 ] & 0x80 ) == 0 ) return( TRUE );  // 返回的数据的位7代表ACK应答位,ACK=0有效
	}
	return( FALSE );
}

 I2C 发送设备地址,等待设备应答(可用于检测设备是否连接,并工作)

BOOL    WINAPI  CH341CheckDev(  //检查I2C设备是否连接
	ULONG			iIndex,     // 指定CH341设备序号
	UCHAR           iDevAddr    //设备地址
							)
{
	UCHAR buf ;
	buf = (iDevAddr<<1);
	
	IIC_IssueStart(0);
	if( IIC_OutByteCheckAck(0,buf) )
	{
		IIC_IssueStop(0);
		return TRUE;
	}else{
		IIC_IssueStop(0);
		return FALSE;
	}
}

 CH341StreamI2C_Delay(CH341StreamI2C接口函数的升级版) 可指定I2C连续写数据之间的延时,写地址和读地址之间的延时,读地址和读数据之间的延时,连续读数据之间的延迟。


BOOL WINAPI CH341StreamI2C_Delay(
    ULONG iIndex,          // 指定CH341设备序号
    ULONG iWriteLength,    // 准备写出的数据字节数
    PVOID iWriteBuffer,    // 指向一个缓冲区,放置准备写出的数据,首字节通常是I2C设备地址及读写方向位
    ULONG iReadLength,     // 准备读取的数据字节数
    PVOID oReadBuffer,     // 指向一个缓冲区,返回后是读入的数据
    UCHAR iWriteDataDelay, // 连续写数据之间的延时,单位US,数值范围:0~15
    UCHAR iAddrDelay1,     // 写地址到读地址之间的延时,单位US,数值范围:0~15
    UCHAR iAddrDelay2,     // 读地址和读数据的延时,单位US,数值范围:0~15
    UCHAR iReadDataDelay)  // 连续读数据之间的延时,单位US,数值范围:0~15
{
    UCHAR mBuffer[mDEFAULT_COMMAND_LEN + mDEFAULT_COMMAND_LEN / 8];
    ULONG i, j, k, mLength;
    PUCHAR mWrBuf;
	UCHAR iWriteTimes;
	
    mLength = max(iWriteLength, iReadLength);
    if (mLength > mMAX_BUFFER_LENGTH)
        return (FALSE);
    if (mLength <= mDEFAULT_BUFFER_LEN)
        mWrBuf = (PUCHAR)mBuffer;                                                               // 不超过默认缓冲区长度
    else {                                                                                      // 超过则需要另外分配内存
        mWrBuf = (PUCHAR)LocalAlloc(LMEM_FIXED, mMAX_COMMAND_LENGTH + mMAX_COMMAND_LENGTH / 8); // 分配内存
        if (mWrBuf == NULL)
            return (FALSE); // 分配内存失败
    }
    i = 0;
    mWrBuf[i++] = mCH341A_CMD_I2C_STREAM;  // 命令码
    mWrBuf[i++] = mCH341A_CMD_I2C_STM_STA; // 产生起始位
    if (iWriteLength) {
        for (j = 0; j < iWriteLength;) {
            mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 当前包剩余长度,<mCH341A_CMD_I2C_STM_MAX
            if (mLength <= 3) {
                while (mLength--)
                    mWrBuf[i++] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束
                mLength = mCH341_PACKET_LENGTH;
            }
            if (mLength >= mCH341_PACKET_LENGTH) {
                mWrBuf[i++] = mCH341A_CMD_I2C_STREAM; // 新包的命令码
                mLength = mCH341_PACKET_LENGTH - 1;
            }
            mLength--; // 去掉尾部的提前结束码
            if (mLength > 3 * (iWriteLength - j))
                mLength = 3 * (iWriteLength - j); // 本次输出有效数据长度
			iWriteTimes = mLength / 3;
            for (k = 0; k < iWriteTimes; k++) {
                mWrBuf[i++] = (UCHAR)(mCH341A_CMD_I2C_STM_OUT | 0x01); // 输出数据,位5-位0为长度
                mWrBuf[i++] = *((PUCHAR)iWriteBuffer + j++);           // 复制数据
                mWrBuf[i++] = mCH341A_CMD_I2C_STM_US | (iWriteDataDelay & 0x0f);
				mLength -= 3;
            }
        }
    }
    if (iReadLength) {
        mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 当前包剩余长度,<mCH341A_CMD_I2C_STM_MAX
        if (mLength <= 3) {
            while (mLength--)
                mWrBuf[i++] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束
            mLength = mCH341_PACKET_LENGTH;
        }
        if (mLength >= mCH341_PACKET_LENGTH)
            mWrBuf[i++] = mCH341A_CMD_I2C_STREAM; // 新包的命令码
        mWrBuf[i++] = mCH341A_CMD_I2C_STM_US | (iAddrDelay1 & 0x0f);
        if (iWriteLength > 1) {                                 // 先输出
            mWrBuf[i++] = mCH341A_CMD_I2C_STM_STA;              // 产生起始位
            mWrBuf[i++] = (UCHAR)(mCH341A_CMD_I2C_STM_OUT | 1); // 输出数据,位5-位0为长度
            mWrBuf[i++] = *(PUCHAR)iWriteBuffer | 0x01;         // I2C目标设备地址,最低位为1则进行读操作
        } else if (iWriteLength) {                              // 输出一字节后直接输入
            i--;
            mWrBuf[i++] = *(PUCHAR)iWriteBuffer | 0x01; // I2C目标设备地址,最低位为1则进行读操作
        }
        mWrBuf[i++] = mCH341A_CMD_I2C_STM_US | (iAddrDelay2 & 0x0f); // 延时10微秒
        for (j = 1; j < iReadLength;) {
            mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 当前包剩余长度,<mCH341A_CMD_I2C_STM_MAX
            if (mLength <= 1) {
                if (mLength)
                    mWrBuf[i++] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束
                mLength = mCH341_PACKET_LENGTH;
            }
            if (mLength >= mCH341_PACKET_LENGTH)
                mWrBuf[i++] = mCH341A_CMD_I2C_STREAM; // 新包的命令码
            mLength = iReadLength - j >= mCH341A_CMD_I2C_STM_MAX ? mCH341A_CMD_I2C_STM_MAX : 1; // 本次输入有效数据长度
            mWrBuf[i++] = (UCHAR)(mCH341A_CMD_I2C_STM_IN | mLength);                            // 输入数据,位5-位0为长度
            j += mLength;
            if (mLength >= mCH341A_CMD_I2C_STM_MAX) {                 // 当前包将满
                mWrBuf[i] = mCH341A_CMD_I2C_STM_END;                  // 当前包提前结束
                i += mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 跳过当前包剩余部分
            }
            mWrBuf[i++] = mCH341A_CMD_I2C_STM_US | (iReadDataDelay & 0x0f); // 延时10微秒
        }
        mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 当前包剩余长度,<mCH341A_CMD_I2C_STM_MAX
        if (mLength <= 1) {
            if (mLength)
                mWrBuf[i++] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束
            mLength = mCH341_PACKET_LENGTH;
        }
        if (mLength >= mCH341_PACKET_LENGTH)
            mWrBuf[i++] = mCH341A_CMD_I2C_STREAM; // 新包的命令码
        mWrBuf[i++] = mCH341A_CMD_I2C_STM_IN;     // 输入数据,只接收一个字节并发送无应答
    }
    mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 当前包剩余长度,<mCH341A_CMD_I2C_STM_MAX
    if (mLength <= 1) {
        if (mLength)
            mWrBuf[i++] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束
        mLength = mCH341_PACKET_LENGTH;
    }
    if (mLength >= mCH341_PACKET_LENGTH)
        mWrBuf[i++] = mCH341A_CMD_I2C_STREAM; // 新包的命令码
    mWrBuf[i++] = mCH341A_CMD_I2C_STM_STO;    // 产生停止位
    mWrBuf[i++] = mCH341A_CMD_I2C_STM_END;    // 当前包提前结束
    mLength = 0;
    if (iReadLength)
        j = CH341WriteRead(iIndex, i, mWrBuf, mCH341A_CMD_I2C_STM_MAX, (iReadLength + mCH341A_CMD_I2C_STM_MAX - 1) / mCH341A_CMD_I2C_STM_MAX, &mLength, oReadBuffer); // 执行数据流命令,先输出再输入
    else
        j = CH341WriteData(iIndex, mWrBuf, &i); // 写出数据块
    if (j && mLength != iReadLength)
        j = FALSE;
    if (mWrBuf != mBuffer)
        LocalFree(mWrBuf); // 如果是分配的内存则释放
    return (j);
}

演示示意图,红色部分为作用间隔时间。

如上为CH341的I2C功能使用说明,其他平台上Linux和Android系统上接口函数均保持类似,可直接参考移植。

注:如果对I2C功能有更高要求,可选用增强版的CH347芯片来实现。链接:

高速USB转JTAG/SPI/I2C/UART/GPIO应用_PC技术小能手的博客-CSDN博客

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

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

相关文章

Piccolo傻瓜式环境配置

首先下载Piccolo的代码 Piccolo下载网址点击Code然后点击Download ZIP。可能有点慢&#xff0c;总共要下139M。 下载CMAKE CMAKE下载网址下载完后安装CMAKE 构建环境 将下来的Piccolo-main压缩包解压为Piccolo-main文件夹。打开CMAKE&#xff0c;如下图进行目录选择&…

Linux - 第19节 - 网络基础(传输层二)

1.TCP相关实验 1.1.理解listen的第二个参数 在编写TCP套接字的服务器代码时&#xff0c;在进行了套接字的创建和绑定之后&#xff0c;需要调用listen函数将创建的套接字设置为监听状态&#xff0c;此后服务器就可以调用accept函数获取建立好的连接了。其中listen函数的第一个参…

LeetCode - 1049 最后一块石头的重量 II (0-1背包)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/130935119 LeetCode:1049. 最后一块石头的重量 II 题目:有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选…

人脸识别3:C/C++ InsightFace实现人脸识别Face Recognition(含源码)

人脸识别3&#xff1a;C/C InsightFace实现人脸识别Face Recognition(含源码) 目录 1. 前言 2. 项目安装 &#xff08;1&#xff09;项目结构 &#xff08;2&#xff09;配置开发环境(OpenCVOpenCLbase-utilsTNN) &#xff08;3&#xff09;部署TNN模型 &#xff08;4&a…

【C++】手把手教你模拟实现string类

模拟实现string 前言类的成员变量构造函数析构函数size和length[ ] 重载迭代器赋值运算符重载和拷贝构造函数拷贝构造函数赋值运算符重载现代式写法 reserve 和 resizereserveresize 字符串追加push_backappend insertpos位置插字符pos位置插字符串 erase>> 和 <<&…

Linux---用户权限(权限位、chowd、chown)

1. 权限位 序号1&#xff0c;表示文件、文件夹的权限控制信息 序号2&#xff0c;表示文件、文件夹所属用户 序号3&#xff0c;表示文件、文件夹所属用户组 权限细节总共分为10个槽位&#xff1a; 举例&#xff1a;drwxr-xr-x&#xff0c;表示&#xff1a; 这是一个文件夹&…

如何使用Metasploit进行后渗透攻击?

后渗透攻击&#xff08;PostExploitation&#xff09;是整个渗透测试过程中最能够体现渗透测试团队创造力与技术能力的环节。前面的环节可以说都是在按部就班地完成非常普遍的目标&#xff0c;而在这个环节中&#xff0c;需要渗透测试团队根据目标组织的业务经营模式、保护资产…

关于PyQt5的环境搭建

目录 一、需要的环境 二、安装python 1、python安装链接 三、安装PyQt5 1、使用豆瓣的镜像 2、配置环境变量 四、安装pycharm 1、pycharm官网链接 五、配置环境 1、找到设置 2、添加designer 3、配置ui 4、配置rc 六、注意问题 一、需要的环境 1、安装好python安装…

【Linux CAN应用编程(1)】初识CAN总线(附全文代码)

接下来我们学习 CAN 应用编程&#xff0c;CAN 是目前应用非常广泛的现场总线之一&#xff0c;主要应用于汽车电子和工业领域&#xff0c;尤其是汽车领域&#xff0c;汽车上大量的传感器与模块都是通过 CAN 总线连接起来的。CAN 总线目前是自动化领域发展的热点技术之一&#xf…

1、Vue简介与环境搭建

目录 一、Vue简介二、Vue开发环境1 - 环境安装2 - 新建Vue项目3 - VS Code4 - Vue项目的目录结构 一、Vue简介 官方文档&#xff1a;https://cn.vuejs.orgVue的api风格&#xff1a;选项式 API&#xff08;Vue 2&#xff09; 和组合式 API&#xff08;Vue 3&#xff09;**选项式…

怎么把pdf转成word?转换途径一览

在日常生活和工作中&#xff0c;我们常常需要处理各种文档格式。其中&#xff0c;PDF 作为一种流行的跨平台文件格式&#xff0c;广泛应用于技术文档、报告、合同和电子书等领域。但是&#xff0c;当我们需要修改 PDF 文件内容时&#xff0c;却往往会遇到困难。这时&#xff0c…

JavaScript引擎,V8引擎的原理

为什么需要JavaScript引擎&#xff1f; 高级的编程语言都是需要转成最终的机器指令来执行 我们所编写的js无论h是交给浏览器或者node执行&#xff0c;最后都是需要被CPU执行的 CPU只认识自己的指令集&#xff08;机器语言&#xff09;才能被CPU所执行 所以我们需要js引擎帮助我…

掌握了它,软件测试拿下25K轻轻松松!

了解软件测试这行的人都清楚&#xff0c;功能测试的天花板可能也就15k左右&#xff0c;而自动化的起点就在15k左右&#xff0c;当然两个岗位需要掌握的技能肯定是不一样的。 如果刚入门学习完软件测试&#xff0c;那么基本薪资会在7-8k左右&#xff0c;这个薪资不太高主要是因…

JQuery - JavaScript 的框架 - 语法简化版本

目录 js文件与 script 标签的位置问题总结&#xff1a; 有的时候是很坑&#xff0c;看了挺多资料&#xff0c;有时候乱糟糟的&#xff0c;都不说清楚&#xff0c;这是JavaScript的语法&#xff0c;还是 JQuery的语法&#xff0c;所以就会因为没有导入 JQuery的js文件&#xff0…

「功能测试进阶到自动化测试」一路走来都离不每个阶段的计划

关于「从功能测试&#xff0c;转岗到自动化测试」&#xff0c;主要的几个问题 &#xff1a; 001 目前一直在走功能测试&#xff0c;工作中也没有机会接触自动化测试 。想后续从事自动化测试&#xff0c;我应该从哪里开始学 &#xff1f; 解答&#xff1a;自动化 &#xff0c…

【六】设计模式~~~结构型模式~~~适配器模式(Java)

【学习难度&#xff1a;★★☆☆☆&#xff0c;使用频率&#xff1a;★★★★☆】 1.1. 模式动机 在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式。通常情况下&#xff0c;客户端可以通过目标类的接口访问它所提供的服务。有时&#xff0c;现有的类可以满…

全渠道电子商务指南

希望将全渠道电子商务纳入您的业务战略&#xff0c;但不确定从哪里开始。这篇博文将指导您了解全渠道商务的基础知识&#xff0c;以及它与多渠道方法的区别。 全渠道电子商务旨在为线上和线下多个平台的客户创造全面的购物体验。客户可以通过各种接触点&#xff08;例如网站、…

网络安全-02-BurpSuite工具安装

网络安全-02-BurpSuite工具安装 &#x1f53b;一、BurpSuite简介&下载&#x1f4d7; 二、Windows安装Jdk&#x1f4f0; 2.1 下载Jdk并安装&#x1f4f0; 2.2 设置Jdk环境变量&#x1f4dc; 2.2.1 设置JAVA_HOME&#x1f4dc; 2.2.2 设置path&#x1f4dc; 2.2.3 Jdk验证 &a…

数据库基础——8.单行函数

这篇文章我们来讲一下数据库里面的单行函数 目录 1. 函数的理解 1.1 什么是函数 1.2 不同DBMS函数的差异 1.3 MySQL的内置函数及分类 2. 数值函数 2.1 基本函数 2.2 角度与弧度互换函数 2.3 三角函数 2.4 指数与对数 2.5 进制间的转换 3. 字符串函数 4. 日期和…

PyCharm配置Opencv

具体方案&#xff1a; Plan A&#xff1a;可以直接在pycharm中配置&#xff08;如果有梯子可以试试&#xff0c;没有可能下载不了&#xff09; 参考视频&#xff1a;直接在Pycharm中配置即可 两分钟用Pycharm安装并配置OpenCV_哔哩哔哩_bilibili PlanB&#xff1a;通过终端安…