DMA+串口空闲中断实现RS485不定长数据接收和发送

目录

    • 1、环境说明
    • 2、实现不定长数据接收需要做哪些事?
      • 2.1、数据的接收与缓存
      • 2.2、数据帧的结束判断
      • 2.3、数据帧的长度计算
    • 3、RS485串口实现不定长数据发送
    • 4、代码实现
    • 结语:

1、环境说明

单片机型号;Cortex-M4架构,AT32F437
说明:实现只是一个思路,只要了解到单片机存在这些功能,对照着官方手册和例程,实现并不难。

2、实现不定长数据接收需要做哪些事?

  • 数据的接收与缓存
  • 数据帧的结束判断
  • 数据帧的长度计算

解决以上几点,基本上就可以实现不定长数据的接收了。下面将依次给出应对措施。

2.1、数据的接收与缓存

数据的接收通常是通过单片机的usart–>dt(数据寄存器)来完成的,每次能够存储一个字节。单片机可以通过定时查询、接收中断、DMA等方式进行数据的缓存工作。其中DMA作为效率最高的方式,是本次讲解的重点。
在这里插入图片描述

什么是DMA?在每一个32位单片机的手册里应该都会有说明
DMA是单片机集成在芯片内部的一个数据搬运工,它可以代替单片机对数据进行传输、存储。举一个简单的例子:
要发一个快递,我们需要填写快递的大致体积大小、从哪里发走、在哪里收货。DMA就像快递员,我们只需要负责填写信息,等待快递员上门取货、发货就可以了,我们只需考虑要填的信息和签收工作。
DMA不仅仅是串口能用,它能满足单片机绝大多数的数据传输工作,比如支持定时器、ADC、DAC、SDIO、I²S、SPI、I²C、DVP、QSPI和USART。无需了解太多,我认为嵌入式工程师对于这一类的工具能做到快速上手使用即可。
因此我们可以派出DMA对usart->dt中存储的数据进行一个接收和缓存工作。我们只需要知道什么时候数据都送到了,然后取出处理即可。
在这里插入图片描述

2.2、数据帧的结束判断

在串口通信中,通常我们对一帧数据的结束判定是在一定时间后,没有下一个数据到来。这一段时间在单片机内认为是一个空闲时刻。如果串口接收到一个数据后,隔了一个空闲时刻仍然没有数据继续到达,则串口的状态寄存器就会对空闲位进行一个置起。当单片机触发该中断后,就可以认为本次串口接收已经结束。在2.1我们已经让DMA对数据进行接收缓存了,因此我们就可以直接去DMA中取出这段数据。
在这里插入图片描述

2.3、数据帧的长度计算

在串口通信中,数据的长度是一个非常重要的信息,它可以帮助我们对数据帧进行解析。那具体要怎么知道呢?
在2.1中我们知道,在使用DMA时,需要预先填写一些信息。比如“快递”的大致体积。比如DMA最大支持是65536个字节,我们预估本次接收最大可能会用到x个字节。实际我们接收到了y个字节。那么DMA的长度寄存器就会记录下本次接收剩余的一个容量z。那么我们实际上接收到的数据长度y=x-z(x<=65536)。
在这里插入图片描述

3、RS485串口实现不定长数据发送

熟悉RS485的朋友都知道,RS485是一种半双工通信,发送和接收必须分时进行,因此对于收发转换控制的就非常重要,既要保证数据能够全部接收到,也必须保证数据能够全部发出,否则会造成数据的丢包。因此我们必须知道我们何时结束数据的发送,将RS485由发送切换到接收状态,切换早了会导致数据发送不完整,晚了会导致数据接收不及时不完整。
在单片机的串口状态寄存器里存在一个发送数据完成寄存器,当数据发送结束时,会将此位置起,产生一个发送结束中断。因此在此中断产生后,我们就可以安心切换至接收状态了。
在这里插入图片描述

4、代码实现

#include "rs485.h"
#include "stdio.h"
#include "comm_protocol.h"
/*
*********************************************************************************************************
*                                           与FreeRTOS相关的一些变量
*********************************************************************************************************
*/
TaskHandle_t rs485_handler;/*RS485数据处理任务句柄*/
SemaphoreHandle_t BinarySemphore;/*创建用于串口中断与任务同步的信号量*/
/*
*********************************************************************************************************
*                                            该文件内调用的全局变量
*********************************************************************************************************
*/
static uint8_t		Uart1RecBuffer[MaxNumOfUart1RecBuffer];		/* 接收缓冲区*/
static uint8_t		Uart1SendBuffer[MaxNumOfUart1SendBuffer];	/* 发送缓冲区*/


//数据接收标志位,
volatile uint8_t usart1_rx_dma_status = 0;
volatile uint8_t usart1_tx_dma_status=1;
/*
*********************************************************************************************************
*                                           部分函数声明
*********************************************************************************************************
*/
void TestProtocol(stCommBufBlock *BufBlockPtr);
/*
*********************************************************************************************************
*                                            驱动配置(外部比如MAIN.C , APP_HOOKS.c可能引用该全局变量)
*********************************************************************************************************
*/
#define PRINT_UART USART1
//RS485 1 用
stCommBSPInfo	RS485BSPInfo1 = {
	USART1,  //使用串口1
	19200,						/* 通讯波特率默认值19200*/
	0,							 /* 485通讯地址,在系统初始化的时候,会重新赋值*/

	DMA1_CHANNEL2,   //串口1接收数据使用的DMA地址
	DMA1MUX_CHANNEL2,
	DMAMUX_DMAREQ_ID_USART1_RX,			/* 通讯模块接收的源号*/
	Uart1RecBuffer,				/* 接收缓存指针*/
	MaxNumOfUart1RecBuffer,		/* 接收缓存大小*/

	DMA1_CHANNEL1,
	DMA1MUX_CHANNEL1,
	DMAMUX_DMAREQ_ID_USART1_TX,			/* 通讯模块发送 的源号*/
	Uart1SendBuffer,			/* 发送缓存指针*/
	MaxNumOfUart1SendBuffer,		/* 发送缓存大小*/

	0,							/* 接收计数器*/
	5,							/* 接收间隔,单位5ms*/
	5,							/* 发送间隔,单位5ms ,RS485用*/

	TestProtocol,				/* 通信协议函数指针*/
	BSPTYPE_485,					/* 接口选项,比如RS232,485,SPI等*/

	GPIO_PINS_11,							/* 控制485芯片的IO 序号0~31,232 不用,RS485 用*/
	GPIOA,
	0,
};
void usartConfiguration(void) {
	gpio_init_type gpio_init_struct;

	/* enable the usart1 and gpio clock */
	crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

	gpio_default_para_init(&gpio_init_struct);

	/* configure the usart2 tx, rx pin */
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	gpio_init_struct.gpio_pins = GPIO_PINS_9 | GPIO_PINS_10;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init(GPIOA, &gpio_init_struct);
	gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_7);
	gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_7);

	/* config usart nvic interrupt */
	nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
	nvic_irq_enable(USART1_IRQn, 2, 0);

	/* configure usart1 param */
	usart_init(USART1, RS485BSPInfo1.BaudRate, USART_DATA_8BITS, USART_STOP_1_BIT);
	usart_transmitter_enable(USART1, TRUE);
	usart_receiver_enable(USART1, TRUE);

	/* enable usart1 and usart2 and usart3 interrupt */
	usart_enable(USART1, TRUE);

	usart_dma_transmitter_enable(USART1, TRUE);
	usart_dma_receiver_enable(USART1, TRUE);

	usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);//使能空闲中断
	usart_interrupt_enable(USART1, USART_TDC_INT, TRUE); //使能发送完成中断
}
//初始化DMA的时钟
void dmaInit(void) {
	/* enable dma1 clock */
	crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
	dmamux_enable(DMA1, TRUE);/*一旦开启,就不要关闭,*/
	//配置通道1,用于串口1的发送
	dma_reset(RS485BSPInfo1.Send_Dma_Chn);
	dmamux_init(RS485BSPInfo1.Send_Dmamux_Chn, RS485BSPInfo1.CommSendSlotNumber);

	//配置通道2,用于串口1的接收
	dma_reset(RS485BSPInfo1.Rec_Dma_Chn);
	dmamux_init(RS485BSPInfo1.Rec_Dmamux_Chn, RS485BSPInfo1.CommRecSlotNumber);
}

//PA11 PD3 PD11
void usartCtrlIOInit(void) {
	gpio_init_type gpio_init_struct;

	/* enable the usart1 and gpio clock */
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	gpio_default_para_init(&gpio_init_struct);

	/* configure the usart2 tx, rx pin */
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_mode =  GPIO_MODE_OUTPUT;
	gpio_init_struct.gpio_pins = GPIO_PINS_11;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init(GPIOA, &gpio_init_struct);
	gpio_init_struct.gpio_pins = GPIO_PINS_3;
//默认接收状态
	gpio_bits_set(RS485BSPInfo1.gpio_x, RS485BSPInfo1.IoNumber);
}
//DMA最大传输量为65536
//用于串口接收和发送
void dmaUsartTXorRX(dma_dir_type dir, uint8_t* buf, uint16_t size, dma_channel_type *dmax_channely, usart_type* usart_x) {
	dma_init_type dma_init_struct;
	dma_reset(dmax_channely);//重置此通道
	
	if (dir == SEND) {
		if (usart_x == USART1) {
			while(!usart1_tx_dma_status){}
				usart1_tx_dma_status=0;
			gpio_bits_reset(GPIOA, GPIO_PINS_11);
		} 
	}
	/* dma1 channel1 for usart2 tx configuration */
	dma_default_para_init(&dma_init_struct);
	dma_init_struct.buffer_size = size;
	dma_init_struct.direction = dir;
	dma_init_struct.memory_base_addr = (uint32_t)buf;
	dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
	dma_init_struct.memory_inc_enable = TRUE;
	dma_init_struct.peripheral_base_addr = (uint32_t)&usart_x->dt;
	dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
	dma_init_struct.peripheral_inc_enable = FALSE;
	dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
	dma_init_struct.loop_mode_enable = FALSE;
	dma_init(dmax_channely, &dma_init_struct);
	dma_channel_enable(dmax_channely, TRUE); //一旦开启,就会立刻开始传输,不受MCU控制
}
/*
*********************************************************************************************************
*                                            TestProtocol()
*
* 描述: 测试用例协议
*
* 参数: BufBlockPtr-- 接收数据信息块
*
* 附注: 无
*
*********************************************************************************************************
*/

void TestProtocol(stCommBufBlock *BufBlockPtr)
{
	CPU_INT32U i;

	// 以同样的字节数将接收到的数据返回
	BufBlockPtr->SendByteNum = BufBlockPtr->RecByteNum;
	// 将返回的数据都扩大两倍
	for (i = 0; i < BufBlockPtr->SendByteNum; i++)
	{
		*(BufBlockPtr->SendBufPtr + i) = *(BufBlockPtr->RecBufPtr + i);
	}
}
/*
*********************************************************************************************************
*                                            CommProcess()
*
* 描述: 串口(232,485)通讯进程,改为任务函数,当有数据完成接收后,及时处理该函数
*
* 参数: CBinfo--通信端口配置信息
*
* 附注: 无
*
*********************************************************************************************************
*/
void CommProcess(stCommBSPInfo *CBinfo) {
	stCommBufBlock BufBlock;
	uint16_t sendnum;

	//先关闭相应的DMA接收
	dma_channel_enable(CBinfo->Rec_Dma_Chn, FALSE);
	//调用通信协议,RecCount 为接收数据个数参数,CBinfo.RecBuff 为接收数组地址
	CBinfo->RecCntTemp = CBinfo->RecBuffLength - dma_data_number_get(CBinfo->Rec_Dma_Chn); //根据接收的数据剩余量得出
	BufBlock.RecByteNum = CBinfo->RecCntTemp;
	BufBlock.RecBufPtr = CBinfo->RecBuff;
	BufBlock.SendBufPtr = CBinfo->SendBuff;
	BufBlock.Address = CBinfo->Address;

	//跳转至CBinfo.ProtocolFunPtr 指向的通信协议函数
	//该函数处理BufBlock.RecBufPtr 所指向的BufBlock.RecByteNum个字节的数据,
	//然后将处理出来的BufBlock.SendByteNum个字节的数据存放在BufBlock.SendBufPtr
	//所指向的地方
	(*CBinfo->ProtocolFunPtr)(&BufBlock);

	//防止要发送的数据个数超过SENDBUF最大值
	if (BufBlock.SendByteNum <= CBinfo->SendBuffLength) {
		sendnum = BufBlock.SendByteNum;
	} else {
		sendnum = CBinfo->SendBuffLength;
	}
	//如果地址不对,就不会有数据需要发送
	if (sendnum > 0) {
		dmaUsartTXorRX(SEND, BufBlock.SendBufPtr, sendnum, CBinfo->Send_Dma_Chn, CBinfo->usart_x);
	}
}
//建立一个任务,用于处理通信进程
void communication_485_task(void *pvParameters) { 
	BaseType_t semaphore485 = pdFALSE;
	dmaInit();
	dmaUsartTXorRX(RECEIVE, RS485BSPInfo1.RecBuff, RS485BSPInfo1.RecBuffLength, USART1RX, USART1); //开启DMA接收
	while (1) {
		//还需要判断当前协议。
		//等待信号量
		if (BinarySemphore != NULL) {
			//获取信号量
			semaphore485 = xSemaphoreTake(BinarySemphore, portMAX_DELAY);
			if (semaphore485 == pdTRUE) { //获取信号量成功
				if (usart1_rx_dma_status == 1) { //串口1,数据接收完成
					usart1_rx_dma_status = 0;
					CommProcess(&RS485BSPInfo1);//进入通信进程
					dmaUsartTXorRX(RECEIVE, RS485BSPInfo1.RecBuff, RS485BSPInfo1.RecBuffLength, USART1RX, USART1); //开启DMA接收
				}
				}
			}
		}

	}
}
void USART1_IRQHandler(void) {
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;

	if (usart_flag_get(USART1, USART_IDLEF_FLAG) != RESET) { //发生了空闲中断
		//一帧数据接收结束
		usart1_rx_dma_status = 1;
		usart_flag_clear(USART1, USART_IDLEF_FLAG);
		xSemaphoreGiveFromISR(BinarySemphore, &xHigherPriorityTaskWoken);
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	}
	if (usart_flag_get(USART1, USART_TDC_FLAG) != RESET) { //发送完成中断
		//一帧数据接收结束
		gpio_bits_set(GPIOA, GPIO_PINS_11);
		usart1_tx_dma_status=1;
		usart_flag_clear(USART1, USART_TDC_FLAG);
	}
}
/*end file*/

.h文件

#ifndef _RS485_H_
#define _RS485_H_

#include "config.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/*
*********************************************************************************************************
*                                               接口定义
*********************************************************************************************************
*/
#define	BSPTYPE_485			2
/*
*********************************************************************************************************
*                                               与RS485接口相关定义
*********************************************************************************************************
*/
#define SEND    DMA_DIR_MEMORY_TO_PERIPHERAL //发送
#define RECEIVE DMA_DIR_PERIPHERAL_TO_MEMORY //接收
#define USART1TX DMA1_CHANNEL1 //串口1发送
#define USART1RX DMA1_CHANNEL2 //串口1接收
#define MaxNumOfUart1RecBuffer 128
#define MaxNumOfUart1SendBuffer 256
/*
*********************************************************************************************************
*                                           自定义数据结构
*********************************************************************************************************
*/

typedef	struct
{
	uint32_t		Address;			/* 该端口地址*/
	uint32_t		RecByteNum;		/* 接收数组字节个数*/
	uint8_t		*RecBufPtr;			/* 接收指针指向缓冲数组*/
	uint32_t		SendByteNum;		/* 发送数组字节个数*/
	uint8_t		*SendBufPtr;		/* 发送指针指向缓冲数组*/
}stCommBufBlock;

typedef void (*tCommProtocolFunPtr)(stCommBufBlock*);		/* 通信协议函数指针*/

typedef	struct
{
	
	usart_type*		usart_x;          /* 串口外设 */
	uint32_t		BaudRate;					/* 通讯波特率*/
	uint32_t		Address;					/* 通讯波地址*/
	
	dma_channel_type * Rec_Dma_Chn;  /* 用于串口接收的DMA外设 */
	dmamux_channel_type* Rec_Dmamux_Chn; /* 用于串口接收的DMA通道号 */
	dmamux_requst_id_sel_type		CommRecSlotNumber;		/* 用于串口接收的接收的源号*/
	uint8_t		*RecBuff;					/* 接收缓存指针*/
	uint16_t		RecBuffLength;		/* 接收缓存大小,由接收最大值减去当前DMA剩余接收量得到 */
	
	dma_channel_type* Send_Dma_Chn;  /* 用于串口发送的DMA外设 */
	dmamux_channel_type* Send_Dmamux_Chn; /* 用于串口发送的DMA通道号 */
	dmamux_requst_id_sel_type		CommSendSlotNumber;		/* 用于串口发送的接收的源号*/
	uint8_t		*SendBuff;					/* 发送缓存指针*/
	uint16_t		SendBuffLength;				/* 发送缓存大小,由协议给出*/
	
	uint32_t		RecCntTemp;				/* 接收计数器,现在使用的是串口空闲中断来判断帧数据是否结束,该变量可以省去*/
	uint32_t		RecTimeInterval;			/* 接收间隔,单位5ms*/
	uint32_t		SendTimeInterval;			/* 发送间隔,单位5ms,RS485用*/
	
	tCommProtocolFunPtr	ProtocolFunPtr;				/* 通信协议函数指针*/
	uint32_t		BSPType;					/* 接口选项,比如RS232,485,SPI等*/
	
	uint32_t		IoNumber;					/* 控制485芯片的IO 序号0~31*/
	gpio_type* 		gpio_x;							/*PORT地址*/
	uint8_t		CommCnt;
}stCommBSPInfo;

extern TaskHandle_t rs485_handler;
extern SemaphoreHandle_t BinarySemphore;/*创建用于串口中断与任务同步的信号量*/

extern  stCommBSPInfo	RS485BSPInfo1;
extern volatile uint8_t usart1_tx_dma_status;
void communication_485_task(void *pvParameters);
void usartConfiguration(void);
void dmaInit(void);
void usartCtrlIOInit(void);
void dmaUsartTXorRX(dma_dir_type dir,uint8_t* buf,uint16_t size,dma_channel_type *dmax_channely,usart_type* usart_x);
#endif

结语:

首先此篇文章仅作为对RS485不定长数据的接收与发送的一种探讨,方式不止一种,本文是我的一种愚见罢了。其次,单片机开发并不难,我们只是要要了解到有这么一种方式可以实现想要的功能,那么就基本离成功不远了,耐心看手册耐心调试程序,没有不能完成的事情的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言操作符

文章目录 1:算术操作符2:移位操作符(移动的是二进制序列中的补码)2.1:知识补充(原码,反码,补码与二进制)2.2:左移操作符(<<)2.2:右移操作符(>>)2.2.1:逻辑右移2.2.2:算术右移 3:位操作符(运算用的是二进制位的补码)3.1:按位与操作符(&)3.2:按位或操作符(|)3.3:…

五大架构风格之一:数据流风格

数据流风格详细介绍 系统架构数据流风格是一种软件体系结构风格&#xff0c;它强调了系统内部不同部分之间的数据流动。这种风格侧重于描述系统中的数据处理过程&#xff0c;以及数据是如何从一个组件传递到另一个组件的。以下是系统架构数据流风格的详细介绍&#xff1a; 1 基…

width:100% 与 width:auto 的区别

width:100% 与 width:auto 的区别 一、当两者的子元素没有 border 或 padding 或 margin 的时候 先看一下示例代码和效果图 <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevi…

【数据结构 03】循环队列

一、原理 循环队列从功能角度具有队列的性质&#xff0c;即遵从先进先出原则&#xff0c;但是其存储方式是顺序存储。 循环队列的存储空间大小通常都是固定的&#xff0c;通过前指针和尾指针的移动控制循环队列数据的增删。 特征&#xff1a;顺序存储、先进先出、容量有限&a…

从前有条街 脚本 辅助 跳一跳

最近沉迷从前有条街。。。即将弃坑。 天工时间长的难以忍受。还好跳一跳能获得快乐水。找了一圈没有可用的脚本&#xff0c;于是自己写。。。 autojsx编写的 需要开启辅助功能跟悬浮窗 具体自行研究。 支持自动开始 无限续盘。目前只适配了1800*2400分辨率 。花了半个小时写的…

LeetCode —— 17. 电话号码的字母组合

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

树和二叉树基础

树和二叉树基础 1.1树的概念 树是在数据结构中第一次接触到的非线性结构。 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它 叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&am…

Kotlin 协程:深入理解 ‘lifecycleScope‘

Kotlin 协程&#xff1a;深入理解 ‘lifecycleScope’ Kotlin 协程是一种强大的异步编程工具&#xff0c;它提供了一种简洁、易读的方式来处理并发和异步操作。在 Kotlin 协程库中&#xff0c;lifecycleScope 是一个关键的概念&#xff0c;它允许我们将协程的生命周期绑定到 An…

基于SSM的高校班级同学录网站设计与实现(有报告)。Javaee项目,ssm项目。

演示视频&#xff1a; 基于SSM的高校班级同学录网站设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm项目。 项目介绍&#xff1a; Javaee项目&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&…

【C++】构造函数和析构函数详解

目录 前言 类中的六个默认成员函数 构造函数 概念 特性 析构函数 概念 特性&#xff1a; 前言 类中的六个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编…

好用的IDEA插件,免费!

今天给大家推荐一款IDEA插件&#xff1a;Apipost-Helper-2.0&#xff0c;写完代码IDEA内一键生成API文档&#xff0c;无需安装、打开任何其他软件&#xff1b;写完代码IDEA内一键调试&#xff0c;无需安装、打开任何其他软件&#xff1b;生成API目录树&#xff0c;双击即可快速…

利用二分法及不动点迭代求解非线性方程(MatLab)

一、问题描述 利用二分法及不动点迭代求解非线性方程。 二、实验目的 掌握二分法及不动点迭代的算法原理&#xff1b;能分析两种方法的收敛性&#xff1b;能熟练编写代码实现利用二分法及不动点迭代来求解非线性方程。 三、实验内容及要求 二分法 (1) 编写代码计算下列数字…

1990-2021年各省绿色金融指数数据(含原始数据+测算结果)

1990-2021年全国各省绿色金融指数数据&#xff08;含原始数据结果&#xff09; 1、时间&#xff1a;1990-2021年 2、指标&#xff1a;地区、年份、该省环保项目信贷总额&#xff08;亿元&#xff09;、全省信贷总额&#xff08;亿元&#xff09;、绿色信贷、环境污染治理投资…

应用keras建立ANN模型.

介绍&#xff1a; Keras是一个开源的神经网络库&#xff0c;它基于Python语言&#xff0c;并能够在多个深度学习框架上运行&#xff0c;包括TensorFlow、Theano和CNTK。Keras提供了一种简洁而高层次的API&#xff0c;使得用户能够快速构建、训练和部署神经网络模型。 Keras的设…

【算法与数据结构】198、213、337LeetCode打家劫舍I, II, III

文章目录 一、198、打家劫舍二、213、打家劫舍 II三、337、打家劫舍III三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、198、打家劫舍 思路分析&#xff1a;打家劫舍是动态规划的的经典题目。本题的难点在于递归公式…

如何在Excel中清除单元格的格式?这里有详细步骤

Microsoft Excel提供了大量样式选项来自定义电子表格的外观。但是&#xff0c;如果你需要删除格式&#xff0c;则可以很容易地删除选定单元格和整个工作表的格式。我们将向你展示如何操作。 ​注意&#xff1a;清除格式只会删除文本的样式&#xff1b;将保留你的实际文本。 如…

Modern C++ std::get<n>(tuple)的原理

1. 前言 前面我们讲过std::tuple的实现原理&#xff0c;但没有讲如何取出数据&#xff0c;本节着重讲讲这点。本节与之前的blog有较大关联&#xff0c;如果您没看&#xff0c;这里有链接&#xff0c;链接已按由浅入深排好序&#xff0c;您可以按顺序阅读。如果时间少可以直接看…

安卓视图基础

目录 设置视图的宽高 设置视图的间隔 设置视图的对齐方式 设置视图的宽高 设置视图的间隔 设置视图的对齐方式 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"a…

vue使用mpegts.js教程

vue使用mpegts.js教程 最简单好用的H265网页播放器-mpegts.js简介特征受限性 使用步骤安装引入HTML 中添加视频标签video知识扩展 在容器里创建播放器 最简单好用的H265网页播放器-mpegts.js H265是新一代视频编码规范&#xff0c;与H264相比压缩比更高&#xff0c;同样的码率下…
最新文章