STM32单片机入门学习——第14节: [6-2] 定时器定时中断定时器外部时钟

news2025/4/7 7:10:30

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!

本文写于:2025.04.04

STM32开发板学习——第14节: [6-2] 定时器定时中断&定时器外部时钟

  • 前言
  • 开发板说明
  • 引用
  • 解答和科普
  • 一、定时器中断代码
  • 二、外部时钟
  • 问题
  • 总结

前言

   本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
   欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
   在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
   另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!

开发板说明

   本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
   原理图如下
1、开发板原理图
在这里插入图片描述
2、STM32F103C6和51对比
在这里插入图片描述
3、STM32F103C6核心板
在这里插入图片描述

视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。

下图是实物图
在这里插入图片描述

引用

【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)
在这里插入图片描述
数据手册
在这里插入图片描述

解答和科普

一、定时器中断代码

定时器不涉及外部硬件,所以放在了System文件夹下,
在这里插入图片描述
在这里插入图片描述
第一步:RCC开启时钟,这个基本上每个代码都是第一步,不用想
定时器的基准时钟和整个外设的工作时钟就都会同时打开了。
第二步:选择时基单元的时钟源,对于定时中断,我们就选择内部时钟源
第三步:配置时基单元:包括这里的预分频器、自动重装定时器、技术模式等等
第四步:配置输出中断控制,允许更新中断输出到NVIC
第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
第六步:运行控制了,
整个模块配置完成后,我们还需要是能一下计数器,要不然计数器不会运行的.当定时器使能后,计数器就会开始计数了,当计数器更新时,触发中断,
最后在写一个定时器中断函数。这样这个中断函数每隔一段时间就能自动执行一次了。

标记一下
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
因为在初始化结构体里有很多关键的参数,比如自动重装值和预分频值等,这些参数可能会在初始化之后还需呀更改,如果为了更改某个参数还要再调用一次初始化函数,那太麻烦了,所有这有一些单独的函数,可以方便地更改这些关键参数,比如

TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);

单独写预分频值的:第一个为那个定时器,第二个为值,第三个为模式,写入的值在更新事件后才有效

void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);

改变计数器的技术模式

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

自动重装器预装功能配置:有预装还是物预装

void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);

给计数器写入一个值:如果你想手动写一个计数值,就可以用这个函数;

void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);

给自动重装值写入一个值:手动给一个自动重装值,用这个函数;

uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);

获取当前计数器计数值:如果你想看当前计数器计到哪里了,调用这个函数,返回值就是当前计数器的值;

uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);

获取当前预分频器值:如果想看预分频器值,就调用这个函数;

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

这四个和之前的一样:获取标志位和清除标志位的。

初始化TIM2,第一步开启时钟

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
}

选择时基单元的时钟

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

	TIM_InternalClockConfig(TIM2);		//好多人不写,默认的是内部时钟
	
	
}

配置时基单元

TIM_TimeBaseInitStructure.TIM_ClockDivision=;

这个时钟分频的参数在之前的原理一直没出现过,那它是用来干啥的,
在这里插入图片描述
关键点来了,这个采样频率f从哪来,手册写的是它可以由内部时钟直接而来,也可以是由内部时钟加一个时钟分频而来,那分频多少,就由我们这个参数ClockDivision决定的;可加这个参数和时基单元关系不大,在这里我们随便配一个。

TIM_TimeBaseInitStructure.TIM_Period=;
TIM_TimeBaseInitStructure.TIM_Prescaler=;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=;

TIM_Period:周期,就是ARR自动重装器的值;
TIM_Prescaler: PSC就是预分频器的值;
TIM_RepetitionCounter:就是重复计数器的值;只有高级定时器才有。给0;
不过这里面并没有CNT计数器的参数,如果我们之后需要的话,需要用SetCounter和GetCounter这两个函数来操作计数器;
在这里插入图片描述
定时频率=72M/(PSC+1)(ARR+1),定时1s,也就是定时频率1Hz,那么PSC给一个7200,ARR给一个10000,然后两个参数都再减一个1,这样就完成了。因为预分频器和计数器都有一个数的偏差,所以这里要减个1,然后注意PSC和ARR的取值都在0 ~ 65535,不要超范围了。
你可以预分频器给少点,自动重装给多点,这样就是一个较高的频率计比较多的数(说明预分频后的时间短),也可以预分频器给多点,自动重装给少点,这样就是一个较低的频率计比较少的数(说明预分频后的时间长);预分频对72M进行7200分频,得到的就是10k的计数频率,在10K的频率下,计10000个数,那不就是1s的时间吗?

	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;			//滤波的分频关系不大
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ;		//向上计数
	TIM_TimeBaseInitStructure.TIM_Period=7200-1;						//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=10000-1;					//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);

使能更新中断

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);			//更新中断到NVIC的通路
	

配置NVIC

	NVIC_InitTypeDef	NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);

使能定时器

	TIM_Cmd(TIM2,ENABLE);

定时器初始化

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

	TIM_InternalClockConfig(TIM2);		//好多人不写,默认的是内部时钟
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;			//滤波的分频关系不大
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ;		//向上计数
	TIM_TimeBaseInitStructure.TIM_Period=7200-1;						//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=10000-1;					//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);			//更新中断到NVIC的通路
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef	NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);
}

接下来写中断函数
在这里插入图片描述

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{
	
	
		
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}

我们现在想让显示1s进行计数,uint16_t Num;然后这个Num要在中断函数里执行++;但是中断函数是在Timer模块里的,如果直接在主程序写Num++,那Num就是跨越不同.C文件的变量了,会报错;Num++:在主函数中会跨文件,所以我们有这几种方法:
1、 如果你想跨文件使用变量,那可以在使用变量的那个文件上面,用external unit6_t Num,这样就行了,使用extern声明;就是告诉编译器,我现在有Num这个变量,他在别的文件定义了,至于在哪里,你自己帮我找好,最终在main。c找到,那编译器就知道了,他就会把这个external声明的变量,当作main.C变量的一个引用,注意这个过程没有新定义变量,他操作的还是main.c里的这个Num,其实我们头文件里面的函数声明,也是用extern 实现的。在这个函数的前面,是有一个extern的,只不过这个extern可以省略,所以我们一般不写。
当我们用extern声明了主函数的Num变量时,就可以在这里直接使用主函数的Num变量了,
在这里插入图片描述

在这里插入图片描述

2、 把定时器中断函数移动到主函数中去。这样变量就这一个.c文件里了,就不用再使用extern了;

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Timer.h"
#include "OLED.h"

uint16_t Num;
int main(void)
{
							
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1,2,"Hello STM32 MCU");
	OLED_ShowString(2,1,"Num:");
	while(1)
	{

		OLED_ShowNum(1,5,Num,5);

	}
}


void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{
	
	
			Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}

初始化后看到直接进入中断1次,为什么:
在这里插入图片描述
有个缓存寄存器,这时为了我们写的值只有在更新事件时,才会真正起作用,所以这里为了让值立刻起作用,就在这最后,手动生成了一个更新事件,这样预分频器的值就有效了,但同时,它的副作用就是,更新事件和更新中断是同时发生的,,更新中断会置更新中断标志位,当我们之后一但初始化
完了,更新中断就会立刻进入,这就是我们刚一上电,就立刻进中断的原因,解决方案也很简单,在TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure)的后面,开启中断的前面,再手动调用一下,TIM_ClearFlag(TIM2,TIM_FLAG_Update);手动把更新标志位清除一下,就能避免刚初始化完就进中断的问题了。

TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);			//手动把更新标志位清除一下,就能避免刚初始化完就进中断的问题了
	

ARR和PSC

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Timer.h"
#include "OLED.h"

uint16_t Num;
int main(void)
{
							
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1,2,"Hello STM32 MCU");
	OLED_ShowString(2,1,"Num:");
	while(1)
	{

		OLED_ShowNum(2,5,Num,5);
		OLED_ShowNum(3,5,TIM_GetCounter (TIM2),5);		//查看CNT计数器值的变化

	}
}


void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{

			Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}

代码

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Timer.h"
#include "OLED.h"

uint16_t Num;
int main(void)
{
							
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1,2,"Hello STM32 MCU");
	OLED_ShowString(2,1,"Num:");
	while(1)
	{

		OLED_ShowNum(2,5,Num,5);
		

	}
}


void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{

			Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}

Timer.Ch

#include "stm32f10x.h"                  // Device header

extern uint16_t Num;

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

	TIM_InternalClockConfig(TIM2);		//好多人不写,默认的是内部时钟
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;			//滤波的分频关系不大
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ;		//向上计数
	TIM_TimeBaseInitStructure.TIM_Period=7200-1;						//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=10000-1;					//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);			//手动把更新标志位清除一下,就能避免刚初始化完就进中断的问题了
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);			//更新中断到NVIC的通路
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef	NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);
}

/*
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{
	
	
			Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}
*/

#ifndef  __TIMER_H
#define  __TIMER_H
void Timer_Init(void);


#endif

实验现象

定时器中断Num++

二、外部时钟

在这里插入图片描述

TIM_ETRClockMode2Config();
通过ETR引脚的外部时钟模式2配置,

TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x00);

引脚要用到GOIO,在这之前还要配置GPIO,
在这里插入图片描述
给了上啦输入,也是可以的。浮空输入时外部功率很小,内部的上拉电阻可能影响到这个输入信号,这时候就可以用浮空输入,防止影响外部输入的电平,

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Timer.h"
#include "OLED.h"

uint16_t Num;
int main(void)
{
							
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1,2,"Hello STM32 MCU");
	
	OLED_ShowString(2,1,"Num:");
	OLED_ShowString(3,1,"CNT:");
	while(1)
	{
		OLED_ShowNum(2,5,Num,5);
		OLED_ShowNum(3,5,Timer_GetCounter(),5);
		

	}
}


void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{

			Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}

main.C

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Timer.h"
#include "OLED.h"

uint16_t Num;
int main(void)
{
							
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1,2,"Hello STM32 MCU");
	
	OLED_ShowString(2,1,"Num:");
	OLED_ShowString(3,1,"CNT:");
	while(1)
	{
		OLED_ShowNum(2,5,Num,5);
		OLED_ShowNum(3,5,Timer_GetCounter(),5);
		

	}
}


void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{

			Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}

Timer.CH

#include "stm32f10x.h"                  // Device header

extern uint16_t Num;

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitTypeDef   GPIO_InitStructure;
	 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	
	//TIM_InternalClockConfig(TIM2);		//好多人不写,默认的是内部时钟
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0xaa);
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;			//滤波的分频关系不大
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ;		//向上计数
	TIM_TimeBaseInitStructure.TIM_Period=10-1;						//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;					//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);			//手动把更新标志位清除一下,就能避免刚初始化完就进中断的问题了
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);			//更新中断到NVIC的通路
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef	NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);
}

uint16_t Timer_GetCounter(void)
{
	return TIM_GetCounter (TIM2);
}

/*
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)== SET)
	{
	
	
			Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}

}
*/

#ifndef  __TIMER_H
#define  __TIMER_H
void Timer_Init(void);
uint16_t Timer_GetCounter(void);

#endif

实验现象
这时上面是Num,下面是CNT计数器的值,我们用挡光片档一下,CNT加1,因为现在时基单元没有预分频,所以每次遮挡CNT都会加1如果有预分频了就是遮挡几次,才能加1次,然后加到9后,自动清零,同时申请中断,Num++;这里不准需要加滤波。

外部时钟源完成计数

问题

1、复杂凌乱

总结

本节课主要学了了如何配置定时器,首先是定时器中断,其中还多了对滤波器的设置,外部毛刺确实可以设置,主要是按照上一节课的理论也是打通这个线路,第一步:RCC开启时钟,这个基本上每个代码都是第一步,不用想定时器的基准时钟和整个外设的工作时钟就都会同时打开了。第二步:选择时基单元的时钟源,对于定时中断,我们就选择内部时钟源第三步:配置时基单元:包括这里的预分频器、自动重装定时器、技术模式等等;第四步:配置输出中断控制,允许更新中断输出到NVIC;第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级;第六步:运行控制了。整个模块配置完成后,我们还需要是能一下计数器,要不然计数器不会运行的.当定时器使能后,计数器就会开始计数了,当计数器更新时,触发中断,最后在写一个定时器中断函数。这样这个中断函数每隔一段时间就能自动执行一次了。然后是选择外部时钟作为时钟源的设置。

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

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

相关文章

2025-04-03 Latex学习1——本地配置Latex + VScode环境

文章目录 1 安装 Latex2 安装 VScode3 配置环境3.1 汉化 VScode3.2 安装 latex 插件3.3 配置解释 4 编译示例5 加快你的编译5.1 取消压缩5.2 使用 PDF 代替图片 6 参考文章 1 安装 Latex 本文配置环境: Windows11 打开清华大学开源软件镜像站:https://mi…

【CF】Day24——Codeforces Round 994 (Div. 2) D

D. Shift Esc 题目: 思路: 典DP的变种 如果这一题没有这个变换操作,那么是一个很典型的二维dp,每一个格子我们都选择上面和左边中的最小值即可 而这题由于可以变换,那我们就要考虑变换操作,首先一个显然…

【Java集合】LinkedList源码深度分析

参考笔记:java LinkedList 源码分析(通俗易懂)_linkedlist源码分析-CSDN博客 目录 1.前言 2.LinkedList简介 3.LinkedList的底层实现 4.LinkedList 与 ArrayList 的对比 4.1 如何选择 4.2 对比图 5.LinkedList 源码Debug 5.1 add(E e) &#xff…

Python办公自动化(2)对wordpdf的操作

一、操作word文档 终端下载操作word文件的工具库: pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple python-docx 1.遍历文档中内容 paragraphs:段落属性,返回列表类型的段落地址,遍历每一个段落地址,通过…

pip安装第三方库,但PyCharm中却无法识别

点击菜单栏File,选择Settings 系统默认的是PyCharm安装目录下的python.exe 解释器,不要用。 选择你的PYTHON的安装目录下的python.exe 解释器。如果不存在的话,增加进去 如果文件》设置打不开,需移除法化包。 打开 pycharm 安装目…

Linux C++编译及g++使用操作

编译的步骤 编译选项参数 编译生成库文件 静态库 动态库 运行可执行文件 静态库由于已经包含了链接的文件所以可以直接执行;动态库方式由于是运行时链接,所以需要指定链接的路径;

【Android】界面布局-线性布局LinearLayout-例子

线性布局(LinearLayout)是一种重要的界面布局中,也是经常使用到的一种界面布局 • 在线性布局中,所有的子元素都按照垂直或水平的顺序在界面上排列 ➢如果垂直排列,则每行仅包含一个界面元素 ➢如果水平排列&…

windows技术基础知识

NT架构 NT 就是new techonology 的英文单词缩写,是微软1993年推出操作系统的重大升级,如内存管理,安全机制,多任务,多线程支持。在此之前操作系统都是基于MS-DOS上面的图形化界面,只有有限的内存管理和多任…

在 Windows 环境下使用 VSCode 和 TinyGo 开发 ESP8266(NodeMcu) or STM32

支持的型号 https://tinygo.org/docs/reference/microcontrollers/ 1. 安装Go 2. 安装TinyGo,并添加环境变量 https://github.com/tinygo-org/tinygo/releases 3. VSCode配置,安装插件,选择设备 package mainimport ("machine"&q…

计算机视觉算法实战——基于YOLOv8的汽车试验场积水路段识别系统

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 引言:汽车试验场智能化管理的迫切需求 在现代汽车研发流程中,试验场作为验证车辆性…

One API:LLM API 管理 分发系统,github 24.2K Star!

随着人工智能领域的不断发展,国内外各大厂商纷纷推出了自己的 AI 大模型。面对 DeepSeek、OpenAI、Claude、腾讯元宝等众多平台的 API 接口差异,开发者常常需要花费大量时间调整代码、处理密钥管理与流量调控。One API 正是在这种背景下诞生,…

Android Settings 有线网设置界面优化

Android Settings 有线网设置界面优化 文章目录 Android Settings 有线网设置界面优化一、前言二、简单修改1、修改的EthernetSettings代码:2、有线网ip获取代码:3、AndroidManifest.xml定义有线网的Activity4、修改后界面: 三、其他1、有线网…

正则入门到精通

​ 一、正则表达式入门​ 正则表达式本质上是一串字符序列,用于定义一个文本模式。通过这个模式,我们可以指定要匹配的文本特征。例如,如果你想匹配一个以 “abc” 开头的字符串,正则表达式可以写作 “^abc”,其中 …

微信小程序基于Canvas实现头像图片裁剪(上)

序言 嘿,打工人混迹职场这么久,图片处理肯定都没少碰。不过咱说实话,大部分时候都是直接 “抄近道”,用现成的三方组件😏。就像我,主打一个会用工具,毕竟善用工具可是咱人类的 “超能力”&…

基于VMware的Cent OS Stream 8安装与配置及远程连接软件的介绍

1.VMware Workstation 简介: VMware Workstation(中文名“威睿工作站”)是一款功能强大的桌面虚拟计算机软件,提供用户可在单一的桌面上同时运行不同的操作系统,和进行开发、测试 、部署新的应用程序的最佳解决方案。…

Ubuntu环境基于Ollama部署DeepSeek+Open-Webui实现本地部署大模型-无脑部署

Ollama介绍 Ollama是一款简单好用的模型部署工具,不仅可以部署DeepSeek,市面上开源模型大部分都可以一键部署,这里以DeepSeek为例 官网 DeepSeek 版本硬件要求 安装Ollama 环境 sudo apt update sudo apt install curl sudo apt install lsof1.命令一键安装 在官网点击…

goto在Java中的用法

说明:goto 在一些编程语言(如C语言)中,是用来表示跳转的,即代码执行到此处跳转到对应位置继续执行。 举例 举个例子,如下,是一个双层嵌套循环。现在我需要代码在内层循环符合某条件时跳出双层…

Vue3+Vite+TypeScript+Element Plus开发-03.主页设计与router配置

系列文档目录 Vue3ViteTypeScript安装 Element Plus安装与配置 主页设计与router配置 静态菜单设计 Pinia引入 文章目录 目录 系列文档目录 文章目录 前言 一、主页设计 二、配置代替别名 三、配置router 四、运行效果 五、参考文献 前言 本文将重点介绍如何使用…

无限滚动(Infinite Scroll)页面谷歌不收录!必须改回分页吗?

近三年,全球超过58%的网站采用无限滚动设计(数据来源:PageTraffic 2023) 谷歌官方数据显示,动态加载内容的索引失败率高达73%(Google Webmaster Report 2022),而采用纯无限滚动的页…

Git相关笔记1 - 本地文件上传远程仓库

Git相关笔记 目录 Git相关笔记Git上传相关文件第一步创建一个仓库:第二步本地创建空文件夹:第三步开始在gitbush上传文件:解决外网网络连接的问题:中文文件的编码问题:参考资料 Git上传相关文件 第一步创建一个仓库&a…