> 文档中心 > STM32RTC秒中断--基于HAL库(第八届蓝桥杯嵌入式省赛)

STM32RTC秒中断--基于HAL库(第八届蓝桥杯嵌入式省赛)

文章目录

  • 前言
  • 一、CubeMX配置(第十三届模拟题完整版)
  • 二、代码相关定义、声明
    • 1.函数声明
    • 2.宏定义
    • 3.变量定义
  • 三、主要函数
    • 1.按键扫描
    • 2.数组排序
    • 3.电梯运行
    • 4.RTC秒中断
    • 5.PWM输出
    • 5.Main函数
  • 四、实验结果
  • 五、源码(转载请注明出处)
  • 总结

前言

相关说明:

开发板:CT117E-M4(STM32G431RB 蓝桥杯嵌入式比赛板)
开发环境: CubeMX+Keil5
涉及题目:第八届蓝桥杯嵌入式省赛
题目难点:LCD显示与LED冲突(RTC秒中断),电梯运行逻辑
(有关RTC秒中断详情请看STM32RTC秒中断–第九届蓝桥杯嵌入式省赛)


CubeMX配置、主要函数代码及说明:

一、CubeMX配置(第十三届模拟题完整版)

1.使能外部高速时钟:
在这里插入图片描述
2.配置时钟树:在这里插入图片描述

3.GPIO:

在这里插入图片描述

4.RTC:在这里插入图片描述
在这里插入图片描述

5.PWM:在这里插入图片描述
下图框图中的参数使用默认即可,后续在代码中配置
在这里插入图片描述

6.TIM4:在这里插入图片描述
在这里插入图片描述

7.TIM6、TIM7(1s中断、2s中断):
在这里插入图片描述
TIM7配置同理
在这里插入图片描述

8.NVIC(中断配置):在这里插入图片描述

二、代码相关定义、声明

1.函数声明

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//定时器中断函数void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc);//闹钟中断函数(RTC秒中断)uint8_t Floor_CanSel(uint8_t floor_press);//判断当前楼层是否可被按下(判断是否为当前楼层或在将要前往的楼层中)void PWM_OutPut(uint8_t statue);//PWM输出函数void PWM_Stop(void);//PWM停止函数void Elevator_Close(void);//电梯门关闭void Elevator_Open(void);//电梯门打开void Elevator_Down(void);//电梯下降void Elevator_Rise(void);//电梯上升void Elevator_Run(void);//电梯根据排序好的数组运行void LCD_Init_Show(void);//LCD初始化界面void LCD_Show(void);//LCD显示void KEY_Scan(void);//按键扫描void Sort_Buff(void);//选择楼层数组排序

2.宏定义

#define KEY1_GPIO_PORT GPIOB#define KEY1_GPIO_PINGPIO_PIN_0#define KEY2_GPIO_PORT GPIOB#define KEY2_GPIO_PINGPIO_PIN_1#define KEY3_GPIO_PORT GPIOB#define KEY3_GPIO_PINGPIO_PIN_2#define KEY4_GPIO_PORT GPIOA#define KEY4_GPIO_PINGPIO_PIN_0#define ON  GPIO_PIN_RESET#define OFF GPIO_PIN_SET#define LED_GPIO_PORTGPIOC#define LED1_GPIO_PINGPIO_PIN_8#define LED2_GPIO_PINGPIO_PIN_9#define LED3_GPIO_PINGPIO_PIN_10#define LED4_GPIO_PINGPIO_PIN_11#define LED5_GPIO_PINGPIO_PIN_12#define LED6_GPIO_PINGPIO_PIN_13#define LED7_GPIO_PINGPIO_PIN_14#define LED8_GPIO_PINGPIO_PIN_15#define ON  GPIO_PIN_RESET#define OFF GPIO_PIN_SET#define LED1(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED1_GPIO_PIN,a)#define LED2(a)HAL_GPIO_WritePin(LED_GPIO_PORT,LED2_GPIO_PIN,a)#define LED3(a)HAL_GPIO_WritePin(LED_GPIO_PORT,LED3_GPIO_PIN,a)#define LED4(a)HAL_GPIO_WritePin(LED_GPIO_PORT,LED4_GPIO_PIN,a)#define LED5(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED5_GPIO_PIN,a)#define LED6(a)HAL_GPIO_WritePin(LED_GPIO_PORT,LED6_GPIO_PIN,a)#define LED7(a)HAL_GPIO_WritePin(LED_GPIO_PORT,LED7_GPIO_PIN,a)#define LED8(a)HAL_GPIO_WritePin(LED_GPIO_PORT,LED8_GPIO_PIN,a)#define LED5_TOGGLE() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED5_GPIO_PIN)#define LED6_TOGGLE() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED6_GPIO_PIN)#define LED7_TOGGLE() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED7_GPIO_PIN)#define LED8_TOGGLE() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED8_GPIO_PIN)

3.变量定义

uint8_t sel_dex=0;//楼层选择数组下标,排完序后清零,等待下一次选择uint8_t go_dex=0;//电梯运行数组下标,按照题目逻辑保存待运行楼层uint8_t floor_sel[floor_canSel];//楼层选择数组uint8_t floor_go[floor_canSel]; //电梯运行数组uint8_t floor_led[floor_canSel+2];//哪个下标对应的值为1则对应哪层楼被选中,供LED点亮函数使用,保证所有已选择且未到的楼层对应的LED点亮uint8_t floor_now=1;//当前楼层uint8_t sort_flag=0;//数组排序标志位,最后一个按键按下一秒后在中断函数中置1,主函数判断为1则执行排序函数uint8_t run_flag=0;//电梯运行标志位,每进入一次Time7中断置1,主函数判断为1继续让电梯工作,目的为控制等待时间uint8_t delay;//等待秒数(开关门4s,电梯上下行6s,等待2s)uint8_t delay_num=1;//等待次数,一次为2s,进入中断函数时已经经过一次等待,故初始值为1uint8_t key_canPress=1;//当前按键按下有效uint8_t led_dir=0;//LED方向标志位,1为上行,2为下行uint8_t has_next_floor=0;//是否还有目标楼层,如果有则不排序当前选择楼层,等待上一次选择楼层走完后,再对本次选择进行排序uint8_t door_open=1;//门是否打开标志位,1为开,0为关uint8_t lcd_refresh=0;//LCD更新标志位RTC_DateTypeDef GET_Date;//RTC获取日期结构体RTC_TimeTypeDef GET_Time;//RTC获取时间结构体TIM_OC_InitTypeDef sConfigOC = {0};//PWM相关结构体,用于调整频率char str[30];//用于组合字符串

三、主要函数

1.按键扫描

void KEY_Scan()//按键扫描{if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET && Floor_CanSel(key1_floor)){HAL_Delay(10);if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET){/*将该楼层存储进选择楼层数组中*/floor_sel[sel_dex++]=key1_floor;/*LED更新数组 对应楼层置1*/floor_led[key1_floor]=1;/*LED更新*/Led_Change();/*开启定时器 按下一秒之后进入定时器中断*/TIM6->CNT=0;HAL_TIM_Base_Start_IT(&htim6);while(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET);}}else if(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET && Floor_CanSel(key2_floor)){HAL_Delay(10);if(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET){floor_sel[sel_dex++]=key2_floor;floor_led[key2_floor]=1;Led_Change();TIM6->CNT=0;HAL_TIM_Base_Start_IT(&htim6);while(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET);}}else if(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET && Floor_CanSel(key3_floor)){HAL_Delay(10);if(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET){floor_sel[sel_dex++]=key3_floor;floor_led[key3_floor]=1;Led_Change();TIM6->CNT=0;HAL_TIM_Base_Start_IT(&htim6);while(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET);}}else if(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET && Floor_CanSel(key4_floor)){HAL_Delay(10);if(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET){floor_sel[sel_dex++]=key4_floor;floor_led[key4_floor]=1;Led_Change();TIM6->CNT=0;HAL_TIM_Base_Start_IT(&htim6);while(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET);}}}

2.数组排序

按照题目的逻辑对选择数组进行排序,当前为最低层则将选择数组从小到大排序即可;当前为最高层则将选择数组从大到小排序即可;当前为中间层时,先将选择数组按从大到小排序,找出比当前楼层高且距离最近的楼层下标,以该下标为分界线,将该下标之前的数据先放入运行数组,再将该下标之后的数据放入运行数组。

void Sort_Buff()//数组排序{uint8_t max_dex,temp,first_dex=0;uint8_t floor_wait_go[floor_canSel]={0};int i,j;/*如果电梯不再执行*/if(!has_next_floor){sel_dex=0;//选择数组下标重置has_next_floor=1;for(i=0;i<floor_canSel;i++)//将选择的楼层储存到待前往楼层数组{floor_wait_go[i]=floor_sel[i];floor_sel[i]=0;//选择楼层清零}}else//如果电梯需要继续执行则先退出{return;}/*待前往楼层数组排序 从大到小*/for(i=0;i<floor_canSel-1;i++){max_dex=i;for(j=i+1;j<floor_canSel;j++){if(floor_wait_go[j]>floor_wait_go[max_dex]){max_dex=j;}}temp=floor_wait_go[i];floor_wait_go[i]=floor_wait_go[max_dex];//将大的换到前面floor_wait_go[max_dex]=temp;}/*最高层*/if(floor_now==floor_canSel+1){for(i=0;i<floor_canSel;i++){floor_go[i]=floor_wait_go[i];}}/*最低层*/else if(floor_now==1){j=0;for(i=floor_canSel;i>=0;i--){if(floor_wait_go[i]!=0)floor_go[j++]=floor_wait_go[i];}}/*中间层*/else if(floor_now!=floor_canSel+1 && floor_now!=1){for(i=0;i<floor_canSel;i++){if(floor_wait_go[i]>floor_now){first_dex=i;}}j=0;for(i=first_dex;i>=0;i--){floor_go[j++]=floor_wait_go[i];}for(i=first_dex+1;i<floor_canSel;i++){floor_go[j++]=floor_wait_go[i];}}/*Tim6关*/HAL_TIM_Base_Stop_IT(&htim6);/*关门*/Elevator_Close();door_open=0;delay=4;/*开定时器*/TIM7->CNT=0;HAL_TIM_Base_Start_IT(&htim7);}

3.电梯运行

void Elevator_Run()//电梯根据排序好的数组运行{if(door_open)//门打开时{key_canPress=1;//按的楼层有效}else{key_canPress=0;}run_flag=0;switch(delay){case 2://开门等待printf("wait people\n");if(delay_num==1)//等待完成{delay_num=1;PWM_Stop();HAL_TIM_Base_Stop_IT(&htim7);if(floor_go[++go_dex]!=0)//还有目标平台{/*下次为电梯关门等待*/delay=4;Elevator_Close();//电梯关门has_next_floor=1;}else//无目标平台{has_next_floor=0;//无下一楼层go_dex=0;//运行数组下标重置}}break;//未达到2s 继续等待case 4://开关门等待printf("wait door\n");if(delay_num==2)//开关完成{if(door_open){printf("---open---\n");}else{printf("---close---\n");}delay_num=1;PWM_Stop();HAL_TIM_Base_Stop_IT(&htim7);/*下次电梯升降或开门等待*/if(door_open)//下次为等待{delay=2;}else//下次为升降{printf("%d->%d\n",floor_now,floor_go[go_dex]);delay=6;if(floor_go[go_dex]>floor_now)//高楼层{/*电梯上升*/Elevator_Rise();}else//低楼层{/*电梯下降*/Elevator_Down();}}}else//未达到4s 继续等待{delay_num++;}//开定时器TIM7->CNT=0;HAL_TIM_Base_Start_IT(&htim7);break;case 6://升降等待if(led_dir==1){printf("*rise*\n");}else{printf("*down*\n");}if(delay_num==3)//升降完成{delay_num=1;PWM_Stop();HAL_TIM_Base_Stop_IT(&htim7);/*更新当前楼层*/floor_now=floor_go[go_dex];/*LED状态改变*/Led_Change();/*下次为开门*/delay=4;Elevator_Open();}else//未达到6s 继续等待{delay_num++;}TIM7->CNT=0;HAL_TIM_Base_Start_IT(&htim7);//开定时器break;}}

4.RTC秒中断

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc){Get_Time();//获取时间Show_Time();//显示时间Set_Alarm(); //设置下一秒的中断/*受到LCD影响 LED状态更新*/Led_Change();//LED改变Led_Run(); //流水灯}

5.PWM输出

void PWM_OutPut(uint8_t statue)//PWM输出{switch(statue){case elevator_close:htim3.Init.Period = 500-1;sConfigOC.Pulse = 250-1;HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);HAL_TIM_PWM_Init(&htim3);HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);break;case elevator_open:htim3.Init.Period = 500-1;sConfigOC.Pulse = 300-1;HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);HAL_TIM_PWM_Init(&htim3);HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);break;case elevator_rise:htim3.Init.Period = 1000-1;sConfigOC.Pulse = 800;HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);HAL_TIM_PWM_Init(&htim3);HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);break;case elevator_down:htim3.Init.Period = 1000-1;sConfigOC.Pulse = 600;HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);HAL_TIM_PWM_Init(&htim3);HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);break;}}

5.Main函数

int main(void){uint8_t i;  /* 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_TIM6_Init();  MX_TIM7_Init();  MX_RTC_Init();  MX_TIM3_Init();  MX_USART1_UART_Init();  MX_TIM4_Init();  /* USER CODE BEGIN 2 *///初始化排序和运行数组for(i=0;i<floor_canSel;i++){floor_sel[i]=0;floor_go[i]=0;}//中断请求标志位初始状态设置为关闭TIM4->SR=0;TIM6->SR=0;TIM7->SR=0;printf("usart test\n");//定时器结构体初始化sConfigOC.OCMode = TIM_OCMODE_PWM1;  sConfigOC.Pulse = 800;  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);HAL_TIM_PWM_Init(&htim3);//重新初始化HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);//开启PWMPWM_Stop();//LCD初始化及显示LCD_Init();LCD_Init_Show();//LED初始化状态为关闭Led_All_Close();  /* USER CODE END 2 */  /* Infinite loop */  /* USER CODE BEGIN WHILE */  while (1)  {    /* USER CODE END WHILE */    /* USER CODE BEGIN 3 */if(key_canPress)//如果按键可以被按下{KEY_Scan();}if(sort_flag)//如果排序标志位为1{sort_flag=0;Sort_Buff();}if(run_flag)//如果电梯运行标志位为1{run_flag=0;Elevator_Run();}if(lcd_refresh)//如果lcd更新标志位为1{lcd_refresh=0;LCD_Show();}  }  /* USER CODE END 3 */}

四、实验结果

五、源码(转载请注明出处)

STM32RTC秒中断--基于HAL库(第八届蓝桥杯嵌入式省赛)


总结

以上就是全部内容,如有错误请批评指正。