单片机学习笔记---红外遥控红外遥控电机调速(完结篇)

news2025/1/17 15:16:01

目录

低电平触发中断和下降沿触发中断的区别

红外遥控

Int0.c

Int.h

Timer0.c

Timer0.h

IR.c

IR.h

main.c 

红外遥控电机调速

Timer1.c

Timer.h

Motor.c

Motor.h

main.c


上一节讲了红外发送和接收的工作原理,这一节开始代码演示!

提前说明,本节代码演示中会涉及定时器和中断系统!

如果不懂定时器和中断系统的话,建议去看看我之前已经详细写过的中断系统和定时器的博客,也写的比较全面的了,看过后肯定能让你明白中断系统和定时器的工作原理!

单片机学习笔记---中断系统(含外部中断)-CSDN博客

单片机学习笔记---定时器/计数器(简述版!)_定时计数器ea-CSDN博客

单片机学习笔记---定时器和中断系统如何连起来工作-CSDN博客

低电平触发中断和下降沿触发中断的区别

在正式演示红外遥控的代码之前我们先来看看配置外部中断时,选择低电平触发和下降沿触发有什么区别?

我们用外部中断INT0来举个例子:

我们单片机的原理图上,INT0接的是单片机的P32口,

而独立按键K3正好也是P32口。

那么我们按下K3的时候就相当于给单片机的P32口一个下降沿

那么我们现在来写一个程序验证一下选择低电平触发和下降沿触发有什么区别:

先创建一个工程文件,把我之前的博客中讲过的LCD1602的程序文件添加进来

然后在主程序main.c中调用这个函数来显示中断触发的现象

首先是选择下降沿触发:

#include <REGX52.H>
#include "LCD1602.h"

unsigned char Num;

void main()
{
	LCD_Init();//初始化液晶屏
	
	//配置中断系统
	IT0=1;//选择下降沿触发方式
	IE0=0;//中断标志位清零
	EX0=1;//打开中断
	EA=1;//打开总中断
	PX0=1;//一般都选择高优先级中断
	
	//跳转到中断函数
	
	//中断函数执行完进入while循环
	while(1)
	{
		LCD_ShowNum(1,1,Num,3);
	}
}

//中断函数
void Init0_Routine(void) interrupt 0
{
	Num++;
}

下降沿触发的话,你按下的时候加一次,松开再按下的时候才再加一次。“松开状态再按下”这一个过程就是给一个下降沿的过程。

效果请看视频:

选择下降沿触发中断的结果现象

再来看看选择低电平触发:

#include <REGX52.H>
#include "LCD1602.h"

unsigned char Num;

void main()
{
	LCD_Init();//初始化液晶屏
	
	//配置中断系统
	IT0=0;//选择低电平触发方式
	IE0=0;//中断标志位清零
	EX0=1;//打开中断
	EA=1;//打开总中断
	PX0=1;//一般都选择高优先级中断
	
	//跳转到中断函数
	
	//中断函数执行完进入while循环
	while(1)
	{
		LCD_ShowNum(1,1,Num,3);
	}
}

//中断函数
void Init0_Routine(void) interrupt 0
{
	Num++;
}

而如果是低电平触发的话,只要按键按下这个中断会一直处于触发状态,当中断函数结束之后它会再次进入,直到变成高电平为止。那它的现象就是按下不松的时候,这个数值是一直加的,直到松手,数值才停止加。

效果请看视频:

选择低电平触发中断的结果现象

以上就是低电平触发中断和下降沿触发中断的区别

而本节红外遥控的示例代码要用的是下降沿触发中断的这种方式!

红外遥控

现在开始正式演示代码:

新创建一个工程文件:红外遥控

将我之前的博客讲过的程序模块直接添加进来

然后先创建Int0.c,Int.h,IR.c,IR.h和main.c文件

开始代码讲解:

首先写一个初始化中断系统的函数

Int0.c

#include <REGX52.H>

void Int0_Init(void)
{
	IT0=1;//选择下降沿触发中断
	IE0=0;//中断标志位清零
	EX0=1;//把中断打开
	EA=1;//打开总中断
	PX0=1;//选择高优先级中断
}

声明一下这个函数

Int.h

#ifndef __INT0_H__
#define __INT0_H__

void Int0_Init(void);

#endif

Timer0.c

接下来我们把Timer0.c文件的程序改造一下

将计时器初始化函数中的中断系统配置部分删掉,将初值清零,并且关闭计时

#include <REGX52.H>
//定时器0初始化
void Timer0_Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0;		//设置定时初值
	TH0 = 0;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 0;		//定时器0不计时
}

单独写一个给定时器0设置初值的函数

//定时器0设置计数器值
void Timer0_SetCounter(unsigned int Value)
{
	TH0=Value/256;//取出高八位赋值给TH0
	TL0=Value%256;//取出低八位赋值给TH0
}
//Value,要设置的计数器值,范围:0~65535

定时器0设置好初值后,再写一个获取定时器0当时的计数器值的函数

 //定时器0获取计数器值,范围:0~65535
unsigned int Timer0_GetCounter(void)
{
	return (TH0<<8)|TL0;
    //将TH0的8位数据左移8位,然后和TL0的8位数据组合成16位数据作为返回值
}

然后再写一个函数用来控制定时器的开始和结束

//定时器0启动停止控制
//Flag 启动停止标志,
//在TMOD寄存器中的GATE位等于0的情况下,TR0是定时器0在方式1的工作模式下的启停控制位
//1为启动,0为停止

void Timer0_Run(unsigned char Flag)
{
	TR0=Flag;
}

将这几个函数声明一下

Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);
void Timer0_SetCounter(unsigned int Value);
unsigned int Timer0_GetCounter(void);
void Timer0_Run(unsigned char Flag);

#endif

接下来写一下红外解码的程序函数

IR.c

先定义好一些变量,后面会用到

#include <REGX52.H>
#include "Timer0.h"
#include "Int0.h"

unsigned int IR_Time;//上一次中断到此次中断的时间
unsigned char IR_State;//接收的状态

unsigned char IR_Data[4];//数据,4个字节,32位
unsigned char IR_pData;//告知当前是在第几位,每次进来pData++,告诉告知现在收到第几位了,收满32位之后就结束了


unsigned char IR_DataFlag;//收到连发帧标志位
unsigned char IR_RepeatFlag;//重发标志
unsigned char IR_Address;//存的是地址
unsigned char IR_Command;//存的是命令码(就是遥控上的键码)

然后写一个红外遥控初始化函数

void IR_Init(void)
{
	Timer0_Init();//初始化定时器0
	Int0_Init();//初始化外部中断0
}

红外遥控获取收到数据帧标志位
返回值:是否收到数据帧,1为收到,0为未收到

unsigned char IR_GetDataFlag(void)
{
	if(IR_DataFlag)
	{
		IR_DataFlag=0;//将收到连发帧标志位置0,方便下一次进行
		return 1;//代表已经收到了
	}
	return 0;//如果IR_DataFlag=0,直接return 0
}

红外遥控获取收到连发帧标志位
返回值:是否收到连发帧,1为收到,0为未收到

unsigned char IR_GetRepeatFlag(void)
{
	if(IR_RepeatFlag)
	{
		IR_RepeatFlag=0;
		return 1;
	}
	return 0;
}

红外遥控获取收到的地址数据
返回值: 收到的地址数据

unsigned char IR_GetAddress(void)
{
	return IR_Address;
}

红外遥控获取收到的命令数据
返回值:收到的命令数据

unsigned char IR_GetCommand(void)
{
	return IR_Command;
}

外部中断0中断函数,下降沿触发执行 

这部分主要是根据这张图定义的函数

void Int0_Routine(void) interrupt 0
{
	//第一次进入中断函数时
	if(IR_State==0)				//状态0,空闲状态
	{
		Timer0_SetCounter(0);	//定时计数器清0
		Timer0_Run(1);			//定时器启动
		IR_State=1;				//置状态为1
	}
	
	//下一次进入中断函数时
	else if(IR_State==1)		//状态1,等待Start信号或Repeat信号
	{
		IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间
		Timer0_SetCounter(0);	//定时计数器清0,方便下次计时
		//计数器每加1就是1微秒,1000us=1ms
		//如果计时为13.5ms即13500us,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
		//因为有一些误差,所以有可能不是13500us整,需允许波动的范围
		//13500-11250=2250,允许波动的范围不能超过2250,可以给上下500的范围,上下500即1000的波动范围
		//所以给个上下500波动的范围即13500-500~13500+500合理
		if(IR_Time>13500-500 && IR_Time<13500+500)
		{
			IR_State=2;			//置状态为2,下次再来中断就要开始解码数据
		}
		//如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
		else if(IR_Time>11250-500 && IR_Time<11250+500)
		{
			//如果接收到这个信号就说明一帧已经结束了,后面就不用数据了
			IR_RepeatFlag=1;	//置收到连发帧标志位为1
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
		else					//接收出错
		{
			IR_State=1;			//置状态为1,继续收Start信号或者repeat信号
		}
	}
	
	//以上情况执行完就接收完了起始信号
	//那再次进入中断函数来就要开始解码
	else if(IR_State==2)		//状态2,接收数据
	{
		IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间
		Timer0_SetCounter(0);	//定时计数器清0,方便下次计时
		
		//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
		if(IR_Time>1120-500 && IR_Time<1120+500)
		{
			//收到0之后就要把数据写进去
			
			IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));	//数据对应位清0
			//假设pData的范围是0~7,即一个字节长度
			//那么如果要将第一个字节的8位对应位清零
			//可以写成IR_Data[0]&=~(0x01<<IR_pData);
			//但是我们是要4个字节,把pData定义为告知32位数据中的哪一位数据,变化范围是0~31
			//要将pData的范围0~31拆成4个字节,也就是4个数组元素,一个字节8位
			//那么每8位就是一个数组元素,所以左移的范围要限制在一个字节中
			//因此左移的范围要限制在0~7,则IR_pData%8
			//4个数组元素范围是IR_Data[0]~IR_Data[3],则IR_pData/8,
			//这样程序就可以自动跳到下一个元素的第0位
			
			IR_pData++;			//数据位置指针自增
		}
		
		//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
		else if(IR_Time>2250-500 && IR_Time<2250+500)
		{
			IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));	//数据对应位置1
			IR_pData++;			//数据位置指针自增
		}
		else					//接收出错
		{
			IR_pData=0;			//数据位置指针清0
			IR_State=1;			//置状态为1
		}
		
		//32位数据解码完成后,开始验证
		if(IR_pData>=32)		//如果接收到了32位数据
		{
			IR_pData=0;			//数据位置指针清0
			if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3]))	//数据验证
			{
				IR_Address=IR_Data[0];	//转存数据
				IR_Command=IR_Data[2];
				IR_DataFlag=1;	//置收到连发帧标志位为1
			}
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
	}
}

IR.h

声明一下这些函数,并且把键码重定义,方便主程序调用,不用每次都查找对应的键码

#ifndef __IR_H__
#define __IR_H__

#define IR_POWER		0x45
#define IR_MODE			0x46
#define IR_MUTE			0x47
#define IR_START_STOP	0x44
#define IR_PREVIOUS		0x40
#define IR_NEXT			0x43
#define IR_EQ			0x07
#define IR_VOL_MINUS	0x15
#define IR_VOL_ADD		0x09
#define IR_0			0x16
#define IR_RPT			0x19
#define IR_USD			0x0D
#define IR_1			0x0C
#define IR_2			0x18
#define IR_3			0x5E
#define IR_4			0x08
#define IR_5			0x1C
#define IR_6			0x5A
#define IR_7			0x42
#define IR_8			0x52
#define IR_9			0x4A

void IR_Init(void);
unsigned char IR_GetDataFlag(void);
unsigned char IR_GetRepeatFlag(void);
unsigned char IR_GetAddress(void);
unsigned char IR_GetCommand(void);

#endif

main.c 

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"

unsigned char Num;
unsigned char Address;
unsigned char Command;

void main()
{
	LCD_Init();
	LCD_ShowString(1,1,"ADDR  CMD  NUM");
	LCD_ShowString(2,1,"00    00   000");
	
	IR_Init();
	
	while(1)
	{
		if(IR_GetDataFlag() || IR_GetRepeatFlag())	//如果收到数据帧或者收到连发帧
		{
			Address=IR_GetAddress();		//获取遥控器地址码
			Command=IR_GetCommand();		//获取遥控器命令码
			
			LCD_ShowHexNum(2,1,Address,2);	//显示遥控器地址码
			LCD_ShowHexNum(2,7,Command,2);	//显示遥控器命令码,即键码
			
			if(Command==IR_VOL_MINUS)		//如果遥控器VOL-按键按下
			{
				Num--;						//Num自减
			}
			if(Command==IR_VOL_ADD)			//如果遥控器VOL+按键按下
			{
				Num++;						//Num自增
			}
			
			LCD_ShowNum(2,12,Num,3);		//显示Num
		}
	}
}

效果请看视频:

红外遥控显示键码值

注意:如果程序没有出凑,但是没有结果反应的话,请查看一下自己的开发板的晶振到底是12MHz还是11.0592MHz,这两种晶振的机器周期是不一样的,要在IR.c文件中的程序对应修改,要修改的地方在IR.c文件程序中已经给出了注释,请认真查看并修改!

红外遥控电机调速

新创建一个工程:红外遥控电机调速

这个程序是建立在之前写的直流电机调速的那个程序的基础上改造的,之前是用独立按键用控制电机的运转的速度,这次改为用红外遥控来控制电机的运转速度。

复用到的程序:

Delay函数

数码管

中断系统配置,定时器0配置,红外解码

Timer1.c

由于红外解码部分用了定时器0,所以我们要加一个定时器1程序,即将Timer0.c复制一份并且对应的地方改成定时器

#include <REGX52.H>

void Timer1_Init(void)
{
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x9C;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1=1;
	EA=1;
	PT1=0;
}

Timer.h

#ifndef __TIMER1_H__
#define __TIMER1_H__

void Timer1_Init(void);

#endif

Motor.c

写一个驱动电机的模块

#include <REGX52.H>
#include "Timer1.h"

//引脚定义
sbit Motor=P1^0;

unsigned char Counter,Compare;

//电机初始化
void Motor_Init(void)
{
	Timer1_Init();
}

//电机设置速度
//Speed 要设置的速度,范围0~100
void Motor_SetSpeed(unsigned char Speed)
{
	Compare=Speed;
}

//定时器1中断函数
void Timer1_Routine() interrupt 3
{
	TL1 = 0x9C;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	Counter++;
	Counter%=100;	//计数值变化范围限制在0~99
	if(Counter<Compare)	//计数值小于比较值
	{
		Motor=1;		//输出1
	}
	else				//计数值大于比较值
	{
		Motor=0;		//输出0
	}
}

Motor.h

#ifndef __MOTOR_H__
#define __MOTOR_H__

void Motor_Init(void);
void Motor_SetSpeed(unsigned char Speed);

#endif

main.c

#include <REGX52.H>
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Motor.h"
#include "IR.h"

unsigned char Command,Speed;

void main()
{
	Motor_Init();//初始化电机(定时器1初始化)
	IR_Init();//红外遥控初始化(定时器0和中断系统初始化)
	while(1)
	{
		if(IR_GetDataFlag())	//如果收到数据帧
		{
			Command=IR_GetCommand();		//获取遥控器命令码
			
            //将命令码/键码和遥控上的数字对应起来
			if(Command==IR_0){Speed=0;}		//根据遥控器命令码设置速度
			if(Command==IR_1){Speed=1;}
			if(Command==IR_2){Speed=2;}
			if(Command==IR_3){Speed=3;}
			
            //Motor_SetSpeed相当于PWM输出中用到的比较值
			if(Speed==0){Motor_SetSpeed(0);}	//速度输出
			if(Speed==1){Motor_SetSpeed(50);}
			if(Speed==2){Motor_SetSpeed(75);}
			if(Speed==3){Motor_SetSpeed(100);}
		}
		Nixie(1,Speed);						//数码管显示速度
	}
}

 效果请看视频:

红外摇控调档速的小风扇

注意:如果程序没有出凑,但是没有结果反应的话,请查看一下自己的开发板的晶振到底是12MHz还是11.0592MHz,这两种晶振的机器周期是不一样的,要在IR.c文件中的程序对应修改,要修改的地方在IR.c文件程序中已经给出了注释,请认真查看并修改!

以上就是本篇的内容,源码会放在评论区(含12MHz和11.0592MHz两种源码),如有问题可评论区留言!

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

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

相关文章

九州金榜|家庭教育中孩子焦虑怎么办?

随着现代社会的快速发展&#xff0c;孩子们面临的压力和焦虑感也在逐渐增强。家庭教育作为孩子成长过程中的重要环节&#xff0c;对于如何有效缓解孩子焦虑情绪产生是家长不得不面对的问题&#xff0c;九州金榜家庭教育以为&#xff0c;我们需要了解孩子焦虑的根源&#xff0c;…

mysql同类型的多行变成一行value1和value2不同的列

关键字 row_number() over (partition by) 例如&#xff0c;下面的数据&#xff0c; 这是按照name分组后&#xff0c;展示property值。 我们想得到这样的值; 第一步&#xff1a;将每一组的property标上序号 select name,property,row_number() over (partition by name order…

Java中的Arrays和Lambda表达式

Arrays和Lambda Arrays常用方法数组中是对象&#xff08;如何排序&#xff09; Lambda什么是LambdaLambda表达式的省略规则 Arrays 是一个用来操作数组的工具类 常用方法 数组中是对象&#xff08;如何排序&#xff09; 方式一 方式二 Lambda 什么是Lambda 是JDK 8 开始新…

fastApi笔记03-请求体

请求体是客户端发送给API的数据&#xff0c;fastApi使用 Pydantic 模型来声明请求体 不能使用 GET操作&#xff08;HTTP 方法&#xff09;发送请求体。 要发送数据&#xff0c;必须使用下列方法之一&#xff1a;POST&#xff08;较常见&#xff09;、PUT、DELETE 或 PATCH 创…

自养号测评低成本高效率推广,安全可控

测评的作用在于让用户更真实、清晰、快捷地了解产品以及产品的使用方法和体验。通过买家对产品的测评&#xff0c;也可以帮助厂商和卖家优化产品缺陷&#xff0c;提高用户的使用体验。这进而帮助他们获得更好的销量&#xff0c;并更深入地了解市场需求。因此&#xff0c;测评在…

2024 互联网大厂职级和薪资一览表!

在向往互联网的朋友们的眼中&#xff0c;互联网大厂的工作可是一个“香饽饽”&#xff0c;无论是薪资福利、还是晋升制度&#xff0c;都是整个行业的标杆。 “大厂经验”更是互联网就业环境中的一块金字招牌&#xff0c;让简历光鲜度up up&#xff0c;对找工作有很大的帮助。 所…

GitHub | 在 GitHub 上在线展示 Vue 项目

简洁版&#xff1a;上传所有代码 << 构建项目并上传 dist 目录 << 设置仓库 << 访问 Step1&#xff1a;在 GitHub 上新建仓库&#xff0c;并将 Vue 项目的代码 push 到该仓库中。坑点在于&#xff0c;如果你是从 GitHub 上 clone 的别人的项目&#xff0c;那…

多层深度土壤墒情监测站

TH-GTS05随着科技的不断进步&#xff0c;农业生产的智能化和精准化已成为大势所趋。多层深度土壤墒情监测站作为现代农业的重要组成部分&#xff0c;为农业生产提供了强大的技术支持。 一、什么是多层深度土壤墒情监测站&#xff1f; 多层深度土壤墒情监测站是一种高科技农业设…

OpenCV 4基础篇| 色彩空间类型转换

目录 1. 色彩空间基础2. 色彩空间类型2.1 GRAY 色彩空间2.2 BGR 色彩空间2.3 CMY(K) 色彩空间2.4 XYZ 色彩空间2.5 HSV 色彩空间2.6 HLS 色彩空间2.7 CIEL*a*b* 色彩空间2.8 CIEL*u*v* 色彩空间2.9 YCrCb 色彩空间 3. 类型转换函数3.1 cv2.cvtColor3.2 cv2.inRange 1. 色彩空间…

Git基本操作(2)

Git基本操作&#xff08;2&#xff09; 上交文件之后&#xff0c;git文件的变化git cat-file HEAD指针里面有啥文件被修改git statusgit diff 文件名 版本回退&#xff08;git reset&#xff09;撤销回退git reflog 撤销的三种情况还没有addgit checkout -- [file] 已经add还没…

不买服务器也可以将本地服务放到互联网(ngrok内网穿透)

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 不买服务器也可以将本地服务放到互联网 前言ngrok基础&#xff1a;穿越网络边界的魔法使用场景&#xff1a;突破网络限制的利器实战 前言 在网络的世界里&#xff0c;有时候你的服务像是困在一座数字…

BTC网络 之 区块裁剪

BTC网络区块总大小 由于BTC网络的区块一直在增长&#xff0c;截至 2024年02月19日&#xff0c;区块总大小已达 550GB 如何节省存储空间 一旦最新交易已经被足够多的区块覆盖&#xff0c;这之前的支付交易就可以被裁剪以节省空间。 单个区块数据 下面我们对 交易0&#xff0c;1&…

AI破局俱乐部,你要了解的都在这里

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

CentOS已安装宝塔的情况下手动安装phpMyAdmin

CentOS 7.9.2009&#xff0c;宝塔7.9.4。 服务器中已有MySQL&#xff0c;可能不是通过宝塔安装的&#xff0c;而是手动安装的。用命令行可以正常进入MySQL查看和管理数据&#xff0c;说明已有的MySQL是正常的。在宝塔中点击数据库提示“未安装本地数据库&#xff0c;已隐藏无法…

VOC赋能人工智能:聆听客户之声,打造智能服务新体验

在当今这个信息爆炸的时代&#xff0c;客户的声音成为了企业宝贵的资源之一。如何有效收集、分析和利用这些声音&#xff0c;成为了企业在激烈的市场竞争中脱颖而出的关键。VOC&#xff08;客户之声&#xff09;作为一种先进的管理工具&#xff0c;正在逐渐受到企业的重视&…

【7-1】实验——实体统一和歧义消除

一、使用jieba完成公司名的实体统一 #核心代码&#xff1a;建立main_extract&#xff0c;当输入公司名&#xff0c;返回会被统一的简称 def main_extract(company_name,d_4_delete,stop_word,d_city_province): """ company_name 输入的公司名 stop_word 停…

Linux CentOS stream 9 firewalld

随着互联网行业快速发展&#xff0c;服务器成为用户部署网络业务重要的网络工具&#xff0c;但随之而来的就是更密集的网络攻击&#xff0c;这给网站带来了很大的阻碍。防火墙作为保障网络安全的主要设备&#xff0c;可以很好的抵御网络攻击。 防火墙基本上使用硬件和软件两种…

HTML世界核心

目录 一、基本文档(Basic Documentation) 二、基本标签(Basic Tags) 三、文本格式化(Formatting) 四、链接(Links) 五、图片(Images) 六、样式/区块(Styles/Sections) 七、无序列表(Disorder List) 八、有序列表(Sequence List) 九、定义列表(Definin…

html+css+jquery实现轮播图自动切换、左右切换、点击切换

pc端也好、移动端也好&#xff0c;轮播图很常见&#xff0c;今天用htmlcssjquery实现小米商城轮播图&#xff0c;套UI框架更容易实现 步骤1&#xff1a;把静态轮播图用divcss布局出来&#xff0c;采用盒子模型、相对绝对定位实现 代码如下&#xff1a; <!doctype html>…

如何在CentOS安装SQL Server数据库并实现无公网ip环境远程连接

文章目录 前言1. 安装sql server2. 局域网测试连接3. 安装cpolar内网穿透4. 将sqlserver映射到公网5. 公网远程连接6.固定连接公网地址7.使用固定公网地址连接 前言 简单几步实现在Linux centos环境下安装部署sql server数据库&#xff0c;并结合cpolar内网穿透工具&#xff0…