【STM32G4】备战蓝桥杯嵌入式---实战---第八届嵌入式国赛(频率控制器)


前言

国赛在即,友友们一起准备国赛吧。

一、题目

功能简述

在这里插入图片描述
在这里插入图片描述

二、模块初始化以及功能分析

1.模块的初始化

需要使用的模块:LCD、按键B1~B4、TIM2测频率、TIM3输出方波、ADC2双路检测、EEPROM参数存储
在这里插入图片描述

2.模块功能分析

LCD–>屏幕显示
按键B1~B4–>按键实现人机交互
TIM2–>测量PLUS1、PLUS2的频率
TIM3–>输出两路不同频率的方波
ADC2–>两路注入通道测量电压值
EEPROM–>参数存储

三、函数实现

1.主函数分析

参数获取:EEPROM检测是否第一次写入,若为第一次写入则默认参数,反则读取存储的参数

	/* LCD初始化 */
	LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	/* iic初始化 */
	I2CInit();
	/* 开启输入捕获通道 */
	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
	/* 开启输出比较通道 */
	HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_1);
	HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_2);
	/* 参数获取 */
	mode = Location = 0;
	if(IIC_Read(0x02) != 1)
	{
		IIC_Write(0x00,1);HAL_Delay(5);
		IIC_Write(0x01,1);HAL_Delay(5);
		IIC_Write(0x02,1);HAL_Delay(5);
	}
	Coefficient[0] = IIC_Read(0x00);HAL_Delay(5);
	Coefficient[1] = IIC_Read(0x01);HAL_Delay(5);
	
	/* 关闭LED提示 */
	GPIOC->ODR |= 0xff00;
	GPIOD->ODR |= (1 << 2);
	GPIOD->ODR &= ~(1 << 2);

while(1)

		/* 屏幕显示以及按键处理 */
		Display();
		key = KEY_Scan(0);
		if(key) KEY_Handle(key);
		/* ADC采集以及转换成电压 */
		HAL_ADC_Start(&hadc2);
		Value[0] = (double)(HAL_ADC_GetValue(&hadc2)&0xfff)/4096*3.3f;
		HAL_ADC_Start(&hadc2);
		Value[1] = (double)(HAL_ADC_GetValue(&hadc2)&0xfff)/4096*3.3f;
		HAL_ADC_Stop(&hadc2);
		/* 通过PLUSx的频率计算出输出频率 */
		fre1 = (1000000*Coefficient[0])/(2*PWM[0]);
		fre2 = (1000000)/(2*PWM[1]*Coefficient[1]);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		/* LED提示 */
		if(mode)
			GPIOC->ODR &= ~(1<<8);
		else
			GPIOC->ODR |= 1<<8;
		if(Value[0] > Value[1])
			GPIOC->ODR &= ~(1<<15);
		else
			GPIOC->ODR |= 1<<15;
		
		GPIOC->ODR |= 0x7e00;
		GPIOD->ODR |= (1 << 2);
		GPIOD->ODR &= ~(1 << 2);

2.子函数分析

1.void Display(void)

mode为0,屏幕显示1,反之显示2.

void Display(void)
{
	if(!mode)
	{
		sprintf((char *)str,"     Measure    ");
		LCD_DisplayStringLine(Line0,str);
		
		if(PWM[0] > 1000)
			sprintf((char *)str," PLUS1:%2dkHz",(uint16_t)PWM[0]/1000);
		else
			sprintf((char *)str," PLUS1:%3dHz",(uint16_t)PWM[0]);
		LCD_DisplayStringLine(Line2,str);
		
		if(PWM[1] > 1000)
			sprintf((char *)str," PLUS2:%2dkHz",(uint16_t)PWM[1]/1000);
		else
			sprintf((char *)str," PLUS2:%3dHz",(uint16_t)PWM[1]);
		LCD_DisplayStringLine(Line4,str);

		sprintf((char *)str," AO1: %.2lfV",Value[0]);
		LCD_DisplayStringLine(Line6,str);
		sprintf((char *)str," AO2: %.2lfV       1",Value[1]);
		LCD_DisplayStringLine(Line8,str);
	}
	else if(mode == 1)
	{
		sprintf((char *)str,"       Setup    ");
		LCD_DisplayStringLine(Line0,str);
		if(Location == 0)
			LCD_SetTextColor(Green);
		sprintf((char *)str," DIV: %d",Coefficient[0]);
		LCD_DisplayStringLine(Line4,str);
		LCD_SetTextColor(White);
		if(Location == 1)
			LCD_SetTextColor(Green);
		sprintf((char *)str," MUL: %d",Coefficient[1]);
		LCD_DisplayStringLine(Line6,str);
		LCD_SetTextColor(White);
		sprintf((char *)str,"                  2");
		LCD_DisplayStringLine(Line8,str);
	}
}

2.uint8_t KEY_Scan(void)

按键识别

uint8_t KEY_Scan(uint8_t mode)
{
	static uint8_t flag=1;
	if(mode)	flag = 1;
	if(flag &&(KEY_B1 == 0 || KEY_B2	== 0 || KEY_B3 == 0 ||	KEY_B4== 0 ))
	{
		HAL_Delay(10);
		flag = 0;
		if (KEY_B1 == 0)	return B1_Press;
		else if (KEY_B2 == 0) return B2_Press;
		else if (KEY_B3 == 0) return B3_Press;
		else if (KEY_B4 == 0) return B4_Press;
	}else if(KEY_B1 == KEY_B2 == KEY_B3 == KEY_B4 == 1)	flag = 1;
	return 0;
}

3.void KEY_Handle(uint8_t key)

根据按键的功能,分别对其进行编写
Location表示对某一参数进行修改

void KEY_Handle(uint8_t key)
{
	if(key == B1_Press)
	{
		mode = !mode;
		LCD_Clear(Black);
		HAL_TIM_OC_Stop_IT(&htim3, TIM_CHANNEL_1);
		HAL_TIM_OC_Stop_IT(&htim3, TIM_CHANNEL_2);
		if(!mode)
		{
			EEPROM_Conserve();
			HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_1);
			HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_2);
		}
	}
	else if(key == B2_Press)
	{
		Location++;
		Location %= 2;
	}
	else if(key == B3_Press && mode == 1)
	{
		if(Coefficient[Location] < 4)
			Coefficient[Location]++;
	}
	else if(key == B4_Press && mode == 1)
	{
		if(Coefficient[Location] > 1)
			Coefficient[Location]--;
	}
}

4.EEPROM读写函数

根据时许编写

void IIC_Write(uint8_t address, uint8_t data)
{
	I2CStart();
	I2CSendByte(0xA0);
	I2CWaitAck();
	
	I2CSendByte(address);
	I2CWaitAck();
	I2CSendByte(data);
	I2CWaitAck();
	I2CStop();
}
uint8_t IIC_Read(uint8_t address)
{
	uint16_t data;
	I2CStart();
	I2CSendByte(0xA0);
	I2CWaitAck();
	
	I2CSendByte(address);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xA1);
	I2CWaitAck();
	data = I2CReceiveByte();
	I2CSendNotAck();
	I2CStop();
	
	return data;
}

5.void EEPROM_Conserve(void)

对分频系数和倍频系数进行存储

void EEPROM_Conserve(void)
{
	IIC_Write(0x00, Coefficient[0]);HAL_Delay(5);
	IIC_Write(0x01, Coefficient[1]);HAL_Delay(5);
}

6.void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

两路输入捕获,得到PLUS1、PLUS2的频率PWM[0]、PWM[1]

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim == &htim2)
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			if(Value2 < TIM2->CCR2)
				Value2 = TIM2->CCR2 - Value2;
			else
				Value2 = 0xffff+TIM2->CCR2 - Value2;
			PWM[0] = 1000000 / Value2;
			Value2 = TIM2->CCR2;
		}
		else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
		{
			if(Value3 < TIM2->CCR3)
				Value3 = TIM2->CCR3 - Value3;
			else
				Value3 = 0xffff+TIM2->CCR3 - Value3;
			PWM[1] = 1000000 / Value3;
			Value3 = TIM2->CCR3;
		}
	}
}

7.HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)

不同频率的双通道输出分频方波和倍频方波

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim == &htim3)
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			TIM3->CCR1 += fre1;
		}
		else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			TIM3->CCR2 += fre2;
		}
	}
}

测试:

在这里插入图片描述

总结

以上代码全是个人思路(除仿照按键设别),如果觉得不错请支持一下。
在此声明一下,本人是提供一些思路,所以直接放c文件、h文件就没有意义。
分段解析更通俗易懂,所以请多理解,不喜勿喷,谢谢。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值