第十四届蓝桥杯嵌入式详解

news2024/11/17 17:33:40

 

目录

第一部分 客观试题(15 分)

不定项选择(1.5 分/题)

 第二部分 程序设计试题(85 分)

 2.1 STM32CubeMX初始化配置

         2.1.1 配置GPIO

         2.1.2 配置ADC

         2.1.3 配置RCC

         2.1.4 配置定时器TIM

         2.1.5 配置ADC1、ADC2

         2.1.6 配置定时器2

         2.1.7 配置定时器3

         2.1.8 可以选择配置操作系统

         2.1.9 时钟树设置

2.2 代码详解

         2.2.1 LCD task

         2.2.2 KEYtask

         2.2.3 PWM信号输出控制


 总耗时:4.5h  

第十四届蓝桥杯嵌入式


第一部分 客观试题(15 分)

不定项选择(1.5 分/题)

        01. 下列电路中属于时序逻辑电路的是( ABC)。

        A. 计数器         B. 分频器         C. D 触发器         D. 编码器

         02. 一个 8 位二进制减法计数器,初始状态为 0000 0000,经过 300 个输入脉冲后,计 数器的状态为(B )。

        A. 0010 1100         B. 1101 0011         C. 0010 0011         D. 1101 0100

        03. 晶体管的穿透电流 ICEO能够体现( A)。

        A. 晶体管的温度稳定性         B. 晶体管允许通过最大电流极限参数

        C. 晶体管放大能力                D. 晶体管的频率特性

        04. STM32 系列微控制器,程序可以在哪些区域上运行(AB )。

        A. ROM         B. RAM         C. 寄存器         D. E2PROM

        05. 一个 8 位的 DAC 转换器,供电电压为 3.3V,参考电压 2.4V,其 1LSB 产生的输出 电压增量是(D )V。

        A. 0.0129         B. 0.0047         C. 0.0064         D. 0.0094

        06. 下列门电路中,输出端可以直接相连实现线与的是(AC )。

        A.OC 门         B.TTL 或非门         C.OD 门         D.CMOS 与非门

        07. 在 STM32 系列微控制器中,中断优先级可配置的是(BC )。

        A. RCC         B. NMI         C. HardFault         D. Systick

        08. 工作在线性区域的运算放大器应处于什么状态( A)。

        A. 负反馈         B. 正反馈         C. 开环         D. 振荡

        09. 同步电路和异步电路的区别是(D )。

        A. 电路中是否包含缓冲器                 B. 电路中是否包含触发器

        C. 电路中是否存在时钟信号             D. 电路中是否存在统一的时钟信号

        10. 下列关于关键字 inline 的描述,正确的是(ABD )。

        A. 降低栈内存的消耗。                          B. 可以提高代码的运行效率。

        C. 可以提高微控制器访问内部寄存器的速度。

        D. 程序中大量使用,会增大代码编译后的可执行文件的大小


 第二部分 程序设计试题(85 分)

 

 2.1 STM32CubeMX初始化配置

        选择STM32G431RBTx系列芯片;

        2.1.1 配置GPIO

         2.1.2 配置ADC

         2.1.3 配置RCC

         2.1.4 配置定时器TIM

         2.1.5 配置ADC1、ADC2

        一般是默认设置就可以了,开启全局中断,打开DMA通道1、DMA通道2;

        2.1.6 配置定时器2

        将PA1引脚配置定时器PWM模式1,使PA1输出PWM脉冲信号让PA7捕获。

         2.1.7 配置定时器3

        将PA7引脚配置定时器为输入捕获模式,用来捕捉PWM信号。

         2.1.8 可以选择配置操作系统

        1.添加FreeRTOS定时器

        PWM信号定时器,PWM输出高速模式,PWM输出低速模式

         2.添加任务,提前设置好任务的内存块

        堆栈空间的大小。定义句柄

        3.建立消息队列

        按键功能复杂可以使用队列简化复杂度进行调度, PWM信号分高频和低频模式也可以使用队列进行调度。

        4.其他设置

        使能固件库pack

         使能定义任务函数

         2.1.9 时钟树设置

2.2 代码详解

        定义全局变量Generator_Mode用来选择LCD界面3个模式的显示,Generator_FreqMode用来选择PWM高频和低频模式。Generator_KeyLock用来标志按键是否锁定,如果锁定则不能使用,Generator_DutyLock用来标志占空比锁。Generator_FreqShifting用来选择PWM高低模式,Generator_ShiftNum记录频率切换次数,多于10次则转1。Generator_ShiftNum、Generator_K参数界面的R和K。MaxSpeed_HighFreq、MaxSpeed_LowFreq记录高低频率下的最大速度。

低频输出频率是4k,高频输出频率是8k,可以用const静态关键字进行固定。

// 屏幕显示模式(0为数据,1为参数,2为统计)和频率模式(0低1高)
uint8_t Generator_Mode = 0, Generator_FreqMode = 0;
// 按键锁定标志位(低高频切换过程置高),占空比锁定标志位(数据界面长按B4置高,再短按B4置低)
uint8_t Generator_KeyLock = 0, Generator_DutyLock = 0;
// 正在切换的频率模式(0低1高)
uint8_t Generator_FreqShifting = 0;
// 记录的频率切换次数
uint32_t Generator_ShiftNum = 0;
// 参数界面的R和K
int8_t Generator_R = 1, Generator_K = 1;
// 记录的高/低频率下的最大速度
float MaxSpeed_HighFreq = 0, MaxSpeed_LowFreq = 0;
// PA1输出的占空比,PA7采样计算得到的速度
float Generator_PWMDuty = 0, Generator_Speed = 0;
// PA1输出的频率
uint16_t Generator_Freq = 4000;
//PA1高、低频模式下的频率(因为是固定的,所以声明为const)
const uint16_t Generator_HFreq = 8000, Generator_LFreq = 4000;

        2.2.1 LCD task

        全局变量已经解释过了,按照任务需求进行LCD界面选择显示,

LCD_Printf:va_list关键字作用是宏定义一个para变量,va_start(para, format)执行para = (va_list)&format + _INTSIZEOF(format),para指向参数format之后的那个参数的地址,即para指向第一个可变参数在堆栈的地址。vsnprintf函数用来向一个字符串缓冲区打印格式化字符串,且可以限定打印的格式化字符串的最大长度。va_end(para)用来清空para。LCD_DisplayStringLine函数是官方给的lcd.c文件中的函数用来定位行,直接调用就行。

void LCD_Printf(u8 line, const char *format, ...)
{
  char buf[22] = {0};
  va_list para;
  va_start(para, format);
  int len = vsnprintf(buf, sizeof(buf), format, para);
  va_end(para);
  LCD_DisplayStringLine(line, (unsigned char *)buf);
}

 osMessageQueueGet接收按键队列的消息,osOK枚举确认接收到了队列消息,

void LCD_Handler(void *argument)
{
  /* USER CODE BEGIN LCD_Handler */

  int8_t Generator_TempR = 1, Generator_TempK = 1;//R,K两个参数的暂存
  uint8_t Modified = 0;//0为修改R,1为修改K

  uint32_t online_cnt = 0;
  /* Infinite loop */
  for (;;)
  {
    LED_Ctrl(0, (Generator_Mode == 0) ? 1 : 0);//如果在数据模式下才点亮LD1
    LED_Ctrl(2, Generator_DutyLock);//如果占空比锁定则点亮LD3

    switch (Generator_Mode)//根据显示模式切换LCD显示
    {
    case 0:
      LCD_Printf(Line1, "        DATA        ");
      LCD_Printf(Line3, "     M=%c           ", ((Generator_FreqMode) ? 'H' : 'L'));
      LCD_Printf(Line4, "     P=%.0f%%       ", Generator_PWMDuty * 100.0f);
      LCD_Printf(Line5, "     V=%.1f         ", Generator_Speed);
      break;
    case 1:
      LCD_Printf(Line1, "        PARA        ");
      LCD_Printf(Line3, "     R=%d           ", Generator_TempR);
      LCD_Printf(Line4, "     K=%d           ", Generator_TempK);
      break;
    case 2:
      LCD_Printf(Line1, "        RECD        ");
      LCD_Printf(Line3, "     N=%d           ", Generator_ShiftNum);
      LCD_Printf(Line4, "     MH=%.1f        ", MaxSpeed_HighFreq);
      LCD_Printf(Line5, "     ML=%.1f        ", MaxSpeed_LowFreq);
      break;

    default:
      break;
    }

    uint8_t key = 0xff;//暂存变量,接收按键队列传出的按键信息
    if (osMessageQueueGet(Key_QueueHandle, &key, 0, 0) == osOK)//按键队列有最新按键信息
    {
      switch (key)
      {
      case 0://B1短按
        LCD_Clear(Black);
        Generator_Mode++;//刷屏,换模式
        if (Generator_Mode == 1)//换模式后如果是参数模式,也即按下按键后进入参数模式
        {
          Generator_TempR = Generator_R, Generator_TempK = Generator_K;//暂存变量更新为现在设置的值。
          Modified = 0;//进入模式默认先修改R,所以Modified不管之前是什么值都改为0
        }
        if (Generator_Mode > 2)//超过2则返回数据模式
          Generator_Mode = 0;
        if (Generator_Mode == 2)//换模式后如果是统计模式,也即刚刚是从参数模式退出来的
        {
          Generator_R = Generator_TempR, Generator_K = Generator_TempK;//实际参数用暂存值更新。
        }
        break;
      case 1://B2短按
        if (!Generator_KeyLock && Generator_Mode == 0)//此时按键未锁定且处于数据模式下
        {
          osMessageQueuePut(PWM_Signal_QueueHandle, &key, 0, 0);//启动频率切换进程
        }
        else if (Generator_Mode == 1)//此时在参数模式下
        {
          Modified = (Modified) ? 0 : 1;//Modified在0,1之间切换
        }
        break;
      case 2://B3短按
        if (Generator_Mode == 1)//此时在参数模式下
        {
          if (Modified)//0为修改R,1为修改K
            Generator_TempK++;
          else
            Generator_TempR++;
          if (Generator_TempK > 10)//参数越界判定
            Generator_TempK = 1;
          if (Generator_TempR > 10)
            Generator_TempR = 1;
        }
        break;
      case 3://B4短按
        if (Generator_Mode == 1)
        {
          if (Modified)//0为修改R,1为修改K
            Generator_TempK--;
          else
            Generator_TempR--;
          if (Generator_TempK < 1)//参数越界判定
            Generator_TempK = 10;
          if (Generator_TempR < 1)
            Generator_TempR = 10;
        }
        else if (Generator_Mode == 0)//此时在数据模式下
        {
          Generator_DutyLock = 0;//短按是解除占空比锁
        }
        break;

      case 4:
        /* code */
        break;
      case 5:
        /* code */
        break;
      case 6:
        /* code */
        break;
      case 7://B4触发长按条件
        if (Generator_Mode == 0)//此时在数据模式下
        {
          Generator_DutyLock = 1;//长按是占空比锁上锁
        }
        break;

      default:
        break;
      }
    }

    osDelayUntil((online_cnt + 1) * 100);//刷新用时控制在100ms左右
    online_cnt++;
  }
  /* USER CODE END LCD_Handler */
}

         2.2.2 KEYtask

        将按键按下次数存入数组中,返回到按键扫描函数。

uint8_t Key_IsUp(uint8_t pos)
{
    return Key_Up[pos];
}
uint8_t Key_IsLongPress(uint8_t pos)
{
    return Key_LongPress[pos];
}

        遍历按键gpio是否按下,按下则往Key_Reg数组中存入1,方便接下来取反,判断按键按下次数,并将按键按下次数存入Key_Cnt数组中。

uint8_t Key_Reg[4], Key_Constant[4], Key_Up[4], Key_LongPress[4], Key_LongTemp[4];
uint16_t Key_Cnt[4], Key_Delay = 78;
void Key_Scan(void)
{
    if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
        Key_Reg[0] = 1;
    }
    else
    {
        Key_Reg[0] = 0;
    }

    if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
        Key_Reg[1] = 1;
    }
    else
    {
        Key_Reg[1] = 0;
    }

    if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
    {
        Key_Reg[2] = 1;
    }
    else
    {
        Key_Reg[2] = 0;
    }

    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
        Key_Reg[3] = 1;
    }
    else
    {
        Key_Reg[3] = 0;
    }

    for (int i = 0; i < 4; i++)
    {
        Key_Up[i] = ~Key_Reg[i] & (Key_Reg[i] ^ Key_Constant[i]);
        Key_Constant[i] = Key_Reg[i];
        if (Key_Cnt[i] >= Key_Delay)
        {
            if (Key_Up[i])
            {
                Key_LongPress[i]=1;
                // Key_LongPress[i] = Key_Up[i] & (Key_Up[i] ^ Key_LongTemp[i]);
                Key_Up[i] = 0;
            }
            // Key_LongPress[i] = Key_Reg[i] & (Key_Reg[i] ^ Key_LongTemp[i]);
            Key_LongTemp[i] = Key_Reg[i];
        }
        else
        {
            Key_LongPress[i] = 0;
            Key_LongTemp[i] = 0;
        }
    }

    if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
        Key_Cnt[0]++;
    }
    else
    {
        Key_Cnt[0] = 0;
    }

    if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
        Key_Cnt[1]++;
    }
    else
    {
        Key_Cnt[1] = 0;
    }

    if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
    {
        Key_Cnt[2]++;
    }
    else
    {
        Key_Cnt[2] = 0;
    }

    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
        Key_Cnt[3]++;
    }
    else
    {
        Key_Cnt[3] = 0;
    }
}

         这里用for循环用来判断按键4是否长按,如果i>3则触发长按,

void Key_Handler(void *argument)
{
  /* USER CODE BEGIN Key_Handler */
  uint32_t online_cnt = 0;
  /* Infinite loop */
  for (;;)
  {
    Key_Scan();//扫描按键
    for (uint8_t i = 0; i < 4; i++)
    {
      if (Key_IsUp(i))
      {
        osMessageQueuePut(Key_QueueHandle, &i, 0, 0);//触发短按条件,B1-4对应数字0-3
      }
      if (Key_IsLongPress(i))
      {
        uint8_t j = i + 4;
        osMessageQueuePut(Key_QueueHandle, &j, 0, 0);//触发长按条件,B1-4对应数字4-7
      }
    }

    osDelayUntil((online_cnt + 1) * 25);//扫描周期粗略为25ms
    online_cnt++;
  }
  /* USER CODE END Key_Handler */
}

        2.2.3 PWM信号输出控制

        由题目知道,电压处于0-3V之间,占空比同时随着电压变换。(只展示部分核心代码)

void PWM_Handler(void *argument)
{
  /* USER CODE BEGIN PWM_Handler */
  uint32_t online_cnt = 0;
  /* Infinite loop */
  for (;;)
  {
    if (Generator_DutyLock == 0)//未启用占空比锁
    {//根据题目实时修改占空比(介于10-85%之间)
      if (R1_Vol < 1.0f)
      {
        Generator_PWMDuty = 0.1f;
      }
      else if (R1_Vol >= 3.0f)
      {
        Generator_PWMDuty = 0.85f;
      }
      else
      {
        Generator_PWMDuty = -0.275f + R1_Vol * 0.375f;
      }
    }//上锁则保持原有占空比不变

    Timer_PWMSetDuty(Generator_PWMDuty);//控制占空比
    Timer_PWMSetFreq(Generator_Freq);//控制频率

    Generator_Speed = (IC_Freq * 2 * 3.14f * Generator_R) / 100 / Generator_K;//根据PA7输入频率,计算得到“速度”。
    switch (Generator_FreqMode)//0为低频率模式,1为高频率模式
    {
    case 0:
      if (Generator_Speed > MaxSpeed_LowFreq && !osTimerIsRunning(Lspeed_UpdateTimerHandle))
      {//发现现有速度高于记录的低频率最高速度,且低频率最高速度更新定时器未启动
        osTimerStart(Lspeed_UpdateTimerHandle, 2000U);//启动更新定时器,准备2s后更新低频率最高速度
      }
      else if (Generator_Speed <= MaxSpeed_LowFreq && osTimerIsRunning(Lspeed_UpdateTimerHandle))
      {//发现现有速度已经低于记录的低频率最高速度,且低频率最高速度更新定时器已经启动
        osTimerStop(Lspeed_UpdateTimerHandle);//不必再更新低频率最高速度,停止更新定时器
      }
      break;
    case 1://高频率部分道理同上
      if (Generator_Speed > MaxSpeed_HighFreq && !osTimerIsRunning(Hspeed_UpdateTimerHandle))
      {
        osTimerStart(Hspeed_UpdateTimerHandle, 2000U);
      }
      else if (Generator_Speed <= MaxSpeed_HighFreq && osTimerIsRunning(Hspeed_UpdateTimerHandle))
      {
        osTimerStop(Hspeed_UpdateTimerHandle);
      }
      break;
    default:
      break;
    }

    uint8_t info = 0;
    if (osMessageQueueGet(PWM_Signal_QueueHandle, &info, 0, 0) == osOK)//收到LCD控制任务下发的频率切换指令
    {
      Generator_KeyLock = 1;//锁定B2按键
      Generator_FreqShifting = Generator_FreqShifting ? 0 : 1;//此时高频则改为低频(1->0),此时低频则改为高频(0->1)
      osTimerStart(PWM_Signal_TimerHandle, 100U);//启动频率修改定时器(0.1s刷新一次)
    }

    osDelayUntil((online_cnt + 1) * 10);//整个PWM控制任务大概执行一次,延时10ms
    online_cnt++;
  }
  /* USER CODE END PWM_Handler */
}
void PWM_Signal_CB(void *argument)
{
  /* USER CODE BEGIN PWM_Signal_CB */
  //频率修改定时器回调函数(0.1s触发一次)
  if (Generator_FreqShifting)//切换目标是高频还是低频
  {
    Generator_Freq += (Generator_HFreq - Generator_LFreq) / 50;//单个周期(0.1s)增加80HZ,5s后正好为8KHZ
  }
  else
  {
    Generator_Freq -= (Generator_HFreq - Generator_LFreq) / 50;//单个周期(0.1s)减少80HZ,5s后正好为4KHZ
  }
  LED_Toggle(1);//LD1以0.1s为周期闪烁
  if (Generator_FreqShifting && Generator_Freq >= Generator_HFreq)
  {//低频切高频时PWM频率增加后已经超过了8KHZ,也即切换5s之后
    Generator_FreqMode = Generator_FreqShifting;//现在的频率模式更新为高频
    Generator_ShiftNum++;//PWM切换次数加一
    Generator_Freq = Generator_HFreq;//现在的频率和最高频率对齐
    Generator_KeyLock = 0;//按键B2解锁
    LED_Ctrl(1, 0);//熄灭LD1
    osTimerStop(PWM_Signal_TimerHandle);//完成任务,停止定时器
  }
  if (!Generator_FreqShifting && Generator_Freq <= Generator_LFreq)
  {//高频切低频时PWM频率减少后已经低于4KHZ,也即切换5s之后
    Generator_FreqMode = Generator_FreqShifting;//现在的频率模式更新为低频
    Generator_ShiftNum++;//PWM切换次数加一
    Generator_Freq = Generator_LFreq;//现在的频率和最低频率对齐
    Generator_KeyLock = 0;//按键B2解锁
    LED_Ctrl(1, 0);//熄灭LD1
    osTimerStop(PWM_Signal_TimerHandle);//完成任务,停止定时器
  }
  //注意该定时器为周期性定时器(osTimerPeriodic),完成切换后需要手动终止定时器
  /* USER CODE END PWM_Signal_CB */
}

         

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

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

相关文章

【从零开始学Skynet】基础篇(二):了解Skynet

1、节点和服务 在下图所示的服务端系统中&#xff0c;每个Skynet进程&#xff08;操作系统进程&#xff09;都称为一个节点&#xff0c;每个节点都可以开启数千个Lua服务&#xff0c;每个服务都是一个Actor。不同节点可以部署在不同的物理机上&#xff0c;提供分布式集群的能力…

Velocity入门到精通(上篇)

最近自己所做的项目使用到这个Velocity模板引擎&#xff0c;分享一下在互联网找的学习资料。 目录 一. velocity简介 1. velocity简介 2. 应用场景 3. velocity 组成结构 二. 快速入门 1. 需求分析 2. 步骤分析 3. 代码实现 3.1 创建maven工程 3.2 引入坐标 3.3 编…

Redis锁的租约问题

目录Redis的租约问题Redis租约问题的想法Redis租约问题的解决方案Redis的租约问题 首先我们先来说一说什么是Redis的租约问题。   在我们实现Redis分布式锁的时候&#xff0c;我们会出现Redis锁的时间<业务执行执行时间&#xff0c;这其实就是一个典型的租约问题&#xf…

【C++】你了解命名空间吗?

C语言之父&#xff1a;Bjarne Stroustrup博士(本贾尼) 当我们在编写代码的时候&#xff0c;可能会产生一些命名冲突&#xff0c;为了解决这一冲突我们引出命名空间的概念 (ps:命名冲突的产生主要包括两个方面原因&#xff1a;1、与库函数名冲突&#xff1b;2、相互之间的冲突&…

【LeetCode】剑指 Offer 51. 数组中的逆序对 p249 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/ 1. 题目介绍&#xff08;51. 数组中的逆序对&#xff09; 在数组中的两个数字&#xff0c;如果前面一个数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。输入一个数组&#xf…

python3 DataFrame一些好玩且高效的操作

pandas在处理Excel/DBs中读取出来&#xff0c;处理为DataFrame格式的数据时&#xff0c;处理方式和性能上有很大差异&#xff0c;下面是一些高效&#xff0c;方便处理数据的方法。 map/apply/applymaptransformagg遍历求和/求平均shift/diff透视表切片&#xff0c;索引&#x…

VS Code 将推出更多 AI 功能给 Java 开发者

大家好&#xff0c;欢迎来到我们的二月更新&#xff01;我们将为您带来与 JUnit 5 并行测试相关的新功能以及用于 Spring Boot Dashboard 的过滤功能。另外&#xff0c;OpenAI 和 ChatGPT 是最近的热点&#xff0c;所以在 GitHub Copilot 方面也有一些令人激动的消息&#xff0…

【郭东白架构课 模块二:创造价值】19|节点二:架构活动的目标为什么常常被忽略?

你好&#xff0c;我是郭东白。从这节课开始&#xff0c;我们就进入到架构活动第二个环节的学习&#xff0c;那就是目标确认。 为架构活动确认一个正确目标&#xff0c;是架构师能为架构活动做出最大贡献的环节。从我的个人经验来看&#xff0c;一大半架构活动的目标都不具备正…

类文件具有错误的版本 55.0, 应为 52.0

最近在编译时报如下错误 java: 无法访问com.xx错误的类文件: /xxx.jar!/aa.class类文件具有错误的版本 55.0, 应为 52.0请删除该文件或确保该文件位于正确的类路径子目录中。 原来我依赖的jar包的编译版本是jdk11,而我本地代码编译的版本的jdk1.8,两个版本不一致&#xff0c;所…

C++类和对象终章——友元函数 | 友元类 | 内部类 | 匿名对象 | 关于拷贝对象时一些编译器优化

文章目录&#x1f490;专栏导读&#x1f490;文章导读&#x1f337;友元&#x1f33a;概念&#x1f33a;友元函数&#x1f341;友元函数的重要性质&#x1f33a;友元类&#x1f341;友元类的重要性质&#x1f337;内部类&#xff08;不常用&#xff09;&#x1f33a;内部类的性…

Ubuntu 下载并切换Python默认版本(无痛顺畅版)

Ubuntu 下载并切换Python默认版本的方法 文章目录Ubuntu 下载并切换Python默认版本的方法一&#xff0c;前言二&#xff0c;在ubantu中下载指定python版本1&#xff0c;更新apt版本为最新2&#xff0c;安装software-properties-common3&#xff0c;将 deadsnakes PPA 添加到你的…

并发 并行 进程 线程

并发 并行 进程 线程 进程和线程介绍 程序、进程和线程的关系示意图 并发和并行 1)多线程程序在单核上运行&#xff0c;就是并发 2)多线程程序在多核上运行&#xff0c;就是并行 示意图: 小结

大模型时代的“Linux”生态,开启人工智能新十年

演讲 | 林咏华 智源人工智能研究院副院长 整理 | 何苗出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;2018 年以来&#xff0c;超大规模预训练模型的出现推动了 AI 科研范式从面向特定应用场景、训练专有模型&#xff0c;转变为大模型微调模型服务的AI工业化开…

016 - 如何写一个 C++ 类

到目前为止&#xff0c;我们学了类 class&#xff0c;本期我们要尝试着从头开始写一个类。 本期不会讲的太深。我们不会写非常复杂的类&#xff0c;我们要会完成一个基本的 log 类&#xff0c;来演示一下我们已经学过的相关知识。 接下来的几期&#xff0c;我们会继续学习类。…

银行数字化转型导师坚鹏:《银行业金融机构数据治理指引》

《银行业金融机构数据治理指引》 ——“监”听则明 护航银行高质量发展课程背景&#xff1a; 很多金融机构存在以下问题&#xff1a; 不清楚《银行业金融机构数据治理指引》出台背景&#xff1f; 不知道如何理解《银行业金融机构数据治理指引》相关规定&#xff1f; 不清楚…

重生之我是孔乙己——查找数组缺失元素的几种方法

&#x1f48c; 博客内容&#xff1a;查找缺失元素 &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准前端&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家&#xff1a;这里是…

【MySQL | 基础篇】03、MySQL 约束

目录 一、概述 二、约束演示 三、外键约束 3.1 介绍 3.2 语法 3.3 删除/更新行为 一、概述 概念: 约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 目的&#xff1a;保证数据库中数据的正确、有效性和完整性。 分类&#xff1a; 注意&#xff1a…

千耘农机导航的“星地一体”能力究竟是什么?

伴随农业机械化和智能化的发展&#xff0c;越来越多的人开始使用农机自动驾驶系统助力耕作&#xff0c;千耘农机导航的“星地一体”能力可有效解决信号受限的问题&#xff0c;实现作业提效。究竟什么是“星地一体”&#xff0c;又是如何解决智能化农机作业的痛点的&#xff1f;…

CTFHub | 00截断

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

Java模拟星空

目录 前言 JavaFX基础 1. GraphicsContext 2. AnimationTimer 代码实现 完整代码 前言 看了Python模拟星空很漂亮&#xff0c;Java也应该必须有一个&#xff01; 环境&#xff1a;只需要JDK1.8就好&#xff01;不需要外部包&#xff01;&#xff01;&#xff01; Jav…