蓝桥杯嵌入式第八届省赛模拟升降控制器工程参考
我的理解
这套题,算是把状态机用的淋漓尽致需要时刻判断升降器,也就是电梯的运动方向,在电梯上升或者下行时不接受输入,只在开门和关门时接受输入,且需要不断地去计算电梯地运动方向(流水灯指示)以及需要不断地去计算下一站台是几号站台。
电梯状态
获得需要运行标志->关门(计时)->根据运动方向选择上行或下行->到站->开门->判断是否需要继续运行->重复直到没有需要到达地站台.
工程参考
链接:https://pan.baidu.com/s/13paH1t7fVlYu99uV3H6BhQ
提取码:yzh1
主要代码
#include "work.h"
#include "rtc.h"
RTC_TimeTypeDef T;
RTC_DateTypeDef D;
#define ReadB1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define ReadB2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define ReadB3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define ReadB4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
u8 LEDINDEX[] = {0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
u8 LEDDT[10]={0};
u8 ledflsuh_t =0;
u16 doort = 0;//开关门时间
u16 runtime = 0;//运行时间 上下每层楼为6s
u16 rtct = 0; //采集RTC时间
u16 keywait=0;
u8 ct = 0;
typedef struct KEY {
u16 keytime;
u8 key_state;
bool sflag;
bool lflag;
bool state;
}KEY;
KEY keys[4]={0};
u8 floors[4]={0};
u8 current =0;
u8 sign = 0;//上升或下降状态或停止
u8 nextfloor = 99;
u8 floorstate = 0;//等待按键,1s后开始,关门,运行电机,开门,停止
#define UP {HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);TIM16->CCR1=80;}
#define DOWN { HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);TIM16->CCR1 =60;}
#define OPEN {HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);TIM17->CCR1=60;}
#define CLOSE {HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);TIM17->CCR1=50;}
//读取RTC时钟
void ReadRtc(void)
{
if(rtct > 881)
{
rtct = 0;
HAL_RTC_GetDate(&hrtc,&D,RTC_FORMAT_BIN);
HAL_RTC_GetTime(&hrtc,&T,RTC_FORMAT_BIN);
printf("%d %d %d\r\n",T.Hours,T.Minutes,T.Seconds);
}
}
void led_scan(void){
if(ledflsuh_t >20)
{
ledflsuh_t = 0;
u8 res= 0x00;
for (int i = 1 ; i<=8;i++) res|=LEDINDEX[LEDDT[i]];
DisPlayLed(res);
}
}
void upOrdown(void)
{
static char ci = 0;
static u16 ledst = 0;//上升下降led时间
if(ledst++ == 500)
{
ledst=0;
if(sign == 2) //上升 5-8
{
switch(ci)
{
case 1:
LEDDT[5]=5; LEDDT[6]=LEDDT[7]=LEDDT[8]=0;
ci++;
break;
case 2:
LEDDT[6]=6; LEDDT[7]=LEDDT[5]=LEDDT[8]=0;
ci++;
break;
case 3:
LEDDT[7]=7; LEDDT[6]=LEDDT[5]=LEDDT[8]=0;
ci++;
break;
case 4:
LEDDT[8]=8; LEDDT[6]=LEDDT[5]=LEDDT[7]=0;
ci++;
break;
default:
ci=1;
}
}
else if(sign == 1) //下降
{
switch(ci){
case 1:
LEDDT[5]=5;
LEDDT[8]=LEDDT[6]=LEDDT[7]=0;
ci--;
break;
case 2:
LEDDT[6]=6;
LEDDT[5]=LEDDT[8]=LEDDT[7]=0; ci--;
break;
case 3:
LEDDT[7]=7;
LEDDT[5]=LEDDT[6]=LEDDT[8]=0; ci--;
break;
case 4:
LEDDT[8]=8;
LEDDT[5]=LEDDT[6]=LEDDT[7]=0;ci--;
break;
default :
ci =4;
}
}
{ //刷新LED灯
u8 res= 0x00;
for (int i = 1 ; i<=8;i++) res|=LEDINDEX[LEDDT[i]];
DisPlayLed(res);
}
}
}
void key_scan(void)
{
keys[0].state =ReadB1;
keys[2].state =ReadB3;
keys[1].state =ReadB2;
keys[3].state =ReadB4;
for(int i = 0; i<4;i++)
{
switch(keys[i].key_state)
{
case 0:
if(!keys[i].state)keys[i].key_state=1;
break;
case 1:
if(!keys[i].state)
{
keys[i].key_state=2;
keys[i].keytime=10;
}
else keys[i].key_state=0;
break;
case 2:
keys[i].sflag = 0 ;
if(!keys[i].state){
keys[i].keytime+=10;
//长按键判断
}
else
{
// if(keys[i].keytime > 500)keys[i].lflag=1;
keys[i].keytime = 0;
keys[i].key_state = 0;
keys[i].sflag=1;
}
break;
}
}
}
void key_action(void)
{
if(floorstate == 3) return ; //电机运转期间按键无效
if(keys[0].sflag || keys[1].sflag || keys[2].sflag || keys[3].sflag ){
keywait = 0;
floorstate=1;
}
if(keys[0].sflag && current!=0)floors[0]=1,LEDDT[1]=1,keys[0].sflag=0;
if(keys[1].sflag && current!=1)floors[1]=1,LEDDT[2]=2,keys[1].sflag=0;
if(keys[2].sflag && current!=2)floors[2]=1,LEDDT[3]=3,keys[2].sflag=0;
if(keys[3].sflag && current!=3)floors[3]=1,LEDDT[4]=4,keys[3].sflag=0;
}
int fputc( int ch,FILE * F)
{
HAL_UART_Transmit(&huart1,(u8 *)&ch,1,0XFFFF);
return ch;
}
void floorrunning(void)
{
if(!floorstate)return;
switch(floorstate)
{
case 1://等待按键1s后
if(keywait++ ==1000)
{
floorstate = 2;
keywait = 0;
}
break;
case 2: //关门
if(doort++ == 0)CLOSE;
if(doort ==4000)
{
doort = 0;
floorstate =3;
}
break;
case 3:
if(runtime++ == 0){
if(sign==1) DOWN
else UP
}
if(runtime == 6000)
{
runtime = 0; //到达下一层
if(nextfloor != 99) {
u8 temp = current;
if(sign == 2){ //上升
if(nextfloor-current>1)temp++;
else temp=nextfloor, floorstate =4;
}
else if(sign == 1) { //下降
if(current-nextfloor >1)temp--;
else temp= nextfloor, floorstate =4;
}
current =temp,floors[temp]=0;
LEDDT[temp+1]=0;
}
}
break;
case 4:
if(doort++ ==0)OPEN;
if(doort == 4000){
doort = 0;
if(sign==0)floorstate=0;
else floorstate =5;//继续寻找平台
}
break;
case 5:
if(doort++ == 2000)
{
doort = 0;
floorstate =2;//关门后继续寻找
}
break;
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance ==TIM4) //10ms进入一次
{
key_scan();
key_action();
}
else if(htim->Instance == TIM2) //1ms进入一次
{
ledflsuh_t++;
ct++;
rtct++;
upOrdown();
floorrunning();
}
}
void DisPlayLed(u8 ds)
{
HAL_GPIO_WritePin(GPIOC,0xff<<8,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,ds<<8,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
void LcdDisPlay(void)
{
char temp[20] = {0};
LCD_DisplayStringLine(Line1,(u8*)" ----CURRENT---- ");
sprintf(temp," %d ",current+1);
LCD_DisplayStringLine(Line3,(u8*)temp);
sprintf(temp," %d: %d: %d ",T.Hours,T.Minutes,T.Seconds);
LCD_DisplayStringLine(Line5,(u8*)temp);
}
//获得前进方向 并计算出下一层
void Correction(void)
{
if(ct< 223)return;
ct=0;
u8 flag =0;
u8 updt[4]={0};
u8 downdt[4]={0};
u8 m=0,n=0;
for (u8 i =0;i<4;i++)
{
if(floors[i]){
if(current > i)flag=1,downdt[n++]=i;
else if(current < i){
if(flag == 1) flag =7,updt[m++]=i;
else flag =2,updt[m++]=i;
}
}
}
if(flag == 7){
sign = 2;//先上后下
nextfloor = updt[0];
}
else if(flag ==1){
sign =1; //下降
nextfloor = downdt[n-1]; //找到最近
}
else if(flag == 2) {
sign= 2; //上升
nextfloor = updt[0];
}
else
sign =0,nextfloor = 99;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?