2023蓝桥杯嵌入式14届程序题
这里占空比需要用斜率求
Y=kx+bY = kx+bY=kx+b
k=y−y0x−x0k = \\frac{y-y0}{x-x0}k=x−x0y−y0
b=y0−kx0b = y0-kx0b=y0−kx0
代入公式:
k=0.85−0.13−1=0.375k = \\frac{0.85-0.1}{3-1}=0.375k=3−10.85−0.1=0.375
0.85−0.375×3=−0.2750.85-0.375\\times3 = -0.2750.85−0.375×3=−0.275
Y=0.375x−0.275Y=0.375x-0.275Y=0.375x−0.275
main.c
int main(void)
{vHardware_Init();while(1){vLcd_Display_function();vRun_Flag_function();}
}
my.h
#ifndef __MY_H
#define __MY_H
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "lcd.h"#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>#define KEY1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KEY2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KEY3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KEY4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
#define TEST 0 //打印测试typedef struct
{uint8_t HightLight_Flag; //高亮标志位默认Rfloat Adc_Value; //ADC值bool LCD_OVER_FLAG; //LCD刷新标志位uint8_t Key_Down_State[8]; //按键状态bool Adc_Over_Flag; //ADC接收完成标志位uint8_t H_or_L_State; //高低频状态bool Fre_5s_Flag; //频率5s标志位uint8_t Lock_State; //是否锁标志位uint8_t Lcd_Dis_Choose_State; //界面显示状态
} MYDATA_TypeDef;typedef struct
{uint16_t PA1_Fre; //PA1输出频率uint8_t Data_P; //实时占空比float Data_V; //实时速度uint8_t Para_R; //参数Ruint8_t Para_K; //参数Kuint16_t Recd_N; //输出模式切换次数float Recd_MH; //输出模式下高频模式速度最大值float Recd_ML; //输出模式下低频模式速度最小值} PARAMETER_TypeDef;typedef struct
{bool IC_OVER_FLAG; //计算速度完成标志位uint32_t One_Value; //第1次uint32_t Two_Value; //第2次uint32_t Three_Value; //第3次uint32_t Four_Value; //第4次uint16_t Fre_Value; //频率float Duty_Value; //占空比uint8_t IC_RUN_STATE; //运行状态
} PWMDATA_TypeDef;extern MYDATA_TypeDef MyData;
extern PARAMETER_TypeDef ParameterData;
extern PWMDATA_TypeDef PwmData;void vLed_Control2(uint8_t swch, uint8_t num);
void vAdc_Get_function(void);
void vRun_Flag_function(void);
uint8_t ucKey_Scan(void);
void vKey_function(void);
void vHardware_Init(void);
void vLed_Control(uint8_t led_num);
void vLcd_Display_function(void);
#endif
my.c
MYDATA_TypeDef MyData =
{.HightLight_Flag = 1,.Adc_Value = 0.0,.LCD_OVER_FLAG = 0,.Key_Down_State = {0},.Adc_Over_Flag = 0,.H_or_L_State = 1,.Fre_5s_Flag = 0,.Lock_State = 0,.Lcd_Dis_Choose_State = 1,
};PARAMETER_TypeDef ParameterData =
{.PA1_Fre = 4000,.Data_P = 0,.Data_V = 0,.Para_R = 1,.Para_K = 1,.Recd_N = 0,.Recd_MH = 0,.Recd_ML = 0,
};PWMDATA_TypeDef PwmData =
{.IC_OVER_FLAG = 0,.One_Value = 0,.Two_Value = 0,.Three_Value = 0,.Four_Value = 0,.Fre_Value = 0,.Duty_Value = 0,.IC_RUN_STATE = 0,
};//全局变量
uint16_t Led_State = 0xFF; //LED初始状态
uint8_t Key_Up, Key_Down, Key_Value; //按键相关
uint16_t Key_Time = 0;//显示数组
char Lcd_dis1_Arr[20] = "\\0";
char Lcd_dis2_Arr[20] = "\\0";
char Lcd_dis3_Arr[20] = "\\0";
char Lcd_dis4_Arr[20] = "\\0";
uint8_t R_temp = 1; //临时变量 用于LCD显示
uint8_t K_temp = 1; //临时变量
uint32_t ADC_BUFF[10]; //ADC DMA存储数组void vHardware_Init(void)
{LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);vLed_Control2(RESET, 0xFF);HAL_TIM_Base_Start_IT(&htim6);HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED);HAL_ADC_Start_DMA(&hadc2, (uint32_t *)&ADC_BUFF, 10);TIM2->CCR2 = 125;HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2);
}
void vLed_Control(uint8_t led_num)
{uint16_t a = GPIOC->ODR;GPIOC->ODR = (uint16_t)led_num << 8;HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);GPIOC->ODR = a;
}void vLed_Control2(uint8_t swch, uint8_t num)
{if(SET == swch){HAL_GPIO_WritePin(GPIOC, (uint16_t)num << 8, GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(GPIOC, (uint16_t)num << 8, GPIO_PIN_SET);}HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
void vLcd_Display_function(void)
{if(MyData.LCD_OVER_FLAG){memset(Lcd_dis1_Arr, ' ', sizeof(Lcd_dis1_Arr));memset(Lcd_dis2_Arr, ' ', sizeof(Lcd_dis2_Arr));memset(Lcd_dis3_Arr, ' ', sizeof(Lcd_dis3_Arr));memset(Lcd_dis4_Arr, ' ', sizeof(Lcd_dis4_Arr));if(1 == MyData.Lcd_Dis_Choose_State){MyData.HightLight_Flag = 1; //高亮索引初始化snprintf(Lcd_dis1_Arr, sizeof(Lcd_dis1_Arr), " DATA ");LCD_DisplayStringLine(Line1, (uint8_t *)Lcd_dis1_Arr);if(1 == MyData.H_or_L_State) //低 默认上电{snprintf(Lcd_dis2_Arr, sizeof(Lcd_dis2_Arr), " M=L ");LCD_DisplayStringLine(Line3, (uint8_t *)Lcd_dis2_Arr);}else if(2 == MyData.H_or_L_State) //高{snprintf(Lcd_dis2_Arr, sizeof(Lcd_dis2_Arr), " M=H ");LCD_DisplayStringLine(Line3, (uint8_t *)Lcd_dis2_Arr);}snprintf(Lcd_dis3_Arr, sizeof(Lcd_dis3_Arr), " P=%d%% ", ParameterData.Data_P);LCD_DisplayStringLine(Line4, (uint8_t *)Lcd_dis3_Arr);snprintf(Lcd_dis4_Arr, sizeof(Lcd_dis4_Arr), " V=%.1f ", ParameterData.Data_V);LCD_DisplayStringLine(Line5, ( uint8_t *)Lcd_dis4_Arr);Led_State = (~0x01)&Led_State; //LED1亮}else if(2 == MyData.Lcd_Dis_Choose_State){snprintf(Lcd_dis1_Arr, sizeof(Lcd_dis1_Arr), " PARA ");LCD_DisplayStringLine(Line1, (uint8_t *)Lcd_dis1_Arr);snprintf(Lcd_dis2_Arr, sizeof(Lcd_dis2_Arr), " R=%d ", R_temp);snprintf(Lcd_dis3_Arr, sizeof(Lcd_dis3_Arr), " K=%d ", K_temp);if(1 == MyData.HightLight_Flag) //高亮R{LCD_SetTextColor(White);LCD_DisplayStringLine(Line3, (uint8_t *)Lcd_dis2_Arr);LCD_SetTextColor(Green);LCD_DisplayChar(Line3, 319 - (5 * 16), 'R');LCD_SetTextColor(White);LCD_DisplayStringLine(Line4, (uint8_t *)Lcd_dis3_Arr);}else if(2 == MyData.HightLight_Flag) //高亮K{LCD_SetTextColor(White);LCD_DisplayStringLine(Line4, (uint8_t *)Lcd_dis3_Arr);LCD_SetTextColor(Green);LCD_DisplayChar(Line4, 319 - (5 * 16), 'K');LCD_SetTextColor(White);LCD_DisplayStringLine(Line3, (uint8_t *)Lcd_dis2_Arr);}Led_State = (0x01) | Led_State; //LED1灭}else if(3 == MyData.Lcd_Dis_Choose_State){//退出参数页面,参数生效ParameterData.Para_R = R_temp;ParameterData.Para_K = K_temp;snprintf(Lcd_dis1_Arr, sizeof(Lcd_dis1_Arr), " RECD ");LCD_DisplayStringLine(Line1, (uint8_t *)Lcd_dis1_Arr);snprintf(Lcd_dis2_Arr, sizeof(Lcd_dis2_Arr), " N=%d ", ParameterData.Recd_N);LCD_DisplayStringLine(Line3, (uint8_t *)Lcd_dis2_Arr);snprintf(Lcd_dis3_Arr, sizeof(Lcd_dis3_Arr), " MH=%.1f ", ParameterData.Recd_MH);LCD_DisplayStringLine(Line4, (uint8_t *)Lcd_dis3_Arr);snprintf(Lcd_dis4_Arr, sizeof(Lcd_dis4_Arr), " ML=%.1f ", ParameterData.Recd_ML);LCD_DisplayStringLine(Line5, (uint8_t *)Lcd_dis4_Arr);Led_State = (0x01) | Led_State; //LED1灭}vLed_Control(Led_State);MyData.LCD_OVER_FLAG = 0;}
}
//获取ADC值并且计算占空比
void vAdc_Get_function(void)
{uint32_t Adc_temp = 0;uint8_t count = 0;uint16_t Adc_temp2 = 0;double Adc_temp3 = 0.0;static double Adc_Old_Value = 0;HAL_ADC_Stop_DMA(&hadc2);for(uint8_t i = 0; i < 10 - 1; i++){count = 0;for(uint8_t j = 0; j < 10 - 1 - i; j++){if(ADC_BUFF[j] > ADC_BUFF[j + 1]){uint32_t temp = ADC_BUFF[j];ADC_BUFF[j] = ADC_BUFF[j + 1];ADC_BUFF[j + 1] = temp;count++;}}if(!count){break;}}for(uint8_t k = 1; k < 10 - 1; k++){Adc_temp += ADC_BUFF[k];}HAL_ADC_Start_DMA(&hadc2, (uint32_t *)&ADC_BUFF, 10);MyData.Adc_Value = (double)(Adc_temp / 8) / 4096 * 3.3f;Adc_temp2 = MyData.Adc_Value * 10; //扩大10倍Adc_temp3 = (double)Adc_temp2 / 10;//改了频率,记得占空比也要改!!if(!MyData.Lock_State) //解锁状态下{if((Adc_temp3 >= 0) && (Adc_temp3 <= 1)) //10%占空比{TIM2->CCR2 = (TIM2->ARR * 0.1);ParameterData.Data_P = 10;}else if(Adc_temp3 >= 3) //85%占空比{TIM2->CCR2 = (TIM2->ARR * 0.85);ParameterData.Data_P = 85;}else //其余情况{Adc_temp3 = (0.375 * Adc_temp3) - 0.275;TIM2->CCR2 = ((TIM2->ARR) * Adc_temp3);ParameterData.Data_P = Adc_temp3 * 100;}}MyData.Adc_Over_Flag = 1;
}
uint8_t ucKey_Scan(void)
{if((!KEY1) || (!KEY2) || (!KEY3) || (!KEY4)){if(!KEY1)return 1;if(!KEY2)return 2;if(!KEY3)return 3;if(!KEY4)return 4;}return 0;
}void vKey_function(void)
{static uint8_t Key_Old_Value;Key_Value = ucKey_Scan();Key_Up = ~Key_Value & (Key_Value ^ Key_Old_Value);Key_Down = Key_Value & (Key_Value ^ Key_Old_Value);Key_Old_Value = Key_Value;if(Key_Down){Key_Time = 0;}if(Key_Time < 20){switch(Key_Up){case 1:{MyData.Key_Down_State[0] = 1;break;}case 2:{MyData.Key_Down_State[1] = 1;break;}case 3:{MyData.Key_Down_State[2] = 1;break;}case 4:{MyData.Key_Down_State[3] = 1;break;}default:break;}}else{switch(Key_Value){case 1:{MyData.Key_Down_State[4] = 1;break;}case 2:{MyData.Key_Down_State[5] = 1;break;}case 3:{MyData.Key_Down_State[6] = 1;break;}case 4:{MyData.Key_Down_State[7] = 1;break;}default:break;}}
}
void vRun_Flag_function(void)
{static uint8_t choose_Flag = 1; //R、K切换if(MyData.Key_Down_State[0]) //界面切换{MyData.Key_Down_State[0] = 0;MyData.Lcd_Dis_Choose_State++;if(MyData.Lcd_Dis_Choose_State > 3){MyData.Lcd_Dis_Choose_State = 1;}LCD_Clear(Black); //清屏}if(MyData.Key_Down_State[1]){MyData.Key_Down_State[1] = 0;if((1 == MyData.Lcd_Dis_Choose_State) && (0 == MyData.Fre_5s_Flag)) //数据页面下{MyData.Fre_5s_Flag = 1;}else if(2 == MyData.Lcd_Dis_Choose_State) //参数页面下{choose_Flag = !choose_Flag;if(!choose_Flag) //选择K{MyData.HightLight_Flag = 2;}else //选择R{MyData.HightLight_Flag = 1;}}else{;}}if(MyData.Key_Down_State[2]){MyData.Key_Down_State[2] = 0;if(2 == MyData.Lcd_Dis_Choose_State){if(1 == MyData.HightLight_Flag){R_temp++;if(R_temp > 10){R_temp = 10;}}if(2 == MyData.HightLight_Flag){K_temp++;if(K_temp > 10){K_temp = 10;}}}}if(MyData.Key_Down_State[3]){MyData.Key_Down_State[3] = 0;if(2 == MyData.Lcd_Dis_Choose_State){if(1 == MyData.HightLight_Flag){R_temp--;if(R_temp < 1){R_temp = 1;}}if(2 == MyData.HightLight_Flag){K_temp--;if(K_temp < 1){K_temp = 1;}}}else if(1 == MyData.Lcd_Dis_Choose_State){if(MyData.Lock_State) //锁状态{MyData.Lock_State = 0; //解锁Led_State = (0x04) | Led_State; //LED3灭vLed_Control(Led_State);}}}if(MyData.Key_Down_State[7]) //长按{MyData.Key_Down_State[7] = 0;MyData.Lock_State = 1; //锁Led_State = (~0x04)&Led_State; //LED3亮vLed_Control(Led_State);}if(MyData.Adc_Over_Flag){MyData.Adc_Over_Flag = 0;
#if TESTchar arr[20];snprintf(arr, sizeof(arr), "ADC:%.1f\\r\\n", MyData.Adc_Value);HAL_UART_Transmit(&huart1, (uint8_t *)arr, strlen(arr), 500);
#endif}if(4 == PwmData.IC_RUN_STATE) //计算实时速度{PwmData.Fre_Value = 1000000 / (PwmData.Four_Value - PwmData.Two_Value);PwmData.Duty_Value = (float)(PwmData.Four_Value - PwmData.Three_Value) / (float)(PwmData.Four_Value - PwmData.Two_Value) * 100;ParameterData.Data_V = (float)(PwmData.Fre_Value * 2 * 3.14 * ParameterData.Para_R) / (float)(100 * ParameterData.Para_K);
#if TESTchar arr[20];snprintf(arr, sizeof(arr), "fre:%d--%.1f\\r\\n", PwmData.Fre_Value, PwmData.Duty_Value);HAL_UART_Transmit(&huart1, (uint8_t *)arr, strlen(arr), 500);
#endifPwmData.IC_RUN_STATE = 0;HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2);PwmData.IC_OVER_FLAG = 1; //计算完成标志位}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim == &htim3){if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2){switch(PwmData.IC_RUN_STATE){case 0:{PwmData.One_Value = TIM3->CCR2;__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); //下降沿PwmData.IC_RUN_STATE = 1;break;}case 1:{PwmData.Two_Value = TIM3->CCR2;__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING); //上升沿PwmData.IC_RUN_STATE = 2;break;}case 2:{PwmData.Three_Value = TIM3->CCR2;__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); //下降沿PwmData.IC_RUN_STATE = 3;break;}case 3:{PwmData.Four_Value = TIM3->CCR2;__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING); //上升沿HAL_TIM_IC_Stop_IT(&htim3, TIM_CHANNEL_2);__HAL_TIM_SetCounter(&htim3, 0);PwmData.IC_RUN_STATE = 4;break;}}}}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{static uint8_t Tim_10ms_count = 0;static uint8_t Tim_100ms_count = 0;static uint8_t Tim_150ms_count = 0;static uint16_t Tim_5s_count = 0;static uint16_t Tim_2s_count = 0;if(htim == &htim6){Tim_10ms_count++;Tim_100ms_count++;Tim_150ms_count++;if(10 == Tim_10ms_count){Tim_10ms_count = 0;vKey_function();}if(100 == Tim_100ms_count){Tim_100ms_count = 0;MyData.LCD_OVER_FLAG = 1;Key_Time++;}if(150 == Tim_150ms_count){Tim_150ms_count = 0;vAdc_Get_function();}if(MyData.Fre_5s_Flag) //5s计时{Tim_5s_count++;if(5000 == Tim_5s_count){Tim_5s_count = 0;MyData.Fre_5s_Flag = 0;//转换完成if(1 == MyData.H_or_L_State){MyData.H_or_L_State = 2;} else if(2 == MyData.H_or_L_State){MyData.H_or_L_State = 1;} ParameterData.Recd_N++; //切换次数加1}if(0 == (Tim_5s_count % 100)) //50次{Led_State ^= 2;vLed_Control(Led_State);if(1 == MyData.H_or_L_State) //当前为低频---》高{ParameterData.PA1_Fre += 80;if(ParameterData.PA1_Fre >= 8000){ParameterData.PA1_Fre = 8000;}//改了频率,记得占空比也要改!!TIM2->ARR = (1000000.0f / ParameterData.PA1_Fre) - 1;TIM2->CCR2 = (ParameterData.Data_P / 100.0f) * (TIM2->ARR);}else if(2 == MyData.H_or_L_State) //当前为高频---》低{ParameterData.PA1_Fre -= 80;TIM2->ARR = ParameterData.PA1_Fre - 1;if(ParameterData.PA1_Fre <= 4000){ParameterData.PA1_Fre = 4000;}//改了频率,记得占空比也要改!!TIM2->ARR = (1000000.0f / ParameterData.PA1_Fre) - 1;TIM2->CCR2 = (ParameterData.Data_P / 100.0f) * (TIM2->ARR);}}}if((1 == PwmData.IC_OVER_FLAG) && (0 == MyData.Fre_5s_Flag)) //最大值(高低频切换期间的不算入){if(1 == MyData.H_or_L_State){if(ParameterData.Recd_ML < ParameterData.Data_V) //当前速度最大值小于实时速度{Tim_2s_count++;if(Tim_2s_count >= 2000){Tim_2s_count = 0;ParameterData.Recd_ML = ParameterData.Data_V;PwmData.IC_OVER_FLAG = 0;}}else{Tim_2s_count = 0;PwmData.IC_OVER_FLAG = 0;}} else if(2 == MyData.H_or_L_State){if(ParameterData.Recd_MH < ParameterData.Data_V) //当前速度最大值小于实时速度{Tim_2s_count++;if(Tim_2s_count >= 2000){Tim_2s_count = 0;ParameterData.Recd_MH = ParameterData.Data_V;PwmData.IC_OVER_FLAG = 0;}}else{Tim_2s_count = 0;PwmData.IC_OVER_FLAG = 0;}} }}
}
实验现象:https://www.bilibili.com/video/BV14a4y1T7pp/?spm_id_from=333.999.0.0&vd_source=5fb3f08926cbdbc6d84b3f2bda38c0b1