蓝桥杯嵌入式STM32G431RBT6竞赛指南与模板——最后的绝唱

news2024/12/23 9:32:38

谨以此文和我去年前的一篇蓝桥杯单片机的教程构成电子类的青铜双壁.

国信长天单片机竞赛训练之原理图讲解及常用外设原理(遗失的章节-零)_昊月光华的博客-CSDN博客

目录

时钟树

串口重定向:printf输出

动态点灯(点灯大师)

按键(常用状态机)

同一时刻对多个按键按下进行判断

系统滴答定时器(Systick)

*ADC的DMA多通道采样+平均滤波处理

*串口的DMA+空闲中断不定长接受任意类型的数据

定时器通道的输入捕获

运行期间动态更改PWM的频率

PWM波的生成

IIC读写epprom

扩展板之ds18b20温度传感器

扩展板之dht11温度传感器


时钟树

串口重定向:printf输出

注意:

  1. 勾选微库.若发现根本进不了main函数里面一般是这个原因.
  2. 包含#include "stdio.h"

int fputc(int ch,FILE * f )
{
    HAL_UART_Transmit(&huart1,  (uint8_t *)&ch,1,0xff);
    
    return ch;
    
}

动态点灯(点灯大师)

u8 LEDINDEX[]= {0X00,1<<0,1<<1,1<<2,1<<3,1<<4,1<<5,1<<6,1<<7};
u8 LEDDT[]={0,0,0,0,0,0,0,0,0};
void led_display(u8 ds)
{
    HAL_GPIO_WritePin(GPIOC,0xff<<8,GPIO_PIN_SET);
     HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
       HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
    
    
     HAL_GPIO_WritePin(GPIOC,ds<<8,GPIO_PIN_RESET);
     HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
       HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
     
}
void led_scan(){
    int ds = 0;
    for(int i = 0 ;i < 4;i++)
    {
        ds|=LEDINDEX[LEDDT[i]];
        
    }
    led_display(ds);
}

运行期间只需要更改LEDDT的值就行,LEDDT没有顺序,表示最多同时点亮的灯的数目。

按键(常用状态机)

(状态机,假设同时只有一个按键按下,无论长按还是短按都只判断按下,记作一次)这个代码只能一次性判断一个按键按下,无法对同一时刻多个按键按下进行判断,一般这个代码就够用了)

使用定时器7,配置为20ms进入一次回调函数。这种我认为是日常中比较常用的按键操作,因为以前对51单片机按键扫描的记忆,故回顾了下。

#define ReadB1  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define ReadB2  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define ReadB3  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define ReadB4  HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
u8 key_state= 0;
u8 rkey = 0;
u8 key = 0;
void  HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    
    if(htim->Instance == TIM2)
    {
        LedFlusht++;
        if(time++ == 1000)
        {
            time = 0;
            LEDDT[1] = LEDDT[1]?0:1;
            
            
        }
        
    
        
    }
    else if(htim->Instance == TIM7)
    {
        
        //执行按键扫描
        switch(key_state)
        {
            
            case 0:
                if(!ReadB1 || !ReadB2 ||!ReadB3 || !ReadB4)
                {
                    key_state = 1;
  
                }
                break;
            case 1:
                  if(!ReadB1 || !ReadB2 ||!ReadB3 || !ReadB4)
                {
                    key_state = 2;
                    if(!ReadB1) key = 1;
                    else if(!ReadB2) key=2;
                    else if(!ReadB3) key=3;
                    else if(!ReadB4) key =4;
                    rkey = key;
  
                }
                else 
                {
                    
                    key_state = 0;
                    key = 0;
                    
                }
                break;
            case 2:
                rkey = 0;//在只需要判断按下之后,不管长按短按(有没有松开)都试做按下一次
                if(!ReadB1 || !ReadB2 ||!ReadB3 || !ReadB4)
                {
                    
                }
                else 
                {
                    key = 0;
                    key_state= 0;
                    
                }
                break;
            
            
        }
        
        
        keyAction();
        
        
        
        
    }
    
    
}

同一时刻对多个按键按下进行判断

原理:把按键定义成一个结构体变量:


typedef struct Key{
    u16 keytime;
    u8 keystate;
    bool sflag;
    bool lflag;


}Key;

按键扫描:(按下小于500ms属于短按,大于500ms属于长按) ,按键扫描函数单独用一个定时器,每10ms产生一次中断去执行,这也就是为什么keytime+=10的原因.

#define ReadB1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define ReadB2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define ReadB3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define ReadB4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)

 void key_scan()
{
    
    keys[0].state =  READB1;
    keys[1].state =  READB2;
    keys[2].state =  READB3;
    keys[3].state =  READB4;
    
    for(int i = 0 ; i < 4 ;i++)
    {
        switch(keys[i].keystate)
        {
            
            case 0:
                 if( !keys[i].state){
                     keys[i].keystate =1;
                     
                 }
                break;
            case 1:
                  if(!keys[i].state){
                     keys[i].keystate =2;
                     
                 }
                  else 
                      keys[i].keystate = 0;
                break;
            case 2:
                if(!keys[i].state)
                {
                    
                    keys[i].keytime+=10;
                   
                }
                else 
                {
                        if(keys[i].keytime > 500)
                        {
                            keys[i].lflag = 1;
                        }
                        else 
                            keys[i].sflag = 1;
                        
                        
                        keys[i].keytime = 0;
                        keys[i].keystate=0;
                        
                    
                    
                }    
                break;
            default:
                break;
            
            
        }   
    }  
}

//串口测试代码
void keywork(void)
{
    
    if(keys[0].sflag)
    {
        
        printf("0\r\n");
        keys[0].sflag = 0;
        
    }
    else if(keys[0].lflag)
    {
        
        printf("long 0\r\n");
        keys[0].lflag = 0;
    }
     if(keys[1].sflag)
    {
        
        printf("1\r\n");   keys[1].sflag = 0;
        
    }
    
    
      else if(keys[1].lflag)
    {
        
        printf("long 1\r\n");
        keys[1].lflag = 0;
    }
    
    
    
    
    
    
     if(keys[2].sflag)
    {
        
        printf("2\r\n");
           keys[2].sflag = 0;
    }
     if(keys[3].sflag)
    {
        
        printf("3\r\n");
           keys[3].sflag = 0;
        
    }
    
    
    
}

逻辑处理: 处理完后sflag (短按标志)或lflag(长按标志)记得清零处理。

系统滴答定时器(Systick)

HAL_GetTick() 函数是 STM32 微控制器 HAL(硬件抽象层)库提供的函数。它返回当前以毫秒为单位的节拍计数。默认情况下,系统定时器每1ms生成一个中断以更新节拍计数。因此,在大多数情况下,每个节拍的速率为1ms。

此函数可用于实现基于时间的操作,例如延迟、超时和任务调度。通过比较当前节拍计数与之前保存的值,可以确定自那个事件以来经过的时间。

例如,要创建100ms的延迟,您可以使用 HAL_GetTick() 保存当前节拍计数,然后在循环中等待,直到保存的节拍计数和当前节拍计数之间的差达到100ms。

uint32_t startTick = HAL_GetTick(); while ((HAL_GetTick() - startTick) < 100);

请注意,当节拍计数达到其最大值(0xFFFFFFFF)后,它会绕回,并且在计算长时间内经过的时间时必须考虑到这一点。

我们使用DHT11,DS18B20需要用到的us级延时就需要通过systick来实现。

HAL_GetTick(); 获取当前节拍.默认是1ms产生1个tick(节拍),则systick的计数值1ms发生溢出产生中断,

systick的默认中断函数:(每次中断溢出则增加节拍 ”Tick“)

Systick的主频:

SysTick定时器的主频取决于所使用的系统时钟(HCLK)频率和它的分频系数。在STM32微控制器中,SysTick定时器的时钟源可以配置为HCLK/8或HCLK。

如果SysTick定时器的时钟源被配置为HCLK/8,则SysTick定时器的主频将为HCLK/8。例如,如果HCLK的频率为72MHz,则SysTick定时器的主频将为9 MHz。

如果SysTick定时器的时钟源被配置为HCLK,则SysTick定时器的主频将为HCLK。例如,如果HCLK的频率为72MHz,则SysTick定时器的主频将为72 MHz。

需要注意的是,SysTick的主频越高,计数器溢出的时间间隔就越短,因此可以获得更高的精度和分辨率。但是,SysTick的主频和计数器位数的组合也会影响 SysTick 的最大定时周期。

systick的时钟源一般被设置为AHB总线上的时钟频率,比如常见的80MHZ.

 

配置systick的时钟频率 HAL_SYSTICK_CLKSourceConfig() 

两种选择 HCLK 或 HCLK/8 

 

 溢出时间判断:SYSTICK->LOAD的装载值为79999,所以:

产生一次中断的时间为:1/(80M-1)*(79999+1) =1/10^3 = 1ms

默认的SYSTICK中断函数:

/**
  * @brief This function handles System tick timer.
  */
__weak void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

/**
  * @brief This function is called to increment a global variable "uwTick"
  *        used as application time base.
  * @note In the default implementation, this variable is incremented each 1ms
  *       in SysTick ISR.
  * @note This function is declared as __weak to be overwritten in case of other
  *      implementations in user file.
  * @retval None
  */
__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}

 把SYSTICK做定时用,重写systick的中断函数.(节省定时器,一般情况下,我们都不会这样去做,因为OS会把它作为时基,而我们的一些ms级延时也要得益改变systick的频率得到)

此时需要把原来的SysTick_Handler标记为weak。不好的地方在于每次生成代码都需要改.

这一点纯属当拓展知识去用,知道可以这么干就可以了.

void SysTick_Handler(void)
{
    
     HAL_IncTick();
    static uint32_t ick = 0;   // 定义静态变量tick,记录自系统启动以来经过的毫秒数
    ick++;                     // 每次中断触发时tick值加1
    if (ick == 1000) {         // 如果tick值等于1000,则表示已经过了1秒钟
        // TODO: 执行每秒钟需要执行的任务
        ick = 0;               // 将tick值重置为0,开始新的计数
        printf("hello world\r\n");
    }
}

 

*ADC的DMA多通道采样+平均滤波处理

比赛实际上用单通道就可以,每次采样需要指定adc的通道.

STM32基于hal库的adc以DMA的多通道采样以及所遇问题解决_stm32 hal adc dma_昊月光华的博客-CSDN博客

*串口的DMA+空闲中断不定长接受任意类型的数据

(记得数据宽度设置为1个字节 8位)

若是hal库的版本并不是特别的新,那么还是用串口接受中断+空闲中断吧,我这边测试1.3的固件包是可以用DMA的那个空闲中断函数 ,如:

   HAL_UARTEx_ReceiveToIdle_DMA(&huart1,Rx1Buf,200); //串口1开启DMA接受

基于HAL库的STM32的串口DMA发送数据(解决只发送一次数据)及DMA+空闲中断接受数据_hal 串口dma发送_昊月光华的博客-CSDN博客

定时器通道的输入捕获

对输入的脉冲进行捕获,算出求频率和占空比.设置定时器的频率的1M用来对输入的脉冲进行计数,假设输入脉冲一个周期的计数值为t(从一个脉冲的上升沿到下一个脉冲的上升沿).则频率计算为   1000000 /  t  .

比如对PA15信号发生器.

 配置(PA15接脉冲发生器测出来的占空比大概为50%。

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    
    static u16 t = 0;
    static u16 d = 0;
    if(htim->Instance == TIM2)
    {
        if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
        {
            LEDDT[0]=1;
            t = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;
            freq = 1000000 / t;
            duty = (float)d/t*100;
            
        }
        
        else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
        {
              LEDDT[1]=2;
            d =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;
        }
        
        
    }
}

 通过按键打印

运行期间动态更改PWM的频率

pwm的频率 = 定时器的频率/autoreload的值.其中定时器的频率 = 时钟频率/分频系数.

之前参加过蓝桥杯单片机的相信有过经历:用定时器去实习pwm波:

记得我们是如何实现的?

假设定时器的频率是1M.每1us计数值加1,若设置为1000个计数值后溢出则产生一次中断,则1ms进入一次中断,在中断函数内,我们让其定义一个变量,让其加到200后归0,其中前100ms设置为高电平,后100ms设置为低电平,则周期为200ms,频率为1/200ms=5HZ,占空比为50%。(假设有效电平为高电平).

再回到STM32来,这里的autoreload就是计数值,一个计数的时间是1/定时器的频率。则PWM的频率为1  /   [autoreload*1/定时器的频率) ]  = 定时器的频率/ autoreload .证明完毕.

我们通过更改autoreload的值去动态的更改pwm的频率,需要注意的是当autoreload的值发生改变,需要重新去计算占空比。 占空比 = TIM15->CCR1 /autoreload .

//改变PWM的频率且稳定占空比保持不变 以TIM15->CCR1为例
void changePwmFreqAndkeepDuty(float duty,u16 autoloadval)
{
    
        extern TIM_HandleTypeDef htim15;
        TIM15->CCR1 = duty*autoloadval;
        printf("new freq: %d\r\n",10000/autoloadval);
        __HAL_TIM_SetAutoreload(&htim15,autoloadval-1);
        HAL_TIM_GenerateEvent(&htim15, TIM_EVENTSOURCE_UPDATE);
    
   
}

通过按键触发更改

按键触发的demo

if(keys[0].sflag)
    {
        
        static  u8 t =0;
        t++;
        static bool flag = false;
        if( t == 100) t=0;
         
       void changePwmFreqAndkeepDuty(float duty,u16 autoloadval);
        
        flag =!flag;
        if(flag)    changePwmFreqAndkeepDuty(0.8,50);
        else changePwmFreqAndkeepDuty(0.5,100);
     
        printf("0\r\n");
        keys[0].sflag = 0;
        
    }

PWM波的生成

相信看到这,PWM的产生原理已经很清楚了,用cubeMX配置将会更加清楚.

 一个定时器可以配置多个通道产生多组PWM波.

 开启PWM波:

   HAL_TIM_PWM_Start_IT(&htim15,TIM_CHANNEL_1);

更改PWM的值(如TIM15) TIM15->CCR1 =XXX (表示TIM15的通道1)

IIC读写epprom

需要注意在读数据时,需要主机发送应答信号表示。以及需要初始化.

 I2CInit(void);

//EEPROM读写代码
void eeprom_write(unsigned char *pucBuf, unsigned char ucAddr, unsigned char Size)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(ucAddr);	
	I2CWaitAck();
	
	while(Size--)
	{
		I2CSendByte(*pucBuf++);
		I2CWaitAck();	
	}
	I2CStop();
	 
}

void eeprom_read(unsigned char *pucBuf, unsigned char ucAddr, unsigned char Size)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(ucAddr);	
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	while(ucNum--)
	{
		*pucBuf++ = I2CReceiveByte();
		if(Size)
			I2CSendAck();	
		else
			I2CSendNotAck();
	}
	I2CStop();	
}

扩展板之ds18b20温度传感器

驱动代码比赛官方会给出.只需要自己写一个读取温度的函数就行.给出的驱动有个不稳定的因素,那就是delay_us()这个延时函数没有重写。驱动是以80M做的一个微秒级延时,当在更改系统时钟频率时则有大问题(因为指令周期会随着系统的时钟频率而变化!),同样的,DHT11的驱动也有这个问题.,这完全是让学生专注于与逻辑业务的实现,驱动能跑就行(记得设置系统主频为80M).

资源包给的延时函数:

#define Delay_us(X)  delay((X)*80/5)

void delay(unsigned int n)
{
    while(n--);
}

跳线帽连接 P4 与 P3 的 TDQ进行连接.

main函数中调用初始化:

  ds18b20_init_x();

读取温度

float ds18b20_read(void)
{
    
    unsigned char  th,tl;
    unsigned short res;
    ow_reset();
    ow_byte_wr(0xcc);
    ow_byte_wr(0x44);
    
    
     ow_reset();
    ow_byte_wr(0xcc);
    ow_byte_wr(0xbe);
    
    tl =    ow_byte_wr(0xff);
    th =     ow_byte_wr(0xff);
    
    res=(th<<8)|tl;
    
    return res*0.0625;
    
    
    
}

扩展板之dht11温度传感器

每次读取完后的下一次读取则会失败,这不是我们的问题。只需要得到在它正确读取时的值就行。

dht11比赛赛点资料包(14届)给的驱动代码只给了2个函数,两个改变DQ输入输出的函数。。。

dht11_hal.h

#ifndef __DHT11_HAL_H
#define __DHT11_HAL_H

#include "stm32g4xx_hal.h"

#define HDQ		GPIO_PIN_7

 
 
		 

typedef struct {
	
    float temp;
    float humi;
    
}dht11Data;

void dht11Init(void);
int Readdht11(void);


#endif

dht11_hal.c

#include "dht11_hal.h"

#define  OUTDQLOW		HAL_GPIO_WritePin(GPIOA, HDQ, GPIO_PIN_RESET)
#define OUTDQHIGH      HAL_GPIO_WritePin(GPIOA, HDQ, GPIO_PIN_SET)
#define READDQ          HAL_GPIO_ReadPin(GPIOA,HDQ)
dht11Data dht11;

//
static void usDelay(uint32_t us)
{
	uint16_t i = 0;
	while(us--){
		i = 30;
		while(i--);
	}
}

//
void outDQ(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	
	GPIO_InitStructure.Pin = HDQ;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
	
 
}

//
void inDQ(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.Pin = HDQ;
	GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
	GPIO_InitStructure.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
}

//
void dht11Init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();
	outDQ();
    OUTDQHIGH;
}

//
uint8_t recData(void)
{
	uint8_t i,temp=0,j=220;
	
	for(i=0; i<8; i++){
		
		while(!HAL_GPIO_ReadPin(GPIOA,HDQ));
		usDelay(40);
		if(HAL_GPIO_ReadPin(GPIOA,HDQ))
		{
			temp=(temp<<1)|1;
			while(HAL_GPIO_ReadPin(GPIOA,HDQ)&&(j--));	
		}	
		else
		{
			temp=(temp<<1)|0;
		}
	}
	return temp;
}

//复位DHT11
void DHT11_Rst(void)
{
    outDQ(); 	//设置为输出
    OUTDQLOW;
    HAL_Delay(20);	//拉低至少18ms
    OUTDQHIGH;
    usDelay(60);     	//主机拉高20~40us
}

//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
unsigned char DHT11_Check(void)
{
    unsigned char re = 0;
    inDQ();    //设置为输入
    while (READDQ && re < 100) //DHT11会拉低40~80us
    {
        re++;
        usDelay(1);
    };
    if(re >= 100)return 1;
    else re = 0;
    while (!READDQ && re < 100) //DHT11拉低后会再次拉高40~80us
    {
        re++;
        usDelay(1);
    };
    if(re >= 100)return 1;
    return 0;
}


int Readdht11(void)
{
    
     unsigned char  buf[5];
     unsigned char  i;
    DHT11_Rst();
    if(DHT11_Check() == 0)
    {
        for(i = 0; i < 5; i++)
        {
            buf[i] = recData();
        }
        if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        {
            dht11.humi = buf[0];
             dht11.temp =buf[2];
            
        }
    }
    else return 1;
    return 0;
     
}

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

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

相关文章

RabbitMQ学习-发布确认高级

发布确认springboot版本 确认机制方案&#xff1a; 代码架构图&#xff1a; 配置文件&#xff1a; 在application.properties全局配置文件中添加spring.rabbitmq.publish-confirm-type属性&#xff0c;这个属性有以下几种值 none:禁用发布确认模式(默认)0 correlated:发布消…

Redis的SDS+IntSet+Dict

一)SDS 在redis中&#xff0c;保存key的是字符串&#xff0c;value往往是字符串或者是字符串的集合&#xff0c;可见字符串是redis中最常用的一种数据结构: 但是在redis中并没有直接使用C语言的字符串&#xff0c;因为C语言的字符串存在很多问题 1)获取字符串的长度需要通过运算…

算法12.从暴力递归到动态规划5

算法|12.从暴力递归到动态规划5 1.机器人行进问题 题意&#xff1a;假设有排成一行的N个位置记为1~N&#xff0c;N一定大于或等于2 开始时机器人在其中的M位置上(M一定是1~N中的一个) 如果机器人来到1位置&#xff0c;那么下一步只能往右来到2位置&#xff1b; 如果机器人来到…

stc15w404as使用keil做库,提供头文件,供调用

背景 有个项目使用需要使用库&#xff0c;将代码封装起来&#xff0c;仅仅留下调试接口&#xff0c;给用户使用&#xff0c;调试一些参数。这样工程看起来更简单&#xff0c;也方便客户维护。 也有一些使用场景&#xff0c;需要把自己的代码封装起来&#xff0c;这个是怕被别…

电脑msvcp120.dll缺失怎么办?由于找不到msvcp120.dll的解决方案

MSVCP120.dll文件是Windows操作系统中的一种动态链接库文件。它是由Microsoft C软件包提供的重要组件。当系统提示“MSVCP120.dll文件缺失”时&#xff0c;可能会导致某些应用程序无法正常运行。 以下是修复MSVCP120.dll缺失问题的几种方法&#xff1a; 方法一&#xff1a;修复…

如何在华为OD机试中获得满分?Java实现【公共子串计算】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1、题目描述2、输入描述3、输出描述…

<学习笔记>从零开始自学Python-之-web应用框架Django( 十四)上线部署(阿里云+Nginx+uwsgi+MySQL)

好了&#xff0c;我们现在有了一个完整的网站&#xff0c;在自己电脑上跑起来没问题了&#xff0c;但是我们做网站肯定不只是为了在本机上自己欣赏&#xff0c;总要放到网上去让别人来浏览。这一章我们就完整跑一遍Django项目的生产环境部署。 1、基本原理 想让你的网站在公网…

【P38】JMeter 随机控制器(Random Controller)

文章目录 一、随机控制器&#xff08;Random Controller&#xff09;参数说明二、测试计划设计2.1、测试计划一2.2、测试计划二2.3、勾选忽略子控制器块 一、随机控制器&#xff08;Random Controller&#xff09;参数说明 可以让控制器内部的逻辑随机执行一个&#xff0c;一般…

如何在华为OD机试中获得满分?Java实现【24点游戏算法】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1、题目描述2、输入描述3、输出描述…

python自动演奏Freepiano【双手合奏】

文章编写背景 玩了N久的Freepiano,碍于本人没有天赋&#xff0c;左右手一直没法协调。 于是&#xff0c;突然奇想&#xff0c;也是代码设计的思路&#xff1a; 用多线程的方式&#xff0c;开两个线程&#xff0c;然后通过按键模拟的方式&#xff0c;分别模拟左右手去演奏。觉…

分布式网络通信框架(一)——集群和分布式

单机聊天服务器 缺点&#xff1a; 受限于硬件资源&#xff0c;服务器所能承受的用户并发量不够大&#xff1b; 任意模块修改&#xff0c;都会导致整个项目代码重新编译、部署&#xff1b; 系统中&#xff0c;有些模块是CPU密集型&#xff0c;有些是IO密集型&#xff0c;造成…

计算机网络五 传输层

传输层 概念 传输层是指ISO/OSI模型中的第四层&#xff0c;在计算机网络中起着非常重要的作用。它负责数据在网络中的传输&#xff0c;管理数据传输的可靠性和流量控制&#xff0c;保证数据在网络中不会丢失或重复。 提供的服务 传输层提供的主要服务有两种&#xff0c;分别…

《数据库应用系统实践》------ 包裹信息管理系统

系列文章 《数据库应用系统实践》------ 包裹信息管理系统 文章目录 系列文章一、需求分析1、系统背景2、 系统功能结构&#xff08;需包含功能结构框图和模块说明&#xff09;3&#xff0e;系统功能简介 二、概念模型设计1&#xff0e;基本要素&#xff08;符号介绍说明&…

9. Linux下实现简单的UDP请求

本文简单介绍了UDP传输层协议&#xff0c;并在Linux下实现简单的socket通讯 一、UDP UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种无连接的传输层协议&#xff0c;它不保证数据包的可靠性和顺序。UDP在IP协议的基础上增加了简单的差错…

阿里云服务器配置CPU内存、带宽和系统盘选择方法

阿里云服务器配置怎么选择&#xff1f;CPU内存、公网带宽和系统盘怎么选择&#xff1f;个人用户选择轻量应用服务器或ECS通用算力型u1云服务器&#xff0c;企业用户选择ECS计算型c7、通用型g7云服务器&#xff0c;阿里云服务器网分享阿里云服务器配置选择方法&#xff1a; 目录…

大数据周会-本周学习内容总结015

开会时间&#xff1a;2023.05.28 15:30 线下会议 目录 01【fhzny项目】 02【Spark】 03【调研-数仓构建】 3.1【数仓构建&#xff0c;流程图、架构图、使用场景】 场景选择 组件设计 构建流程 04【专利】 05【导师点评】 01【fhzny项目】 GitLabMyBatis-PlusSpringbo…

Java001——基本的Dos命令

打开CMD的方式 1、win10&#xff1a;开始&#xff0d;>系统&#xff0d;>命令提示符 win11&#xff1a;开始&#xff0d;>windows工具&#xff0d;>命令提示符 2、Win键R输入cmd 打开控制台 3、进入文件夹&#xff0c;按住shift键鼠标右键点击&#xff0c;在此…

路径规划算法:基于萤火虫优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于萤火虫优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于萤火虫优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法…

[第一章 web入门]SQL注入-1

拿到题目是一篇日记&#xff0c;是GET型请求方式&#xff0c;我们可以直接在url栏中注入数据 判断注入类型&#xff0c;页面有回显所以不是整型注入 id 1 and 1 2 id 1 页面无回显&#xff0c;判断为字符型注入&#xff0c;闭合符应该就是单引号 id 1 order by 4-- 无回显&…

C#,码海拾贝(26)——求解“一般带状线性方程组”之C#源代码,《C#数值计算算法编程》源代码升级改进版

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static partial class LEquations { /// <summary> /…