西宁网站建设哪家公司好,网站建设表格的属性,陕西企业网站建设哪家专业,电影网站html源码目录
第一部分 客观试题#xff08;15 分#xff09;
不定项选择#xff08;1.5 分/题#xff09; 第二部分 程序设计试题#xff08;85 分#xff09; 2.1 STM32CubeMX初始化配置 2.1.1 配置GPIO 2.1.2 配置ADC 2.1.3 配置RCC 2.1.4 配置定时器TIM 2.1.5 配置ADC1、AD…
目录
第一部分 客观试题15 分
不定项选择1.5 分/题 第二部分 程序设计试题85 分 2.1 STM32CubeMX初始化配置 2.1.1 配置GPIO 2.1.2 配置ADC 2.1.3 配置RCC 2.1.4 配置定时器TIM 2.1.5 配置ADC1、ADC2 2.1.6 配置定时器2 2.1.7 配置定时器3 2.1.8 可以选择配置操作系统 2.1.9 时钟树设置
2.2 代码详解 2.2.1 LCD task 2.2.2 KEYtask 2.2.3 PWM信号输出控制 总耗时4.5h
第十四届蓝桥杯嵌入式第一部分 客观试题15 分
不定项选择1.5 分/题 01. 下列电路中属于时序逻辑电路的是 ABC。 A. 计数器 B. 分频器 C. D 触发器 D. 编码器 02. 一个 8 位二进制减法计数器初始状态为 0000 0000经过 300 个输入脉冲后计 数器的状态为B 。 A. 0010 1100 B. 1101 0011 C. 0010 0011 D. 1101 0100 03. 晶体管的穿透电流 ICEO能够体现 A。 A. 晶体管的温度稳定性 B. 晶体管允许通过最大电流极限参数 C. 晶体管放大能力 D. 晶体管的频率特性 04. STM32 系列微控制器程序可以在哪些区域上运行AB 。 A. ROM B. RAM C. 寄存器 D. E2PROM 05. 一个 8 位的 DAC 转换器供电电压为 3.3V参考电压 2.4V其 1LSB 产生的输出 电压增量是D V。 A. 0.0129 B. 0.0047 C. 0.0064 D. 0.0094 06. 下列门电路中输出端可以直接相连实现线与的是AC 。 A.OC 门 B.TTL 或非门 C.OD 门 D.CMOS 与非门 07. 在 STM32 系列微控制器中中断优先级可配置的是BC 。 A. RCC B. NMI C. HardFault D. Systick 08. 工作在线性区域的运算放大器应处于什么状态 A。 A. 负反馈 B. 正反馈 C. 开环 D. 振荡 09. 同步电路和异步电路的区别是D 。 A. 电路中是否包含缓冲器 B. 电路中是否包含触发器 C. 电路中是否存在时钟信号 D. 电路中是否存在统一的时钟信号 10. 下列关于关键字 inline 的描述正确的是ABD 。 A. 降低栈内存的消耗。 B. 可以提高代码的运行效率。 C. 可以提高微控制器访问内部寄存器的速度。 D. 程序中大量使用会增大代码编译后的可执行文件的大小 第二部分 程序设计试题85 分 2.1 STM32CubeMX初始化配置 选择STM32G431RBTx系列芯片 2.1.1 配置GPIO 2.1.2 配置ADC 2.1.3 配置RCC 2.1.4 配置定时器TIM 2.1.5 配置ADC1、ADC2 一般是默认设置就可以了开启全局中断打开DMA通道1、DMA通道2 2.1.6 配置定时器2 将PA1引脚配置定时器PWM模式1使PA1输出PWM脉冲信号让PA7捕获。 2.1.7 配置定时器3 将PA7引脚配置定时器为输入捕获模式用来捕捉PWM信号。 2.1.8 可以选择配置操作系统 1.添加FreeRTOS定时器 PWM信号定时器PWM输出高速模式PWM输出低速模式 2.添加任务提前设置好任务的内存块 堆栈空间的大小。定义句柄 3.建立消息队列 按键功能复杂可以使用队列简化复杂度进行调度 PWM信号分高频和低频模式也可以使用队列进行调度。 4.其他设置 使能固件库pack 使能定义任务函数 2.1.9 时钟树设置 2.2 代码详解 定义全局变量Generator_Mode用来选择LCD界面3个模式的显示Generator_FreqMode用来选择PWM高频和低频模式。Generator_KeyLock用来标志按键是否锁定如果锁定则不能使用Generator_DutyLock用来标志占空比锁。Generator_FreqShifting用来选择PWM高低模式Generator_ShiftNum记录频率切换次数多于10次则转1。Generator_ShiftNum、Generator_K参数界面的R和K。MaxSpeed_HighFreq、MaxSpeed_LowFreq记录高低频率下的最大速度。
低频输出频率是4k,高频输出频率是8k可以用const静态关键字进行固定。
// 屏幕显示模式0为数据1为参数2为统计和频率模式0低1高
uint8_t Generator_Mode 0, Generator_FreqMode 0;
// 按键锁定标志位低高频切换过程置高占空比锁定标志位数据界面长按B4置高再短按B4置低
uint8_t Generator_KeyLock 0, Generator_DutyLock 0;
// 正在切换的频率模式0低1高
uint8_t Generator_FreqShifting 0;
// 记录的频率切换次数
uint32_t Generator_ShiftNum 0;
// 参数界面的R和K
int8_t Generator_R 1, Generator_K 1;
// 记录的高/低频率下的最大速度
float MaxSpeed_HighFreq 0, MaxSpeed_LowFreq 0;
// PA1输出的占空比PA7采样计算得到的速度
float Generator_PWMDuty 0, Generator_Speed 0;
// PA1输出的频率
uint16_t Generator_Freq 4000;
//PA1高、低频模式下的频率因为是固定的所以声明为const
const uint16_t Generator_HFreq 8000, Generator_LFreq 4000; 2.2.1 LCD task 全局变量已经解释过了按照任务需求进行LCD界面选择显示
LCD_Printfva_list关键字作用是宏定义一个para变量va_start(para, format)执行para (va_list)format _INTSIZEOF(format)para指向参数format之后的那个参数的地址即para指向第一个可变参数在堆栈的地址。vsnprintf函数用来向一个字符串缓冲区打印格式化字符串且可以限定打印的格式化字符串的最大长度。va_end(para)用来清空para。LCD_DisplayStringLine函数是官方给的lcd.c文件中的函数用来定位行直接调用就行。
void LCD_Printf(u8 line, const char *format, ...)
{char buf[22] {0};va_list para;va_start(para, format);int len vsnprintf(buf, sizeof(buf), format, para);va_end(para);LCD_DisplayStringLine(line, (unsigned char *)buf);
} osMessageQueueGet接收按键队列的消息osOK枚举确认接收到了队列消息
void LCD_Handler(void *argument)
{/* USER CODE BEGIN LCD_Handler */int8_t Generator_TempR 1, Generator_TempK 1;//RK两个参数的暂存uint8_t Modified 0;//0为修改R1为修改Kuint32_t online_cnt 0;/* Infinite loop */for (;;){LED_Ctrl(0, (Generator_Mode 0) ? 1 : 0);//如果在数据模式下才点亮LD1LED_Ctrl(2, Generator_DutyLock);//如果占空比锁定则点亮LD3switch (Generator_Mode)//根据显示模式切换LCD显示{case 0:LCD_Printf(Line1, DATA );LCD_Printf(Line3, M%c , ((Generator_FreqMode) ? H : L));LCD_Printf(Line4, P%.0f%% , Generator_PWMDuty * 100.0f);LCD_Printf(Line5, V%.1f , Generator_Speed);break;case 1:LCD_Printf(Line1, PARA );LCD_Printf(Line3, R%d , Generator_TempR);LCD_Printf(Line4, K%d , Generator_TempK);break;case 2:LCD_Printf(Line1, RECD );LCD_Printf(Line3, N%d , Generator_ShiftNum);LCD_Printf(Line4, MH%.1f , MaxSpeed_HighFreq);LCD_Printf(Line5, ML%.1f , MaxSpeed_LowFreq);break;default:break;}uint8_t key 0xff;//暂存变量接收按键队列传出的按键信息if (osMessageQueueGet(Key_QueueHandle, key, 0, 0) osOK)//按键队列有最新按键信息{switch (key){case 0://B1短按LCD_Clear(Black);Generator_Mode;//刷屏换模式if (Generator_Mode 1)//换模式后如果是参数模式也即按下按键后进入参数模式{Generator_TempR Generator_R, Generator_TempK Generator_K;//暂存变量更新为现在设置的值。Modified 0;//进入模式默认先修改R所以Modified不管之前是什么值都改为0}if (Generator_Mode 2)//超过2则返回数据模式Generator_Mode 0;if (Generator_Mode 2)//换模式后如果是统计模式也即刚刚是从参数模式退出来的{Generator_R Generator_TempR, Generator_K Generator_TempK;//实际参数用暂存值更新。}break;case 1://B2短按if (!Generator_KeyLock Generator_Mode 0)//此时按键未锁定且处于数据模式下{osMessageQueuePut(PWM_Signal_QueueHandle, key, 0, 0);//启动频率切换进程}else if (Generator_Mode 1)//此时在参数模式下{Modified (Modified) ? 0 : 1;//Modified在0,1之间切换}break;case 2://B3短按if (Generator_Mode 1)//此时在参数模式下{if (Modified)//0为修改R1为修改KGenerator_TempK;elseGenerator_TempR;if (Generator_TempK 10)//参数越界判定Generator_TempK 1;if (Generator_TempR 10)Generator_TempR 1;}break;case 3://B4短按if (Generator_Mode 1){if (Modified)//0为修改R1为修改KGenerator_TempK--;elseGenerator_TempR--;if (Generator_TempK 1)//参数越界判定Generator_TempK 10;if (Generator_TempR 1)Generator_TempR 10;}else if (Generator_Mode 0)//此时在数据模式下{Generator_DutyLock 0;//短按是解除占空比锁}break;case 4:/* code */break;case 5:/* code */break;case 6:/* code */break;case 7://B4触发长按条件if (Generator_Mode 0)//此时在数据模式下{Generator_DutyLock 1;//长按是占空比锁上锁}break;default:break;}}osDelayUntil((online_cnt 1) * 100);//刷新用时控制在100ms左右online_cnt;}/* USER CODE END LCD_Handler */
} 2.2.2 KEYtask 将按键按下次数存入数组中返回到按键扫描函数。
uint8_t Key_IsUp(uint8_t pos)
{return Key_Up[pos];
}
uint8_t Key_IsLongPress(uint8_t pos)
{return Key_LongPress[pos];
} 遍历按键gpio是否按下按下则往Key_Reg数组中存入1方便接下来取反判断按键按下次数并将按键按下次数存入Key_Cnt数组中。
uint8_t Key_Reg[4], Key_Constant[4], Key_Up[4], Key_LongPress[4], Key_LongTemp[4];
uint16_t Key_Cnt[4], Key_Delay 78;
void Key_Scan(void)
{if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) GPIO_PIN_RESET){Key_Reg[0] 1;}else{Key_Reg[0] 0;}if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) GPIO_PIN_RESET){Key_Reg[1] 1;}else{Key_Reg[1] 0;}if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) GPIO_PIN_RESET){Key_Reg[2] 1;}else{Key_Reg[2] 0;}if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_RESET){Key_Reg[3] 1;}else{Key_Reg[3] 0;}for (int i 0; i 4; i){Key_Up[i] ~Key_Reg[i] (Key_Reg[i] ^ Key_Constant[i]);Key_Constant[i] Key_Reg[i];if (Key_Cnt[i] Key_Delay){if (Key_Up[i]){Key_LongPress[i]1;// Key_LongPress[i] Key_Up[i] (Key_Up[i] ^ Key_LongTemp[i]);Key_Up[i] 0;}// Key_LongPress[i] Key_Reg[i] (Key_Reg[i] ^ Key_LongTemp[i]);Key_LongTemp[i] Key_Reg[i];}else{Key_LongPress[i] 0;Key_LongTemp[i] 0;}}if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) GPIO_PIN_RESET){Key_Cnt[0];}else{Key_Cnt[0] 0;}if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) GPIO_PIN_RESET){Key_Cnt[1];}else{Key_Cnt[1] 0;}if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) GPIO_PIN_RESET){Key_Cnt[2];}else{Key_Cnt[2] 0;}if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_RESET){Key_Cnt[3];}else{Key_Cnt[3] 0;}
} 这里用for循环用来判断按键4是否长按如果i3则触发长按
void Key_Handler(void *argument)
{/* USER CODE BEGIN Key_Handler */uint32_t online_cnt 0;/* Infinite loop */for (;;){Key_Scan();//扫描按键for (uint8_t i 0; i 4; i){if (Key_IsUp(i)){osMessageQueuePut(Key_QueueHandle, i, 0, 0);//触发短按条件B1-4对应数字0-3}if (Key_IsLongPress(i)){uint8_t j i 4;osMessageQueuePut(Key_QueueHandle, j, 0, 0);//触发长按条件B1-4对应数字4-7}}osDelayUntil((online_cnt 1) * 25);//扫描周期粗略为25msonline_cnt;}/* USER CODE END Key_Handler */
} 2.2.3 PWM信号输出控制 由题目知道电压处于0-3V之间占空比同时随着电压变换。只展示部分核心代码
void PWM_Handler(void *argument)
{/* USER CODE BEGIN PWM_Handler */uint32_t online_cnt 0;/* Infinite loop */for (;;){if (Generator_DutyLock 0)//未启用占空比锁{//根据题目实时修改占空比介于10-85%之间if (R1_Vol 1.0f){Generator_PWMDuty 0.1f;}else if (R1_Vol 3.0f){Generator_PWMDuty 0.85f;}else{Generator_PWMDuty -0.275f R1_Vol * 0.375f;}}//上锁则保持原有占空比不变Timer_PWMSetDuty(Generator_PWMDuty);//控制占空比Timer_PWMSetFreq(Generator_Freq);//控制频率Generator_Speed (IC_Freq * 2 * 3.14f * Generator_R) / 100 / Generator_K;//根据PA7输入频率计算得到“速度”。switch (Generator_FreqMode)//0为低频率模式1为高频率模式{case 0:if (Generator_Speed MaxSpeed_LowFreq !osTimerIsRunning(Lspeed_UpdateTimerHandle)){//发现现有速度高于记录的低频率最高速度且低频率最高速度更新定时器未启动osTimerStart(Lspeed_UpdateTimerHandle, 2000U);//启动更新定时器准备2s后更新低频率最高速度}else if (Generator_Speed MaxSpeed_LowFreq osTimerIsRunning(Lspeed_UpdateTimerHandle)){//发现现有速度已经低于记录的低频率最高速度且低频率最高速度更新定时器已经启动osTimerStop(Lspeed_UpdateTimerHandle);//不必再更新低频率最高速度停止更新定时器}break;case 1://高频率部分道理同上if (Generator_Speed MaxSpeed_HighFreq !osTimerIsRunning(Hspeed_UpdateTimerHandle)){osTimerStart(Hspeed_UpdateTimerHandle, 2000U);}else if (Generator_Speed MaxSpeed_HighFreq osTimerIsRunning(Hspeed_UpdateTimerHandle)){osTimerStop(Hspeed_UpdateTimerHandle);}break;default:break;}uint8_t info 0;if (osMessageQueueGet(PWM_Signal_QueueHandle, info, 0, 0) osOK)//收到LCD控制任务下发的频率切换指令{Generator_KeyLock 1;//锁定B2按键Generator_FreqShifting Generator_FreqShifting ? 0 : 1;//此时高频则改为低频1-0此时低频则改为高频0-1osTimerStart(PWM_Signal_TimerHandle, 100U);//启动频率修改定时器0.1s刷新一次}osDelayUntil((online_cnt 1) * 10);//整个PWM控制任务大概执行一次延时10msonline_cnt;}/* USER CODE END PWM_Handler */
}void PWM_Signal_CB(void *argument)
{/* USER CODE BEGIN PWM_Signal_CB *///频率修改定时器回调函数0.1s触发一次if (Generator_FreqShifting)//切换目标是高频还是低频{Generator_Freq (Generator_HFreq - Generator_LFreq) / 50;//单个周期0.1s增加80HZ5s后正好为8KHZ}else{Generator_Freq - (Generator_HFreq - Generator_LFreq) / 50;//单个周期0.1s减少80HZ5s后正好为4KHZ}LED_Toggle(1);//LD1以0.1s为周期闪烁if (Generator_FreqShifting Generator_Freq Generator_HFreq){//低频切高频时PWM频率增加后已经超过了8KHZ也即切换5s之后Generator_FreqMode Generator_FreqShifting;//现在的频率模式更新为高频Generator_ShiftNum;//PWM切换次数加一Generator_Freq Generator_HFreq;//现在的频率和最高频率对齐Generator_KeyLock 0;//按键B2解锁LED_Ctrl(1, 0);//熄灭LD1osTimerStop(PWM_Signal_TimerHandle);//完成任务停止定时器}if (!Generator_FreqShifting Generator_Freq Generator_LFreq){//高频切低频时PWM频率减少后已经低于4KHZ也即切换5s之后Generator_FreqMode Generator_FreqShifting;//现在的频率模式更新为低频Generator_ShiftNum;//PWM切换次数加一Generator_Freq Generator_LFreq;//现在的频率和最低频率对齐Generator_KeyLock 0;//按键B2解锁LED_Ctrl(1, 0);//熄灭LD1osTimerStop(PWM_Signal_TimerHandle);//完成任务停止定时器}//注意该定时器为周期性定时器(osTimerPeriodic)完成切换后需要手动终止定时器/* USER CODE END PWM_Signal_CB */
}