蓝桥杯嵌入式

蓝桥杯嵌入式

一点

流程:1、配置时钟 2、配置CubeMX生成MDK工程 3、配置工程分开生成c和h文件 4、移植LCD屏幕 5、配置MDK为DAP烧录,并且烧录后自动重启运行 6、CubeMX配置锁存器,使led初始化为全灭

MX添加芯片包

image-20250409163012991

image-20250409163122357

image-20250409163257082

开启代码补全

image-20250409162519680

ctrl + alt +空格

考点

image-20241207162736049

image-20241207162715155

1、配置时钟RCC__HSE,很重要,配置错误灯都点不亮

image-20241207104425400

输入24MHz的HSE通过PLL锁相环输出80MHz

输入24MHz(Input frequency)

输出80MHz(HCLK)

image-20250405151531024

如果忘了外部晶振频率,可以通过赛场资源包原理图得知

image-20250207204939824

LED:

LD1~8 ---PC8~15,低电平亮

锁存器LE:PD2

1选通,0锁存

先将锁存器LE引脚初始化为低电平,锁存LED状态,需要操作LED时再开启,操作完即关闭,避免LED与LCD的互相影响

image-20241207153800382

image-20241201155549021

key:

从上到小,按键B14,PB13,PA0image-20241211104944901

PB0~2,PA0,上拉,检测低电平

按键扫描函数(延时):

类似检测下降沿,单次按键单次触发(仍有小概率多次触发)

uint8_t B1_state,B1_last_state;
uint8_t B2_state,B2_last_state;
uint8_t B3_state,B3_last_state;
uint8_t B4_state,B4_last_state;
uint16_t keynum=0;
uint16_t num=0;
void key_process()
{
	B1_last_state=B1_state;
	B2_last_state=B2_state;
	B3_last_state=B3_state;
	B4_last_state=B4_state;
	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,上次按键状态未按下,此刻按键按下则触发,(状态变化触发)
		{
			HAL_Delay(20);keynum=1;num++;
		}	
		if(B2_state==0&&B2_last_state==1) //B2
		{
			HAL_Delay(20);keynum=2;num++;
		}
		if(B3_state==0&&B3_last_state==1) //B3
		{
			HAL_Delay(20);keynum=3;num++;
		}		
		if(B4_state==0&&B4_last_state==1) //B3
		{
			HAL_Delay(20); keynum=4;num++;
		}		
}

代码来自b站up主:【蓝桥杯嵌入式省赛快速入门教程(诚心分享+全程干货+免费无套路)】https://www.bilibili.com/video/BV1uH4y1E7G4?p=5&vd_source=cdeca744628183bf6ce46fc0a3b3e75c

struct key
{
	uint8_t key_val;//当前电平
	uint8_t key_state;//按脚循环状态
    
	uint8_t key_long_flag;//长按标志位
    uint8_t key_double_flag;
	uint8_t key_single;

     uint8_t long_time;
	uint8_t double_time;
	uint8_t key_double;
};
struct key keys[4]={0,0,0,0,0,0,0,0};
uint8_t  keynum;
void key_process(void)//放在10ms定时器回调函数中
{
                                keys[0].key_val=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);//������ƽ��ȡ
                                keys[1].key_val=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
                                keys[2].key_val=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
                                keys[3].key_val=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);

						for(int i=0;i<4;i++)
						{
										switch(keys[i].key_state)
										{
													case 0://状态0:初始检测
													{
															if(keys[i].key_val==0)keys[i].key_state=1;
													}break;
													
													case 1://状态1:消抖确认
													{
															if(keys[i].key_val==0)keys[i].key_state=2;
															else keys[i].key_state=0;
													}break;
													
													case 2://状态2:长按检测
													{
															if(keys[i].key_val==1)
															{
																if(keys[i].long_time>100)
																{
																	keys[i].key_long_flag=1;//长按
																	keys[i].key_state=0;
																}
																else keys[i].key_state=3;//检测跳转短按或双击检测
																keys[i].long_time=0;
																
															}
															else keys[i].long_time++;
													}break;
													
													
													case 3://状态3:双击(短按)检测
													{
														if(keys[i].key_val==0)
														{
															if(keys[i].double_time<=35)
															{
																keys[i].key_double_flag=1;//
															}
														}
														else 
														{
															keys[i].double_time++;
															if(keys[i].double_time>35)
															{
																keys[i].key_single=1;//短按
																keys[i].double_time=0;
																keys[i].key_state=0;
															}
														}
														if(keys[i].key_double_flag==1&&keys[i].key_val==1)
														{
																keys[i].key_double=1;//双击
																keys[i].double_time=0;
																keys[i].key_state=0;
																keys[i].key_double_flag=0;
														}
													}break;
							//				default:break;
										}
						}
}

按键检测(放while循环中)

static struct key
{
	uint8_t key_state;//按键循环状态
	uint8_t key_val;//按键当前电平
	uint8_t key_one_flag;//短按
	uint8_t key_long_flag;//长按
	uint8_t long_time;	//长按时长
};

struct key keys[4]={0};
void key_process(void) 
{
    // 读取按键电平(假设按下为低电平)
    keys[0].key_val = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
    keys[1].key_val = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
    keys[2].key_val = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
    keys[3].key_val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

    for (uint8_t i = 0; i < 4; i++) 
    {
        switch (keys[i].key_state) 
        {
            case 0: // 初始状态:检测按下
						{
                if (keys[i].key_val == 0) //按下
                {
                    keys[i].key_state = 1;//跳转消抖
                    keys[i].long_time = 0; // 重置长按计时
                }
						}break;

            case 1: // 消抖确认
						{
                if (keys[i].key_val == 0) //按下
                {
                        keys[i].key_state = 2;//跳转长按检测
                        keys[i].long_time = 0; // 重置计时,用于长按检测
                } 
                else //抖动
                {
                    keys[i].key_state = 0;
                    keys[i].long_time = 0;
                }
						}break;

            case 2: // 长按检测:按住期间计时/短按判断
						{
                if (keys[i].key_val == 0) 
                    keys[i].long_time++; // 每10ms递增
                else 
                {
                    // 松开按键时判断长按/短按
                    if (keys[i].long_time >= 50) // 长按0.5秒
                        keys[i].key_long_flag = 1; // 标记长按(仅触发一次)
										
                    else 
                        keys[i].key_one_flag = 1;   // 标记短按

                    // 重置状态
                    keys[i].key_state = 0;
                    keys[i].long_time = 0;
                }
						}break;
        }
    }
}

按键长按加短按


static struct key
{
	uint8_t key_state;//按键循环状态
	uint8_t key_val;//按键当前电平
	uint8_t key_one_flag;//短按
	uint8_t key_long_flag;//长按
	uint8_t long_time;	//长按时长
};

struct key keys[4]={0};
void key_process(void) 
{
    // 读取按键电平(假设按下为低电平)
    keys[0].key_val = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
    keys[1].key_val = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
    keys[2].key_val = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
    keys[3].key_val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

    for (uint8_t i = 0; i < 4; i++) 
    {
        switch (keys[i].key_state) 
        {
            case 0: // 初始状态:检测按下
						{
                if (keys[i].key_val == 0) 
                {
                    keys[i].key_state = 1;
                    keys[i].long_time = 0; // 重置长按计时
                }
						}break;

            case 1: // 消抖确认:持续检测50ms
						{
                if (keys[i].key_val == 0) 
                {
                        keys[i].key_state = 2;
                        keys[i].long_time = 0; // 重置计时,用于长按检测
                } 
                else 
                {
                    // 抖动或短按释放,返回初始
                    keys[i].key_state = 0;
                    keys[i].long_time = 0;
                }
						}break;

            case 2: // 长按检测:按住期间计时
						{
                if (keys[i].key_val == 0) 
                    keys[i].long_time++; // 每10ms递增
                else 
                {
                    // 松开按键时判断长按/短按
                    if (keys[i].long_time >= 50) // 长按0.5秒
                        keys[i].key_long_flag = 1; // 标记长按(仅触发一次)
										
                    else 
                        keys[i].key_one_flag = 1;   // 标记短按

                    // 重置状态
                    keys[i].key_state = 0;
                    keys[i].long_time = 0;
                }
						}break;
        }
    }
}

uint8_t keynum;
void key_w_process(void)
{
	if(keys[0].key_one_flag==1)
	{
		keynum++;
		keys[0].key_one_flag=0;
	}
	
	if(keys[0].key_long_flag==1)
	{
		keynum--;
		keys[0].key_long_flag=0;
	}
}

移植LCD:

不需要再CubeMX中进行引脚配置

include <stdio.h>

将下类文件添加进工程文件夹

image-20241207160808608

main中只用声明lcd.h头文件就可以使用LCD(不用声明fonts.h否则报错,嵌套引用)

UART串口通信

UART1(9600)

PA9,10(需手动配置,默认为PC端口)

异步模式:

开启串口中断

image-20250406194057868

添加的头文件

stdio.h(标准输入输出头文件)

string.h(字符串处理头文件)

#include <stdio.h>  //
#include <string.h>  //
  1. 输入输出函数
    • printf:格式化输出函数,用于将数据输出到标准输出(通常是屏幕)。
    • scanf:格式化输入函数,用于从标准输入(通常是键盘)读取数据。
    • fopen:打开文件。
    • fclose:关闭文件。
    • fread:从文件中读取数据。
    • fwrite:向文件中写入数据。
    • fgets:从文件中读取一行数据。
    • fputs:向文件中写入一行数据。
  2. 文件操作函数
    • remove:删除文件。
    • rename:重命名文件。
    • tmpfile:创建临时文件。
    • tmpnam:生成临时文件名。
  3. 控制函数
    • setbuf:设置缓冲区。
    • setvbuf:设置缓冲区。
    • getchar:从标准输入读取一个字符。
    • putchar:向标准输出写入一个字符。

string.h头文件中包含了以下几类函数:

  1. 字符串操作函数
    • strlen:计算字符串的长度。
    • strcpy:复制字符串。
    • strncpy:复制字符串的一部分。
    • strcat:连接两个字符串。
    • strncat:连接两个字符串的一部分。
    • strcmp:比较两个字符串。
    • strncmp:比较两个字符串的一部分。
    • strchr:查找字符串中首次出现的字符。
    • strrchr:查找字符串中最后一次出现的字符。
    • strstr:查找子字符串。
    • strtok:分割字符串。
  2. 内存操作函数
    • memcpy:复制内存块。
    • memmove:移动内存块。
    • memcmp:比较内存块。
    • memset:设置内存块。
  3. 字符操作函数
    • isalpha:检查字符是否为字母。
    • isdigit:检查字符是否为数字。
    • islower:检查字符是否为小写字母。
    • isupper:检查字符是否为大写字母。
    • isspace:检查字符是否为空白字符。
    • toupper:将字符转换为大写。
    • tolower:将字符转换为小写。

声明串口句柄

UART_HandleTypeDef huart1;

因为CubeMX中自动生成了串口初始化,并包含在MX_GPIO_Init()中,故不用再次初始化

设置串口

串口发送

unsigned char str[100]; 

sprintf(str, "%04d:Hello,world.\r\n", counter);//**格式化字符串**
HAL_UART_Transmit(&huart1,(unsigned char *)str, strlen(str), 50);//**通过UART发送字符串**strlen():计算字符串的长度

image-20250406200135466

串口接收

main():

HAL_UART_Receive_IT(&huart1, rx, 1);//启动接收中断。
uint8_t rx[100];

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口接收回调函数(弱函数)
{
	GPIOC->ODR = ((rx[0]  <<  8) | 0x00FF);//将接收到的二进制数据写入C端口,控制LED
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);//1选通锁存器
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);	//0	锁存
	HAL_UART_Receive_IT(&huart1, rx, 1);
}

image-20250408151351540

函数弱定义,可以ctrl+f搜索_weak,快速找到该函数定义

image-20250408152112751

ADC电压测量

image-20241206225840867

PB15__J11 电压采集1 ADC2_IN15

PB12__J12 电压采集2 ADC1_IN11

image-20241207104134156

image-20241207104246397

image-20241207104258941image-20241207104314183

不用设置NVIC(默认)

image-20241207104346097

获取ADC数值函数:

uint16_t getADC2_PB15_VL1(void)//PB15--ADC2_IN15
{
	uint16_t adc = 0;
	HAL_ADC_Start(&hadc2);//开启ADC2
	adc = HAL_ADC_GetValue(&hadc2);//获取adc数值
	return adc;	
}
uint16_t getADC1_PB12_VL2(void)//PB12--ADC1_IN11
{
	uint16_t adc = 0;
	HAL_ADC_Start(&hadc1);
	adc = HAL_ADC_GetValue(&hadc1);
	return adc;
}

image-20250411112014926

显示电压函数:

#include <stdio.h>  // 添加此头文件
unsigned char buf[20];//存储电压值
sprintf(buf, "      VAL:%.2fV", getADC2_PB15_VL1()*3.3/4096);//转化成电压值,保存在buf
LCD_DisplayStringLine(Line8, (uint8_t *)buf);//将cahr型变量转化成unsigned char 型变量,并在lcd中显示
sprintf(buf, "      VAL:%.2fV", getADC1_PB12_VL2()*3.3/4096);	
LCD_DisplayStringLine(Line9, (uint8_t *)buf);

解决LCD与LED引脚冲突

先将锁存器LE引脚初始化为低电平,锁存LED状态,需要操作LED时再开启,操作完即关闭,避免LED与LCD的互相影响

image-20241207153800382

//LED off 熄灭所有led
  HAL_GPIO_WritePin(GPIOC, LD6_Pin|LD7_Pin|LD8_Pin|LD1_Pin
                          |LD2_Pin|LD3_Pin|LD4_Pin|LD5_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(LE_GPIO_Port, LE_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(LE_GPIO_Port, LE_Pin, GPIO_PIN_RESET);

TIME1定时1s

选择定时器时钟输入源:

Internal Clock:内部时钟

image-20241207230619582

NVIC开启定时器1更新中断

image-20241207230843318

定时周期1s,(8000PSCX1000ARR)/8*10^6=0.1s

image-20241207230957973

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器回调函数(中断服务函数)处理定时器周期溢出事件
{
		t++;//定时溢出时执行程序
}
main(){
HAL_TIM_Base_Start_IT(&htim1);//开启定时器中断
......
}

while(1)中

		sprintf(buf, "      t=%d", t);//,保存在char型变量buf【20】中

		LCD_DisplayStringLine(Line8, (uint8_t *)buf);//将cahr型变量转化成unsigned char 型变量,并在lcd中显示

基础定时器TIM6

activate:激活

pluse:脉冲

image-20241207163221162

系统时钟80MHz

image-20241207165548336

定时周期T=(8000X1000)/8X10^6=0.1s

PSC:8000-1,ARR=1000-1

自动重装预寄存器:auto-reload preload,无影响

image-20241208100333267

开启更新中断

image-20241208101041133

定时器TIM17定时10ms

image-20250405210931036

image-20250405210956432

初始化:

	HAL_TIM_Base_Start_IT(&htim17);//启动基础定时器 TIM17 的基础计数功能并开启中断

定时器中断回调函数

unsigned char ms_10;
unsigned char s;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
		if(htim->Instance ==TIM17)//判断是否是定时器3触发的中断
	{
		ms_10++;
		if(ms_10>=100)
		{
			s++;
			ms_10=0;
		}		
//		HAL_TIM_Base_Start_IT(&htim17);//重新启动定时器的输入捕获功能,并使能相应的中断。
	}
}

频率测量,(定时器输入捕获,当计数器)

image-20241208102212215

R39__PB4 TIM3_CH1,TIM16_CH1

R40__PA15 TIM2_CH1,TIM8_CH1

原理:将预分频80后,定时器时钟频率为1MHz

配置定时器为输入捕获模式

image-20241208204626346

因为时钟树输出时钟80MHz,预分频80,则计数n为1/1MHz=1*10的-6次方=n us

配置PSC为80-1,重装值为0xFFFF(65536),最大计时值为65536us,65.5ms

频率为计时值倒数,1/n(us)=

image-20241208204701583

开启定时器中断

image-20241208204817600

测周法:两个上升沿内,以标准频率fc计次,得到N,则频率

f(捕获)=1MHz(分频后)/计数值

fc=80MHz/80=1MHz
$$
fc=1Mhz/N=1000000/N
$$

定时器回调函数:

uint32_t  cc1_value_1,cc1_value_2 = 0; uint32_t  f39,f40 = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//定时器回调函数
{
	if(htim->Instance ==TIM3)//判断是否是定时器3触发的中断
	{
		cc1_value_1 = __HAL_TIM_GET_COUNTER(&htim3);//获取计数值
		__HAL_TIM_SetCounter(&htim3,0);//清除计数值
		f39 = 1000000/cc1_value_1;//计算频率(10……6)
		HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);//重新启动定时器的输入捕获功能,并使能相应的中断。
	}
		
	if(htim->Instance ==TIM2)
	{
		cc1_value_2 = __HAL_TIM_GET_COUNTER(&htim2);
		__HAL_TIM_SetCounter(&htim2,0);
		f40 = 1000000/cc1_value_2;//(10^6)
		HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
	}
}

相关初始化

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//启动定时器的输入捕获功能,并使能相应的中断。
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);

可通过搜索关键词输入捕获开启

_IC_st

查找,因为IC是Input capture输入捕获的缩写,st是start开启的缩写

image-20250409111220926

读取频率

	 while (1)
  {
    /* USER CODE END WHILE */
         
    /* USER CODE BEGIN 3 */
   		sprintf(buf, "  FRQ(R39):%dHz   ",f39);
		LCD_DisplayStringLine(Line8, (uint8_t *)buf);
		HAL_Delay(200);
			
		sprintf(buf, "  FRQ(R40):%dHz   ",f40);
		LCD_DisplayStringLine(Line9, (uint8_t *)buf);
		HAL_Delay(200);
  }

PWM输出(占空比调节)

PA2__TIM2_CH2

选择定时器2通道2功能为

image-20241210151706138

设置为1Khz频率

PSC:800

ARR:100

f输出=80MHz/(PSC*ARR)=80x10^6/(800x100)=1000hz

image-20241210152445386

开启输出比较(默认)

image-20241210152757813

不开定时器中断(默认)

初始化PWM输出

HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);//开启time2,通道2pwm输出
uint16_t pwmduty=50;//占空比
TIM2->CCR2 =pwmduty;

//TIM2->CCR2 =50;
//uint16_t pwmduty=50;//占空比

占空比=输出比较寄存器值/自动重装载值,pwmduty=CCR/ARR=CCR2/100,即在ARR=100时,CCR的值即为占空比(<=100)

更改占空比(自己定义)

	TIM2->CCR2 =pwmduty;
	pwmduty++;
	HAL_Delay(10);
	if(pwmduty>95)pwmduty=0;

EEPROM(移植库文件,无需CubeMX配置)

image-20241210160110510

A2=A1=A0=0

地址0xa0写

0xa1读

将下面文件拷贝进工程

image-20241210165141995

引用头文件

在i2c_hal.c文件中编写iic读取EEPROM和写入函数

写入函数(器件内地址,要写入的数据)

void eeprom_write(uint8_t addr, uint8_t dat)
{
	I2CStart();
	I2CSendByte(0xa0);//器件地址
	I2CWaitAck();//等待应答(只有写操作后需要)
	I2CSendByte(addr);//期间内要操作的地址0~255???
	I2CWaitAck();
	I2CSendByte(dat);//写入的数据
	I2CWaitAck();
	I2CStop();
	

	HAL_Delay(20);//一定要加

}

读取函数(器件内地址)

uint8_t eeprom_read(uint8_t addr)
{
	I2CStart();
	I2CSendByte(0xa0);//器件地址
	I2CWaitAck();//等待应答
	I2CSendByte(addr);//期间内要操作的地址0~255???
	I2CWaitAck();
	I2CStop();	//一定要关闭IIC总线后重新开启
	
	I2CStart();
	I2CSendByte(0xa1);//读取命令
	I2CWaitAck();
	uint8_t dat = I2CReceiveByte();//接收数据
	I2CSendNotAck();   //主机不应答 从机不再发数据---------------------
	I2CStop();	
	
	return dat;

}

初始化,写入,读取

I2CInit();
eeprom_write(0, 15);//在0地址写入15

uint8_t dat = eeprom_read(0);//读取0地址
char text[20];

显示到Lcd

	sprintf(text, "      %d       ", dat);//将数据dat转化成字符串保存在text数组变量中
	LCD_DisplayStringLine(Line0, (uint8_t *)text);

RTC时钟+闹钟

在RTC中勾选

开启时钟

开启闹钟

选择内部闹钟1

image-20241210222308113

选择24h制式

image-20241210222432603

选择数据格式转化为二进制

image-20241210222516843

设置初始化时间和日期

image-20241210222557656

闹钟A设置时间

image-20241210222627367

选择是否屏蔽(屏蔽日期则闹钟不考虑日期)

image-20241210222640008

开启闹钟中断(闹钟时间时进入中断)

image-20241210222743866

设置保存时间的结构体

char text[20];
RTC_TimeTypeDef sTime = {0};//save time
RTC_DateTypeDef sDate = {0};//save day

获取时间和日期保存到结构体

HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

读取时间并显示到LCD上

sprintf(text, "      test          ");
LCD_DisplayStringLine(Line0, (uint8_t *)text);
sprintf(text, "      %2d:%2d:%2d   ", sTime.Hours, sTime.Minutes, sTime.Seconds);
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text, "      %d-%d-%d-%d   ", sDate.Year, sDate.Month, sDate.Date, sDate.WeekDay);
LCD_DisplayStringLine(Line2, (uint8_t *)text);

需要自己添加的闹钟回调函数(rtc.c)闹钟时间到达时执行

void  HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
		HAL_GPIO_TogglePin(GPIOC,LD8_Pin);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

真题训练要点记录

1、首先设置时钟树,24MHz输入,80MHz输出

led全灭初始化:

  HAL_GPIO_WritePin(GPIOC, LD6_Pin|LD7_Pin|LD8_Pin|LD1_Pin
                          |LD2_Pin|LD3_Pin|LD4_Pin|LD5_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(LE_GPIO_Port, LE_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(LE_GPIO_Port, LE_Pin, GPIO_PIN_RESET);

定时器捕获频率:

CubeMX:

选择定时器输入通道并开启,配置预分频为80-1,开启触发中断。

MDK:

main中初始化

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//启动定时器的输入捕获功能,并使能相应的中断。
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);

完成定时器中断回调函数

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance ==TIM2)
	{
		cc1_value_2 = __HAL_TIM_GET_COUNTER(&htim2);
		__HAL_TIM_SetCounter(&htim2,0);
		f40 = 1000000/cc1_value_2;
		T40=1000000/f40;
		HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
	}
}

LCD显示浮点数据(两位小数)

if (f39 < 1000){
			sprintf(buf, "     B=%dHz   ", f39);
			LCD_DisplayStringLine(Line4, (uint8_t *)buf);
}
else {
    // 将f39转换为浮点数,并除以1000,保留两位小数
	sprintf(buf, "     B=%.2fKHz   ", (float)f39/1000);
	LCD_DisplayStringLine(Line4, (uint8_t *)buf);
	}
	HAL_Delay(200);

添加头文件

#include "stdio.h"//转换字符串	

各种需记住函数:

定时器:
计时器:
//基础定时器中断初始化
HAL_TIM_Base_Start_IT(&htim17);
//定时器基础回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)


 PWM:

    

posted @ 2024-12-05 09:05  沁拒离  阅读(407)  评论(0)    收藏  举报