蓝桥杯嵌入式STM32G431RBT6知识点(主观题部分)
目录
1 前置准备
1.1 Keil
1.1.1 编译器版本及微库
1.1.2 添加官方提供的LCD及I2C文件
1.2 CubeMX
1.2.1 时钟树
1.2.2 其他
1.2.3 明确CubeMX路径,放置芯片包
2 GPIO
2.1 实验1:LED1-LED8循环亮灭
编辑
2.2 实验2:按键控制LED亮灭(检测电平法)
2.3 实验3:按键控制LED亮灭(外部中断法)
2.4 实验4:蜂鸣器
2.5 实验5:按键消抖
2.6 实验6:长按短按
2.7 实验7:双击
2.8 实验8: 长按双击综合
3 ADC/DAC
3.1 实验1:获取电位器引脚的电压
3.2 实验2:设定双引脚电压并读取
4 I2C EEPROM
4.1 实验1:EEPROM的读写+浮点数的处理
4.2 实验2:大位数读取
4.3 实验3:EEPROM掉电不丢失
4.4 实验4:第一次上电问题
4.5 实验5:MCP4017可编程电阻
5 UART/USART
5.1 实验1:轮询收发
5.2 实验2:中断收发
5.3 实验3:中断回调函数
5.4 字符串问题注意
5.5 实验4:发送指定格式的字符串并从字符串中提取指定信息
5.6 实验5:DMA及几种收发方式的分析
5.7 实验6:串口的不定长收发(DMA+空闲中断)
6 TIM
6.1 实验1:延时
6.2 实验2:PWM输出(控制蜂鸣器)
6.3 实验3:检测555信号发生器信号频率和占空比
6.4 实验4:检测自己输出的PWM频率和占空比(上升沿中断)
6.5 实验5:检测自己输出的PWM频率和占空比(PWM中断)
7 RTC
7.1 实验1:显示年月日时分秒
7.2 实验2:秒中断
7.3 实验3:闹钟中断
1 前置准备
1.1 Keil
1.1.1 编译器版本及微库
编译器版本调整至version 5,勾选Micro LIB
1.1.2 添加官方提供的LCD及I2C文件
这五个文件是需要添加进自己的工程中的
这个是官方比赛提供的数据包,有关I2C的文件从2中提取,有关LCD的文件从5中提取(.c文件在Src中,.h文件在Inc中)
1.2 CubeMX
1.2.1 时钟树
1.2.2 其他
1.2.3 明确CubeMX路径,放置芯片包
2 GPIO
2.1 实验1:LED1-LED8循环亮灭
在最小系统原理图中找到LED1-LED8对应的引脚是PC8-PC15,那么我们在CubeMX中将这几个引脚配置成GPIO_Output即可
while内的代码:
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);//常用函数1HAL_Delay(100);//常用函数2HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_RESET);
2.2 实验2:按键控制LED亮灭(检测电平法)
参考按键的引脚,同时别忘了把按键对应的引脚调整为上拉输入(起始高电平)
while内代码:
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET){HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);HAL_Delay(500);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);}
2.3 实验3:按键控制LED亮灭(外部中断法)
找到按键对应引脚:
打开外部中断:
/* USER CODE BEGIN PFP */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN)
{if(GPIO_PIN==GPIO_PIN_0){HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);}
}
/* USER CODE END PFP */
2.4 实验4:蜂鸣器
当PB3为高电平时,二极管断开,所以蜂鸣器路通; 当PB3为低电平时,二极管导通,所以蜂鸣器路短路
只要配置好PB3的GPIO,就能轻松使用,这里不再用代码解释
2.5 实验5:按键消抖
按键按下和放下的过程中会出现抖动,进而出现高低电平的交替,我们通过扫描两次按键的情况来具体判断情况
1.如果第一次扫描为高电平,那么按键没有被按下
2.如果第一次扫描为低电平,第二次扫描为高电平,那么认为是抖动,不计入成功按键
3.如果两次扫描均为低电平,成功按键
两次扫描的间隔用定时器中断来做
芯片信号频率为80MHz,分频系数设置为8000-1,计数器溢出值设置为100-1,那么定时器溢出时间为10ms
/* USER CODE BEGIN PTD */
char buf[20];
struct keys{int step;int state;
}key[4];
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM1){key[0].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].state=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(int i=0;i<4;i++){switch(key[i].step){case 0:{if(key[i].state==GPIO_PIN_RESET){key[i].step=1;}}break;case 1:{if(key[i].state==GPIO_PIN_RESET){key[i].step=2;sprintf(buf,"%d",i);LCD_DisplayStringLine(Line4,(uint8_t*)buf);}else{key[i].step=0;}}break;case 2:{if(key[i].state==GPIO_PIN_SET){key[i].step=0;}}break;}}}
}
/* USER CODE END PFP *//* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);I2CInit();HAL_TIM_Base_Start_IT(&htim1);/* USER CODE END 2 */
2.6 实验6:长按短按
1.如果第一次扫描为高电平,则没有按键
2.如果第一次扫描为低电平,第二次扫描为高电平,那么认为是抖动,不计入成功按键
3.如果两次扫描均为低电平,成功按键,如果按键时间大于700ms,则视为长按,若小于700ms,则视为短按
/* USER CODE BEGIN PTD */
char buf[20];
struct keys{int step;int state;
}key[4];
int a=-1;
int cnt;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM1){key[0].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].state=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(int i=0;i<4;i++){switch(key[i].step){case 0:{if(key[i].state==GPIO_PIN_RESET){key[i].step=1;cnt=0;}}break;case 1:{if(key[i].state==GPIO_PIN_RESET){key[i].step=2;sprintf(buf,"SINGLE");LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);}else{key[i].step=0;}}break;case 2:{if(key[i].state==GPIO_PIN_RESET){if(i==a&&cnt>70){sprintf(buf,"%d %d",i,cnt);LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);}else{a=i;}cnt++;}else{key[i].step=0;}}break;}}}
}
/* USER CODE END PFP */
2.7 实验7:双击
1.如果第一次能够被视为成功按键,那么计时开始
2.如果两次成功按键的间隔小于700ms,视为双击成功
/* USER CODE BEGIN PTD */
char buf[20];
struct keys{int step;int state;int cnt;
}key[4];
int a=-1;
int cnt;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM1){key[0].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].state=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(int i=0;i<4;i++){switch(key[i].step){case 0:{if(key[i].state==GPIO_PIN_RESET){key[i].step=1;}}break;case 1:{if(key[i].state==GPIO_PIN_RESET){sprintf(buf,"SINGLE");LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf); if(i==a){if(key[i].cnt<70){sprintf(buf,"%d %d",i,key[i].cnt);LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);key[i].step=0;a=-1;}key[0].cnt=0;key[1].cnt=0;key[2].cnt=0;key[3].cnt=0;}else{a=i;}key[i].step=2;}else{key[i].step=0;}}break;case 2:{if(key[i].state==GPIO_PIN_SET){key[i].step=0;}}break;}}key[a].cnt++;}
}
/* USER CODE END PFP */
2.8 实验8: 长按双击综合
其实不用写在一个定时器内,那样逻辑会比较复杂。我们可以开两个定时器,一个定时器检测长按,一个定时器检测双击
/* USER CODE BEGIN PTD */
char buf[20];
struct keys{int state;int step1;int step2;int double_time;
}key[4];
int a=-1,b=-1;
int cnt;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM3){key[0].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].state=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(int i=0;i<4;i++){switch(key[i].step2){case 0:{if(key[i].state==GPIO_PIN_RESET){key[i].step2=1;cnt=0;}}break;case 1:{if(key[i].state==GPIO_PIN_RESET){key[i].step2=2;/*sprintf(buf,"SINGLE");LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);*/}else{key[i].step2=0;}}break;case 2:{if(key[i].state==GPIO_PIN_RESET){if(i==b&&cnt>70){sprintf(buf,"LONG:%d %d",i,cnt);LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);}else{b=i;}cnt++;}else{key[i].step2=0;}}break;}}}if(htim->Instance==TIM1){key[0].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].state=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(int i=0;i<4;i++){switch(key[i].step1){case 0:{if(key[i].state==GPIO_PIN_RESET){key[i].step1=1;}}break;case 1:{if(key[i].state==GPIO_PIN_RESET){sprintf(buf,"SINGLE");LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);if(i==a){if(key[i].double_time<70){sprintf(buf,"DOUBLE:%d %d",i,key[i].double_time);LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);key[i].step1=0;a=-1;}key[0].double_time=0;key[1].double_time=0;key[2].double_time=0;key[3].double_time=0;}else{a=i;}key[i].step1=2;}else{key[i].step1=0;}}break;case 2:{if(key[i].state==GPIO_PIN_SET){key[i].step1=0;}}break;}}key[a].double_time++;}
}
/* USER CODE END PFP */
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);HAL_TIM_Base_Start_IT(&htim1);HAL_TIM_Base_Start_IT(&htim3);/* USER CODE END 2 */
3 ADC/DAC
3.1 实验1:获取电位器引脚的电压
我们想获取两个电位器的电压:
这里以PB12为例:
/* USER CODE BEGIN PTD */
char buf[20];
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
double getADC()
{HAL_ADC_Start(&hadc1);return HAL_ADC_GetValue(&hadc1)*3.3/4096;
}
/* USER CODE END PFP */
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);/* USER CODE END 2 */
/* USER CODE BEGIN 3 */sprintf(buf,"%.3lf",getADC());LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);HAL_Delay(1000);}/* USER CODE END 3 */
转动电位器R38可观察到电压发生明显变化
3.2 实验2:设定双引脚电压并读取
这里我们发现测量ADC的两个引脚均在ADC1上,所以获取电压会有先后之分
采样时间调长,采样准确些,这里我们看到优先采集PA4,再采集PA3
/* USER CODE BEGIN PFP */
void setDAC()
{HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_1,0,1.1*4096/3.3);HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_2,0,2.2*4096/3.3);
}
double getADC()
{HAL_ADC_Start(&hadc2);return HAL_ADC_GetValue(&hadc2)*3.3/4096;
}
/* USER CODE END PFP *//* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);setDAC();/* USER CODE END 2 *//* USER CODE BEGIN 3 */sprintf(buf,"%.3lf",getADC());LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);HAL_Delay(1);//需要延时sprintf(buf,"%.3lf",getADC());LCD_ClearLine(Line5);LCD_DisplayStringLine(Line5,(uint8_t*)buf);HAL_Delay(1000);}/* USER CODE END 3 */
4 I2C EEPROM
4.1 实验1:EEPROM的读写+浮点数的处理
对于EEPROM读写的函数我们有固定模板:
uint8_t EEPROM_Read(uint8_t addr)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CStart();I2CSendByte(0xa1);I2CWaitAck();uint8_t temp=I2CReceiveByte();I2CWaitAck();I2CStop();return temp;
}
void EEPROM_Write(uint8_t addr,uint8_t info)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CSendByte(info);I2CWaitAck();I2CStop();
}
借用3.2的实验数据进行读写,建议EEPROM不要写在while内,EEPROM的读写是有寿命的,每次读写都要延时一下:
/* USER CODE BEGIN PTD */
char buf[20];
double V1[5],V2[5];
uint8_t addr,res1,res2,res3,res4;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void setDAC()
{HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_1,0,1.1*4096/3.3);HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_2,0,2.2*4096/3.3);
}
double getADC()
{HAL_ADC_Start(&hadc2);return HAL_ADC_GetValue(&hadc2)*3.3/4096;
}
uint8_t EEPROM_Read(uint8_t addr)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CStart();I2CSendByte(0xa1);I2CWaitAck();uint8_t temp=I2CReceiveByte();I2CWaitAck();I2CStop();return temp;
}
void EEPROM_Write(uint8_t addr,uint8_t info)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CSendByte(info);I2CWaitAck();I2CStop();
}
/* USER CODE END PFP *//* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);I2CInit();setDAC();HAL_Delay(1);for(int i=0;i<5;i++){V1[i]=getADC();HAL_Delay(1);V2[i]=getADC();HAL_Delay(1);}for(int i=0;i<5;i++){EEPROM_Write(addr++,(uint8_t)V1[i]);HAL_Delay(50);EEPROM_Write(addr++,(V1[i]-(uint8_t)V1[i])*100);HAL_Delay(50);EEPROM_Write(addr++,(uint8_t)V2[i]);HAL_Delay(50);EEPROM_Write(addr++,(V2[i]-(uint8_t)V2[i])*100);HAL_Delay(50);}addr=0;for(int i=0;i<5;i++){res1=EEPROM_Read(addr++);HAL_Delay(50);res2=EEPROM_Read(addr++);HAL_Delay(50);res3=EEPROM_Read(addr++);HAL_Delay(50);res4=EEPROM_Read(addr++);HAL_Delay(50);sprintf(buf,"%.2lf %.2lf",res1+(double)res2/100,res3+(double)res4/100);LCD_DisplayStringLine(Line4,(uint8_t*)buf);}/* USER CODE END 2 */
4.2 实验2:大位数读取
8位范围:0-255
16位范围:0-65535
24位范围:0-16777215
32位范围:0-4294967296
这里以到24位为例
/* USER CODE BEGIN PTD */
char buf[20];
int num[10]={105798,367842,56674,4,256,8917,56565,34343,1025,788};
uint8_t temp1,temp2,temp3,res1,res2,res3;
uint8_t addr;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
uint8_t EEPROM_Read(uint8_t addr)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CStart();I2CSendByte(0xa1);I2CWaitAck();uint8_t temp=I2CReceiveByte();I2CWaitAck();I2CStop();return temp;
}
void EEPROM_Write(uint8_t addr,uint8_t info)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CSendByte(info);I2CWaitAck();I2CStop();
}
/* USER CODE END PFP */
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);I2CInit();for(int i=0;i<10;i++){temp1=num[i]&0xFF;temp2=((num[i]-temp1)>>8)&0xFF;temp3=((num[i]-temp1-(temp2<<8))>>16)&0xFF;EEPROM_Write(addr++,temp1);HAL_Delay(50);EEPROM_Write(addr++,temp2);HAL_Delay(50);EEPROM_Write(addr++,temp3);HAL_Delay(50);}addr=0;for(int i=0;i<10;i++){res1=EEPROM_Read(addr++);HAL_Delay(50);res2=EEPROM_Read(addr++);HAL_Delay(50);res3=EEPROM_Read(addr++);HAL_Delay(50);sprintf(buf,"%d",res1+(res2<<8)+(res3<<16));LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);HAL_Delay(1000);}/* USER CODE END 2 */
4.3 实验3:EEPROM掉电不丢失
去掉上面程序的写的部分,重新烧录即可验证
4.4 实验4:第一次上电问题
我们以这道题为例:如果我们将程序烧录到新板时,EEPROM的值是不确定的,而题目要求初次上电就要能读取相关值。所以我们需要判断板子是否是第一次上电,然后做出相关步骤
if(EEPROM_Read(0xaa)!=1&&EEPROM_Read(0xab)!=1)
{EEPROM_Write(0xaa,1);//我们设定0xaa为是否是第一次上电(新板)的标志位1HAL_Delay(20);EEPROM_Write(0xab,1);//我们设定0xab为是否是第一次上电(新板)的标志位2HAL_Delay(20);EEPROM_Write(0xa0,30);HAL_Delay(20);EEPROM_Write(0xa1,50);HAL_Delay(20);EEPROM_Write(0xa2,70);HAL_Delay(20);
}
4.5 实验5:MCP4017可编程电阻
原理:
Rs为单个电阻阻值;RWS为总阻值,与R17串联,两者对VDD电压进行分压,可以通过测量PB14的电压判断可编程电阻的阻值。
MCP4017的默认总阻值为100kΩ ,对应0-127个档位,当寄存器为0时,阻值为0;当寄存器为0x7F时阻值为100kΩ
void RWrite(uint8_t value)
{I2CStart();I2CSendByte(0x5e);I2CWaitAck();I2CSendByte(value);I2CWaitAck();I2CStop();
}
uint8_t RRead(void)
{uint8_t value;I2CStart();I2CSendByte(0x5F);I2CWaitAck();value = I2CReceiveByte();I2CSendNotAck();I2CStop();return value;
}
检测从0-127,PB14的电压
/* USER CODE BEGIN PFP */
void RWrite(uint8_t value)
{I2CStart();I2CSendByte(0x5e);I2CWaitAck();I2CSendByte(value);I2CWaitAck();I2CStop();
}
uint8_t RRead(void)
{uint8_t value;I2CStart();I2CSendByte(0x5F);I2CWaitAck();value = I2CReceiveByte();I2CSendNotAck();I2CStop();return value;
}
double getADC()
{HAL_ADC_Start(&hadc1);return HAL_ADC_GetValue(&hadc1)*3.3/4096;
}
/* USER CODE END PFP */
/* USER CODE BEGIN WHILE */for(int i=0;i<128;i++){RWrite(i);HAL_Delay(20);sprintf(buf,"%d %lf",RRead(),getADC());LCD_ClearLine(Line4);LCD_DisplayStringLine(Line4,(uint8_t*)buf);HAL_Delay(1000);}while (1){/* USER CODE END WHILE */
5 UART/USART
CubeMX默认的引脚是不对的,所以别忘了更改引脚
5.1 实验1:轮询收发
HAL_UART_Receive:接收不完指定数量的字符不会进行下一步,设置的等待时间一般为无限大
/* USER CODE BEGIN WHILE */HAL_UART_Receive(&huart1,(uint8_t*)buf,5,0xFFFF);//接收不完指定数量的字符不会进行下一步HAL_UART_Transmit(&huart1,(uint8_t*)buf,5,0xFFFF);while (1){/* USER CODE END WHILE */
5.2 实验2:中断收发
CubeMX别忘打开串口中断
HAL_UART_Receive_IT:不会等待,最多收指定个数,收几个无所谓,但是只有收满了才会进入中断回调函数
下面这个程序如果不写在while里是不会收到除了空白以外的任何字符的,因为只执行一次的话Receive函数已经过了,不会再执行
while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_UART_Receive_IT(&huart1,(uint8_t*)buf,5);//不会等待,最多收5个,收几个无所谓HAL_UART_Transmit_IT(&huart1,(uint8_t*)buf,5);}/* USER CODE END 3 */
5.3 实验3:中断回调函数
/* USER CODE BEGIN PFP */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance==USART1){HAL_UART_Transmit_IT(&huart1,(uint8_t*)buf,5);HAL_UART_Receive_IT(&huart1,(uint8_t*)buf,5);}
}
/* USER CODE END PFP *//* USER CODE BEGIN WHILE */HAL_UART_Receive_IT(&huart1,(uint8_t*)buf,5);//不会等待,最多收5个,收几个无所谓while (1){/* USER CODE END WHILE */
5.4 字符串问题注意
每个字符串结尾都有\r\n占两个位置,而且如果我们在串口助手里勾选发送新行后,每次发送的字符串后都带\r\n
5.5 实验4:发送指定格式的字符串并从字符串中提取指定信息
比如我们想发送时间,指定格式为时:分:秒,我们想从串口收到的字符串中提取到时,分,秒三个信息
这里用到sscanf函数来提取信息
当然也可以根据实际情况单个单个提取,不过会略显复杂
/* USER CODE BEGIN PTD */
char buf[20];
int hour,min,second;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance==USART1){sscanf(buf,"%d:%d:%d",&hour,&min,&second);sprintf(buf,"hour:%d",hour);LCD_ClearLine(Line2);LCD_ClearLine(Line4);LCD_ClearLine(Line6);LCD_DisplayStringLine(Line2,(uint8_t*)buf);sprintf(buf,"min:%d",min);LCD_DisplayStringLine(Line4,(uint8_t*)buf);sprintf(buf,"second:%d",second);LCD_DisplayStringLine(Line6,(uint8_t*)buf);memset(buf,0,sizeof(buf));HAL_UART_Receive_IT(&huart1,(uint8_t*)buf,8);}
}
/* USER CODE END PFP */
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);I2CInit();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */HAL_UART_Receive_IT(&huart1,(uint8_t*)buf,8);while (1){/* USER CODE END WHILE */
5.6 实验5:DMA及几种收发方式的分析
打开DMA:
打开中断:
DMA是默认打开中断的
因为DMA是不占用CPU的,我们可以尽量使用DMA来提高效率
这里我们发现收到的数据不完整,然后我们延时一下,这次数据完整
/* USER CODE BEGIN PTD */
char buf[20];
int hour,min,second;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance==USART1){sscanf(buf,"%d:%d:%d",&hour,&min,&second);sprintf(buf,"hour:%d",hour);LCD_ClearLine(Line2);LCD_ClearLine(Line4);LCD_ClearLine(Line6);LCD_DisplayStringLine(Line2,(uint8_t*)buf);sprintf(buf,"min:%d",min);LCD_DisplayStringLine(Line4,(uint8_t*)buf);sprintf(buf,"second:%d",second);LCD_DisplayStringLine(Line6,(uint8_t*)buf);sprintf(buf,"%02d:%02d:%02d",hour,min,second);HAL_UART_Transmit_DMA(&huart1,(uint8_t*)buf,8);//int t=100000; while(t--);LCD_DisplayStringLine(Line8,(uint8_t*)buf);memset(buf,0,sizeof(buf));HAL_UART_Receive_DMA(&huart1,(uint8_t*)buf,8);}
}
/* USER CODE END PFP */
/* USER CODE BEGIN WHILE */HAL_UART_Receive_DMA(&huart1,(uint8_t*)buf,8);while (1){/* USER CODE END WHILE */
然后我们试图将Transmit一句改成IT,然后将USART1的中断优先级调整比DMA高,然后发现仍然可以接收到
但是如果我们全部改成IT,就不可取了,初步分析是中断回调函数的事件过多
所以我们尽量采取DMA的方式收发数据
5.7 实验6:串口的不定长收发(DMA+空闲中断)
其中中断服务函数需要到
中找
/* USER CODE BEGIN WHILE */HAL_UART_Receive_DMA(&huart1,(uint8_t*)buf,20);__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);while (1){/* USER CODE END WHILE */
void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 */if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)==SET){__HAL_UART_CLEAR_IDLEFLAG(&huart1);HAL_UART_DMAStop(&huart1);len=20-__HAL_DMA_GET_COUNTER(huart1.hdmarx);HAL_UART_Transmit_DMA(&huart1,(uint8_t*)buf,len);HAL_UART_Receive_DMA(&huart1,(uint8_t*)buf,20);}/* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(&huart1);/* USER CODE BEGIN USART1_IRQn 1 *//* USER CODE END USART1_IRQn 1 */
}
6 TIM
6.1 实验1:延时
while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if(__HAL_TIM_GetCounter(&htim1)==10000){HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);__HAL_TIM_SetCounter(&htim1,0);}}/* USER CODE END 3 */
6.2 实验2:PWM输出(控制蜂鸣器)
PWM原理如图所示:
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);I2CInit();LED_Close();HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,5000);/* USER CODE END 2 */
6.3 实验3:检测555信号发生器信号频率和占空比
分析:每次捕捉到上升沿我们就进入一次中断,这时我们就得到了一个信号周期的大小
现在我们已知定时器计一个数的时间,只要我们读取定时器计了多少数,就能通过公式:
信号周期=定时器计一个数的时间*定时器计数值
算出信号周期,进而算出信号频率
占空比的计算可以另外设置一个通道,根据占空比的定义:
占空比=一个周期内高电平的时间/一个周期
测量PA15引脚对应的555信号发生器:
注意:分频系数设置为80比较好,这样记一次数的时间比较短,测量比较精确,而且计数器不容易溢出
注意TIM2CHANNEL1对应的引脚设置成PA15
这里注意打印%的方法
/* USER CODE BEGIN PFP */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM2&&htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1){cnt=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);cnt_down=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2);__HAL_TIM_SetCounter(&htim2,0);f=10000000/cnt;duty=1-(double)cnt_down/(double)cnt;}
}
/* USER CODE END PFP */
/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Blue);LCD_SetBackColor(Blue);LCD_SetTextColor(White);I2CInit();HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);/* USER CODE END 2 */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */sprintf(buf,"%dHz %.2lf%%",f,duty*100);LCD_DisplayStringLine(Line4,(uint8_t*)buf);HAL_Delay(1000);LCD_ClearLine(Line4);}/* USER CODE END 3 */
6.4 实验4:检测自己输出的PWM频率和占空比(上升沿中断)
找到板子上能插杜邦线的两个引脚,一个引脚输出PWM,另一个引脚测量输入的PWM有关性质
我选择了PB15和PB11两个引脚,PB15用来产生PWM波,PB11用来测量PWM的有关性质
PB15:
设置分频系数为8,计数器最大值为1000-1,所以PWM的频率为:
80MHz/8/1000=10000Hz
PB11:
分频系数为80-1,所以计数频率(1/计一个数的时间)为:
80MHz/80=1MHz
set可以设置为在0-1000内的值,假如我们设置为300,那么占空比为30%
/* USER CODE BEGIN PTD */
int cnt,cnt_down,f;
double duty;
char buf[20];
int set;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM2&&htim->Channel==HAL_TIM_ACTIVE_CHANNEL_4){cnt=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_4);cnt_down=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_3);__HAL_TIM_SetCounter(&htim2,0);f=1000000/cnt;duty=1-(double)cnt_down/(double)cnt;}
}
/* USER CODE END PFP *//* USER CODE BEGIN 2 */HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_4);HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_3);HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_2);__HAL_TIM_SetCompare(&htim15,TIM_CHANNEL_2,set);LCD_Init();LCD_Clear(Blue);/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */sprintf(buf,"%dHz %.4lf",f,duty);LCD_DisplayStringLine(Line2,(uint8_t*)buf);HAL_Delay(200);}/* USER CODE END 3 */
最后测量得到频率为10204Hz,占空比为0.5102,和预估结果大致相同
6.5 实验5:检测自己输出的PWM频率和占空比(PWM中断)
捕捉到上升沿中断其实跟PWM中断一样,都是上升沿开始时触发中断
我们打开PWM中断,使用PWM中断回调函数
/* USER CODE BEGIN PTD */
int cnt,cnt_down,f;
double duty;
char buf[20];
int set;
/* USER CODE END PTD */
/* USER CODE BEGIN PFP */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM15&&htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2){cnt=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_4);cnt_down=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_3);__HAL_TIM_SetCounter(&htim2,0);f=1000000/cnt;duty=1-(double)cnt_down/(double)cnt;}
}
/* USER CODE END PFP *//* USER CODE BEGIN 2 */HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_4);HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_3);HAL_TIM_PWM_Start_IT(&htim15,TIM_CHANNEL_2);__HAL_TIM_SetCompare(&htim15,TIM_CHANNEL_2,set);LCD_Init();LCD_Clear(Blue);/* USER CODE END 2 *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */sprintf(buf,"%dHz %.4lf",f,duty);LCD_DisplayStringLine(Line2,(uint8_t*)buf);HAL_Delay(200);}/* USER CODE END 3 */
7 RTC
7.1 实验1:显示年月日时分秒
/* USER CODE BEGIN PTD */
char buf[20];
/* USER CODE END PTD */
/* USER CODE BEGIN PD */
RTC_TimeTypeDef TIME;
RTC_DateTypeDef DATE;
/* USER CODE END PD */
/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_RTC_GetTime(&hrtc,&TIME,RTC_FORMAT_BIN);HAL_RTC_GetDate(&hrtc,&DATE,RTC_FORMAT_BIN);LCD_ClearLine(Line2);LCD_ClearLine(Line4);sprintf(buf,"%d-%d-%d",DATE.Year,DATE.Month,DATE.Date);LCD_DisplayStringLine(Line2,(uint8_t*)buf);sprintf(buf,"%d:%d:%d",TIME.Hours,TIME.Minutes,TIME.Seconds);LCD_DisplayStringLine(Line4,(uint8_t*)buf);}/* USER CODE END 3 */
7.2 实验2:秒中断
上面我们已经设置好RTC的频率为750MHz,按照如上系数配置,750K/125/6000=1Hz
1秒发生一次中断,而跟我们设定的闹钟时间无关
/* USER CODE BEGIN PTD */
char buf[20];
/* USER CODE END PTD */
/* USER CODE BEGIN PD */
RTC_TimeTypeDef TIME;
RTC_DateTypeDef DATE;
/* USER CODE END PD */
/* USER CODE BEGIN PFP */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_3);
}
/* USER CODE END PFP */
/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_RTC_GetTime(&hrtc,&TIME,RTC_FORMAT_BIN);HAL_RTC_GetDate(&hrtc,&DATE,RTC_FORMAT_BIN);LCD_ClearLine(Line2);LCD_ClearLine(Line4);sprintf(buf,"%d-%d-%d",DATE.Year,DATE.Month,DATE.Date);LCD_DisplayStringLine(Line2,(uint8_t*)buf);sprintf(buf,"%d:%d:%d",TIME.Hours,TIME.Minutes,TIME.Seconds);LCD_DisplayStringLine(Line4,(uint8_t*)buf);}/* USER CODE END 3 */
7.3 实验3:闹钟中断
日期时分都不看,只看秒,如果闹钟设定的秒跟当前时间一样,则进入中断,自己需要编写的其它代码跟实验2一致
相关文章:

蓝桥杯嵌入式STM32G431RBT6知识点(主观题部分)
目录 1 前置准备 1.1 Keil 1.1.1 编译器版本及微库 1.1.2 添加官方提供的LCD及I2C文件 1.2 CubeMX 1.2.1 时钟树 1.2.2 其他 1.2.3 明确CubeMX路径,放置芯片包 2 GPIO 2.1 实验1:LED1-LED8循环亮灭 编辑 2.2 实验2:…...

ELAdmin 部署
后端部署 按需修改 application-prod.yml 例如验证码方式、登录状态到期时间等等。 修改完成后打好 Jar 包 执行完成后会生成最终可执行的 jar。JPA版本是 2.6,MyBatis 版本是 1.1。 启动命令 nohup java -jar eladmin-system-2.6.jar --spring.profiles.active…...

计算机功能简介:EC, NVMe, SCSI/ISCSI与块存储接口 RBD,NUMA
一 EC是指Embedded Controller 主要应用于移动计算机系统和嵌入式计算机系统中,为此类计算机提供系统管理功能。EC的主要功能是控制计算机主板上电时序、管理电池充电和放电,提供键盘矩阵接口、智能风扇接口、串口、GPIO、PS/2等常规IO功能,…...

linux上安装bluesky的步骤
1、设备上安装的操作系统如下: orangepiorangepi5b:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.2 LTS Release: 22.04 Codename: jammy 2、在用户家目录下创建一个目录miniconda3目录&a…...

视频监控需求八问:视频智能分析/视频汇聚平台EasyCVR有何特性?
最近TSINGSEE青犀视频在与业内伙伴进行项目合作的过程中,针对安防监控可视化视频管理系统EasyCVR视频融合平台在电信运营商项目中的应用,进行了多方面的项目需求沟通。今天我们就该项目沟通为案例,来具体了解一下用户关心度较高的关于视频智能…...

django rest framework 学习笔记2
注意:该文章部分摘抄之百度,仅当做学习笔记供小白使用,若侵权请联系删除! 显示关联表的数据,本示例会显示所有的关联的数据信息 from rest_framework import serializers from .models import Student class StudentM…...

第四篇【传奇开心果系列】Python文本和语音相互转换库技术点案例示例:pyttsx3自动化脚本经典案例
传奇开心果短博文系列 系列短博文目录Python文本和语音相互转换库技术点案例示例系列 短博文目录前言一、雏形示例代码二、扩展思路介绍三、批量处理文本示例代码四、自定义语音设置示例代码五、结合其他库和API示例代码六、语音交互系统示例代码七、多语言支持示例代码八、添加…...

model.train()和model.eval()两种模式的原理
1. model.train() 在使用 pytorch 构建神经网络的时候,训练过程中会在程序上方添加一句model.train(),作用是 启用 batch normalization 和 dropout 。 如果模型中有BN层(Batch Normalization)和 Dropout ,需要在 训练…...

docker的底层原理六: 联合文件系统(UnionFS)
Docker的底层存储原理基于联合文件系统(UnionFS)。 联合文件系统(UnionFS)是一种特殊的文件系统,它允许独立地叠加多个目录层,呈现给用户的是这些目录层的联合视图。这种结构使得在Docker中,不…...

【动态规划专栏】专题一:斐波那契数列模型--------1.第N个泰波那契数
本专栏内容为:算法学习专栏,分为优选算法专栏,贪心算法专栏,动态规划专栏以及递归,搜索与回溯算法专栏四部分。 通过本专栏的深入学习,你可以了解并掌握算法。 💓博主csdn个人主页:小…...

自养号测评低成本高效率推广,安全可控
测评的作用在于让用户更真实、清晰、快捷地了解产品以及产品的使用方法和体验。通过买家对产品的测评,也可以帮助厂商和卖家优化产品缺陷,提高用户的使用体验。这进而帮助他们获得更好的销量,并更深入地了解市场需求。因此,测评在…...

ubuntu22.04@laptop OpenCV Get Started: 015_deep_learning_with_opencv_dnn_module
ubuntu22.04laptop OpenCV Get Started: 015_deep_learning_with_opencv_dnn_module 1. 源由2. 应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 使用 OpenCV DNN 模块进行图像分类3.1 导入模块并加载类名文本文件3.2 从磁盘加载预训练 DenseNet121 模型3.3 读取图像并准备为模型输…...

【elk查日志 elastic(kibana)】
文章目录 概要具体的使用方式一:查找接口调用历史二:查找自己的打印日志三:查找错误日志 概要 每次查日志,我都需要别人帮我,时间长了总觉得不好意思,所以这次下定决心好好的梳理一下,怎么查日…...

RapidMiner数据挖掘2 —— 初识RapidMiner
本节由一系列练习与问题组成,这些练习与问题有助于理解多个基本概念。它侧重于各种特定步骤,以进行直接的探索性数据分析。因此,其主要目标是测试一些检查初步数据特征的方法。大多数练习都是关于图表技术,通常用于数据挖掘。 为此…...

基于STM32的光照检测系统设计
基于STM32的光照检测系统设计 摘要: 随着物联网和智能家居的快速发展,光照检测系统在智能环境控制中扮演着越来越重要的角色。本文设计了一种基于STM32的光照检测系统,该系统能够实时检测环境光强度,并根据光强度调节照明设备,实现智能照明控制。本文首先介绍了系统的总体…...

车辆管理系统设计与实践
车辆管理系统是针对车辆信息、行驶记录、维护保养等进行全面管理的系统。本文将介绍车辆管理系统的设计原则、技术架构以及实践经验,帮助读者了解如何构建一个高效、稳定的车辆管理系统。 1. 系统设计原则 在设计车辆管理系统时,需要遵循以下设计原则&…...

板块一 Servlet编程:第四节 HttpServletResponse对象全解与重定向 来自【汤米尼克的JAVAEE全套教程专栏】
板块一 Servlet编程:第四节 HttpServletResponse对象全解与重定向 一、什么是HttpServletResponse二、响应数据的常用方法三、响应乱码问题字符流乱码字节流乱码 四、重定向:sendRedirect请求转发和重定向的区别 在上一节中,我们系统的学习了…...

漫谈:C/C++ char 和 unsigned char 的用途
C/C的字符默认是有符号的,这一点非常的不爽,因为很少有人用单字节表达有符号数,毕竟,ASCII码是无符号的,对字符的绝大多数处理都是基于无符号的。 这一点在其它编程语言上就好很多,基本上都提供了byte这种类…...

安全保护制度
安全保护制度 第九条 计算机信息系统实行安全等级保护。安全等级的划分标准和安全等级保护的具体办法,由公安部会同有关部门制定。 第十条 计算机机房应当符合国家标准和国家有关规定。 在计算机机房附近施工,不得危害计算机信息系统的安全。 第十一条 进行国际联网的计算…...

沁恒CH32V30X学习笔记07---多功能按键框架使用
多功能按键框架使用 参考开源框架: GitHub - 0x1abin/MultiButton: Button driver for embedded system 框架使用说明: ch32gpio基本驱动 https://blog.csdn.net/u010261063/article/details/136157718 MultiButton 简介 MultiButton 是一个小巧简单易用的事件驱动型按…...

如何看显卡是几G?
created: 2024-02-20T09:22:13 (UTC 08:00) tags: [] source: https://www.sysgeek.cn/windows-check-gpu-model/ author: 海猴子 6 种简单方法:如何在 Windows 中轻松查看显卡型号 - 系统极客 Excerpt 不确定你的显卡型号?使用这 6 个简单有效的方法&a…...

虚拟机--pc端和macOS端互通
windows开启虚拟化 要在Windows系统中开启虚拟化,您可以按照以下步骤操作: 准备工作: 确保您的计算机CPU支持虚拟化技术。在BIOS中开启相应的虚拟化支持。 开启虚拟化: 打开控制面板,点击程序或功能项&am…...

(14)Hive调优——合并小文件
目录 一、小文件产生的原因 二、小文件的危害 三、小文件的解决方案 3.1 小文件的预防 3.1.1 减少Map数量 3.1.2 减少Reduce的数量 3.2 已存在的小文件合并 3.2.1 方式一:insert overwrite (推荐) 3.2.2 方式二:concatenate 3.2.3 方式三ÿ…...

Linux 驱动开发基础知识——LED 模板驱动程序的改造:设备树(十一)
个人名片: 🦁作者简介:学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755qq.com 🦉个人WeChat:Vir2021GKBS 🐼本文由…...

学习文档:QT QTreeWidget及其代理
学习文档:QT QTreeWidget及其代理 1. QT QTreeWidget简介 QT QTreeWidget是QT框架中的一个重要组件,用于显示树形数据结构。它提供了一种方便的方式来展示并操作带有层次关系的数据。QTreeWidget可以显示包含多个列的树形视图,每个项目可以…...

代码随想录算法训练营——总结篇
不知不觉跟完了代码训练营为期两个月的训练,现在来做个总结吧~ 记得去年12月上旬的时候,我每天都非常浮躁。一方面,经历了三个多月的秋招,我的日常学习和实验室进展被完全打乱,导致状态很差;另一方面&#…...

更改WordPress作者存档链接author和用户名插件Change Author Link Structure
WordPress作者存档链接默认情况为/author/Administrator(用户名),为了防止用户名泄露,我们可以将其改为/author/1(用户ID),具体操作可参考『如何将WordPress作者存档链接中的用户名改为昵称或ID…...

Kernelized Correlation Filters KCF算法原理详解(阅读笔记)(待补充)
KCF 目录 KCF预备知识1. 岭回归2. 循环移位和循环矩阵3. 傅里叶对角化4. 方向梯度直方图(HOG) 正文1. 线性回归1.1. 岭回归1.2. 基于循环矩阵获取正负样本1.3. 基于傅里叶对角化的求解 2. 使用非线性回归对模型进行训练2.1. 应用kernel-trick的非线性模型…...

安卓游戏开发之图形渲染技术优劣分析
一、引言 随着移动设备的普及和性能的提升,安卓游戏开发已经成为一个热门领域。在安卓游戏开发中,图形渲染技术是关键的一环。本文将对安卓游戏开发中常用的图形渲染技术进行分析,比较它们的优劣,并探讨它们在不同应用场景下的适用…...

python+django+vue汽车票在线预订系统58ip7
本课题使用Python语言进行开发。基于web,代码层面的操作主要在PyCharm中进行,将系统所使用到的表以及数据存储到MySQL数据库中 使用说明 使用Navicat或者其它工具,在mysql中创建对应名称的数据库,并导入项目的sql文件; 使用PyChar…...