当前位置: 首页 > news >正文

蓝桥杯嵌入式开发板结构分析及功能学习笔记

目录

    • 板子结构一览
    • 时钟源分析
    • 74LS573锁存器
    • 按键输入
    • 滴答定时器 SysTick
    • 串口收发
    • LCD屏幕
    • ADC采样
    • AT24C02(EEPROM)
    • 可编程电阻
    • TIM定时器
    • 输入捕获
    • DAC

板子结构一览

主控为 **STM32G431RBT6**** 外部晶振频率为 **24MHz

IAP下载为** GD32F350C8T6**

时钟源分析

自己配置的STM32CubeMX选择的是168M的高频时钟 (Max 170MHz),并且用的是外部时钟源,晶振频率为24MHz(来自原理图),

当我解析了工程中的配置文件,时钟树配置参数如下,使用内部时钟(16MHz),并且时钟频率为80MHz

官方历程 中有一个频率校准函数,通过查询资料得知,只有在使用内部时钟的时候采用,需要将其设置为0x40,F103设置的是0x16应该不同的芯片这个值不同,是温度等环境参数动态调整的

/** @defgroup RCC_HSI_Config HSI Config* @{*/
#define RCC_HSI_OFF                    0x00000000U            /*!< HSI clock deactivation */
#define RCC_HSI_ON                     RCC_CR_HSION           /*!< HSI clock activation */
#define RCC_HSICALIBRATION_DEFAULT     0x40U                  /* Default HSI calibration trimming value */RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
**<font style="color:#DF2A3F;background-color:#FBDE28;">使用内部时钟的时候需要增加校准值,并且将其校准为0x40(STM32G4)</font>**

74LS573锁存器

74LS573为锁存器,用于复用GPIO,似的GPIO可以作为输入,同时又可以作为输出,芯片管脚图如左图所示,真值表如右图所示,大概意思是有一个管脚,如果使能后输出的结果就会和 输入同步变化,如果没有使能,就维持上一次的状态不变

OE:输出使能引脚,低电平有效

LE:寄存器使能引脚,高电平有效,为高电平时,输出为输入的状态,为低电平时保持上一次的状态

使用程序编程实现LED流水灯操作,代码如下

  HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,1);//激活74HC573的LE管脚/* USER CODE END 2 */GPIOC->ODR |= 0xff00;GPIOC->ODR &= led_sta;HAL_UART_Transmit(&huart1,(uint8_t *)hello_msg,sizeof(hello_msg),0xff);/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */
//	  HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);led_sta=0x7F00;for(uint8_t i=0;i<8;i++){led_cmd= led_sta>>i;GPIOC->ODR &= led_cmd;HAL_Delay(200);}GPIOC->ODR |= 0xff00;led_sta = 0x100;record_last=led_sta;GPIOC->ODR &=led_sta;HAL_Delay(200);for(uint8_t i=0;i<8;i++){led_cmd= led_sta<<i;led_cmd = (led_cmd | record_last);#if 0memset(data_msg,0,sizeof(data_msg));sprintf((char *)data_msg,"sta:0x%x record_last:0x%x cmd:0x%x\r\n",led_sta,record_last,led_cmd);HAL_UART_Transmit(&huart1,(uint8_t *)data_msg,strlen(data_msg),0xff);#endifGPIOC->ODR |= 0xff00;GPIOC->ODR &= led_cmd;record_last = led_cmd;HAL_Delay(200);}count++;if(count %3 != 0){memset(data_msg,0,sizeof(data_msg));sprintf((char *)data_msg,"74LS573 IS ACTIVE!\r\n");HAL_UART_Transmit(&huart1,(uint8_t *)data_msg,strlen(data_msg),0xff);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,1);//激活74HC573的LE管脚}else{memset(data_msg,0,sizeof(data_msg));sprintf((char *)data_msg,"74LS573 IS Not ACTIVE!\r\n");HAL_UART_Transmit(&huart1,(uint8_t *)data_msg,strlen(data_msg),0xff);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,0);//取消激活74HC573的LE管脚}//	  HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_9);/* USER CODE BEGIN 3 */}

实验现象

按键输入

按键输入部分的原理图如图所示,默认上拉,按下后GPIO接地,可以 通过循环 读取GPIO的状态,或者中断的方式去检查按键状态。

在实验程序中 因为公用的EXIT0 中断线 我设置了两种触发方式,一种是中断触发,需要配置其中断优先级,另外一种是通过循环扫描+消抖去读取按键的状态

/*中断的GPIO配置*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/*扫描按键的GPIO配置*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*设置中断优先级*/
HAL_NVIC_SetPriority(EXTI0_IRQn, 4, 2);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);HAL_NVIC_SetPriority(EXTI1_IRQn, 4, 3);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);HAL_NVIC_SetPriority(EXTI2_IRQn, 4, 4);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);

/*中断线的触发函数*/
/*** @brief This function handles EXTI line0 interrupt.*/
void EXTI0_IRQHandler(void)
{/* USER CODE BEGIN EXTI0_IRQn 0 *//* USER CODE END EXTI0_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);/* USER CODE BEGIN EXTI0_IRQn 1 *//* USER CODE END EXTI0_IRQn 1 */
}/*GPIO中断的回调函数*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_0){memset(send_str,0,sizeof(send_str));sprintf((char  *)send_str,"key0 is  press!\r\n");HAL_UART_Transmit(&huart1,(uint8_t *)send_str,strlen(send_str),0xff);}if(GPIO_Pin == GPIO_PIN_1){memset(send_str,0,sizeof(send_str));sprintf((char  *)send_str,"key1 is  press!\r\n");HAL_UART_Transmit(&huart1,(uint8_t *)send_str,strlen(send_str),0xff);}if(GPIO_Pin == GPIO_PIN_2){memset(send_str,0,sizeof(send_str));sprintf((char  *)send_str,"key2 is  press!\r\n");HAL_UART_Transmit(&huart1,(uint8_t *)send_str,strlen(send_str),0xff);}
}

实验现象:

滴答定时器 SysTick

串口收发

STM32的串口发送非常简单,但是串口接收的方式多种多样

  1. 使用轮训的方式接收
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  1. 使用串口中断的方式接收
  HAL_NVIC_EnableIRQ(USART1_IRQn);HAL_NVIC_SetPriority(USART1_IRQn,4,1);
uint8_t rx_dat[10]; 
HAL_UART_Receive_IT(&huart1,rx_dat,2);
/*** @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.*/
void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(&huart1);/* USER CODE BEGIN USART1_IRQn 1 */HAL_UART_Receive_IT(&huart1,rx_dat, 2);/* USER CODE END USART1_IRQn 1 */
}/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){uint16_t led_cmd = rx_dat[1] & 0x0100;HAL_UART_Transmit(&huart1,rx_dat,2,0xff);    // GPIOC->ODR |= 0xFF00;// GPIOC->ODR &= led_cmd;HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);}}
  1. 使用IDLE接收不定长的数据
	//下方为自己添加的代码__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);/*打开idle 接收中断*/HAL_UARTEx_ReceiveToIdle_IT(&huart1,rec_buf,64);void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart->Instance  == USART1){HAL_UART_Transmit(&huart1,rec_buf,Size,0xff);HAL_UARTEx_ReceiveToIdle_IT(&huart1,rec_buf,64);}
}

自定义串口打印函数,模仿printf

void MyPrintf(const char *__format, ...)
{va_list ap;va_start(ap, __format);/* 清空发送缓冲区 */memset(TxBuf, 0x0, TX_BUF_LEN);/* 填充发送缓冲区 */vsnprintf((char*)TxBuf, TX_BUF_LEN, (const char *)__format, ap);va_end(ap);int len = strlen((const char*)TxBuf);/*  */HAL_UART_Transmit(&huart2, (uint8_t*)&TxBuf, len, 0xFFFF);
}

LCD屏幕

LCD的移植程序非常简单 只需要将**lcd.c lcd.h,** 放置在代码下,在主程序中初始化LCD_Init即可,然后就可以开始调用函数去显示字符。

原理图

LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Green);
LCD_SetTextColor(Blue);
LCD_DisplayStringLine(Line1,(uint8_t *)"Hello,Harbin!");
LCD_DisplayStringLine(Line0,(uint8_t *)"LCD Test");
LCD_DisplayStringLine(Line3,(uint8_t *)"Designed By NS");
实现效果

提供的库函数如下

void LCD_Init(void);/*初始化*/
void LCD_SetTextColor(vu16 Color);/*设置文字颜色*/
void LCD_SetBackColor(vu16 Color);/*设置背景颜色*/
void LCD_ClearLine(u8 Line);/*清除某一行*/
void LCD_Clear(u16 Color);/*设置为某一种颜色*/
void LCD_SetCursor(u8 Xpos, u16 Ypos);/*设置坐标*/
void LCD_DrawChar(u8 Xpos, u16 Ypos, uc16 *c);/*显示一个字符*/
void LCD_DisplayChar(u8 Line, u16 Column, u8 Ascii);/*显示字符??*/
void LCD_DisplayStringLine(u8 Line, u8 *ptr);/*按行显示字符串*/
void LCD_SetDisplayWindow(u8 Xpos, u16 Ypos, u8 Height, u16 Width);/*设置显示区域*/
void LCD_WindowModeDisable(void);
void LCD_DrawLine(u8 Xpos, u16 Ypos, u16 Length, u8 Direction);/*画线*/
void LCD_DrawRect(u8 Xpos, u16 Ypos, u8 Height, u16 Width);/*画矩形*/
void LCD_DrawCircle(u8 Xpos, u16 Ypos, u16 Radius);/*画圆*/
void LCD_DrawMonoPict(uc32 *Pict);
void LCD_WriteBMP(u32 BmpAddress);
void LCD_DrawBMP(u32 BmpAddress);//画bmp图像
void LCD_DrawPicture(const u8* picture);//画图像

ADC采样

蓝桥杯板子的ADC接在了PB15 和PB12上,其中PB12对用的是ADC1->IN11 PB15对应的是ADC2->IN15,如果同时采样这两个ADC必须得同时使用ADC1和ADC2

/*获取ADC1 的值*/
uint16_t GetADC1(void)
{uint16_t adcVal = 0;HAL_ADC_Start(&hadc1);adcVal = HAL_ADC_GetValue(&hadc1);return adcVal;
}/*获取ADC2 的值*/
uint16_t GetADC2(void)
{uint16_t adcVal = 0;HAL_ADC_Start(&hadc2);adcVal = HAL_ADC_GetValue(&hadc2);return adcVal;
}

在主程序中需要初始化LCD并且控制了一下LED灯 因为LCD和LED共用了GPIOC的口 所以通过锁存器 提前 配置好LED的灯的状态

    LCD_Init();/*熄灭LED灯 */HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);//激活锁存器GPIOC->ODR |= 0xFF00;GPIOC->ODR &= 0xaa00;HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);LCD_Clear(White);LCD_SetBackColor(White);LCD_SetTextColor(Red);LCD_DisplayStringLine(Line0,(u8 *)"ADC Test!");LCD_SetBackColor(Blue2);LCD_SetTextColor(Black);LCD_DisplayStringLine(Line8,(u8 *)"Designed By NS.");/* USER CODE END 2 */LCD_SetBackColor(Green);/*while循环*/while (1){/* USER CODE END WHILE */memset(adc_buf,0,sizeof(adc_buf));sprintf(adc_buf,"ADC1_VAL:%.2f V",(GetADC1()*3.3)/4095);LCD_DisplayStringLine(Line5,(u8 *)adc_buf);memset(adc_buf,0,sizeof(adc_buf));sprintf(adc_buf,"ADC2_VAL:%.2f V",(GetADC2()*3.3) / 4096);LCD_DisplayStringLine(Line6 ,(u8 *)adc_buf);HAL_Delay(200);/* USER CODE BEGIN 3 */}

效果展示

AT24C02(EEPROM)

AT24C02是存储单元 通过I2C读取数据

AT24C02的 地址构成 ,高四位固定位**0xa **,底三位的A0 A1 A2决定了其后缀地址,当A0 A1 A2都为0时,设备地址为0xa0 ,同时I2C为7为地址模式,第0位决定了读还是写 0-写 1-读

读写的流程

读写的函数

/*AT24C02 Read a Byte data*/
uint8_t AT24C02_ReadByte(uint8_t addr)
{/*1.发送起始信号*/uint8_t val;I2CStart();I2CSendByte(0xA0);//地址0xA0I2CWaitAck();/*发送要读出数据的内部寄存器地址信息*/I2CSendByte(addr);I2CWaitAck();/*开始读数据*/I2CStart();I2CSendByte(0xA1);//读数据的地址I2CWaitAck();val=I2CReceiveByte();I2CWaitAck();I2CStop();return val;}
/*AT24C02 Write a byte data*/
void AT24C02_WriteByte(uint8_t addr,uint8_t data)
{/*发送起始信号*/I2CStart();I2CSendByte(0xA0);I2CWaitAck();/*发送写数据的内部寄存器的 地址*/I2CSendByte(addr);I2CWaitAck();/*发送要写入的数据*/I2CSendByte(data);I2CWaitAck();I2CStop();}

AT24C02读多个字节


/*读取读个字节*/
int AT24C02_ReadMultiBytes(uint8_t devAddr, uint8_t memAddr, uint8_t *buf, uint8_t len) {// 1. StartI2CStart();// 2. 发送设备地址(写模式) + ACK检查(设置内存地址)I2CSendByte(devAddr | 0);  // 0xA0if (I2CWaitAck() != SUCCESS) return -1;// 3. 发送内存起始地址I2CSendByte(memAddr);if (I2CWaitAck() != SUCCESS) return -2;// 4. Repeated StartI2CStart();// 5. 发送设备地址(读模式)I2CSendByte(devAddr | 1);  // 0xA1if (I2CWaitAck() != SUCCESS) return -3;// 6. 循环读取数据for (uint8_t i = 0; i < len; i++) {if (i == len - 1) {buf[i] = I2CReceiveByte();  // 读取并发送 NACK(结束读取)I2CSendNotAck();} else {buf[i] = I2CReceiveByte();  // 读取并发送 ACKI2CSendAck();}}// 7. StopI2CStop();return 0;
}

AT24C02写多个字节

/*写入多个字节*/
int AT24C02_WriteMultiBytes(uint8_t devAddr, uint8_t memAddr, uint8_t *data, uint8_t len) {// 1. StartI2CStart();// 2. 发送设备地址(写模式) + ACK检查I2CSendByte(devAddr | 0);  // 0xA0if (I2CWaitAck() != SUCCESS) {// 处理错误(如无应答)return -1;}// 3. 发送内存起始地址I2CSendByte(memAddr);if (I2CWaitAck() != SUCCESS) return -2;// 4. 循环发送数据字节for (uint8_t i = 0; i < len; i++) {I2CSendByte(data[i]);if (I2CWaitAck() != SUCCESS) break;  // 发送失败则终止}// 5. StopI2CStop();// 6. 等待 EEPROM 完成内部写入(重要!)HAL_Delay(5);return 0;
}

实验效果

可编程电阻

蓝桥杯板子上可编程电阻使用的是MCP4017,其内部结构如下图所示,内部相当于一个滑动变阻器,通过I2C写入数据改变滑子的位置,从而改变电阻器的电阻值,由于其内部B点已经接地,A点有些芯片不会被引出,所以我们能读到的接口只能为RBW之间的阻值。

在看原理图,W点接了10k电阻到VCC(3.3V),B点通过跳线帽接GND,所以我们可以测得W点对地的电压,然后经过推导,算出W的电阻值。

:::color1
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

:::

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们通过I2C去 写数据和读数据,其I2C的地址为0x5E 那么写的地址 位0x5E 读的地址为0x5F

蓝桥板子提供的读取和 写的代码如下

void write_resistor(uint8_t value)
{   I2CStart();I2CSendByte(0x5E);  I2CWaitAck();I2CSendByte(value);  I2CWaitAck();I2CStop();
}uint8_t read_resistor(void)
{   uint8_t value; I2CStart();I2CSendByte(0x5F);  I2CWaitAck();value = I2CReceiveByte();I2CSendNotAck();I2CStop();return value;
}

通过下面的图我们可以看出 写入的数据只有7位 最上面固为A 所以写入的范围为0-127 即0x00-0x7F,MCP4017的可编程电阻值为100kΩ,而调整范围 位0-127所以这个比例关系为,其中Wvalue为写入的值

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

好接下来我们开始实战,接线如下 还是使用U2B调试工具和万用表测量电压来验证

写入值推测电阻

我们写入数据值为0x50

根据理论公式RWB=80/127*100k=63k

测量的电压为2.803V 算出的实际值为 (10*2.803) / (3.3-2.803)=56k

理论值和实际值有7K的误差 可能由于10K电阻有误差,以及可编程电阻有误差 但是还是很接近的

测试2

写入最大值0x7f(127)

根据理论公式 RWB=127/127100k = 100k 算出理论电压为 3.3(100/(10+110))=3V

现在我们测量 实际 电压值为2.958还是很接近理论值的

编程实验

#include "mcp4017.h"#include "i2c_hal.h"void MCP_WriteVal(uint8_t Val)
{/*判断写入值的范围  ,不合适直接退出*/if(Val<=0 || Val>0x7f){return;}I2CStart();I2CSendByte(0x5E);I2CWaitAck();I2CSendByte(Val);I2CWaitAck();I2CStop();
}uint8_t MCP_ReadVal(void)
{I2CStart();I2CSendByte(0x5F);I2CWaitAck();uint8_t val =  I2CReceiveByte();I2CSendNotAck();I2CStop();return val;}
#ifndef __MCP4017_H
#define __MCP4017_H
#include "main.h"uint8_t MCP_ReadVal(void);
void MCP_WriteVal(uint8_t Val);
#endif
 /*写入电阻值*/MCP_WriteVal(20);while (1){/* USER CODE END WHILE */mc_val  =    MCP_ReadVal();      resist = (mc_val*100)/127;vlotage = 3.3*(resist/(10+resist));memset(displayBuf,0,sizeof(displayBuf));sprintf(displayBuf,"val:%d RES:%.2f K",mc_val,resist);LCD_DisplayStringLine(Line7,(u8 *)displayBuf);memset(displayBuf,0,sizeof(displayBuf));sprintf(displayBuf,"Voltage:%.2f V", vlotage);LCD_DisplayStringLine(Line8,(u8 *)displayBuf);/* Infinite loop */HAL_Delay(200);/* USER CODE BEGIN 3 */}

TIM定时器

void MX_TIM2_Init(void)
{/* USER CODE BEGIN TIM2_Init 0 *//* USER CODE END TIM2_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};/* USER CODE BEGIN TIM2_Init 1 *//* USER CODE END TIM2_Init 1 */htim2.Instance = TIM2;htim2.Init.Prescaler = 1000-1;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 79;htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;/*选择自动重装载*/if (HAL_TIM_Base_Init(&htim2) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM2_Init 2 */HAL_TIM_Base_Start_IT(&htim2);/*启动带中断的定时器*//* USER CODE END TIM2_Init 2 */}
uint16_t i=0;
/* USER CODE BEGIN 1 */void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){i++;if(i>=  100){i=0;HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_9);}}
}

输入捕获

输入捕获的PWM波如下,其主要思想是捕获两个上升沿(下降沿 )记录这两个捕获到的CNT0 CNT1之间的数 然后知道这个数了和定时器周期去相乘,就能得到时间,然后倒数一下就是频率。

推导如下:

  1. 定时计数器记一个数的频率等于系统时钟/分频 得到的是记一个数的频率

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 记一个数的时间就等于频率T0的倒数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 两次捕获到上升沿 (一个周期T) 之间的计数器的数值差为CapValue

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 那么PWM的周期就为上升沿之间的数值差*计数周期即PWM的周期

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. PWM的频率就为周期的倒数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 总的公式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

信号发生器的电路图,连接到了A15 B4引脚,其频率通过滑动变阻器R39 R40控制

实验1 生成PWM信号并测试

我们通过定时器2 的CH2 CH3 即A1 A2管脚生成PWM信号,然后通过A7 TIM17->CH1的输入捕获模式去捕获生成的PWM信号 然后去进行计算 先算出周期 后面再算出占空比

// TIM2_Init
htim2.Instance = TIM2;
htim2.Init.Prescaler = 40-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1000-1;//TIM17_Init
htim17.Instance = TIM17;
htim17.Init.Prescaler = 80-1;
htim17.Init.CounterMode = TIM_COUNTERMODE_UP;
htim17.Init.Period = 65530-1;//main.c
/*打开PWM输出 */HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 500);__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 800);/*开启定时器*/HAL_TIM_IC_Start_IT(&htim17,TIM_CHANNEL_1);
在TIM2初始化中我们选择为PWM模式,其中分频为40-1 其频率为2000000HZ(2000kh 2MHZ) 自动重装载值为1000-1 那么其周期为2000kHZ/1000=2000hz 2khz 在下面我们设置了PWM的比较值,那么其占空比为CH2 50% CH3 80%

在TIM17初始化中我们设置了分频为80-1 即 1000000(1000khz 1Mhz) 计数上限为65530,那么他溢出的时间为65530/1Mhz = 6.553*10^-2s ≈65ms 上面我们的周期为2000HZ = 0.5ms 也就是说我们的采样在65ms后才溢出 但是我们需要捕获的信号在5ms就已经溢出了,所以我们的捕获频率可以捕获到信号

在设置好输出的PWM和输入捕获的定时器 后,我们就可以调用中断去实现捕获

extern TIM_HandleTypeDef htim17;
uint32_t fre,CapValue;/*输入捕获的回调函数 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM17){CapValue = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);TIM17->CNT = 0;/*计算频率 */fre = 1000000/(CapValue+1);  }
}
我们在初始化函数中设置的是高电平捕获,那么捕获到高电平时就会进入这个回调函数,在回调函数中读取当前的计数值,然后将其清零,那么从定时器独到的数据值再乘以计数周期就是PWM信号的周期
  while (1){/* USER CODE END WHILE */HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_10);HAL_Delay(500);memset(lcd_string,0,sizeof(lcd_string));sprintf(lcd_string,(char *)"fre:%d K\r\n",fre);HAL_UART_Transmit(&huart1,lcd_string,strlen(lcd_string),0xff);// LCD_DisplayStringLine(Line5,lcd_string);/* USER CODE BEGIN 3 */}
在主函数中我们打印获取并计算后得到的周期值

实验结果如下

通过逻辑分析仪抓到的PWM信号周期为2khz占空比为80% 符合设置

串口的打印也为200kHZ

捕获占空比

捕获占空比的示意图如下所示,定义一个计数器去记录当前捕获的次数 ,首先设置捕获上升沿,在捕获到第一个上升沿时记录其值为Cap1,然后立马设置其捕获下降沿,捕获到下降沿是cnt=2 记录当前的值为cap2,此时cnt++ cnt=3 设置捕获上升沿,捕获到上升沿时记录其值为cap3,此时cnt++ cnt=4 然后将cnt=0 开启下一轮

这里我们需要记录捕获的值CapVlue1 CapVlue2 CapVlue3 记录进入捕获的次数 cnt和记录第几次捕获上升沿的RaiseCnt;

代码如下

extern  uint32_t  fre;
extern uint8_t cap_cnt;
extern uint32_t CapValue1;
extern uint32_t CapValue2;
extern uint32_t CapValue3;
extern uint8_t capRaise_cnt;
float high_duty=0.0;while(1)
{switch (cap_cnt){case 0:cap_cnt++;__HAL_TIM_SET_CAPTUREPOLARITY(&htim17, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);HAL_TIM_IC_Start_IT(&htim17, TIM_CHANNEL_1);	//启动输入捕获       或者: __HAL_TIM_ENABLE(&htim5);break;case 4:capRaise_cnt = 0;cap_cnt = 0;  //清空标志位break;}if(CapValue2-CapValue1 < 0){}else{/*计算周期 */fre = 1000000/(CapValue3-CapValue1);high_duty=(float)(CapValue2-CapValue1)/(CapValue3-CapValue1);high_duty *= 100;memset(lcd_string,0,sizeof(lcd_string));sprintf(lcd_string,(char *)"fre:%d high_duty:%.2f cap1:%d cap2:%d  \r\n",fre,high_duty,CapValue2-CapValue1,CapValue3-CapValue1);HAL_UART_Transmit(&huart1,lcd_string,strlen(lcd_string),0xff);}HAL_Delay(100);
}
extern TIM_HandleTypeDef htim17;
uint32_t fre,CapValue1,CapValue2,CapValue3;
uint8_t cap_cnt=0;
uint8_t capRaise_cnt=0;/*输入捕获的回调函数 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM17){switch(cap_cnt){case 1:if(capRaise_cnt==1){//第二次上升沿捕获CapValue3 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//获取当前的捕获值.TIM17->CNT = 0;}else{CapValue1 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//获取当前的捕获值.}__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);  //设置为下降沿捕获cap_cnt++;capRaise_cnt++;break;case 2:CapValue2 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//获取当前的捕获值.__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);  //设置为上升沿捕获cap_cnt++;break;case 3:CapValue3 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//获取当前的捕获值.__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);  //设置为上升沿捕获cap_cnt++;break;}/*计算频率 */// fre = 1000000/(CapValue+1);  }
}
/* USE
效果演示

存在一个bug 记录的值为负值,可能是中间取值不规范 待解决

XL555定时器捕获 其接在了A15(TIM2->CH1) B4(TIM3->CH1)上面 通过配置定时器 的值来捕获,其中TIM2定时器计数值为32位 最大为0xffffffff TIM3为16位最大为0xffff


TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;/* TIM2 init function */
void MX_TIM2_Init(void)
{/* USER CODE BEGIN TIM2_Init 0 *//* USER CODE END TIM2_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_IC_InitTypeDef sConfigIC = {0};/* USER CODE BEGIN TIM2_Init 1 *//* USER CODE END TIM2_Init 1 */htim2.Instance = TIM2;htim2.Init.Prescaler = 8-1;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 0xffffffff-1;//32BIThtim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim2) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_IC_Init(&htim2) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;sConfigIC.ICFilter = 0;if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM2_Init 2 *//* USER CODE END TIM2_Init 2 */}
/* TIM3 init function */
void MX_TIM3_Init(void)
{/* USER CODE BEGIN TIM3_Init 0 *//* USER CODE END TIM3_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_IC_InitTypeDef sConfigIC = {0};/* USER CODE BEGIN TIM3_Init 1 *//* USER CODE END TIM3_Init 1 */htim3.Instance = TIM3;htim3.Init.Prescaler = 8-1;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 0xffff-1;htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim3) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_IC_Init(&htim3) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;sConfigIC.ICFilter = 0;if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM3_Init 2 *//* USER CODE END TIM3_Init 2 */}
uint32_t cap1,fre1;
uint32_t cap2,fre2;
/* USER CODE BEGIN 1 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){cap1 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);htim->Instance->CNT = 0;fre1  = 1000000/cap1;HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1);}if(htim->Instance == TIM3){cap2 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);htim->Instance->CNT = 0;fre2  = 1000000/cap2;HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1);}}
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);while (1){/* USER CODE END WHILE */HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_10);memset(sendbuf,0,sizeof(sendbuf));sprintf(sendbuf,"fre1:%d fre2:%d\r\n",fre1,fre2);HAL_UART_Transmit(&huart1,sendbuf,strlen(sendbuf),0xff);HAL_Delay(100);/* USER CODE BEGIN 3 */}

实验结果

通过串口打印其捕获到的值为4255HZ 5780HZ 与逻辑分析仪抓到的基本 一致

DAC

相关文章:

蓝桥杯嵌入式开发板结构分析及功能学习笔记

目录 板子结构一览时钟源分析74LS573锁存器按键输入滴答定时器 SysTick串口收发LCD屏幕ADC采样AT24C02(EEPROM)可编程电阻TIM定时器输入捕获DAC 板子结构一览 主控为 **STM32G431RBT6**** 外部晶振频率为 **24MHz IAP下载为** GD32F350C8T6** 时钟源分析 自己配置的STM32Cu…...

C++进阶——C++11_智能指针

目录 1、问题引入 2、RAII和智能指针 3、C标准库的智能指针 3.1 auto_ptr (不好) 3.2 unique_ptr 3.3 shared_ptr (重点) 3.4 weak_ptr (重点) 4、shared_ptr的循环引用问题(重点) 5、shared_ptr的线程安全问题 6、C11智能指针和boost的关系 7、内存泄漏 7.1 什么是…...

音频格式转换

1. 下载ffmpeg https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-7.1.1-full_build.7z 2. 配置ffmpeg环境变量 3.安装pydub pip install pydub 4.编写转化工具代码 from pydub import AudioSegment def convertM4aToWav(m4a,wav):sound AudioSegment.from_file(m4a, f…...

mysql安装配置教程

由于您可能需要针对特定操作系统&#xff08;如Windows、macOS或Linux&#xff09;的MySQL安装配置教程&#xff0c;这里我将提供一个较为通用的指南&#xff0c;适用于大多数情况。如果您有特定的操作系统需求&#xff0c;请告诉我&#xff0c;我可以提供更详细的指导。 ### …...

埃文科技助力山西公共数据运营新发展

近日&#xff0c;郑州埃文科技有限公司&#xff08;以下简称“埃文科技”&#xff09;凭借“数据场景生态”的三维核心竞争力&#xff0c;成为山西云时代政务云技术有限公司专业领域数据类产品授权运营合作伙伴。 埃文科技作为数据全生命周期价值建设先行者&#xff0c;深度赋…...

【STM32】在FreeRTOS下使用硬件SPI收发数据出现的时序耦合问题(WK2124芯片为例)

问题 STM32中在Freertos使用SPI通讯芯片 WK2124进行SPI转4串口时&#xff0c;接收数据为一个任务&#xff0c;发送数据为一个任务&#xff0c;切接受任务优先级更高实测发现收发一段时间&#xff08;约几分钟&#xff09;外扩芯片会死锁导致WK2124复位。 分析 首先&#xff…...

linux Shell编程之函数与数组(四)

目录 一. shell 函数 1. 函数的用法 (1) 两个数求和 (2) 系统资源监控并报警函数 2. 函数变量的作用范围 3. 函数的参数 4. 递归函数 二. shell 数组 (1) 获取数组长度 (2) 读取某下标赋值 (3) 数组遍历 (4) 数组切片 (5) 数组替换 (6) 数组删除 三. shell 脚本…...

4.vtk光照vtkLight

文章目录 VTK中的光照1. vtkLight 的两种类型&#xff1a;位置光照和方向光照2. vtkLight 的常用方法3. 方法命名风格4. vtkProp 的可见性与 vtkLight 的开关 示例 VTK中的光照 vtkLight: 用于定义一个或多个光源。每个光源可以有其颜色、位置、焦点等属性。 vtkActor: 每个vtk…...

定义AIDL 接口

目录 定义 AIDL 接口创建 .aidl 文件实现 AIDL 接口向客户端公开接口接口的版本兼容性小结1. 定义 AIDL 接口 AIDL 接口是什么? 概念 AIDL(Android 接口定义语言)用来定义跨进程通信(IPC)的接口。简单来说,它规定了客户端和服务端之间如何进行数据交换和方法调用。.aidl…...

Linux系统-scp命令--两台服务器之间传输文件

一、定义 scp是secure copy的简写&#xff0c;scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令&#xff0c;可以在linux服务器之间复制文件和目录&#xff0c;scp传输是加密的&#xff0c;可能会稍微影响一下速度。另外&#xff0c;scp还非常不占资源&#xff0c;不会提…...

Visual Studio + OpenCV C++ 安装与配置教程

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,广泛用于图像处理、视频分析、模式识别和机器学习等领域。它由Intel公司于1999年发起,并在2000年由Willow Garage(一个机器人研究机构)进一步开发和维护。OpenCV支持多种编程语言,包括C++、Python…...

怎么通过OPPO手机进行图片编辑?图片编辑攻略,打造专业级照片

在当今数字化时代&#xff0c;手机摄影已成为记录生活、分享瞬间的重要方式。而作为市场上广受欢迎的智能手机品牌之一&#xff0c;OPPO手机不仅在摄影硬件上表现出色&#xff0c;其内置的图片编辑功能也极为强大&#xff0c;能够满足使用者从基础调整到高级创作的各种需求。本…...

基于MFC 的链接库

1. 动态库 MFC Regular dll: ① DLL内部有一个CWinApp类全局对象(像是基于mfc的exe程序那样存在一个theApp)&#xff0c;该CWinApp类的Initstance负责执行dll内部初始化。 ② DLL不能人为提供Dllmain函数&#xff0c;该函数由mfc库提供。 ③在visual studio 的工程配置中&a…...

2025.04.15【Connection】| 生信数据可视化:连接图绘制指南

文章目录 生信数据可视化&#xff1a;连接图绘制指南什么是连接地图&#xff1f;为什么使用连接地图&#xff1f;如何在R中创建连接地图&#xff1f;1. 安装和加载必要的库2. 准备数据3. 计算大圆航线的距离和方位角4. 创建连接地图 高级技巧1. 自定义地图样式2. 添加地理背景 …...

回溯算法:List 还是 ArrayList?一个深拷贝引发的思考

在学习和使用回溯算法解决问题时&#xff0c;我们经常会遇到需要维护一个结果列表&#xff0c;例如所有可能的子集、组合或排列。 这个结果列表通常是一个 List<List<Integer>>&#xff0c;其中内部的 List<Integer> 代表一个具体的解。 然而&#xff0c;在…...

WPS表格中设置折线图随数据列自动变化——存钱计划

效果展示&#xff1a; wps自动更新表格 1.公式>名称管理器>新建 2.修改名称和引用位置 OFFSET(Sheet1!$A$2,0,0,COUNTA(Sheet1!$A:$A)-1,1) 3.插入>图表 4.右键>选择数据 5.添加&#xff0c;输入名称和系列值。 Sheet1!名称管理器里的名字 标签分类里也填入 6如图…...

内网Windows挂载目录到公网服务器

工程目的 最近在研究图像生成&#xff0c;Stable Diffusion的各种模型尤其3.5以后大的飞起来&#xff0c;动不动五六十G&#xff0c;以往上传到服务器费时费力占带宽又占存储空间&#xff0c;更关键的是用学校服务器只能校园网才能上&#xff0c;上传传个半天第二天来一看发现…...

ffmpeg命令(一):信息查询命令

媒体文件信息查看 命令说明ffmpeg -i input.mp4查看媒体文件基本信息&#xff08;封装格式、编解码器、时长等&#xff09;ffprobe input.mp4使用专用工具查看详细信息ffprobe -v error -show_format -show_streams input.mp4输出格式和流的详细信息ffprobe -v quiet -print_f…...

2 cline 提示词工程指南-记忆库

cline 提示词工程指南-记忆库 前言 编程&#xff0c;就是搭建一个系统&#xff0c;该系统在编程过程中逐步长成&#xff0c;最后该系统可以完成某个具体任务。 显然&#xff0c;编程是一个需要仔细规划、逐步推进的系统性、流程性、逻辑性工作。 我们的 ai 能胜任么&#x…...

VueDOMPurifyHTML 防止 ​​XSS(跨站脚本攻击)​​ 风险

VueDOMPurifyHTML 是一个 ​​Vue.js 插件​​&#xff0c;用于在 v-html 指令中安全地渲染 HTML 内容&#xff0c;防止 ​​XSS&#xff08;跨站脚本攻击&#xff09;​​ 风险。 ​​作用​​ ​​解决 v-html 的安全问题​​ Vue 的 v-html 会直接渲染原始 HTML&#xff0…...

关于SQLite轻量数据库的研究

安装本地SQLite 下载地址&#xff1a; https://www.sqlite.org/download.html 下载这两个包 解压到本地&#xff0c;得到这几个文件&#xff1a; 将解压后的目录添加到Path环境变量中&#xff1a; 在cmd中输入 “sqlite3” 和 “.open D:\work\sqliteInstall\mytestdb.…...

使用Python爬取豆瓣电影Top250并保存到Excel完整教程

在当今数据驱动的时代&#xff0c;获取和分析网络数据已成为许多领域的重要技能。本文将详细介绍如何使用Python爬取豆瓣电影Top250榜单数据&#xff0c;并将结果保存到Excel文件中。这个项目不仅适合Python初学者学习网络爬虫基础&#xff0c;也能帮助数据分析师获取有价值的电…...

Redis + Caffeine打造超速两级缓存架构

背景 接口的逻辑非常简单&#xff1a;根据传入的城市、仓库和发货时间&#xff0c;查询快递的预计送达时间。 然而&#xff0c;由于会频繁调用这个接口&#xff0c;尤其是在大促期间&#xff0c;接口的性能要求极高。 数据量虽然不大&#xff0c;但为了确保接口的高性能和高…...

讲讲String类的常用函数

String类在开发过程中经常用到&#xff0c;这里来总结一下。 1.声明与初始化 std::string str;//声明 std::string str "Hello, World!";//初始化 2.连接 std::string str1 "Hello, "; std::string str2 "World!"; std::string result …...

Sentinel实战教程:流量控制与Spring Boot集成

Sentinel实战教程:流量控制与Spring Boot集成 1. Sentinel简介与核心概念 1.1 什么是Sentinel? Sentinel是阿里巴巴开源的流量控制组件,主要用于微服务架构中的流量防护。它通过限流、熔断、热点防护等机制,帮助系统在高并发场景下保持稳定运行。 1.2 核心功能与术语 流…...

【计算机系统结构】MIPSsim

目录 双击MIPSsim.exe 问题1&#xff1a;Microsoft Defender SmartScreen阻止了无法是被的应用启动&#xff0c;运行此应用可能会导致你的电脑存在风险 解决 出现下面的问题的话&#xff0c;建议直接在官网下载 问题2&#xff1a;.NET Framework 3.5安装错误代码0x80240438 …...

Charles 安装与使用详解:实现 App 与小程序 HTTPS 抓包

在日常的移动端开发、接口调试或逆向分析中&#xff0c;我们经常需要抓取移动 App 或微信小程序的 HTTP/HTTPS 请求。Charles 是一款经典强大的代理抓包工具&#xff0c;凭借简单的界面和强大的功能&#xff0c;成为了 macOS 抓包的首选工具之一。 本文将详细介绍 Charles 的安…...

0415美团面试题目详解

基础知识型,基础知识!!! margin-top:100%(基于父元素宽度) “margin-top: 100% 表示元素的上外边距为父元素宽度的 100%。例如,若父元素宽 300px,则上边距为300px。需注意,CSS 中垂直方向的百分比边距(如 margin-top/margin-bottom)均基于父元素宽度计算,而非高度。这…...

【微信小程序】报错: http://127.0.0.1:7001 不在以下 request 合法域名列表中

问题 微信小程序报错: http://127.0.0.1:7001 不在以下 request 合法域名列表中&#xff0c;请参考文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html(env: Windows,mp,1.05.2204250; lib: 3.0.2) 解决方法&#xff1a; 详…...

go的json unmarshal和 k8s的deepcopy对比

Go 的 encoding/json.Unmarshal 和 Kubernetes 的 DeepCopy 虽然都依赖反射&#xff0c;但性能差异显著。以下是两者的对比分析及性能优化原理&#xff1a; 一、反射实现差异 1. json.Unmarshal 的反射特点 动态类型解析&#xff1a;需在运行时解析 JSON 结构&#xff0c;通过…...

1. k8s的简介

Kubernetes&#xff08;k8s&#xff09;简介 1. 产生背景 随着云计算和微服务架构的兴起&#xff0c;传统的单体应用逐渐被拆分为多个小型、松耦合的服务&#xff08;微服务&#xff09;。这种架构虽然提升了开发灵活性和可维护性&#xff0c;但也带来了新的挑战&#xff1a;…...

华为云CloudMatrix 384 超节点将有数万规模上线,赋能AI产业发展

近日&#xff0c;华为公司副总裁张修征表示&#xff0c;华为云 CloudMatrix 384 超节点今年上半年将有数万规模的上线&#xff0c;这或将彻底终结算力焦虑。未来&#xff0c;CloudMatrix 超节点可以构建超过万片的大集群来提供算力。 CloudMatrix 384超节点 华为云 CloudMatri…...

Java基础 4.15

1.重载方法练习 /* 类Methods中定义三个重载方法并调用 方法名为m 分别接受一个int参数 两个int参数 一个字符串参数 分别执行平方运算并输出 相乘并输出结果 输出字符串信息 在main()方法中分别用参数区别调用三个方法 */ public class OverLoadExercise01 {public static v…...

现代c++获取linux系统架构

现代c获取linux系统架构 前言一、使用命令获取系统架构二、使用c代码获取系统架构三、验证四、总结 前言 本文介绍一种使用c获取linux系统架构的方法。 一、使用命令获取系统架构 linux系统中可以使用arch或者uname -m命令来获取当前系统架构&#xff0c;如下图所示 archuna…...

shell编程之函数与数组

目录 shell函数 函数的用法 俩个数求和 系统资源监控并报警函数 函数变量的作用范围 函数的参数 递归函数 shell数组 获取数组的长度 读取某下的标赋值 数组遍历 数组切片 数组替换 数组删除 shell脚步调试 shell函数 函数的用法 Shell函数可用于存放一系列的…...

IntelliJ IDEA 中最常用的快捷键分类整理

以下是 IntelliJ IDEA 中最常用的快捷键分类整理&#xff0c;适用于 Windows/Linux&#xff08;Mac 用户将 Ctrl 替换为 ⌘&#xff0c;Alt 替换为 Option&#xff09;&#xff1a; 一、编辑相关 快捷键功能说明Ctrl Space基础代码补全Ctrl Shift Space智能类型补全Ctrl P…...

大数据面试问答-Kafka/Flink

1. Kafka 1.1 定位 分布式流数据平台&#xff0c;核心解决三大问题&#xff1a; 高吞吐的实时数据管道&#xff1a;支持每秒百万级消息处理。 持久化的消息队列&#xff1a;消息持久化到磁盘&#xff0c;支持多订阅者。 流式数据处理&#xff1a;与 Flink/Spark Streaming 集…...

工厂园区光储充能量管理系统解决方案——助力高效用能与低碳运营

园区痛点&#xff1a;电费高、能效低、碳排压力大 安科瑞 郭海棚 198 21380729 电费成本高&#xff1a;峰谷电价差显著&#xff0c;尖峰时段用电成本激增。设备能效低&#xff1a;老旧设备能耗高&#xff0c;缺乏实时监控与优化手段。供电稳定性差&#xff1a;生产设备突发停电…...

Windows10下Jekyll博客部署全指南|解决GitHub模板运行失败问题

场景&#xff1a;在GitHub拉取的一个Jekyll博客网站运行不起来 这是想要实现的效果 这是项目代码 概要 前置要求 git版本控制工具已安装windows10环境GitHub可以正常上网 相关问题 Jekyll博客部署常见错误GitHub模板运行失败解决方法Windows10环境变量配置Ruby版本兼容性问…...

数字IC设计-VCS和Verdi的使用

#学习记录# 前言&#xff1a;本文以一个简单的计数器来说明vcs和verdi的使用 1 代码文件 1.1 计数器代码 //Engineer&#xff1a;Mr-pn-junction module counter(input clk,input rst,output reg [5:0] count); always(posedge clk or negedge rst)beginif(!rst)coun…...

FastAPI基础知识点精要

一、核心性能优势 1. 异步编程支持 原生async/await语法‌&#xff1a;支持非阻塞IO操作&#xff0c;轻松处理高并发场景‌ASGI协议实现‌&#xff1a;基于Starlette框架构建&#xff0c;支持WebSocket等实时协议‌性能基准‌&#xff1a;测试显示响应速度比Flask快3-5倍&…...

<uniapp><websocket><http>基于uniapp,手机客户端通过websocket进行数据通讯(二维码扫码数据)

前言 本专栏是基于uniapp实现手机端各种小功能的程序,并且基于各种通讯协议如http、websocekt等,实现手机端作为客户端(或者是手持机、PDA等),与服务端进行数据通讯的实例开发。 发文平台 CSDN 环境配置 系统:windows 平台:visual studio code、HBuilderX(uniapp开…...

GitLab-获取token(访问令牌)

一、操作步骤 GitLab-获取token&#xff08;访问令牌&#xff09;主要步骤&#xff1a;以及相关截图 登录 GitLab 打开 GitLab 网站并登录你的账号。 进入用户设置 点击右上角头像 → Edit profile → 左侧菜单选择 Access Tokens。 创建 Token Token name: 输入名称&#…...

python 安装win32com.client库

win32com.client是Python中用于操作Windows COM对象的强大模块&#xff0c;特别适合与Microsoft Office应用程序(如Word、Excel、Outlook等)进行交互。 1. 安装win32com.client 需要安装pywin32库&#xff1a; pip install pywin32如果安装失败或速度慢&#xff0c;可以使用国…...

流量统计--Maven依赖

新建项目Flow 创建依赖&#xff0c;在pm.xml里添加如下内容&#xff1a; <!-- 添加hadoop-client 3.1.3的依赖--> <dependencies> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>…...

L1-6 大勾股定理(PTA)

大勾股定理是勾股定理的推广&#xff1a;对任何正整数 n 存在 2n1 个连续正整数&#xff0c;满足前 n1 个数的平方和等于后 n 个数的平方和。例如对于 n1 有 324252&#xff1b;n2 有 102112122132142 等。给定 n&#xff0c;本题就请你找出对应的解。 输入格式&#xff1a; …...

HarmonyOS-ArkUI V2装饰器: @Computed装饰器:计算属性

引 @Computed是用来装饰一个自己写的getter方法的装饰器,它可以让您像用平常的状态变量那样去用这个getter方法。那么getter方法里怎么获取的值,必然涉及到您写的逻辑。这个逻辑可以是很复杂的一种计算方式,经过一系列复杂方式计算完您吐出相应的结果即可。 为了便于理解,…...

豆瓣图书数据采集与可视化分析

文章目录 一、适用题目二、豆瓣图书数据采集1. 图书分类采集2. 爬取不同分类的图书数据3. 各个分类数据整合 三、豆瓣图书数据清洗四、数据分析五、数据可视化1. 数据可视化大屏展示 源码获取看下方名片 一、适用题目 基于Python的豆瓣图书数据采集与分析基于Python的豆瓣图书…...

网络安全·工具篇1·Nmap的运用

今天我们要介绍网络安全中常用的一种扫描工具Nmap&#xff0c;它被设计用来快速扫描大型网络&#xff0c;主要功能包括主机探测、端口扫描以及版本检测&#xff0c;小编将在下文详细介绍Nmap相应的命令。 Nmap的下载安装地址为&#xff1a;Nmap: the Network Mapper - Free Se…...

MVCC详细介绍及面试题

目录 1.什么是mvcc&#xff1f; 2.问题引入 3. MVCC实现原理&#xff1f; 3.1 隐藏字段 3.2 undo log 日志 3.2.1 undo log版本链 3.3 readview 3.3.1 当前读 ​编辑 3.3.2 快照读 3.3.3 ReadView中4个核心字段 3.3.4 版本数据链访问的规则&#xff08;了解&#x…...