stm32——AD采集以及DMA

        今天继续我们的STM32的内容学习,我使用的单片机是STM32F103VCT6,通过Keil Array Visualization软件来观测AD采样出来的波形。先来看看本次实验用到的硬件知识。

        首先是ADC(Analog-to-Digital Converter)是模拟信号转数字信号的关键组件,用于将来自外部传感器或模拟输入的模拟信号转换为数字形式,以便微处理器或控制器进行数字信号处理。如果大家看我其他文章的话,这个器件就是我们采样需要用到的一个器件。它的功能框图如下。

ADC功能框图

        首先,需要注意的是电压的范围,这也是ADC输入信号的幅值范围[V_{REF-},V_{REF+}],这里我用的电压范围是[0,3]。这样就够了。当然好像也有负的。这里就不做讨论了。其次,就是输入通道,也就是你的采样信号加在哪个地方。每个ADC最多有16个通道。ADC1和ADC2都有16个通道。接下来,这张图就是ADC对应通道的IO口。大家可以参考一下。这个只是STM32F103VET6的ADC的IO分配,具体到单片机大家可以去找参考手册。

         对应的GPIO口要配置成模拟输入模式,即GPIO_Mode_AIN。我使用的是ADC1的4通道,由上图可知,也就是PA4的端口。代码如下。

void GPIO_Configuration(void)
{
    /* 定义 GPIO 初始化结构体 GPIO_InitStructure */
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 将 PA.4 设置为模拟输入脚 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

      接下来就是配置ADC了。这里要根据下面的结构体,慢慢配置。包括工作模式,ADC扫描(单通道还是多通道),转换模式的选择,触发方式的选择,对齐格式的选择(左对齐,右对齐等)、ADC采集通道数。当然我建议大家复制粘贴,毕竟结构体打起来太麻烦了,咱们主要学的是原理。结构体如下。

typedef struct
{
  uint32_t ADC_Mode;                      /*!< Configures the ADC to operate in independent or
                                               dual mode. 
                                               This parameter can be a value of @ref ADC_mode */

  FunctionalState ADC_ScanConvMode;       /*!< Specifies whether the conversion is performed in
                                               Scan (multichannels) or Single (one channel) mode.
                                               This parameter can be set to ENABLE or DISABLE */

  FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in
                                               Continuous or Single mode.
                                               This parameter can be set to ENABLE or DISABLE. */

  uint32_t ADC_ExternalTrigConv;          /*!< Defines the external trigger used to start the analog
                                               to digital conversion of regular channels. This parameter
                                               can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */

  uint32_t ADC_DataAlign;                 /*!< Specifies whether the ADC data alignment is left or right.
                                               This parameter can be a value of @ref ADC_data_align */

  uint8_t ADC_NbrOfChannel;               /*!< Specifies the number of ADC channels that will be converted
                                               using the sequencer for regular channel group.
                                               This parameter must range from 1 to 16. */
}ADC_InitTypeDef;
 /* 定义 ADC 初始化结构体 ADC_InitStructure */
    ADC_InitTypeDef ADC_InitStructure;

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent·;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE ;
    ADC_InitStructure.ADC_ContinuousConvMode =  DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2 ;  // 指定 TIM2 的触发输出作为 ADC 触发源
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

       我配置的结构体如上,其他的都无所谓,重要的是这个ADC_ExternalTrigConv的选择。烦的嘞,我也是服了。为什么说它烦,咱们继续写。这里使用的是TIM2外部触发ADC1,捕获比较事件2会产生一个触发信号,使得ADC在上升沿或者是下降沿的触发。也就是TIM2每到捕获比较事件结束后,它就是采一次样。那什么是捕获比较事件?捕获事件:在定时器模块中捕获外部信号的状态变化或时间点。比如,可以捕获外部传感器产生的脉冲信号的上升沿或下降沿;比较事件:通过比较寄存器中的值和计数器的值,触发比较事件。比如,可以在比较寄存器值等于计数器值时触发一个事件。这就需要继续配置我们的TIM2定时器了。配置如下。

void TIM2_Configuration(void)
{ 
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
		TIM_OCInitTypeDef TIM_OCInitStructure;

		//定时器TIM2初始化
		TIM_TimeBaseStructure.TIM_Period = 3515-1; 		//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
		TIM_TimeBaseStructure.TIM_Prescaler = 1-1; 			//设置用来作为TIMx时钟频率除数的预分频值
		TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 		//设置时钟分割:TDTS = Tck_tim
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 		//TIM向上计数模式
		TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);			//根据指定的参数初始化TIMx的时间基数单位
	
		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;		//选择定时器模式:TIM脉冲宽度调制模式1
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;		//比较输出使能
		TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period/2;
		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;		//输出极性:TIM输出比较极性低
		TIM_OC2Init(TIM2, & TIM_OCInitStructure);		//初始化外设TIM2_CH2
	
		TIM_Cmd(TIM2, ENABLE); 			//使能TIM2
}

        这里的OC呢,就是我所说的输出比较事件,竟然我们能用OC,那能不能用IC输入捕获呢?有没有大佬指导一下,孩子没搞出来。O_O

        接下来,就是配置DMA,与常用的USART串口通信一致。DMA(Direct Memory Access,直接内存访问)是一种无需MCU干预,在外设和存储器之间或者存储器和存储器之间直接进行数据传输的技术。在传统的数据传输方式中,MCU需要参与每个数据的读取和写入操作,这会消耗大量的MCU资源和时间。而 DMA 控制器可以接管数据传输的任务,直接控制数据在不同存储区域之间的移动,从而大大提高了数据传输的效率,减轻了MCU的负担,使MCU能够同时处理其他任务。换句话说,这个DMA传输数据的时候就是点对点的进行传输,不需要经过MCU,不占用内存。有两个DMA,分别为DMA1和DMA2。DMA1上含有7个通道,DMA2上含有5个通道。其功能框图以及通道的分配图如下。

DMA功能框图
DMA1各个通道的映射
DMA2各个通道的映射

        我用的是ADC1,由上图,所以为DMA1。接下来看看DMA配置,包括外设地址,存储地址,传输方向,传输的数据量,外设是否增量,地址是否增量,外设数据宽度,存储器数据宽度,模式选择,通道优先级,什么到什么的模式。结构体如下。

typedef struct
{
  uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */

  uint32_t DMA_MemoryBaseAddr;     /*!< Specifies the memory base address for DMAy Channelx. */

  uint32_t DMA_DIR;                /*!< Specifies if the peripheral is the source or destination.
                                        This parameter can be a value of @ref DMA_data_transfer_direction */

  uint32_t DMA_BufferSize;         /*!< Specifies the buffer size, in data unit, of the specified Channel. 
                                        The data unit is equal to the configuration set in DMA_PeripheralDataSize
                                        or DMA_MemoryDataSize members depending in the transfer direction. */

  uint32_t DMA_PeripheralInc;      /*!< Specifies whether the Peripheral address register is incremented or not.
                                        This parameter can be a value of @ref DMA_peripheral_incremented_mode */

  uint32_t DMA_MemoryInc;          /*!< Specifies whether the memory address register is incremented or not.
                                        This parameter can be a value of @ref DMA_memory_incremented_mode */

  uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
                                        This parameter can be a value of @ref DMA_peripheral_data_size */

  uint32_t DMA_MemoryDataSize;     /*!< Specifies the Memory data width.
                                        This parameter can be a value of @ref DMA_memory_data_size */

  uint32_t DMA_Mode;               /*!< Specifies the operation mode of the DMAy Channelx.
                                        This parameter can be a value of @ref DMA_circular_normal_mode.
                                        @note: The circular buffer mode cannot be used if the memory-to-memory
                                              data transfer is configured on the selected Channel */

  uint32_t DMA_Priority;           /*!< Specifies the software priority for the DMAy Channelx.
                                        This parameter can be a value of @ref DMA_priority_level */

  uint32_t DMA_M2M;                /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.
                                        This parameter can be a value of @ref DMA_memory_to_memory */
}DMA_InitTypeDef;

        说到这里就差不多了。接下来,给大家看看一个完整的代码。本次实验整体的思路是通过TIM2外部触发ADC启动,经过DMA进行传输,通过仿真软件来看到我们所要的波形。这里以波形为主,至于采样率这些就不去深究了,大家可以自由发挥。我这里的输入信号为0~3V的正弦信号,采样率约为20.48KHz。至于为什么20.48KHz?大家结合FFT想想为什么?之后告诉大家。完整代码如下。

/*******************************************************************************
* 文件名          : main.c
* 作者            : Losingamong
* 时间			  : 08/08/2008
* 文件描述        : 主函数
********************************************************************************/

/* 头文件    ------------------------------------------------------------------*/

#include "stm32f10x.h"
#include "stm32f10x_adc.h"
#include "stdio.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_tim.h"
                                      
/* 自定义同义关键字    --------------------------------------------------------*/

/* 自定义参数宏        --------------------------------------------------------*/

/* 自定义函数宏        --------------------------------------------------------*/

/* 自定义变量          --------------------------------------------------------*/
#define ADC1_DR_Address    ((u32)0x40012400 + 0x4c) 

uint16_t AD_Value[512];
uint16_t temp[512];
uint8_t ADC_FLAG;

/* 自定义函数声明      --------------------------------------------------------*/

void RCC_Configuration(void);
void GPIO_Configuration(void);
void ADC_Configuration(void); 
void DMA_Configuration(void);
void TIM2_Configuration(void);


/*******************************************************************************
* 函数名		 : main
* 函数描述       : Main 函数
* 输入参数       : 无
* 输出结果       : 无
* 返回值         : 无
*******************************************************************************/
int main (void)
{
    int i = 0;

    /* 设置系统时钟 */
    RCC_Configuration();

    /* 设置 GPIO 端口 */
    GPIO_Configuration();

    /* 设置 ADC */
    ADC_Configuration();

    /* DMA 初始化 */
    DMA_Configuration();

    /* 配置 TIM2 */
    TIM2_Configuration();

    while(1)
    {
        if(ADC_FLAG == 1)
        {
            for(i = 0; i < 512; i++)
            {    
                temp[i] = AD_Value[i];      
            }
            ADC_FLAG = 0;                                
            DMA_Cmd(DMA1_Channel1, ENABLE);             
        }
    }
}

/*******************************************************************************
* 函数名	: RCC_Configuration
* 函数描述  : 设置系统各部分时钟
* 输入参数  : 无
* 输出结果  : 无
* 返回值    : 无
*******************************************************************************/
void RCC_Configuration(void)
{
    /* 使能各个用到的外设时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}

void TIM2_Configuration(void)
{ 
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
		TIM_OCInitTypeDef TIM_OCInitStructure;
	

		//定时器TIM2初始化
		TIM_TimeBaseStructure.TIM_Period = 3515-1; 		//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
		TIM_TimeBaseStructure.TIM_Prescaler = 1-1; 			//设置用来作为TIMx时钟频率除数的预分频值
		TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 		//设置时钟分割:TDTS = Tck_tim
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 		//TIM向上计数模式
		TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);			//根据指定的参数初始化TIMx的时间基数单位
	
		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;		//选择定时器模式:TIM脉冲宽度调制模式1
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;		//比较输出使能
		TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period/2;
		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;		//输出极性:TIM输出比较极性低
		TIM_OC2Init(TIM2, & TIM_OCInitStructure);		//初始化外设TIM2_CH2
	
		TIM_Cmd(TIM2, ENABLE); 			//使能TIM2

}

/*******************************************************************************
* 函数名  		: GPIO_Configuration
* 函数描述    	: 设置各 GPIO 端口功能
* 输入参数      : 无
* 输出结果      : 无
* 返回值        : 无
*******************************************************************************/
void GPIO_Configuration(void)
{
    /* 定义 GPIO 初始化结构体 GPIO_InitStructure */
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 将 PA.4 设置为模拟输入脚 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/*******************************************************************************
* 函数名  		: ADC_Configuration
* 函数描述    	: 初始化并启动 ADC 转换,由 TIM2 外部触发
* 输入参数      : 无
* 输出结果      : 无
* 返回值        : 无
*******************************************************************************/

void ADC_Configuration(void)
{
    /* 定义 ADC 初始化结构体 ADC_InitStructure */
    ADC_InitTypeDef ADC_InitStructure;

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE ;
    ADC_InitStructure.ADC_ContinuousConvMode =  DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2 ;  // 指定 TIM2 的触发输出作为 ADC 触发源
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    /* 设置 ADC1 使用 8 转换通道,转换顺序 1,采样时间为 55.5 周期 */ 
    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_55Cycles5);
    /* 使能 ADC1 */
    ADC_Cmd(ADC1, ENABLE);
    /* 复位 ADC1 的校准寄存器 */   
    ADC_ResetCalibration(ADC1);
    /* 等待 ADC1 校准寄存器复位完成 */
    while(ADC_GetResetCalibrationStatus(ADC1));
    /* 开始 ADC1 校准 */
    ADC_StartCalibration(ADC1);
    /* 等待 ADC1 校准完成 */
    while(ADC_GetCalibrationStatus(ADC1));
    /* 使能外部触发 启动 ADC1 转换 */ 
    ADC_ExternalTrigConvCmd(ADC1, ENABLE);
	ADC_DMACmd(ADC1,ENABLE);
}

void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//DMA1初始化
	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;				//ADC1地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value; 		//内存地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 				//方向(从外设到内存)
	DMA_InitStructure.DMA_BufferSize = 512; 						//传输内容的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 		//外设地址固定
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 			//内存地址固定
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; //外设数据单位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;    //内存数据单位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular  ; 		//DMA模式:循环传输
	DMA_InitStructure.DMA_Priority = DMA_Priority_High ; 		//优先级:高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;   		//禁止内存到内存的传输
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //配置DMA1
	
	DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);		//使能传输完成中断

	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);
}


void DMA1_Channel1_IRQHandler(void)
{	
    if(DMA_GetITStatus(DMA1_IT_TC1)!= RESET)
    {
//         DMA_Cmd(DMA1_Channel1, DISABLE); // 关闭 DMA1 通道 1 和 ADC1
        ADC_FLAG = 1; // ADC1 采集完成标志
        DMA_ClearITPendingBit(DMA1_IT_TC1); // 清除中断标志
    }
}

        结果如下,

        今天就说到这里,下次讲刺激的FFT。

        欲知后事如何,且听下回分解。OVO........

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

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

相关文章

网络编程!

网络编程 【1】网络开发架构 &#xff08; 1 &#xff09; C / S 架构 C : client &#xff08;客户端&#xff09; S: server (服务端) APP - 就是服务端 C/S 架构通过客户端软件和服务器之间的交互&#xff0c;实现了前端界面和后端业务逻辑的分离&#xff0c;提供了一种…

电脑 DNS 缓存是什么?如何清除?

DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;是互联网的重要组成部分&#xff0c;负责将人类易记的域名转换为机器可读的 IP 地址&#xff0c;从而实现网络通信。DNS 缓存是 DNS 系统中的一个关键机制&#xff0c;通过临时存储已解析的域名信息&#xf…

filex用户手册中文版解读

filex用户手册 filex的用户手册&#xff0c;看着好头疼呢&#xff0c;主要是没有&#x1f58a;记录&#xff0c;感觉就是浮在空中&#xff0c;飘在天上&#xff0c;好像懂了&#xff0c;又好像啥也没了解到&#xff0c;哈哈&#xff0c;有点意思。为了解决这个bug&#xff0c;…

力扣-回溯法

何为回溯法&#xff1f; 在搜索到某一节点的时候&#xff0c;如果我们发现目前的节点&#xff08;及其子节点&#xff09;并不是需求目标时&#xff0c;我们回退到原来的节点继续搜索&#xff0c;并且把在目前节点修改的状态还原。 记住两个小诀窍&#xff0c;一是按引用传状态…

阿里云Linux中安装MySQL,并使用navicat连接以及报错解决

首先查询是否安装MySQL // linux 使用yum安装或者rpm安装。(就是一个安装工具类似于applStore&#xff0c;brew不必在意) // 区别&#xff1a;yum会自动安装你要安装的东西的其他依赖&#xff0c;rpm不会但会提示你需要安装的东西&#xff0c;比较麻烦&#xff0c;所以采用yum安…

日常的学习

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Android ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 正文 7.11 resAndroidManifest 笔记 <> <> selector shape resources main下的AndroidMainifest.xml文件 application …

Windows系统MySQL的安装,客户端工具Navicat的安装

下载mysql安装包&#xff0c;可以去官网下载&#xff1a;www.mysql.com。点击downloads 什么&#xff1f;后面还有福利&#xff1f; 下载MySQL 下载企业版&#xff1a; 下载Windows版 5点多的版本有点低&#xff0c;下载8.0.38版本的。Window系统。下载下面的企业版。不下载…

C++笔试真题

可变分区管理方案 最佳适应&#xff1a;空闲区按容量递增最坏适应&#xff1a;空闲区按容量递减首先适应&#xff1a;空闲区按地址递增 C的结构体中有构造函数。 Linux新建用户或组 useradd&#xff1a;命令用于建立用户账号usermod&#xff1a;修改用户账号groupadd&#…

JAVA中的回溯算法解空间树,八皇后问题以及骑士游历问题超详解

1.回溯算法的概念 回溯算法顾名思义就是有回溯的算法 回溯算法实际上一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&#xff0c;尝试别的路径。回溯法是一种选优搜索法&#xff…

kibana连接elasticsearch(版本8.11.3)

前言 elasticsearch在8版本之后就出现了很大变化&#xff0c;由于kibana版本需要需elasticsearch进行版本对象&#xff0c;kibana连接方式也出现了很大变化。我在这里记录下自己的踩坑记录。 服务部署 本文中的服务都是在docker环境中部署的。其中elasticsearch版本和kibana版…

攻防世界(PHP过滤器过滤)file_include

转换过滤器官方文档&#xff1a;https://www.php.net/manual/zh/filters.convert.php#filters.convert.iconv 这道题因为convert.base64-encode被过滤掉了&#xff0c;所以使用convert.iconv.*过滤器 在激活 iconv 的前提下可以使用 convert.iconv.* 压缩过滤器&#xff0c; 等…

【Python实战因果推断】31_双重差分2

目录 Canonical Difference-in-Differences Diff-in-Diff with Outcome Growth Canonical Difference-in-Differences 差分法的基本思想是&#xff0c;通过使用受治疗单位的基线&#xff0c;但应用对照单位的结果&#xff08;增长&#xff09;演变&#xff0c;来估算缺失的潜…

加减计数器

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请编写一个十进制计数器模块&#xff0c;当mode信号为1&#xff0c;计数器输出信号递增&#xff0c;当mode信号为0&#xff0c;计数器输出信号递减。每次到达0&#xff0c;给出指示信号zero。 模块的接…

昇思25天学习打卡营第18天|MindNLP ChatGLM-6B StreamChat

MindNLP ChatGLM-6B StreamChat MindNLP ChatGLM-6B StreamChat是基于MindNLP框架和ChatGLM-6B模型实现的聊天应用&#xff0c;利用自然语言处理技术&#xff0c;实现与用户的自然语言交流。这样的应用可以广泛应用于智能客服、在线助理和社交聊天等场景。 在当前技术环境下&a…

鸿蒙语言基础类库:【@ohos.application.testRunner (TestRunner)】 测试

TestRunner TestRunner模块提供了框架测试的能力。包括准备单元测试环境、运行测试用例。 如果您想实现自己的单元测试框架&#xff0c;您必须继承这个类并覆盖它的所有方法。 说明&#xff1a; 开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-…

法律咨询援助网站

1 项目介绍 1.1 摘要 随着互联网技术的飞速发展&#xff0c;公众对于便捷、高效的法律咨询服务需求日益增长。传统的法律咨询方式已难以满足人们即时性、多样化的咨询需求&#xff0c;促使法律咨询援助网站应运而生。这些平台旨在通过数字化手段&#xff0c;为用户提供法律知…

教务管理系统

教务管理系统 For Free 本项目免费获取&#xff0c;获取方式在后台发送教务管理系统。系统的实现比较简单&#xff0c;主要是对数据库的读取和前端数据调用的表格展示&#xff0c;并没有太多的交互&#xff0c;比较适合初学者学习Flask和数据库的使用&#xff0c;所以免费获取…

8626 原子量计数

分析&#xff1a; 1. **读取输入**&#xff1a;首先&#xff0c;我们需要读取输入中的第一行&#xff0c;了解有多少个化学式需要处理。之后&#xff0c;对于每个化学式&#xff0c;我们逐行读取并进行处理。 2. **解析化学式**&#xff1a;对于每个化学式&#xff0c;我们需要…

如何在Ubuntu环境下使用加速器配置Docker环境

一、安装并打开加速器 这个要根据每个加速器的情况来安装并打开&#xff0c;一般是会开放一个代理端口&#xff0c;比如1087 二、安装Docker https://docs.docker.com/engine/install/debian/#install-using-the-convenience-script 三、配置Docker使用加速器 3.1 修改配置…

如何处理 PostgreSQL 中由于表锁定导致的并发访问问题?

文章目录 一、表锁定的类型二、表锁定导致的并发访问问题三、解决方案&#xff08;一&#xff09;使用合适的锁定模式&#xff08;二&#xff09;优化事务处理&#xff08;三&#xff09;避免不必要的锁定&#xff08;四&#xff09;使用索引&#xff08;五&#xff09;监控和分…