基于stm32的智能小车(远程控制、避障、循迹)

基于stm32的智能小车(远程控制、避障、循迹)学完stm32,总是想做点东西“大显身手”一下,智能小车就成了首选项目,其核心只是就是PWM输出,I/O口引脚电平判断。制作智能小车的硬件名单:制作智能小车的硬件列表: (1)STM32C8T6核心板 一块 (2)L298N电机驱动 两个 (3)2.4G无线通讯模块 一个 (4)红外壁障模块 两个 (5)红外循迹模块 两个 (6)电源转换模块 一个 (7)18650供电电池

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

学完stm32,总是想做点东西“大显身手”一下,智能小车就成了首选项目,其核心只是就是PWM输出,I/O口引脚电平判断。

制作智能小车的硬件名单:

制作智能小车的硬件列表:
	(1) STM32C8T6核心板				    一块( 遥控  需要两块)
	(2) L298N电机驱动					    两个(或一块)
	(3) 2.4G无线通讯模块					两个
	(4) 红外壁障模块					    三个
	(5) 红外循迹模块					    三个
	(6) 电源转换模块					    一个
	(7) 18650供电电池					    两节
	(8) 带电机轮子的小车支架(自带tt电机)	一个	
	(9) 电子产品专用胶					    一支
	(10) LED灯							若干

接下来就一步步的实现。

一、先让小车跑起来!!!

基于stm32的智能小车(远程控制、避障、循迹)

我们在淘宝上买的那种智能小车底板都是自带tt电机的,不管我们用那种控制方式,首先要做的都是让电机先跑起来。

(一)、驱动一个电机转动:

说到驱动电机,就不得不说一下L298N(电机驱动)了,为什么要说L298N呢?   

当时我第一次用电机的时候,也很疑惑,为什么要用L298N,我电机是5v的,直接连上单片机IO口,让其输出高低电平不久能控制电机转动吗????但其实是不是的,IO口确实能输出5V的电压,也确实是和电机的电压一样,但大家不要忽略IO口输出的电流,也就是驱动能力。IO口输出的电流太小了,根本带不动电机啊。。。。举个例子:“可以想象一下让一个小伙子去耕地,他肯定拉不动,但如果给他一头牛,就让小伙拿着小皮鞭赶牛,让牛去耕地,very  esay。”

而L298N的作用和刚刚说的“牛”的作用一样,,我们只需用单片机IO口控制L298N的工作,其他的脏活累活全让L298n去做,,好奸商的感觉  哈哈哈哈。

基于stm32的智能小车(远程控制、避障、循迹)                  基于stm32的智能小车(远程控制、避障、循迹)

 L298n电源接口的接线:电源12V正极→L298n正极     电源12V负极、单片机GND→L298n的GND

                                        L298n的5V输出→单片机的5V(用L298n产生的5V给单片机供电)

刚刚说过了  我们使用单片机的IO口输出控制L298n的工作,怎么控制呢??看到逻辑输入那四个引脚了吗  对就是他们。

                                     左边两个逻辑输入控制电机A(正传、反转、停止)     

                                     右边两个逻辑输入控制电机B(正传、反转、停止) 

具体如何控制正反转及停止的:简单说IN1、IN2    输出(0,1)正传、输出(1,1)反转、输出(1,1)制动。                     

  具体的解释大家可以看这篇文章 : ​​​L298N具体使用及控制​​​​​​

 那我们只需要输出不同电平就能驱动电机正反转了,但是为了控制电机的转速,不能单纯的输出1、0,可以用PWM控制,通过调整PWM的占空比,就能控制电机的转速。(很好理解吧,我们日常开私家车,也不是一脚踩足油门,一脚刹车踩到底,而是均匀的升速,或者均匀的降速)这就是PWM的功能。

(二)、控制小车前进、后退、左转、右转

刚刚已经了解了如何驱动一个电机的转动,那控制小车的前进方向,无非就是四个轮子搭配着运行。

前行:四个轮子都顺转

后退:四个轮子都逆转

左转:左侧两个轮子不动,右边两个轮子往前走。

右转:右侧两个轮子不动,左边两个轮子往前走。

基于stm32的智能小车(远程控制、避障、循迹)

四个电机,需要两个定时器TIM1、TIM4两个定时器产生两路PWM,一路PWM又有四个通道,一共8个通道,因为两个逻辑输入控制L298n的一个电机呀(这8路pwm输出都是连接到L298N的逻辑输入端)。

 驱动程序代码:

PWM.C

#include "timer_pwm.h"
#include "led.h"
#include "usart.h"


// TIM1_PWM输出初始化 
// TIM1_CH1 = PA8
// TIM1_CH2 = PA9
// TIM1_CH3 = PA10
// TIM1_CH4 = PA11

// TIM1_Reload_Num			= TIM1自动重装值
// TIM1_Frequency_Divide	= 时钟预分频数
//-----------------------------------------------------------------------------------------------------------------
void TIM1_PWM_Init(void)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);			// 使能TIM1时钟	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  			// 使能GPIOB时钟
			
    // 配置IO模式
	GPIO_InitStructure.GPIO_Pin = TIM1_CH1_GPIO_PIN | TIM1_CH2_GPIO_PIN | TIM1_CH3_GPIO_PIN | TIM1_CH4_GPIO_PIN;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  				// 复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(TIM1_CH1_GPIO_PORT, &GPIO_InitStructure);							// 初始化PA8、PA9、PA10、PA11
	
	
   //初始化TIM1的计数模式、分频值、重装载值等
	TIM_TimeBaseStructure.TIM_Period = TIM1_Reload_Num; 					// 设置下一个更新事件后,装入自动重装载寄存器的值
	TIM_TimeBaseStructure.TIM_Prescaler =TIM1_Frequency_Divide; 	// 设置TIM3时钟预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 									// 设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 	// 向上计数模式
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); 							// 根据参数初始化TIM1
	
	 //初始化TIM1_CH1-4的PWM
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 							// 选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 	// 比较输出使能
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputState_Disable;	// 比较输出N不使能
	TIM_OCInitStructure.TIM_Pulse = 0;								
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 			// 输出极性:TIM输出比较极性高
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;		  // 互补输出极性
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;    //在空闲时输出低
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset ;  //在空闲时互补输出低
	
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);  						// 数初始化TIM1_OC1	
	TIM_OC2Init(TIM1, &TIM_OCInitStructure);							// 数初始化TIM1_OC2
	TIM_OC3Init(TIM1, &TIM_OCInitStructure);							// 数初始化TIM1_OC3
	TIM_OC4Init(TIM1, &TIM_OCInitStructure);							// 数初始化TIM1_OC4
	
	
	TIM_ARRPreloadConfig(TIM1,ENABLE);										// 使能TIM1的自动重装载寄存器
	
	TIM_CtrlPWMOutputs(TIM1,ENABLE);											// 主输出使能
	
	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  		// 使能TIM1在OC1上的预装载寄存器
	TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);			// 使能TIM1在OC2上的预装载寄存器
	TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);			// 使能TIM1在OC3上的预装载寄存器
	TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);			// 使能TIM1在OC4上的预装载寄存器
	
	TIM_Cmd(TIM1, ENABLE);  															// 使能TIM1
	
}



//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM4_PWM_Init(void)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	
  //时钟配置
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
	

	
	// 配置IO模式
	GPIO_InitStructure.GPIO_Pin = TIM4_CH1_GPIO_PIN | TIM4_CH2_GPIO_PIN | TIM4_CH3_GPIO_PIN | TIM4_CH4_GPIO_PIN; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(TIM4_CH1_GPIO_PORT, &GPIO_InitStructure);//初始化GPIO
 
	

   //初始化TIM4的计数模式、分频值、重装载值等
	TIM_TimeBaseStructure.TIM_Period = TIM4_Reload_Num; 					//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =TIM4_Frequency_Divide; 	//设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 									//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); 							//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	
	
	//初始化TIM4_CH1-4的PWM	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2(模式二:计数时当计数器值超过设定值时输出有效电平,低于时输出无效电平)
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高(高电平是有效电平,还是低电平是有效电平)
	
	TIM_OC1Init(TIM4, &TIM_OCInitStructure); 
	TIM_OC2Init(TIM4, &TIM_OCInitStructure); 
	TIM_OC3Init(TIM4, &TIM_OCInitStructure); 
	TIM_OC4Init(TIM4, &TIM_OCInitStructure); 

  //TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器(作用:当要改变占空比时,能否立马生效)
 
	TIM_Cmd(TIM4, ENABLE);  //使能TIM3
	

}

PWM.h

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"

#define	TIM1_Frequency_Divide	719		// TIM1时钟预分频值
#define	TIM1_Reload_Num			99		// 自动重装载寄存器的值

#define	TIM4_Frequency_Divide	719		// TIM1时钟预分频值
#define	TIM4_Reload_Num			99		// 自动重装载寄存器的值


//左前电机
#define TIM1_CH1_GPIO_PIN  					GPIO_Pin_8
#define TIM1_CH1_GPIO_PORT  				GPIOA
#define TIM1_CH1_GPIO_CLK  					RCC_APB2Periph_GPIOA

#define TIM1_CH2_GPIO_PIN  					GPIO_Pin_9
#define TIM1_CH2_GPIO_PORT  				GPIOA
#define TIM1_CH2_GPIO_CLK  					RCC_APB2Periph_GPIOA

//左后电机
#define TIM1_CH3_GPIO_PIN  					GPIO_Pin_10
#define TIM1_CH3_GPIO_PORT  				GPIOA
#define TIM1_CH3_GPIO_CLK  					RCC_APB2Periph_GPIOA

#define TIM1_CH4_GPIO_PIN  					GPIO_Pin_11
#define TIM1_CH4_GPIO_PORT  				GPIOA
#define TIM1_CH4_GPIO_CLK  					RCC_APB2Periph_GPIOA



//右前电机
#define TIM4_CH1_GPIO_PIN  					GPIO_Pin_6
#define TIM4_CH1_GPIO_PORT  				GPIOB
#define TIM4_CH1_GPIO_CLK  					RCC_APB2Periph_GPIOB

#define TIM4_CH2_GPIO_PIN  					GPIO_Pin_7
#define TIM4_CH2_GPIO_PORT  				GPIOB
#define TIM4_CH2_GPIO_CLK  					RCC_APB2Periph_GPIOB

//右后电机
#define TIM4_CH3_GPIO_PIN  					GPIO_Pin_8
#define TIM4_CH3_GPIO_PORT  				GPIOB
#define TIM4_CH3_GPIO_CLK  					RCC_APB2Periph_GPIOB

#define TIM4_CH4_GPIO_PIN  					GPIO_Pin_9
#define TIM4_CH4_GPIO_PORT  				GPIOB
#define TIM4_CH4_GPIO_CLK  					RCC_APB2Periph_GPIOB


void TIM1_PWM_Init(void);
void TIM4_PWM_Init(void);
#endif

二、红外循迹

本项目采用三个红外循迹模块。

基于stm32的智能小车(远程控制、避障、循迹)

 基于stm32的智能小车(远程控制、避障、循迹)

 其原理很简单,// 未碰到黑线(接收到红外光):对应状态 = 0
                          // 碰到黑线(未接收到红外光):对应状态 = 1

也就是说,正常沿着黑线行驶,循迹模块输出高电平。当偏离黑线时,循迹模块输出低电平。我们只需采集引脚电平,当左侧出现低电平时,让小车向右转一点调整一定的角度。当右侧出现低电平时,让小车向左转一点调整一定的角度。

程序:

trail.c(循迹)

#include "trail.h"

u8 S_Trail_Input = 0 ;		// 三个寻迹模块的返回值


// 红外寻迹初始化(将PB3、PB4、PB5初始化为上拉输入)
// Trail -- PB3
// Trai2 -- PB4
// Trai3 -- PB5
//----------------------------------------------------------------------------------------------
void Trail_Input_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	// 使能GPIOB端口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);			// GPIOB时钟使能
	
	//PB3、PB4默认设置JTCK引脚,释放为通用GPIO口
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);			// 复用时钟使能
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);			// 将PB3、PB4释放为通用GPIO口
	
	// 寻迹:Trail--PB3、PB4、PB5端口配置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;	// Trail--PB3、PB4、PB5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 					// 上拉输入
	//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;				// 输入模式不需要设端口速度
	GPIO_Init(GPIOB, &GPIO_InitStructure);							// 初始化PB3、PB4、PB5
	
}
//----------------------------------------------------------------------------------------------


// 黑线寻迹函数
// S_Trail_Input的低三位分别对应[PB5、PB4、PB3]的状态值
// 未碰到黑线(接收到红外光):对应状态 = 0
// 碰到黑线(未接收到红外光):对应状态 = 1
//----------------------------------------------------
void Trail_black_line(void)
{
	S_Trail_Input = 0 ;
	
	S_Trail_Input = (((u8)GPIOB->IDR) & 0x38)>>3;
}
//----------------------------------------------------

trail.h

#ifndef	__TRAIL_H
#define __TRAIL_H

#include "stm32f10x.h"


// S_Trail_Input的低三位分别对应[PB5、PB4、PB3]的状态值
// 未碰到黑线(接收到红外光):对应状态 = 0
// 碰到黑线(未接收到红外光):对应状态 = 1
//-----------------------------------------------------
extern u8 S_Trail_Input ;		// 三个寻迹模块的返回值
//-----------------------------------------------------


// 黑线寻迹情况
//---------------------------------------------------------------------
#define		Not_Find_Black_Line				0x00	// 未发现黑线
#define		Middle_Find_Black_Line			0x02	// 中间发现黑线
#define		Left_Find_Black_Line			0x01	// 左侧发现黑线
#define		Left_Middle_Find_Black_Line		0x03	// 左中侧发现黑线
#define		Right_Find_Black_Line			0x04	// 右侧发现黑线
#define		Right_Middle_Find_Black_Line	0x06	// 右中侧发现黑线

#define		Left_Right_Find_Black_Line		0x05	// 左右侧发现黑线

#define		All_Find_Black_Line				0x07	// 全部发现黑线
//---------------------------------------------------------------------


void Trail_Input_Init(void);		// 红外寻迹初始化

void Trail_black_line(void);		// 黑线寻迹函数


#endif	/* __TRAIL_H*/

三、红外避障

原理与红外循迹差不多,用了三个避障模块。

基于stm32的智能小车(远程控制、避障、循迹)

基于stm32的智能小车(远程控制、避障、循迹)

 网上还有很多其他楼主,是用的一个舵机带动一个超声波避障模块做的,但是那种遇到障碍时,必须停下来,然后转动舵机 从而让超声波避障模块转动,测那边没有障碍,从而往那边走。

而我们这种设计不需要停下小车再去判断,在行使的过程中直接判断。

程序:

elude.c (避障)

#include "elude.h"

u8 S_Elude_Input = 0 ;		// 三个红外避障模块的返回值


// 红外避障初始化(将PA1、PA2、PA3初始化为上拉输入)
// Elude_左 -- PA1
// Elude_中 -- PA2
// Elude_右 -- PA3
//----------------------------------------------------------------------------------------------
void Elude_Input_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			// GPIOB时钟使能
	
	
	// 避障:Elude--PA1、PA2、PA3
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;	// Elude--PA1、PA2、PA3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 					// 上拉输入
	//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;				// 输入模式不需要设端口速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);							// 初始化PA1、PA2、PA3
	
}
//----------------------------------------------------------------------------------------------


// 红外避障检测函数
// S_Elude_Input的低三位分别对应[PA3、PA2、PA1]的状态值
// 未遇到障碍(未接收到红外光):对应状态 = 1
// 遇到障碍(接收到红外光):对应状态 = 0
//-------------------------------------------------------------
void Elude_detect_barrier(void)
{
	S_Elude_Input = 0 ;
	
	S_Elude_Input = (((u8)GPIOA->IDR) & 0x0E)>>1;
}
//-------------------------------------------------------------

 elude.h

#ifndef	__ELUDE_H
#define __ELUDE_H

#include "stm32f10x.h"


// S_Elude_Infrared_Input的低三位分别对应[PA3、PA2、PA1]的状态值
// 未遇到障碍(未接收到红外光):对应状态 = 1
// 遇到障碍(接收到红外光):对应状态 = 0
//--------------------------------------------------------------
extern u8 S_Elude_Input ;		// 三个避障模块的返回值
//--------------------------------------------------------------


// 红外避障情况
//-----------------------------------------------------------------
#define		Not_Find_Barrier			0x07	// 未发现障碍
#define		Middle_Find_Barrier			0x05	// 中间发现障碍
#define		Left_Find_Barrier			0x06	// 左边发现障碍
#define		Left_Middle_Find_Barrier	0x04	// 左中侧发现障碍
#define		Right_Find_Barrier			0x03	// 右边发现障碍
#define		Right_Middle_Find_Barrier	0x01	// 右中侧发现障碍

#define		Left_Right_Find_Barrier		0x05	// 左右测发现障碍

#define		All_Find_Barrier			0x00	// 全部发现障碍
//-----------------------------------------------------------------


void Elude_Input_Init(void);		// 红外避障初始化

void Elude_detect_barrier(void);	// 红外避障检测函数


#endif	/* __ELUDE_H*/

智能小车完整工程:https://item.taobao.com/item.htm?spm=a21dvs.23580594.0.0.3f063d0dMDNK4b&ft=t&id=679724523188

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/180919.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • dmesg命令「建议收藏」

    dmesg命令「建议收藏」Linuxdmesg命令 Linux命令大全Linuxdmesg命令用于显示开机信息。kernel会将开机信息存储在ringbuffer中。您若是开机时来不及查看信息,可利用dmesg来查看。开机信息亦保存在/var/log目录中,名称为dmesg的文件里。语法dmesg[-cn][-s]参数说明:-c 显示信息后,清除ri

    2022年10月24日
  • 2020湖南省ACM_acm个人赛

    2020湖南省ACM_acm个人赛记2020年(第16届)湖南ACM省赛写在前面我很喜欢《龙族》里那个叫路明非的衰小孩。虽然我也不知道为什么要说这个,逃这个世界有多大,取决于你认识的人,你每认识一个人,世界对你来说就会变大一些——路明非热身赛今年蓝桥杯和热身赛冲突了,搞完蓝桥杯都1点了,急忙赶去长理签到一下~哈哈外市的参加完蓝桥杯就不太方便过来,就现得热身赛异常冷清了,没多少队伍。打开题目一看,好家伙。是去年省赛的原题。cjm:我不想写了我:??(原来大佬都是这样子的)lb:??(大佬啊)我看到签到题A就想到上

  • mod_wsgi + pymssql通路SQL Server座

    mod_wsgi + pymssql通路SQL Server座

  • java gb2312中文乱码_Java中文乱码问题(转)

    java gb2312中文乱码_Java中文乱码问题(转)大家在JSP的开发过程中,经常出现中文乱码的问题,可能一至困扰着大家,现把JSP开发中遇到的中文乱码的问题及解决办法写出来供大家参考。首先了解一下Java中文问题的由来:Java的内核和class文件是基于unicode的,这使Java程序具有良好的跨平台性,但也带来了一些中文乱码问题的麻烦。原因主要有两方面,Java和JSP文件本身编译时产生的乱码问题和Java程序于其他媒介交互产生的乱码问题。…

  • JUnitParams参数化单元测试使用详解[通俗易懂]

    JUnitParams参数化单元测试使用详解[通俗易懂]JUnitParams(github地址:https://github.com/Pragmatists/JUnitParams)作为一个开源的单元测试框架,提供了参数化测试,Coder不需要通过构造器来设置参数,JUnitParams可以由测试方法提供参数,减少了代码量。接下来咱们就一探究竟。

  • python3.9多线程_python创建多线程

    python3.9多线程_python创建多线程什么是线程?线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号