蓝桥杯嵌入式第八届省赛-模拟升降机

        最近在准备嵌入式国赛,想把近年的试题刷一刷,了解了状态机可能是一个很重要的方向,打算自己认真准备一下这个典型的题目。

        以下程序是我个人的第二版,第一版花了我一天的时间,状态的转化确实比较复杂,但是也是有一定的方法技巧的。比如说提前在演草纸上写好各种相关转化的关系以及转化对应的条件,这样非常有利于编程,此外,我个人感觉用宏定义来标识各种状态也是一个很好的方法,这里我要感谢电子设计工坊所提供的这个宏定义的这个思路,确实比较方便。

        以下是我的代码:

#include "stm32f10x.h"
#include "lcd.h"
#include "io.h"
#include "timer.h"
#include "key.h"
#include "i2c.h"
#include "stdio.h" //sprintf
#include "rtc.h"
#include "pwm.h"


#define LIFT_DOOR_OPENED        0
#define LIFT_DOOR_CLOSED        1
#define LIFT_UPING        			2
#define LIFT_DOWNING        		3
#define LIFT_DOOR_OPENING       4
#define LIFT_DOOR_CLOSING       5

_Bool flag_lcd_brink;
_Bool trogo_lcd = 1;
_Bool flag_lcd_update;
_Bool flag_lift_running;
_Bool flag_door_running;
_Bool flag_wait_opening;
_Bool flag_key_wait = 1000;


u8 count_led_move;
u8 num_trask;
u8 now_plotform = 1;
u8 status_lift = LIFT_DOOR_OPENED;
u16 count_lift_running;
u16 count_wait_opening;
u16 count_door_running;
u16 LED_Store;
u16 count_key_wait;
u16 count_wait_time;


u32 count_1ms;
u32 TimingDelay = 0;
int trask_floor[5] = {0,0,0,0,0};

unsigned char temp[20];

__IO uint32_t TimeDisplay;
extern uint32_t THH, TMM, TSS;
extern float PA6_Duty;
extern float PA7_Duty;

void Delay_Ms(u32 nTime);
void Key_Process(void);
void LCD_Display(void);
void LIFT_Control(void);
void LIFT_Control(void);
void Out_Control(void);


int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	SysTick_Config(SystemCoreClock/1000);
	Delay_Ms(200);

	LED_Init();
	PA45_Init();
	Timer_Init();
	TIM3_PWM_Init();  
	Key_Init();
	STM3210B_LCD_Init();
	LCD_Clear(White);
	i2c_init();
	RTC_Configuration();
	
	
	Time_Adjust(12,50,55);
	LED_Control(0x00,1);
	LCD_DisplayStringLineDec(Line2," Current Plotform",now_plotform);
	while(1){
		
		Key_Process();
		LIFT_Control();
		Out_Control();
		LCD_Display();
		
	}
}
void Key_Process(void){
	if(!(count_1ms%10)){
		Key_Read();
		
		if(status_lift == LIFT_DOOR_OPENED){
			if(Trg == 0x01){
				if(trask_floor[1] != 1 && now_plotform != 1){
					trask_floor[1] = 1;
					num_trask++;
					LED_Store = LED_Store&0xfe|0x01;
					LED_Control(LED_Store,1);
					flag_key_wait = 1;
					count_key_wait = 0;
				}
			}else if(Trg == 0x02){
				if(trask_floor[2] != 1 && now_plotform != 2){
					trask_floor[2] = 1;
					num_trask++;
					LED_Store = LED_Store&0xfd|0x02;
					LED_Control(LED_Store,1);
					flag_key_wait = 1;
					count_key_wait = 0;
				}
			}else if(Trg == 0x04 ){
				if(trask_floor[3] != 1 && now_plotform != 3){
					trask_floor[3] = 1;
					num_trask++;
					LED_Store = LED_Store&0xfb|0x04;
					LED_Control(LED_Store,1);
					flag_key_wait = 1;
					count_key_wait = 0;
				}
			}else if(Trg == 0x08){
				if(trask_floor[4] != 1 && now_plotform != 4){
					trask_floor[4] = 1;
					num_trask++;
					LED_Store = LED_Store&0xf7|0x08;
					LED_Control(LED_Store,1);
					flag_key_wait = 1;
					count_key_wait = 0;
				}
			}
			
		}
	}
}


void LCD_Display(void){
	if(flag_lcd_update){
		flag_lcd_update = 0;
		
		if(trogo_lcd)
			sprintf((char*)temp,"        %1d",now_plotform);
		else 
			sprintf((char*)temp,"          ");
		LCD_DisplayStringLineDec(Line4, temp, 1);
		
		Time_Display(RTC_GetCounter());
		sprintf((char*)temp,"     %2d:%2d:%2d  ",THH,TMM,TSS);
		LCD_DisplayStringLineDec(Line6, temp, 1);
	}
}


void LIFT_Control(void){
	if(status_lift == LIFT_DOOR_CLOSED && num_trask){//说明有任务需要去处理
		int i;
		_Bool go_floor = 0;
		for(i = now_plotform + 1; i <= 4; i++){
			if(trask_floor[i]){ // 说明上方有任务楼层需要到达
				status_lift = LIFT_UPING;
				count_led_move = 0;
				go_floor = 1;
			}
		}
		if(!go_floor){//上方没有任务楼层
			status_lift = LIFT_DOWNING;
			count_led_move = 0;
		}
	}else if(status_lift == LIFT_UPING){
		flag_lift_running = 1;
	}else if(status_lift == LIFT_DOWNING){
		flag_lift_running = 1;
	}else if(status_lift == LIFT_DOOR_OPENING){
		flag_door_running = 1;
	}else if(status_lift == LIFT_DOOR_CLOSING){
		flag_door_running = 1;
	}else if(status_lift == LIFT_DOOR_OPENED){
		if(num_trask){
				flag_wait_opening = 1;
		}else{//等待按键 保持开门的状态
		}
	}
}

void Out_Control(void){
	if(status_lift == LIFT_DOOR_OPENED){
		PA6_Duty = 0;PA7_Duty = 0;
	}else if(status_lift == LIFT_DOOR_CLOSED){
		PA6_Duty = 0;PA7_Duty = 0;
	}else if(status_lift == LIFT_UPING){
		PA4_H;PA6_Duty = 0.8;PA7_Duty = 0;
		LED_Store = LED_Store&0x0f|(0x10<<count_led_move);
		LED_Control(LED_Store,1);
	}else if(status_lift == LIFT_DOWNING){
		PA4_L;PA6_Duty = 0.6;PA7_Duty = 0;
		LED_Store = LED_Store&0x0f|(0x80>>count_led_move);
		LED_Control(LED_Store,1);
	}else if(status_lift == LIFT_DOOR_OPENING){
		PA5_H;PA7_Duty = 0.6;PA6_Duty = 0;
		LED_Store = LED_Store&0x0f|0x00;LED_Control(LED_Store,1);//这句话不能放在中断中,否则可能执行不完全
	}else if(status_lift == LIFT_DOOR_CLOSING){
		PA5_L;PA7_Duty = 0.5;PA6_Duty = 0;
	}
}



void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}


void TIM4_IRQHandler(void){
  if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
		count_1ms++;
		
		if(!(count_1ms%20)){
			flag_lcd_update = 1;
		}
		if(!(count_1ms%200)){
			if(++count_led_move == 4){
				count_led_move = 0;
			}
		}
		
		
		if(flag_lcd_brink){
			static int count_trogo_lcd = 0;
			if(!(count_1ms%250)){
				trogo_lcd = !trogo_lcd;
				if(++count_trogo_lcd == 5){
					count_trogo_lcd = 0;
					flag_lcd_brink = 0;
					trogo_lcd = 1;
				}
			}	
		}
		
		if(flag_key_wait){
			if(++count_key_wait == 1000){
				count_key_wait = 0;
				flag_key_wait = 0;	
			}
		}
		
		
		if(flag_lift_running){
			if(++count_lift_running == 6000){//上下电梯运行时间到
				flag_lift_running = 0;
				count_lift_running = 0;
				if(status_lift == LIFT_UPING){
					now_plotform++;
					if(trask_floor[now_plotform]){//有该层的任务
						trask_floor[now_plotform] = 0;
						num_trask--;
						status_lift = LIFT_DOOR_OPENING;//触发任务查询

						flag_lcd_brink = 1;
					
					if(now_plotform == 1)LED_Store = LED_Store&0xfe|0x00;
					else if(now_plotform == 2)LED_Store = LED_Store&0xfd|0x00;
					else if(now_plotform == 3)LED_Store = LED_Store&0xfb|0x00;
					else if(now_plotform == 4)LED_Store = LED_Store&0xf7|0x00;
					LED_Control(LED_Store,1);
						
					}else{//没有该层的任务
						status_lift = LIFT_UPING;
						count_led_move = 0;
					}
					
				}else if(status_lift == LIFT_DOWNING){
					now_plotform--;
					if(trask_floor[now_plotform]){//有该层的任务
						trask_floor[now_plotform] = 0;
						num_trask--;
						status_lift = LIFT_DOOR_OPENING;
						flag_lcd_brink = 1;
						
					if(now_plotform == 1)LED_Store = LED_Store&0xfe|0x00;
					else if(now_plotform == 2)LED_Store = LED_Store&0xfd|0x00;
					else if(now_plotform == 3)LED_Store = LED_Store&0xfb|0x00;
					else if(now_plotform == 4)LED_Store = LED_Store&0xf7|0x00;
					LED_Control(LED_Store,1);
						
					}else{
						status_lift = LIFT_DOWNING;
						count_led_move = 0;
					}
				}
			}
		}
		
		if(flag_door_running){
			if(++count_door_running == 4000){
				count_door_running = 0;
				flag_door_running = 0;
				if(status_lift == LIFT_DOOR_OPENING)
					status_lift = LIFT_DOOR_OPENED;
				else if(status_lift == LIFT_DOOR_CLOSING)
					status_lift = LIFT_DOOR_CLOSED;
			}
		}
		
		if(flag_wait_opening){
			if(flag_key_wait){
				count_wait_time = 1000;
			}else{
				count_wait_time = 2000;
			}
			if(++count_wait_opening == count_wait_time){
				flag_wait_opening = 0;
				count_wait_opening = 0;
				status_lift = LIFT_DOOR_CLOSING;//还有任务 2s后关闭
				LED_Store = LED_Store&0x0f|0x00;
			}
		}
  }
}

最后,我再总结一下编程的一般思路和需要注意的点:

一、一般思路

1、写出整个工程的要点,整理骨干流程(在这里是按键的操作)
2、设置状态机,分析状态之间的转化,在草稿上备注好之间的转换关系
3、补充因为状态的转变而缺失的输出控制

二、注意

1、中断不要放一些硬件处理函数,而是放一些标志位的处理。比如LED_Control不要放在中断中,如果本身中断进入的频率比较高,而处理的时间又比较长就可能无法完成中断处理。

2、代码的规范很重要。尽量不要把定义的变量和函数随意放置,尤其是在主函数比较长的时候,这样不方便后续查找和定位。

好啦,第一次写博客文章,希望能提供读者一些参考,如果代码有什么不对的地方请不吝赐教啊。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值