蓝桥杯嵌入式学习笔记
用博客来记录一下参加蓝桥杯嵌入式第十六届省赛的学习经历
- 工具
- 环境准备
- cubemx配置
- 外部高速时钟使能
- 设置串口
- 时钟配置
- 项目配置
- keil配置
- 烧录方式
- 注意
- 代码规范
- 头文件配置
- 模块
- led
- cubemx配置
- keil代码
- 实现点亮一只灯
- 实现具体操作的灯,以及点亮还是熄灭
- 按键
- cubemx配置
- keil代码
- LCD
- keil代码
- 引脚冲突问题
- LED闪烁
- cubemx配置
- keil代码
- 按键长按
- cubemx配置
- keil代码
- LCD高亮显示
- keil代码
- PWM输出
- 计算公式
- cubemx配置
- keil代码
- 输入捕获测量引脚输出PWM波周期
- 原理图
- 要求:用PA7来测量PA1生成PWM波的频率
- cubemx配置
- keil代码
- 输入捕获测量555定时器频率
- 原理图
- cubemx配置
- keil代码
- ADC测量
- 原理图
- cubemx配置
- keil代码
- 串口发送和接收
- 原理图
- cubemx配置
- keil代码
- 利用定时器进行串口不定长数据接收
- 原理
- cubemx配置
- keil代码
- EEPROM读写
- 原理
- keil代码
工具
keil5,stm32cube
环境准备
根据赛事方提供的板子来选择cubemx上的器件

cubemx配置
外部高速时钟使能

设置串口

时钟配置
时钟配置为24MHZ因为外部晶振为24MHZ,其余的暂时不清楚原因

项目配置
配置为MDK
需要注意,固件地址需要设置为下载解压后的文件地址(提前从数据包中下载)

勾选生成.c.h文件

注意一下,下载好软件后,要解压固件包,然后在help中设置地址

keil配置
烧录方式

烧录设置

要是没有芯片包,需要从赛事数据包中解压,会自动生成

keil代码自动补全
点击edit,configraution选择跟编译相关的Text Completion,然后勾线第三个

注意
代码需要写入begin - end之间
代码规范
新建code文件夹
右键CMSIS,点击Manage Project,新建一个文件夹

点击魔术棒,c++,include path,添加文件夹路径

然后添加fun.c,fun.h,headfile.h 三个文件
头文件可能显示不出来,所以需要添加existing file 再勾选all file,即可添加
头文件配置
headfile.h

fun.h

fun.c

main.c

模块
led

通过观察开发板led电路图可以发现,led的的引脚控制由PC8~15低电平点亮,同时PD2锁存器控制开关,需要置高电平
cubemx配置
将PC8~15设置为输出,PD2设置为输出
在GPIO配置中,将引脚全部配置为高电平,使得上电时LED灭

keil代码
实现点亮一只灯
fun.c主要代码
void led_show()
{HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}
fun.h代码
void led_show(void);
main.c代码(需要在主函数内)
led_show();
实现具体操作的灯,以及点亮还是熄灭
fun.c代码
void led_show(uint8_t led, uint8_t mode)
{HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);if(mode)HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 << (led - 1), GPIO_PIN_RESET); //GPIO_PIN_8的二进制代码为0000 0001 0000 0000 GPIO_PIN_9的二进制代码为0000 0010 0000 0000,所以用左移移位符elseHAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 << (led - 1), GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}
fun.h代码(需要加上那个头函数)
#include "stm32g4xx.h" // Device headervoid led_show(uint8_t led, uint8_t mode);
main.c代码(灯1, 4,8亮)
led_show(1, 1);led_show(4, 1);led_show(8, 1);
按键
原理图,如图,需要将PB0~2,PA0配置为上拉输入模式。按下为低电平,松开为高电平

cubemx配置

keil代码
fun.c代码
void key_scan()
{B1_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);B2_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);B3_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);B4_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);if(B1_state == 0 && B1_last_state == 1)//°´¼üB1°´ÏÂ{led_show(1, 1);}if(B2_state == 0 && B2_last_state == 1)//°´¼üB1°´ÏÂ{led_show(1, 0);}if(B3_state == 0 && B3_last_state == 1)//°´¼üB1°´ÏÂ{led_show(2, 1);}if(B4_state == 0 && B4_last_state == 1)//°´¼üB1°´ÏÂ{led_show(2, 0);}B1_last_state = B1_state;B2_last_state = B2_state;B3_last_state = B3_state;B4_last_state = B4_state;}
fun.h代码
void key_scan(void);//里面没有这个void会有waring,但影响似乎不大
main.c代码
同样放入while循环中

LCD
首先在赛事方提供的数据包中找到液晶驱动参考程序,HAL库版本,找到lcd.c,font.h,lcd,h,复制到code文件夹,打开keil工程文件,添加这三个文件

初始准备
main.c函数

headfile.h函数

keil代码
实现了在第一行显示字符,按键按下时,第三行数字变化的功能
fun.c代码
#include "headfile.h"int count = 0;void led_show(uint8_t led, uint8_t mode)
{HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);if(mode)HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 << (led - 1), GPIO_PIN_RESET);elseHAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 << (led - 1), GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}uint8_t B1_state;
uint8_t B1_last_state;
uint8_t B2_state;
uint8_t B2_last_state;
uint8_t B3_state;
uint8_t B3_last_state;
uint8_t B4_state;
uint8_t B4_last_state;void key_scan()
{B1_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);B2_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);B3_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);B4_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);if(B1_state == 0 && B1_last_state == 1)//°´¼üB1°´ÏÂ{count ++;}if(B2_state == 0 && B2_last_state == 1)//°´¼üB1°´ÏÂ{count --;}if(B3_state == 0 && B3_last_state == 1)//°´¼üB1°´ÏÂ{led_show(2, 1);}if(B4_state == 0 && B4_last_state == 1)//°´¼üB1°´ÏÂ{led_show(2, 0);}B1_last_state = B1_state;B2_last_state = B2_state;B3_last_state = B3_state;B4_last_state = B4_state;}char text[20]; //linemax = 20void lcd_show()
{sprintf(text, "zlfsgdsg");//¿ÉÒÔµ÷Õû×Ö·û´®Î»Ö㬵«ÊÇ×î¶à20¸ö×Ö·ûLCD_DisplayStringLine(Line0, (uint8_t *)text);sprintf(text, " count: %d ", count);LCD_DisplayStringLine(Line3, (uint8_t *)text);}
fun.h代码
#ifndef _fun_h
#define _fun_h#include "stm32g4xx.h" // Device headervoid led_show(uint8_t led, uint8_t mode);void key_scan(void);void lcd_show(void);#endif
main.c代码

引脚冲突问题
lcd和led的引脚有冲突

解决办法:将PD2引脚提前置低电平,这样数据就不能传入led,led就不会点亮了,但是下次点亮led时依旧会出现这样的问题,所以需要将所有用到的LCD.C函数加上
uint16_t temp = GPIOC->ODR;
GPIOC->ODR = temp;
解决方法如下
main.c (在初始化部分)
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
lcd.c (部分代码)


问题成功解决!
LED闪烁
两个重要参数:PSC,ARR
其中系统频率f为80MHZ,如果要让T=1,则可令ARR = 9999,PSC = 7999;即可确定定时周期为1

初始化
在headfile.h文件中添加tim.h文件头

main.c

cubemx配置
需要配置定时器,正常使用通用定时器TIM2即可,重点是修改PSC和ARR


生成代码后可发现多了tim.c函数,找到stm32g4xx_hal_tim.h文件里面的call_back回调函数

将其复制到fun.c中
keil代码
在fun.c中定义一个变量
uint8_t led_mode;

按键长按
原理,用一个计数器cnt(取10000)计时1s,20000对应2s,5000对应0.5s来计时,达到识别按键长按的目的
cubemx配置
此时TIM3不使能!!

keil代码
fun.c代码
uint8_t B1_state;
uint8_t B1_last_state;
uint8_t B2_state;
uint8_t B2_last_state;
uint8_t B3_state;
uint8_t B3_last_state;
uint8_t B4_state;
uint8_t B4_last_state;void key_scan()
{B1_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);B2_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);B3_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);B4_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);if(B1_state == 0 && B1_last_state == 1)//°´¼üB1°´ÏÂ{TIM3->CNT = 0;}else if(B1_state == 0 && B1_last_state == 0) //°´¼üB1Ò»Ö±°´ÏÂ{if(TIM3->CNT >= 10000)//°´¼üB1³¤°´{count++;}}else if (B1_state == 1 && B1_last_state == 0)//°´¼üB1ËÉ¿ª{if(TIM3->CNT < 10000)//°´¼üB1¶Ì°´{count += 2;}}if(B2_state == 0 && B2_last_state == 1)//°´¼üB1°´ÏÂ{count --;}if(B3_state == 0 && B3_last_state == 1)//°´¼üB1°´ÏÂ{led_show(2, 1);}if(B4_state == 0 && B4_last_state == 1)//°´¼üB1°´ÏÂ{led_show(2, 0);}B1_last_state = B1_state;B2_last_state = B2_state;B3_last_state = B3_state;B4_last_state = B4_state;}
main.c代码
需要注意!给TIM3使能,但因为不是中断,是定时器,所以不用IT

LCD高亮显示
其实就是调用 LCD_SetBackColor(Color);这个函数,把背景颜色改成黄色
keil代码
定义变量
uint8_t lcd_highshow;
按键b1按下时
lcd_highshow ++;lcd_highshow %= 3;
逻辑流程
应该蛮简单的,就不写注释了
void lcd_show()
{sprintf(text, "zlfsgdsg");//¿ÉÒÔµ÷Õû×Ö·û´®Î»Ö㬵«ÊÇ×î¶à20¸ö×Ö·ûLCD_DisplayStringLine(Line0, (uint8_t *)text);if(lcd_highshow == 0){LCD_SetBackColor(Yellow);sprintf(text, " count: %d ", count);LCD_DisplayStringLine(Line3, (uint8_t *)text);LCD_SetBackColor(Black);sprintf(text, " txysgdmn ");LCD_DisplayStringLine(Line4, (uint8_t *)text);sprintf(text, " baozi ");LCD_DisplayStringLine(Line5, (uint8_t *)text); }else if(lcd_highshow == 1){sprintf(text, " count: %d ", count);LCD_DisplayStringLine(Line3, (uint8_t *)text);LCD_SetBackColor(Yellow);sprintf(text, " txysgdmn ");LCD_DisplayStringLine(Line4, (uint8_t *)text);LCD_SetBackColor(Black);sprintf(text, " baozi ");LCD_DisplayStringLine(Line5, (uint8_t *)text); }
PWM输出
一般要求:让PA1输出频率为1000HZ,占空比为50%的方波
计算公式

cubemx配置

keil代码
在生成代码后,发现一个问题:文件中没有头文件!
后面找到解决办法, 编译之后,就能知道每个文件依赖于哪些头文件!还是第一次遇到这种问题
先在main.c函数中将定时器使能
这个函数在头文件里找–stm32g4xx_hal_tim.h
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
设置占空比
TIM2->CCR2 = 50;
原理图(抄袭版),不懂的话看嵌入式的书去

输入捕获测量引脚输出PWM波周期
原理图

要求:用PA7来测量PA1生成PWM波的频率
需要用杜邦线连接PA7和PA1.
cubemx配置
这里PA7用TIM17或者TIM2都行,我就根据视频来了

使能定时器

keil代码
为了省事,将code文件复制到这个工程目录下,记得在main.c文件中添加头文件定义

main.c函数
使能中断17
HAL_TIM_IC_Start_IT(&htim17, TIM_CHANNEL_1);
fun.c代码
参考着原理图一起理解
#include "headfile.h"char text[20]; uint32_t fre, capture_value;void lcd_show()
{sprintf(text, "zlfsgdsg");//¿ÉÒÔµ÷Õû×Ö·û´®Î»Ö㬵«ÊÇ×î¶à20¸ö×Ö·ûLCD_DisplayStringLine(Line0, (uint8_t *)text);sprintf(text, " fre:%d ", fre);LCD_DisplayStringLine(Line3, (uint8_t *)text);}void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM17){capture_value = TIM17->CCR1;TIM17->CNT = 0;fre = 80000000/(80*capture_value);}}
main.c代码
注意不要忘记了给LCD初始化
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);TIM2->CCR2 = 50;HAL_TIM_IC_Start_IT(&htim17, TIM_CHANNEL_1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){lcd_show();/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
输入捕获测量555定时器频率
实现效果:能测量出两个信号发生器输出的PWM波的频率,两个频率可以通过R39,和R40调节
原理图

cubemx配置
将PA15设置为TIM2_CH1,PB4设置为TIM16_CH1;
分别将两个定时器设置为输入捕获模式,PCC设置为80-1,并且使能


keil代码
main.c
需要注意,不要忘记了LCD初始化,不要忘记了中断使能,不要忘记了把lcd_show函数放到循环里
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(&htim16, TIM_CHANNEL_1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){lcd_show();/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
&&& 不要忘记了添加头文件!
#include "headfile.h"
fun.c函数
具体逻辑,我现在看是蛮简单的,不管了,吃饭去了,自己悟去吧
#include "headfile.h"char text[20]; uint32_t fre1, capture_value1, fre2, capture_value2 ;void lcd_show()
{sprintf(text, "zlfsgdsg");//¿ÉÒÔµ÷Õû×Ö·û´®Î»Ö㬵«ÊÇ×î¶à20¸ö×Ö·ûLCD_DisplayStringLine(Line0, (uint8_t *)text);sprintf(text, " R39_fre1:%d ", fre1);LCD_DisplayStringLine(Line2, (uint8_t *)text);sprintf(text, " R40_fre2:%d ", fre2);LCD_DisplayStringLine(Line4, (uint8_t *)text);}void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM16)// R39{capture_value1 = TIM16->CCR1;TIM16->CNT = 0;fre1 = 80000000/(80*capture_value1);}if(htim->Instance == TIM2)//R40{capture_value2 = TIM2->CCR1;TIM2->CNT = 0;fre2 = 80000000/(80*capture_value2);}}
ADC测量
原理图
通过R37和R38两个旋钮,测量AD的电压值

cubemx配置
分别对引脚PB15和PB12进行配置。


keil代码
记得在headfile.h文件中添加ADC头文件

fun.c代码
#include "headfile.h"char text[20];
void lcdshow()
{sprintf(text, " zlfsgdsg ");LCD_DisplayStringLine(Line0, (uint8_t *)text);HAL_ADC_Start(&hadc1); uint32_t adc_value = HAL_ADC_GetValue(&hadc1); //R38sprintf(text, " value:%d ", adc_value);LCD_DisplayStringLine(Line3, (uint8_t *)text);}
main.c
记得将LCD初始化,然后在主函数中调用lcdshow();

即可在lcd中实时读取adc1的值
keil代码2
若是要读取两个ad的电压值
fun.c代码
#include "headfile.h"char text[20];
void lcdshow()
{sprintf(text, " zlfsgdsg ");LCD_DisplayStringLine(Line0, (uint8_t *)text);sprintf(text, " R37_volt:%.2f ", get_vol(&hadc2));LCD_DisplayStringLine(Line3, (uint8_t *)text);sprintf(text, " R38_volt:%.2f ", get_vol(&hadc1));LCD_DisplayStringLine(Line5, (uint8_t *)text);}double get_vol(ADC_HandleTypeDef *hadc)
{HAL_ADC_Start(hadc); uint32_t adc_value = HAL_ADC_GetValue(hadc); //R38return 3.3*adc_value/4096; //因为AD是12位,所以ad最大值是4096}
fun.h
void lcdshow(void);double get_vol(ADC_HandleTypeDef *hadc);
串口发送和接收
原理图

cubemx配置


keil代码
串口发送
main.c代码
记得在前面添加头文件
while (1){char text01[20];sprintf(text01, "zlfsgdgs\r\n");HAL_UART_Transmit(&huart1, (uint8_t *)text01, sizeof(text01), 50);HAL_Delay(1000);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
串口接收
fun.c代码
#include "headfile.h"uint8_t rec_data;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){HAL_UART_Transmit(huart, &rec_data, 1, 50);HAL_UART_Receive_IT(huart, &rec_data, 1);}}
fun.h代码
加一个外部变量定义
extern uint8_t rec_data;
main.c代码

利用定时器进行串口不定长数据接收
原理

cubemx配置
主要是把波特率设置为9600


keil代码
main.c
把定时器使能!!!&&调用函数

fun.c函数
#include "headfile.h"char send_buff[20];
uint8_t rec_data, count;
uint8_t rec_flag;
uint8_t rec_buff[20];void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){//HAL_UART_Transmit(huart, &rec_data, 1, 50);TIM4->CNT = 0;rec_flag = 1;rec_buff[count] = rec_data;count ++;HAL_UART_Receive_IT(huart, &rec_data, 1);}}void uart_data_rec()
{if(rec_data){if(TIM4->CNT > 15){if(rec_buff[0] == 'z' && rec_buff[1] == 'l' && rec_buff[2] == 'f'){sprintf(send_buff, "zlf\r\n");HAL_UART_Transmit(&huart1, (uint8_t *)send_buff, sizeof(send_buff), 50);}else if(rec_buff[3] == 's' && rec_buff[4] == 'g' && rec_buff[5] == 'd'){sprintf(send_buff, "sgd\r\n");HAL_UART_Transmit(&huart1, (uint8_t *)send_buff, sizeof(send_buff), 50);}else if(rec_buff[6] == 's' && rec_buff[7] == 'g'){sprintf(send_buff, "sgd\r\n");HAL_UART_Transmit(&huart1, (uint8_t *)send_buff, sizeof(send_buff), 50);}else{sprintf(send_buff, "error\r\n");HAL_UART_Transmit(&huart1, (uint8_t *)send_buff, sizeof(send_buff), 50);}rec_flag = 0;for(int i=0; i<count; i++)rec_buff[i] = 0;count = 0;}}}
fun.h

headfile.h
要添加usart.h的头文件

EEPROM读写
原理
原理就不说了,学嵌入式I2C的时候学了挺久
keil代码
i2c_hal_c
void eeprom_write(uint8_t addr, uint8_t data)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CSendByte(data);I2CWaitAck();I2CStop();HAL_Delay(20);}uint8_t eeprom_read(uint8_t addr)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0xa1);I2CWaitAck();uint8_t data = I2CReceiveByte();I2CSendNotAck();I2CStop();return data;
}
i2c_hal_h代码
主要就是添加两个文件
void eeprom_write(uint8_t addr, uint8_t data);
uint8_t eeprom_read(uint8_t addr);
main.c代码

相关文章:
蓝桥杯嵌入式学习笔记
用博客来记录一下参加蓝桥杯嵌入式第十六届省赛的学习经历 工具环境准备cubemx配置外部高速时钟使能设置串口时钟配置项目配置 keil配置烧录方式注意代码规范头文件配置 模块ledcubemx配置keil代码实现点亮一只灯实现具体操作的灯,以及点亮还是熄灭 按键cubemx配置k…...
zookeeper详细介绍以及使用
Zookeeper 是一个开源的分布式协调服务,提供了一个高效的分布式数据一致性解决方案。它的主要作用是维护集群中各个节点之间的状态信息,协调节点之间的工作,并处理节点宕机等故障情况。Zookeeper 的核心功能包括数据发布/订阅、分布式锁、集群…...
Blender多摄像机怎么指定相机渲染图像
如题目所说,当blender的场景里面有摄像机的时候,按F12可以预览渲染结果,但是当有多个摄像机的时候就不知道使用哪个进行渲染了。 之前在网上没有找到方法,就用笨方法,把所有的摄像机删除,然后设置自己需要…...
Redis场景问题1:缓存穿透
Redis 缓存穿透是指在缓存系统(如 Redis)中,当客户端请求的数据既不在缓存中,也不在数据库中时,每次请求都会直接穿透缓存访问数据库,从而给数据库带来巨大压力,甚至可能导致数据库崩溃。下面为…...
CSS 如何设置父元素的透明度而不影响子元素的透明度
CSS 如何设置父元素的透明度而不影响子元素的透明度 在 CSS 中,设置父元素的透明度(如通过 opacity 属性)会影响所有子元素的透明度,因为 opacity 是作用于整个元素及其内容的。如果想让父元素透明但不影响子元素的透明度&#x…...
Java的string默认值
在Java中,String类型的默认值取决于其定义和实例化的方式。 以下是关于String默认值的详细说明 未实例化的String变量 如果定义一个String变量但未对其进行实例化(即未使用new关键字或直接赋值),其默认值为:ml-search[null]。这…...
从 MySQL 到时序数据库 TDengine:Zendure 如何实现高效储能数据管理?
小T导读:TDengine 助力广州疆海科技有限公司高效完成储能业务的数据分析任务,轻松应对海量功率、电能及输入输出数据的实时统计与分析,并以接近 1 : 20 的数据文件压缩率大幅降低存储成本。此外,taosX 强大的 transform 功能帮助用…...
观察者模式:解耦对象间的依赖关系
观察者模式:解耦对象间的依赖关系 JDK 中曾直接提供对观察者模式的支持,但因其设计局限性,现已被标记为“过时”(Deprecated)。不过,观察者模式的思想在 JDK 的事件处理、spring框架等仍有广泛应用。下面我…...
windows第二十章 单文档应用程序
文章目录 单文档定义新建一个单文档应用程序单文档应用程序组成:APP应用程序类框架类(窗口类)视图类(窗口类,属于框架的子窗口)文档类(对数据进行保存读取操作) 直接用向导创建单文档…...
通信协议之串口
文章目录 简介电平标准串口参数及时序USART与UART过程引脚配置 简介 点对点,只能两设备通信只需单向的数据传输时,可以只接一根通信线当电平标准不一致时,需要加电平转换芯片(一般从控制器出来的是信号是TTL电平)地位…...
Java入门知识总结——章节(二)
ps:本章主要讲数组、二维数组、变量 一、数组 数组是一个数据容器,可用来存储一批同类型的数据 🔑:注意 类也可以是一个类的数组 public class Main {public static class Student {String name;int age; // 移除 unsignedint…...
Verilog 中寄存器类型(reg)与线网类型(wire)的区别
目录 一、前言 二、基本概念与分类 1.寄存器类型 2.线网类型 三、六大核心区别对比 四、使用场景深度解析 1.寄存器类型的典型应用 2. 线网类型的典型应用 五、常见误区与注意事项 1. 寄存器≠物理寄存器 2.未初始化值陷阱 3.SystemVerilog的改进 六、总结 …...
基于华为设备技术的端口类型详解
以下是基于华为设备技术网页的端口类型详解(截至2025年3月): 一、Access端口 定义:仅允许单个VLAN通过,用于连接终端设备(如PC、打印机) 处理流程: 接收帧:未带标签…...
DFS飞机降落
问题描述 NN 架飞机准备降落到某个只有一条跑道的机场。其中第 ii 架飞机在 TiTi 时刻到达机场上空,到达时它的剩余油料还可以继续盘旋 DiDi 个单位时间,即它最早可以于 TiTi 时刻开始降落,最晚可以于 TiDiTiDi 时刻开始降落。降落…...
Scikit-learn全攻略:从入门到工业级应用
Scikit-learn全攻略:从入门到工业级应用 引言:Scikit-learn在机器学习生态系统中的核心地位 Scikit-learn作为Python最受欢迎的机器学习库,已成为数据科学家的标准工具集。根据2023年Kaggle调查报告,超过83%的数据专业人士在日常工作中使用Scikit-learn。本文将系统性地介…...
Business Trip and Business Travel
Business Trip and Business Travel References Background I would like to introduce the background. Dave is going on a business trip, but he’s very busy, so he needs Leo’s help to buy the plane ticket. Panda is an agent of China Eastern /ˈiːstərn/ Airl…...
【Linux加餐-验证UDP:TCP】-windows作为client访问Linux
一、验证UDP-windows作为client访问Linux UDP client样例代码 #include <iostream> #include <cstdio> #include <thread> #include <string> #include <cstdlib> #include <WinSock2.h> #include <Windows.h>#pragma warning(dis…...
Appium Inspector使用教程
1.下载最新版本 https://github.com/appium/appium-inspector/releases 2.本地启动一个Appium服务 若Android SDK已安装Appium服务,则在任意terminal使用appium启动服务即可 3.Appium Inspector客户端配置连接到Appium服务 Configuring and Starting a Session…...
Rust vs. Go: 性能测试(2025)
本内容是对知名性能评测博主 Anton Putra Rust vs. Go (Golang): Performance 2025 内容的翻译与整理, 有适当删减, 相关数据和结论以原作结论为准。 再次对比 Rust 和 Go,但这次我们使用的是最具性能优势的 HTTP 服务器库---Hyper,它基于 Tokio 异步运…...
第三卷:覆舟山决战(73-108回)正反人物群像
第三卷:覆舟山决战(73-108回)正反人物群像 核心矛盾:寒门称帝→权力异化→历史循环 主题:通过人物群像展现屠龙者成魔的必然性与制度压迫的永恒性 一、正派阵营(理想主义残余) 1. 檀道济&…...
JDBC的详细使用
1. JDBC概述 JDBC[Java Database Connectivity]是 Java 语言中用于连接和操作数据库的一套标准 API。它允许 Java 程序通过统一的方式与各种关系型数据库,如 MySQL、Oracle、SQL Server 等交互,执行 SQL 语句并处理结果。 1.1 JDBC原理 JDBC的核心原理…...
瑞芯微 RKrga接口 wrapbuffer_virtualaddr 使用笔记
一、源码 官方在librga中给了很多 demo 以供参考,例如 imresize 操作: /** Copyright (C) 2022 Rockchip Electronics Co., Ltd.* Authors:* YuQiaowei <cerf.yurock-chips.com>** Licensed under the Apache License, Version 2.0 (the &qu…...
【数据结构】[特殊字符] 并查集优化全解:从链式退化到近O(1)的性能飞跃 | 路径压缩与合并策略深度实战
并查集的优化 导读一、合并优化1.1 基本原理1.2 按大小合并1.3 按秩合并1.4 两种合并的区别**1.4.1 核心目标****1.4.2 数据存储****1.4.3 合并逻辑****1.4.4 树高控制****1.4.5 适用场景****1.4.6 路径压缩兼容性****1.4.7 极端案例对比****1.4.8 小结**二、查找优化2.1 路径压…...
如何在 AI 搜索引擎(GEO)霸屏曝光,快速提升知名度?
虽然大多数人仍然使用 Google 来寻找答案,但正在发生快速转变。ChatGPT、Copilot、Perplexity 和 DeepSeek 等 LLM 已成为主流。这主要是因为每个都有自己的免费和公共版本,并且总是有重大的质量改进。 许多人每天都使用这些工具来提问和搜索互联网&…...
VLAN综合实验二
一.实验拓扑: 二.实验需求: 1.内网Ip地址使用172.16.0.0/分配 2.sw1和SW2之间互为备份 3.VRRP/STP/VLAN/Eth-trunk均使用 4.所有Pc均通过DHCP获取IP地址 5.ISP只能配置IP地址 6.所有…...
Kubernetes》k8s》Containerd 、ctr 、cri、crictl
containerd ctr crictl ctr 是 containerd 的一个客户端工具。 crictl 是 CRI 兼容的容器运行时命令行接口,可以使用它来检查和调试 k8s 节点上的容器运行时和应用程序。 ctr -v 输出的是 containerd 的版本, crictl -v 输出的是当前 k8s 的版本&#x…...
SQL语句及其应用(中)(DQL语句之单表查询)
SQL语句的定义: 概述: 全称叫 Structured Query Language, 结构化查询语言, 主要是实现 用户(程序员) 和 数据库软件(例如: MySQL, Oracle)之间交互用的. 分类: DDL: 数据定义语言, 主要是操作 数据库, 数据表, 字段, 进行: 增删改查(CURD) 涉及到的关键字: create, drop, …...
如何下载主流网站的视频和音频?(支持100+网站视频下载)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、安装与升级1. 安装2. 升级到最新版3. 验证安装二、基础下载命令1. 下载视频/音频/图片2. 指定下载目录3. 自定义文件名4. 基本下载场景三、高级下载控制1. 查看视频信息(清晰度/格式)2. 选择特定清晰度下载3. 下载…...
算法题(111):k与迷宫
审题: 本题需要我们寻找迷宫中的所有出口,若有出口需要输出距离最近的出口的距离,若没有就输出-1 时间复杂度:由于边距为1,我们本题采用bfs算法,在最坏的情况下我们需要遍历所有位置,时间复杂度…...
WinForm真入门-简介
WinForm 简介 WinForm(Windows Forms)是微软基于 .NET Framework 构建的桌面应用程序开发框架,专注于快速创建具有图形用户界面(GUI)的 Windows 客户端程序。其核心以 窗体(Form)…...
