【STM32F1】一种使用通用定时器实现各个通道独立输出不同指定数量脉冲的方法

一种使用通用定时器实现独立通道输出指定数量脉冲的方法

  • 一种使用通用定时器实现独立通道输出指定数量脉冲的方法
    • 概述
    • 实验平台
    • 配置步骤
      • 1. 初始化定时器与GPIO
      • 2. 设置定时器工作模式
      • 3. 编写脉冲计数逻辑
      • 4. 调整参数以满足要求
      • 注意事项
    • 代码实现
      • 电机结构体配置,GPIO配置不单独给出
      • TIM2配置
      • TIM2中断服务配置
      • TIM3配置
      • TIM3中断服务配置
      • TIM4配置与TIM4中断服务配置
      • 输出效果
    • 结论

一种使用通用定时器实现独立通道输出指定数量脉冲的方法

概述

本文档描述了如何在STM32F103ZET6微控制器上,通过配置其内部通用定时器(如TIM2、TIM3等),实现每个定时器通道独立输出指定数量的脉冲。此方法适用于需要精确控制电机、LED亮度调节等应用场景。

实验平台

  • MCU: STM32F103ZET6
  • IDE: Keil MDK
  • 开发方式: 标准库
  • 编程语言: C语言

配置步骤

1. 初始化定时器与GPIO

首先,在代码中初始化相关定时器和GPIO引脚(hal库可使用STM32CubeMX进行相关配置)。确保选择的定时器支持PWM输出模式,并且对应的GPIO引脚已正确配置为复用功能输出。

2. 设置定时器工作模式

对于每个需要输出脉冲的定时器通道,需将其设置为PWM模式。具体来说:

  • 选择PWM模式1或2(根据需求)。
  • 设置自动重装载值(ARR),这决定了PWM周期。
  • 设置比较值(CCR),用于控制单个脉冲宽度。

3. 编写脉冲计数逻辑

为了使每个通道能够输出指定数量的脉冲,需要编写一个简单的计数逻辑。每当一个PWM周期结束时(即定时器更新事件发生时),检查当前已输出的脉冲数是否达到设定的目标值。如果未达到,则继续输出;否则,停止对应通道的PWM输出。

4. 调整参数以满足要求

根据实际应用调整定时器的频率、PWM周期以及每个脉冲的宽度,以满足特定的应用需求。

注意事项

在调整定时器参数时,请注意不要超出硬件限制。
对于不同的应用场合,可能需要对上述方案进行适当调整,比如增加中断处理函数来提高实时性等。

代码实现

以电机应用为例,本案例使用TIM2为主定时器,TIM3、TIM4为从定时器,控制8个独立电机运动

电机结构体配置,GPIO配置不单独给出

u8 CNTtag = 0;
u8 ADD = 0;
struct DJ
{u8    num; //使能(0失能1使能)u8    ena; //使能(0失能1使能)u8    dir; //方向(0反转1正转)u8    state;  //电机状态(0堵转1正常)u32   cycle_pulse; //步进电机转一周的脉冲数(=细分数)u32   pulse_set; //PWM脉冲设定值u32   pulse_cnt; //PWM脉冲计数值(用于单次转动脉冲计数)int   pulse_tot_cnt; //PWM脉冲总计数值(保存电机位置以及用于角度计算)char  string;
};
#define ALL_DJ_Stop (dj[0].state == DISABLE && dj[1].state == DISABLE) && (dj[2].state == DISABLE && dj[3].state == DISABLE) && (dj[4].state == DISABLE && dj[5].state == DISABLE) && (dj[6].state == DISABLE && dj[7].state == DISABLE)
//电机是否旋转代号
#define ENABLE 	1 //ena-停止旋转 state-运动中
#define DISABLE	0 //ena-允许旋转 state-运动结束
//电机旋转方向代号
#define Forward	1 //dir-正方向移动 
#define Revers	0 //dir-负方向移动 //电机操作定时器
#define DJ1_Timer  TIM3
#define DJ2_Timer  TIM3
#define DJ3_Timer  TIM3
#define DJ4_Timer  TIM3#define DJ5_Timer  TIM4
#define DJ6_Timer  TIM4
#define DJ7_Timer  TIM4
#define DJ8_Timer  TIM4//电机操作定时器通道
#define DJ1_Channel  TIM_Channel_1
#define DJ2_Channel  TIM_Channel_2
#define DJ3_Channel  TIM_Channel_3
#define DJ4_Channel  TIM_Channel_4#define DJ5_Channel  TIM_Channel_1
#define DJ6_Channel  TIM_Channel_2
#define DJ7_Channel  TIM_Channel_3
#define DJ8_Channel  TIM_Channel_4

TIM2配置

//通用定时器2中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器2!
void TIM2_Int_Init(u16 arr,u16 psc)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能//定时器TIM3初始化TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM2中断,允许更新中断//中断优先级NVIC设置NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM2中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器TIM_Cmd(TIM2, ENABLE);  //使能TIMx					 
}

TIM2中断服务配置

//定时器2中断服务程序
void TIM2_IRQHandler(void)   //TIM2中断
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  //检查TIM2更新中断发生与否{TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIMx更新中断标志 //LED1=!LED1;TIM_CCxCmd(TIM3, TIM_Channel_1, ENABLE);TIM_CCxCmd(TIM3, TIM_Channel_2, ENABLE);TIM_CCxCmd(TIM3, TIM_Channel_3, ENABLE);TIM_CCxCmd(TIM3, TIM_Channel_4, ENABLE);TIM_Cmd(TIM3,  ENABLE);  //使能TIM3TIM_Cmd(TIM3, ENABLE);  //使能TIM3TIM_CCxCmd(TIM4, TIM_Channel_1, ENABLE);TIM_CCxCmd(TIM4, TIM_Channel_2, ENABLE);TIM_CCxCmd(TIM4, TIM_Channel_3, ENABLE);TIM_CCxCmd(TIM4, TIM_Channel_4, ENABLE);TIM_Cmd(TIM4,  ENABLE);  //使能TIM4TIM_Cmd(TIM4, ENABLE);  //使能TIM4}
}

TIM3配置

//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//TIM_OCInitTypeDef  TIM_OCInitStructure;TIM_OCInitTypeDef TIM_OCInitStructureCh1;TIM_OCInitTypeDef TIM_OCInitStructureCh2;TIM_OCInitTypeDef TIM_OCInitStructureCh3;TIM_OCInitTypeDef TIM_OCInitStructureCh4;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //TIM_CH2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIORCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟//设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; //TIM_CH2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOTIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位// 开启通道1的PWM模式TIM_OCStructInit(&TIM_OCInitStructureCh1);TIM_OCInitStructureCh1.TIM_OCMode = TIM_OCMode_PWM2;TIM_OCInitStructureCh1.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructureCh1.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC1Init(TIM3, &TIM_OCInitStructureCh1);// 开启通道2的PWM模式TIM_OCStructInit(&TIM_OCInitStructureCh2);TIM_OCInitStructureCh2.TIM_OCMode = TIM_OCMode_PWM2;TIM_OCInitStructureCh2.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructureCh2.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC2Init(TIM3, &TIM_OCInitStructureCh2);// 开启通道3的PWM模式TIM_OCStructInit(&TIM_OCInitStructureCh3);TIM_OCInitStructureCh3.TIM_OCMode = TIM_OCMode_PWM2;TIM_OCInitStructureCh3.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructureCh3.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC3Init(TIM3, &TIM_OCInitStructureCh3);// 开启通道4的PWM模式TIM_OCStructInit(&TIM_OCInitStructureCh4);TIM_OCInitStructureCh4.TIM_OCMode = TIM_OCMode_PWM2;TIM_OCInitStructureCh4.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructureCh4.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC4Init(TIM3, &TIM_OCInitStructureCh4);TIM_OC1Init(TIM3, &TIM_OCInitStructureCh1);  //根据T指定的参数初始化外设TIM3 OC1TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器TIM_OC2Init(TIM3, &TIM_OCInitStructureCh2);  //根据T指定的参数初始化外设TIM3 OC2TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器TIM_OC3Init(TIM3, &TIM_OCInitStructureCh3);  //根据T指定的参数初始化外设TIM3 OC3TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器TIM_OC4Init(TIM3, &TIM_OCInitStructureCh4);  //根据T指定的参数初始化外设TIM3 OC4TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器NVIC_EnableIRQ(TIM3_IRQn);// 配置TIM3通道1,并使能比较匹配中断TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update); // PWM模式下一般选择更新事件触发输出// TIM_SetCompare1(TIM3, dutyCycle); // 设置比较值(占空比)TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); // 使能通道1的比较匹配中断TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE); // 使能通道1的比较匹配中断TIM_ITConfig(TIM3, TIM_IT_CC3, ENABLE); // 使能通道1的比较匹配中断TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE); // 使能通道1的比较匹配中断TIM_Cmd(TIM3, DISABLE);  //使能TIM3}

TIM3中断服务配置

void TIM3_IRQHandler(void)   //TIM3中断
{if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET){TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);//脉冲计数if(dj[0].ena == DISABLE){dj[0].pulse_cnt++;if(dj[0].dir == Revers){dj[0].pulse_tot_cnt-=1;}else if(dj[0].dir == Forward){dj[0].pulse_tot_cnt+=1;}}//结束停止if(dj[0].pulse_cnt > dj[0].pulse_set + ADD){TIM_CCxCmd(TIM3, TIM_Channel_1, DISABLE); // TIM_Channel_1对应通道1dj[0].pulse_cnt = 0;dj[0].ena = ENABLE;}}if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET){TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);//脉冲计数if(dj[1].ena == DISABLE){dj[1].pulse_cnt++;if(dj[1].dir == Revers){dj[1].pulse_tot_cnt-=1;}else if(dj[1].dir == Forward){dj[1].pulse_tot_cnt+=1;}}//结束停止if(dj[1].pulse_cnt > dj[1].pulse_set + ADD){TIM_CCxCmd(TIM3, TIM_Channel_2, DISABLE); // TIM_Channel_1对应通道1dj[1].pulse_cnt = 0;dj[1].ena = ENABLE;}}if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET){TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);//脉冲计数if(dj[2].ena == DISABLE){dj[2].pulse_cnt++;if(dj[2].dir == Revers){dj[2].pulse_tot_cnt-=1;}else if(dj[2].dir == Forward){dj[2].pulse_tot_cnt+=1;}}//结束停止if(dj[2].pulse_cnt > dj[2].pulse_set + ADD){TIM_CCxCmd(TIM3, TIM_Channel_3, DISABLE); // TIM_Channel_1对应通道1dj[2].pulse_cnt = 0;dj[2].ena = ENABLE;}}if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET){TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);//脉冲计数if(dj[3].ena == DISABLE){dj[3].pulse_cnt++;if(dj[3].dir == Revers){dj[3].pulse_tot_cnt-=1;}else if(dj[3].dir == Forward){dj[3].pulse_tot_cnt+=1;}}//结束停止if(dj[3].pulse_cnt > dj[3].pulse_set + ADD){TIM_CCxCmd(TIM3, TIM_Channel_4, DISABLE); // TIM_Channel_1对应通道1dj[3].pulse_cnt = 0;dj[3].ena = ENABLE;}}if(dj[0].pulse_cnt==0&&dj[1].pulse_cnt==0&&dj[2].pulse_cnt==0&&dj[3].pulse_cnt==0){TIM_Cmd(TIM3, DISABLE);dj[0].pulse_cnt = 1;dj[1].pulse_cnt = 1;dj[2].pulse_cnt = 1;dj[3].pulse_cnt = 1;dj[0].pulse_set = 1;dj[1].pulse_set = 1;dj[2].pulse_set = 1;dj[3].pulse_set = 1;dj[0].state = DISABLE;dj[1].state = DISABLE;dj[2].state = DISABLE;dj[3].state = DISABLE;//printf("--cccccwwww--\r\n");
//			printf("0,%d,%d,%d,%d,%d,%d,%d\r\n",
//				dj[0].ena, dj[0].dir, dj[0].state, dj[0].cycle_pulse,
//				dj[0].pulse_set, dj[0].pulse_cnt, dj[0].pulse_tot_cnt); 
//			printf("1,%d,%d,%d,%d,%d,%d,%d\r\n",
//				dj[1].ena, dj[1].dir, dj[1].state, dj[1].cycle_pulse,
//				dj[1].pulse_set, dj[1].pulse_cnt, dj[1].pulse_tot_cnt); 
//			printf("2,%d,%d,%d,%d,%d,%d,%d\r\n",
//				dj[2].ena, dj[2].dir, dj[2].state, dj[2].cycle_pulse,
//				dj[2].pulse_set, dj[2].pulse_cnt, dj[2].pulse_tot_cnt); 
//			printf("3,%d,%d,%d,%d,%d,%d,%d\r\n",
//				dj[3].ena, dj[3].dir, dj[3].state, dj[3].cycle_pulse,
//				dj[3].pulse_set, dj[3].pulse_cnt, dj[3].pulse_tot_cnt); 
//			delay_us(5);
//		printf("-------------\r\n");}
}	

TIM4配置与TIM4中断服务配置

类似TIM3实现,不再单独写出

输出效果

测试

结论

通过合理配置STM32F103ZET6上的通用定时器资源,可以方便地实现多通道独立输出指定数量脉冲的功能。这对于控制外部设备如电机速度、灯光强度等提供了灵活有效的手段。

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

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

相关文章

【Java基础】序列化、反序列化和不可变类

Hi~!这里是奋斗的明志,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 🌱🌱个人主页:奋斗的明志 🌱🌱所属专栏:Java基础面经 📚本系列文章为个…

android apk反编译

使用解压工具解压apk,使用dex2jar解析其中的dex文件为jar文件,再使用jd-gui将class反编译为java文件 1 工具下载 dex2jar下载 https://github.com/pxb1988/dex2jar/releases 直接去github上下载最新发布版本 注意,如果后面使用过程中遇到No…

PAT乙级( 1009 说反话 1010 一元多项式求导)C语言版本超详细解析

1009 说反话 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过 80的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母&#x…

C++20导出模块及使用

1.模块声明 .ixx文件为导入模块文件 math_operations.ixx export module math_operations;//模块导出 //导出命名空间 export namespace math_ {//导出命名空间中函数int add(int a, int b);int sub(int a, int b);int mul(int a, int b);int div(int a, int b); } .cppm文件…

鸿蒙接入支付宝SDK后模拟器无法运行,报错error: install parse native so failed.

鸿蒙项目接入支付宝后,运行提示error: install parse native so failed. 该问题可能由于设备支持的 Abi 类型与 C 工程中的不匹配导致. 官网error: install parse native so failed.错误解决办法 根据官网提示在模块build-profile.json5中添加“x86_64”依然报错 问…

MongoDB开发规范

分级名称定义P0核心系统需7*24不间断运行,一旦发生不可用,会直接影响核心业务的连续性,或影响公司名誉、品牌、集团战略、营销计划等,可能会造成P0-P2级事故发生。P1次核心系统这些系统降级或不可用,会间接影响用户使用…

nodejs - vue 视频切片上传,本地正常,线上环境导致磁盘爆满bug

nodejs 视频切片上传,本地正常,线上环境导致磁盘爆满bug 原因: 然后在每隔一分钟执行du -sh ls ,发现文件变得越来越大,即文件下的mp4文件越来越大 最后导致磁盘直接爆满 排查原因 1、尝试将m3u8文件夹下的所有视…

微信小程序如何使用decimal计算金额

第三方库地址:GitHub - MikeMcl/decimal.js: An arbitrary-precision Decimal type for JavaScript 之前都是api接口走后端计算,偶尔发现这个库也不错,计算简单,目前发现比较准确 上代码 导入js import Decimal from ../../uti…

unity学习29:摄像机camera相关skybox 和 Render Texture测试效果

目录 1 摄像机 1.1 每个Scene里都自带一个摄像机 camera 1.2 可以创建多个camera 1.3 下面先看backgroundtype: 2 backgroundtype: 天空盒 skybox 2.1 清除标志,清除:天空盒 自选天空盒 2.2 window /Asset Store 2.3 导入skybox 3 backgroundtype: 纯色…

ximalaya(三) playUriList值解密--webpack

本文主要介绍解密音频播放url参数。 本文仅代表个人理解,如有其他建议可在评论区沟通。 声明 仅仅记录一下自己的学习方法,不作为其他参考、更不作为商业用途。如有侵犯请联系本人删除 目标地址:aHR0cHM6Ly93d3cueGltYWxheWEuY29tL3NvdW5k…

C# Winform怎么设计串口,客户端和相机控件界面显示

首先我们必须把这个类创建好 INIAPI using System; using System.Text; using System.Runtime.InteropServices;namespace Ini {public class IniAPI{#region INI文件操作/** 针对INI文件的API操作方法,其中的节点(Section)、键(KEY&#x…

【redis】数据类型之hash

Redis中的Hash数据类型是一种用于存储键值对集合的数据结构。与Redis的String类型不同,Hash类型允许你将多个字段(field)和值(value)存储在一个单独的key下,从而避免了将多个相关数据存储为多个独立的key。…

Qt:Qt Creator项目创建

目录 认识Qt Creator Qt Creator概览 使用Qt Creator新建项目 选择项目模板 选择项目路径 选择构建系统 填写类信息设置界面 选择语言和翻译文件 选择Qt套件 选择版本控制系统 最终效果 认识Qt Creator Qt Creator概览 从开始菜单或者快捷方式打开Qt Creator集成开…

家用报警器的UML 设计及其在C++和VxWorks 上的实现01

M.W.Richardson 著,liuweiw 译 论文描述了如何运用 UML(统一建模语言)设计一个简单的家用报警器,并实现到 VxWorks 操作系统上。本文分两个部分,第一部分描述了如何用 UML 设计和验证家用报警器的模型,以使…

node.js + html + Sealos容器云 搭建简易多人实时聊天室demo 带源码

node.js html Sealos容器云 搭建简易多人实时聊天室demo 带源码 前言功能介绍(demo演示)sealos官网配置node.js 编写服务端代码前端ui 调用接口整体项目目录部署到服务器 前言 hello哦盆友们,这次我们来十几行代码做一个超简单的多人聊天…

CPP集群聊天服务器开发实践(一):用户注册与登录

目录 1 客户端用户注册与登录 1.1 主要思想 1.2 网络层 1.3 业务层 1.4 数据层 1.5 测试结果 1 客户端用户注册与登录 1.1 主要思想 实现网络层、业务层、数据层的解耦,提高系统的可维护性。 网络层:主要实现对客户端连接、客户端读写请求的捕获…

【C语言】数 组与指针:深度剖析与等价表达

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 💯前言💯数组与指针的基本关系💯数组与指针的互换使用数组下标与指针的等价性 💯六个表达式的等价性💯指针运算的注意事项💯数组…

寒假2.7

题解 web&#xff1a;[HCTF 2018]WarmUp 打开是张表情包 看一下源代码 访问source.php&#xff0c;得到完整代码 代码审计 <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist ["source">"source.p…

sqli-lab靶场学习(五)——Less15-17(post方法盲注、修改密码)

前言 第11-14关开始用post方法&#xff0c;15-17关会用到盲注&#xff0c;post方法盲注和get方法类似。 Less15 这关是单引号闭合&#xff0c;有报错但没有具体情况的回显&#xff0c;因此适合使用错误盲注。 在用户名密码框分别输入 账号&#xff1a;admin and 11 -- asd…

【Spring】什么是Spring?

什么是Spring&#xff1f; Spring是一个开源的轻量级框架&#xff0c;是为了简化企业级开发而设计的。我们通常讲的Spring一般指的是Spring Framework。Spring的核心是控制反转(IoC-Inversion of Control)和面向切面编程(AOP-Aspect-Oriented Programming)。这些功能使得开发者…