您的位置:首页 > 游戏 > 游戏 > 奋进新征程_优秀网页欣赏_手机软文广告300字_西安seo服务公司排名

奋进新征程_优秀网页欣赏_手机软文广告300字_西安seo服务公司排名

2025/5/15 18:59:09 来源:https://blog.csdn.net/pyh1322712308/article/details/146550938  浏览:    关键词:奋进新征程_优秀网页欣赏_手机软文广告300字_西安seo服务公司排名
奋进新征程_优秀网页欣赏_手机软文广告300字_西安seo服务公司排名

参考

第八届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)_蓝桥杯嵌入式第八届-CSDN博客

一、CubeMx 配置

第六届 蓝桥杯 嵌入式 省赛 -CSDN博客,一样的配置,把 .ioc 文件拷贝过来就行。

二、代码编写

1. 头文件

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
//#include "adc.h"
#include "rtc.h"
#include "tim.h"
//#include "usart.h"
#include "gpio.h"
#include <stdio.h>   // 提供 sprintf()
#include <string.h>  // 提供 strlen()/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//#include "lcd.h"
#include "i2c_hal.h"
/* USER CODE END Includes */

2.  全局变量

用户要定义的变量,后面缺啥补啥

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
RTC_TimeTypeDef H_M_S_Time;
RTC_DateTypeDef Y_M_D_Date;/* USER CODE END PTD *//* USER CODE BEGIN PV */
//*减速变量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度
__IO uint32_t uwTick_Usart_Set_Point = 0;//控制Usart_Proc的执行速度//*按键扫描专用变量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;//*LED专用变量
uint8_t ucLed;//*LCD显示专用变量
uint8_t Lcd_Disp_String[21];//最多显示20个字符//用户自定义变量区/* USER CODE END PV */

3. 函数声明

//main.h/* USER CODE BEGIN EFP */
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
//void Usart_Proc(void);
void Elev_Proc(void);/* USER CODE END EFP */

4. 主函数

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();//MX_ADC1_Init();//MX_ADC2_Init();MX_TIM2_Init();MX_TIM6_Init();//MX_USART1_UART_Init();MX_RTC_Init();MX_TIM3_Init();MX_TIM15_Init();MX_TIM17_Init();/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(White);LCD_SetBackColor(White);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */Key_Proc();Led_Proc();Lcd_Proc();//Usart_Proc();Elev_Proc();/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

5. 函数实现

5.1 按键

按键永远是逻辑的开端。

重新审题:

4个按键代表4个楼层。

按下后点亮对应的LED灯(LD1-LD4)。

如果此时再按该楼层,则按键无效。

一次可以设置多个目标楼层。

在最后一次按键按完 1 秒之后,模拟电机开始运行。这句话其实隐含了,只能在空闲状态下进行楼层选择。
  • 首先,空闲状态下有 1秒的按键判断。
    • 那么,按键每次按下,都要刷新这 1秒的时间判断。
  • 其次,由于是可以多目标选择,那么逻辑上4个LED灯是求或的。
    • 需要加个前提,不是当前平台。
    • 举个例子:如果当前在2楼,且空闲状态,此时按平台2,是没有效果的。
  • 最后,LED的高4位不要动,因为要作为流水灯的。
void Key_Proc(void)
{if((uwTick -  uwTick_Key_Set_Point)<50)	return;//减速函数uwTick_Key_Set_Point = uwTick;ucKey_Val = Key_Scan();unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);	ucKey_Old = ucKey_Val;if(state == ELEV_IDLE)//空闲状态{if(unKey_Down == 1)//B1按压{if(ucPlat != 1) ucSet |= 0x01; //ucPlat的1234表示当前所处的平台}	//ucSet用于记录几号按键按下去了。只用低4位,分别对应LD4~LD1,按键B4~B1else if(unKey_Down == 2)//B2按压{if(ucPlat != 2) ucSet |= 0x02; }	else if(unKey_Down == 3)//B3按压{if(ucPlat != 3) ucSet |= 0x04; 	}		else if(unKey_Down == 4)//B4按压{		if(ucPlat != 4) ucSet |= 0x08; 	}		ucLed &= 0xF0;ucLed |= ucSet;		if(unKey_Down != 0)//当有按键按下去,启动计时{uwTick_Set_Point = uwTick;}		}
}

5.2 流水灯

题目没说灯的流动方向和上下方向的关系。这里就设定:

上升的时候,灯从右往左

下降的时候,灯从左往右

枚举方向

typedef enum {DIR_UP = 1,DIR_DOWN = 2
} Direction;
static Direction dir = DIR_UP;
void Led_Proc(void)
{if((uwTick -  uwTick_Led_Set_Point)<200)	return;//减速函数uwTick_Led_Set_Point = uwTick;LED_Disp(ucLed);
}uint8_t Flow = 0x10;//流水的变量void UpdateFlowLED(Direction dir) {ucLed &= 0x0F;ucLed |= Flow;if (dir == DIR_UP) {Flow = (Flow >> 1);if(Flow == 0x08)Flow = 0x80;} else {Flow = (Flow << 1);if(Flow == 0x00)Flow = 0x10;}LED_Disp(ucLed);
}//void LED_Disp(uint8_t ucLed)在gpio.c中定义了

5.3 LCD

void Lcd_Proc(void)
{if((uwTick -  uwTick_Lcd_Set_Point)<100)	return;//减速函数uwTick_Lcd_Set_Point = uwTick;//开机屏幕测试代码sprintf((char *)Lcd_Disp_String, " Current Platform");LCD_DisplayStringLine(Line1, Lcd_Disp_String);	sprintf((char *)Lcd_Disp_String, "          %1d",(unsigned int)ucPlat);LCD_DisplayStringLine(Line3, Lcd_Disp_String);		//*RTC内容显示HAL_RTC_GetTime(&hrtc, &H_M_S_Time, RTC_FORMAT_BIN);//读取日期和时间必须同时使用HAL_RTC_GetDate(&hrtc, &Y_M_D_Date, RTC_FORMAT_BIN);sprintf((char *)Lcd_Disp_String, "       %02d-%02d-%02d",(unsigned int)H_M_S_Time.Hours,(unsigned int)H_M_S_Time.Minutes,(unsigned int)H_M_S_Time.Seconds);LCD_DisplayStringLine(Line6, Lcd_Disp_String);		
}

5.4 状态机

stateDiagram[*] --> IdleIdle --> DoorClosing: 有目标楼层DoorClosing --> DoorClosed: 关门完成DoorClosed --> Moving: 启动电机Moving --> Arrived: 到达目标层Arrived --> DoorOpening: 停止电机DoorOpening --> DoorOpened: 开门完成DoorOpened --> Idle: 无其他目标DoorOpened --> WaitingNext: 有其他目标WaitingNext --> DoorClosing: 等待结束

 枚举状态

typedef enum {ELEV_IDLE,              // 空闲状态(等待按键)ELEV_DOOR_CLOSING,      // 关门中ELEV_DOOR_CLOSED,       // 门已关ELEV_MOVING,            // 运行中(上下行)ELEV_ARRIVED,           // 到达目标层ELEV_DOOR_OPENING,      // 开门中ELEV_DOOR_OPENED,       // 门已开ELEV_WAITING_NEXT      // 等待下一目标
} ElevState;static ElevState state = ELEV_IDLE;

 PWM 宏定义

/* USER CODE BEGIN PD */
// 硬件配置宏(便于修改)
#define DOOR_PWM_TIM        htim17   //PA7
#define DOOR_PWM_CHANNEL    TIM_CHANNEL_1
#define MOTOR_PWM_TIM       htim3    //PA6
#define MOTOR_PWM_CHANNEL   TIM_CHANNEL_1/* USER CODE END PD */

实现

// 主状态机函数
void Elev_Proc(void) {if (!ucSet) return;  // 无目标层时退出switch (state) {//------------------ 空闲状态 ------------------//case ELEV_IDLE:if ((uwTick - uwTick_Set_Point) >= 1000) {state = ELEV_DOOR_CLOSING;}break;//------------------ 关门过程 ------------------//case ELEV_DOOR_CLOSING:HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  // 关门方向__HAL_TIM_SET_COMPARE(&DOOR_PWM_TIM, DOOR_PWM_CHANNEL, 250);  // 50%占空比HAL_TIM_PWM_Start(&DOOR_PWM_TIM, DOOR_PWM_CHANNEL);LCD_ShowMessage(Line8, "Door Closing");stateEnterTime = uwTick;state = ELEV_DOOR_CLOSED;break;case ELEV_DOOR_CLOSED:if ((uwTick - stateEnterTime) >= 4000) {HAL_TIM_PWM_Stop(&DOOR_PWM_TIM, DOOR_PWM_CHANNEL);LCD_ShowMessage(Line8, "Door Closed");state = ELEV_MOVING;}break;//------------------ 运行过程 ------------------//case ELEV_MOVING: {uint8_t targetMask = (1 << (ucPlat - 1));if (ucSet > targetMask) {// 上行dir = DIR_UP;HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);__HAL_TIM_SET_COMPARE(&MOTOR_PWM_TIM, MOTOR_PWM_CHANNEL, 800);  // 80%占空比HAL_TIM_PWM_Start(&MOTOR_PWM_TIM, MOTOR_PWM_CHANNEL);LCD_ShowMessage(Line8, "Elev Upping");} else if (ucSet < targetMask) {// 下行dir = DIR_DOWN;HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);__HAL_TIM_SET_COMPARE(&MOTOR_PWM_TIM, MOTOR_PWM_CHANNEL, 600);  // 60%占空比HAL_TIM_PWM_Start(&MOTOR_PWM_TIM, MOTOR_PWM_CHANNEL);LCD_ShowMessage(Line8, "Elev Downing");}stateEnterTime = uwTick;state = ELEV_ARRIVED;break;}case ELEV_ARRIVED:if ((uwTick - stateEnterTime) >= 6000) {// 更新楼层ucPlat += (dir == DIR_UP) ? 1 : -1;sprintf((char *)Lcd_Disp_String, "          %1d",(unsigned int)ucPlat);LCD_DisplayStringLine(Line3, Lcd_Disp_String);					sprintf((char *)Lcd_Disp_String, "Elev Runned 1 Floor        ");LCD_DisplayStringLine(Line8, Lcd_Disp_String);	// 检查是否到达目标层if (ucSet & (1 << (ucPlat - 1))) {HAL_TIM_PWM_Stop(&MOTOR_PWM_TIM, MOTOR_PWM_CHANNEL);state = ELEV_DOOR_OPENING;} else {// 未到达,继续移动stateEnterTime = uwTick;state = ELEV_MOVING;}} else {// 运行中流水灯效果UpdateFlowLED(dir);HAL_Delay(300);}break;//------------------ 开门过程 ------------------//case ELEV_DOOR_OPENING:HAL_Delay(300);					sprintf((char *)Lcd_Disp_String, "             ");LCD_DisplayStringLine(Line3, Lcd_Disp_String);	HAL_Delay(300);								sprintf((char *)Lcd_Disp_String, "          %1d",(unsigned int)ucPlat);LCD_DisplayStringLine(Line3, Lcd_Disp_String);						HAL_Delay(300);					sprintf((char *)Lcd_Disp_String, "             ");LCD_DisplayStringLine(Line3, Lcd_Disp_String);	HAL_Delay(300);								sprintf((char *)Lcd_Disp_String, "          %1d",(unsigned int)ucPlat);LCD_DisplayStringLine(Line3, Lcd_Disp_String);	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);    // 开门方向__HAL_TIM_SET_COMPARE(&DOOR_PWM_TIM, DOOR_PWM_CHANNEL, 300);  // 60%占空比HAL_TIM_PWM_Start(&DOOR_PWM_TIM, DOOR_PWM_CHANNEL);LCD_ShowMessage(Line8, "Door Opening");stateEnterTime = uwTick;state = ELEV_DOOR_OPENED;break;case ELEV_DOOR_OPENED:if ((uwTick - stateEnterTime) >= 4000) {HAL_TIM_PWM_Stop(&DOOR_PWM_TIM, DOOR_PWM_CHANNEL);LCD_ShowMessage(Line8, "Door Opened");// 清除当前目标层标志ucSet &= ~(1 << (ucPlat - 1));ucLed &= 0xF0;ucLed |= ucSet;LED_Disp(ucLed);state = (ucSet) ? ELEV_WAITING_NEXT : ELEV_IDLE;}break;//------------------ 等待下一目标 ------------------//case ELEV_WAITING_NEXT:if ((uwTick - stateEnterTime) >= 2000) {LCD_ShowMessage(Line8, "                  ");state = ELEV_DOOR_CLOSING;  // 继续下一目标}break;}
}

5.5 PWM

计数器输出频率

计数器占空比

题目要求PA6,也就是TIM3配成1kHz 。

PA7,也就是TIM17配置成2kHz。最好ARR配置成 1000,会更规范点。


__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 800);//修改占空比的基本操作 D=0.8
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);	//PA6   1khz  绿色波形
/*** @brief  Set the TIM Capture Compare Register value on runtime without calling another time ConfigChannel function.* @param  __HANDLE__ TIM handle.* @param  __CHANNEL__ TIM Channels to be configured.*          This parameter can be one of the following values:*            @arg TIM_CHANNEL_1: TIM Channel 1 selected*            @arg TIM_CHANNEL_2: TIM Channel 2 selected*            @arg TIM_CHANNEL_3: TIM Channel 3 selected*            @arg TIM_CHANNEL_4: TIM Channel 4 selected*            @arg TIM_CHANNEL_5: TIM Channel 5 selected*            @arg TIM_CHANNEL_6: TIM Channel 6 selected* @param  __COMPARE__ specifies the Capture Compare register new value.* @retval None*/
#define __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__) \(((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCR1 = (__COMPARE__)) :\((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCR2 = (__COMPARE__)) :\((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCR3 = (__COMPARE__)) :\((__CHANNEL__) == TIM_CHANNEL_4) ? ((__HANDLE__)->Instance->CCR4 = (__COMPARE__)) :\((__CHANNEL__) == TIM_CHANNEL_5) ? ((__HANDLE__)->Instance->CCR5 = (__COMPARE__)) :\((__HANDLE__)->Instance->CCR6 = (__COMPARE__)))

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com