今天在整理电脑文档的时候,发现了自己的上学期的dsp文件夹里还躺着上学期的课程设计。那是设计一个模拟电梯系统的dsp程序,用的c语言写的,平台是L138(实验室好像是这个平台)。第一次觉得模块化编程是高效的,当然也是不分程序语言的。在博客整理一下当时的思路和顺便记录。
实验室的L38板的数字按键只有9个,模拟电梯有四层楼,按键1到4为楼层按键;按键5和6表示楼层上下,按键7和8模拟开关门,按键9 终止程序。当然还有在显示屏上显示电梯的状态——楼层,电梯的上下状态,以及电梯门的开关状态。这部分显示用的是字模软件取字模,具体的字模软件可以自行百度。噢,还有步进电机的顺逆转动方向表示上下的电梯状态。具体的实现附上代码,代码内也有详细的注释:
#include "stdio.h"
#include "types.h"
#include "evmomapl138.h"
#include "evmomapl138_int.h"
#include "evmomapl138_int_timer.h"
#include "evmomapl138_int_gpio.h"
#include "evmomapl138_timer.h"
#include "evmomapl138_emif.h"
#include "evmomapl138_ctr.h"
#include "evmomapl138_ctr_lcd.h"
#include "evmomapl138_ctr_dcmotor.h"
#include "evmomapl138_ctr_keypad.h"
#include "evmomapl138_cpld.h"
#include "evmomapl138_led.h"
#include "evmomapl138_dip.h"
#include "test_ctr_dcmotor.h"
#define TEST_CTR_int_period (2000)
#define Maxfloor 4
#define Minfloor 1
enum EleStatus{open,close};//电梯门状态
enum EleStage{up,down,stop}; //电梯运行状态
static void TEST_ctr_keypad_isr(void);
static uint8_t key_code = 0xFF;
typedef struct {
int floor; //电梯所在层
enum EleStatus status; //电梯当前状态
enum EleStage stage; //电梯运行时期
int CallUp[Maxfloor+1];//每层的Up按钮
int CallDown[Maxfloor+1];//每层的Down按钮
int CallCar[Maxfloor+1];//电梯内的目标层按钮
}Elevator;
Elevator E; //定义电梯为E
uint8_t dip;
uint8_t a=0;
uint8_t in=1;
static uint32_t TEST_CTR_toggle = 0;
static uint32_t TEST_CTR_duty = 30;
static uint32_t TEST_CTR_count = 0;
static uint8_t Clear[1][16] = { //不显示任何东西
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
};
//当前电梯门的开关转态,从上到下分别是对应汉字的字模 分别是门 开 关
static uint8_t door_state[3][32] = {
{0x00,0xF8,0x01,0x06,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x7F,0x00,0x00},
{0x80,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x80,0x00,0x00,0x80,0x40,0x30,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x10,0x11,0x16,0x10,0x10,0xF0,0x10,0x10,0x14,0x13,0x10,0x00,0x00,0x00, 0x81,0x81,0x41,0x41,0x21,0x11,0x0D,0x03,0x0D,0x11,0x21,0x41,0x41,0x81,0x81,0x00}
};
//当前的电梯运行状态,从上到下分别是 上 下 停
static uint8_t run_state[3][32] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00},
{0x02,0x02,0x02,0x02,0x02,0x02,0xFE,0x02,0x02,0x42,0x82,0x02,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
{0x80,0x60,0xF8,0x07,0x00,0x04,0x74,0x54,0x55,0x56,0x54,0x54,0x74,0x04,0x00,0x00,0x00,0x00,0xFF,0x00,0x03,0x01,0x05,0x45,0x85,0x7D,0x05,0x05,0x05,0x01,0x03,0x00}
};
//当前楼层的数字 从上到下分别是 1 2 3 4
static uint8_t cur_floor[4][16] = {
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00},
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00}
};
static void TEST_ctr_dcmotor_isr(void);
extern void intcVectorTable(void);
//清除相应显示,按下楼层
void Dispnot()
{
uint8_t x_locate = (E.floor-1)*16+4; //按键消除的横坐标,分别是 4 20 36 52
ICETEK_CTR_LCD_put_bmp(x_locate,16,Clear[0], 8, 16);
ICETEK_CTR_LCD_update(x_locate,16,8,16);
}
//显示按下一楼
void Disp1()
{
ICETEK_CTR_LCD_put_bmp(4, 16, cur_floor[0], 8, 16);
ICETEK_CTR_LCD_update(4,16,8,16);
}
//显示按下2楼
void Disp2()
{
ICETEK_CTR_LCD_put_bmp(20, 16, cur_floor[1], 8, 16);
ICETEK_CTR_LCD_update(20,16,8,16);
}
//显示按下3楼
void Disp3()
{
ICETEK_CTR_LCD_put_bmp(36, 16, cur_floor[2], 8, 16);
ICETEK_CTR_LCD_update(36,16,8,16);
}
//显示按下4楼
void Disp4()
{
ICETEK_CTR_LCD_put_bmp(52, 16, cur_floor[3], 8, 16);
ICETEK_CTR_LCD_update(52,16,8,16);
}
//显示当前楼层
void DispFloor()
{
ICETEK_CTR_LCD_put_bmp(96, 0, cur_floor[E.floor-1], 8, 16);
ICETEK_CTR_LCD_update(96,0,8,16);
}
//显示门开
void DispOpen()
{
ICETEK_CTR_LCD_put_bmp(0, 0, door_state[0], 16,16 );
ICETEK_CTR_LCD_put_bmp(16, 0, door_state[1], 16, 16);
ICETEK_CTR_LCD_update(0,0,16,16);
ICETEK_CTR_LCD_update(16,0,16,16);
}
//显示门关
void DispClose()
{
ICETEK_CTR_LCD_put_bmp(0, 0, door_state[0], 16,16 );
ICETEK_CTR_LCD_put_bmp(16, 0,door_state[2], 16, 16);
ICETEK_CTR_LCD_update(0,0,16,16);
ICETEK_CTR_LCD_update(16,0,16,16);
}
//显示电梯上升
void DispUp()
{
ICETEK_CTR_LCD_put_bmp(48, 0, run_state[0], 16, 16);
ICETEK_CTR_LCD_update(48,0,16,16);
}
//显示电梯下降
void DispDown()
{
ICETEK_CTR_LCD_put_bmp(48, 0, run_state[1], 16, 16);
ICETEK_CTR_LCD_update(48,0,16,16);
}
//显示电梯停
void DispStop()
{
ICETEK_CTR_LCD_put_bmp(48, 0, run_state[2], 16, 16);
ICETEK_CTR_LCD_update(48,0,16,16);
}
//识别电梯门状态并显示
void DispDoor()
{
switch(E.status)
{
case open:DispOpen();break;
case close:DispClose();break;
}
}
//开门动作
void Open()
{
E.status=open;
DispDoor(); //显示门状态
}
//关门动作
void Close()
{
E.status=close;
DispDoor(); //显示门状态
}
//检测电梯内部按钮
Dip()
{
while(1)
{
switch(ICETEK_CTR_KEYPAD_getkey())
{
case KEYCODE_1:E.CallCar[1]=1;Disp1();break; //按下1楼
case KEYCODE_2:E.CallCar[2]=1;Disp2();break;//按下2楼
case KEYCODE_3:E.CallCar[3]=1;Disp3();break;//按下3楼
case KEYCODE_4:E.CallCar[4]=1;Disp4();break;//按下4楼
case KEYCODE_8:a=1;in=1;break;
default:break;
}
if(a==1) //8键关门并退出
{Close();USTIMER_delay(2000000);a=0;break;}
}
}
//检测电梯外部按钮
void Key()
{
switch(key_code)
{
case KEYCODE_1:E.CallUp[1]=1;break; //一楼上请求
case KEYCODE_2:E.CallDown[2]=1;break;//二楼下请求
case KEYCODE_3:E.CallUp[2]=1;break; //二楼上请求
case KEYCODE_4:E.CallDown[3]=1;break;//三楼上请求
case KEYCODE_5:E.CallUp[3]=1;break; //三楼下请求
case KEYCODE_6:E.CallDown[4]=1;break; //四楼下请i去
case KEYCODE_7: Open();in=0;Dip();break; //7键转换为检测内部按钮,开门
default:break;
}
}
//电梯初始化
void InitLift()
{
int i;
E.floor=1;
E.stage=stop;
E.status=close;
for( i=0;i<=Maxfloor;i++)
{
E.CallUp[i]=0;E.CallDown[i]=0;E.CallCar[i]=0;
}
DispDoor(); //显示初始门状态
DispFloor(); //显示初始楼层
}
//判断是否在当前楼层停留
int IsStop()
{
if(E.CallCar[E.floor]) return 1; //该楼层的楼层按钮被按下
//电梯上升且该楼层按下上升按钮但高楼层或者电梯下降时该楼层按下下降按钮
if(E.stage==up&&E.CallUp[E.floor]||E.stage==down&&E.CallDown[E.floor])
return 1;
//电梯上升时但高楼层没有呼叫时
if(E.stage==up)
{
if(!UpCheck()&&E.CallDown[E.floor]==1)
{E.stage=down;return 1;}
}
//电梯下降时但低楼层没有呼叫时
if(E.stage==down)
{
if(!DownCheck()&&E.CallUp[E.floor]==1)
{E.stage=up;return 1;}
}
return 0;
}
//电梯停
void Stop()
{
//ICETEK_CTR_DCMOTOR_drive(DCMOTOR_DRIVE_LOW);
E.stage=stop; //状态变为停
DispStop(); //显示停
Close(); //门关
DispDoor(); //显示门关
//清除该楼层的请求
E.CallCar[E.floor]=0;
E.CallDown[E.floor]=0;
E.CallUp[E.floor]=0;
}
//电梯上升一层
void GoUp()
{
int i,j;
//ICETEK_CTR_DCMOTOR_direct(DCMOTOR_DIRECTION_CLOCK);
TEST_CTR_duty=50;
ICETEK_CTR_DCMOTOR_enable(true);
USTIMER_delay(2000000);
E.floor++; //楼层加1
Dispnot(); //清除该楼层的按下显示
}
//电梯下降一层
void GoDown()
{
int i,j;
//ICETEK_CTR_DCMOTOR_direct( DCMOTOR_DIRECTION_COUNTER_CLOCK);
TEST_CTR_duty=50;
ICETEK_CTR_DCMOTOR_enable(true);
USTIMER_delay(2000000);
E.floor--; //楼层减1
Dispnot(); //清除该楼层的按下显示
}
//电梯上升
void Up()
{
int i,j;
ICETEK_CTR_DCMOTOR_direct(DCMOTOR_DIRECTION_CLOCK);
DispUp(); //显示上升状态
TEST_CTR_duty=20; //起始速度为20
ICETEK_CTR_DCMOTOR_enable(true);
USTIMER_delay(2000000);
while(E.floor<4) //上升楼层不超过4
{
GoUp(); //上升了一层
DispFloor(); //显示楼层
if(IsStop()) //判断是否需要停留在当前楼层
{
//若停留,缓慢停止
TEST_CTR_duty=20;
ICETEK_CTR_DCMOTOR_enable(true);
USTIMER_delay(2000000);//延时
ICETEK_CTR_DCMOTOR_enable(false);
Stop(); //电梯停止动作
USTIMER_delay(2000000);
Open();//开门
DispDoor();//显示楼层
USTIMER_delay(2000000);//延时2s
break;
}
else
{
TEST_CTR_duty=50;
ICETEK_CTR_DCMOTOR_enable(true); //电机使能
USTIMER_delay(2000000); //延时
}
}
//ICETEK_CTR_DCMOTOR_drive(DCMOTOR_DRIVE_LOW);
ICETEK_CTR_DCMOTOR_enable(false); //停电机
Stop(); //电梯停止动作
}
//电梯下降
void Down()
{
int i,j;
DispDown();//显示下降状态
ICETEK_CTR_DCMOTOR_direct( !DCMOTOR_DIRECTION_CLOCK);//反转表示下降
TEST_CTR_duty=20;//起速20
ICETEK_CTR_DCMOTOR_enable(true);
USTIMER_delay(2000000);
while(E.floor>1) //下降楼层不低于1楼
{
GoDown(); //下降一楼
DispFloor(); //显示当前楼层
if(IsStop()) //判断是否需要停留在当前楼层
{
TEST_CTR_duty=20;
ICETEK_CTR_DCMOTOR_enable(true);
USTIMER_delay(2000000);
ICETEK_CTR_DCMOTOR_enable(false); //停电机
Stop(); //电梯停
USTIMER_delay(2000000);
Open(); //门开
DispDoor();//显示门开
USTIMER_delay(2000000);//延时
break;
}
else
{
TEST_CTR_duty=50;
ICETEK_CTR_DCMOTOR_enable(true);
USTIMER_delay(2000000);
}
}
//ICETEK_CTR_DCMOTOR_drive(DCMOTOR_DRIVE_LOW);
ICETEK_CTR_DCMOTOR_enable(false);//停电机
Stop(); //电梯停,门关
}
//检查是否有高楼层请求
int UpCheck()
{
int i;
for( i=E.floor+1;i<=Maxfloor;i++)
if(E.CallCar[i]||E.CallDown[i]||E.CallUp[i]) return 1;
return 0;
}
//检查是否有低楼层请求
int DownCheck()
{
int i;
for(i=E.floor-1;i>=Minfloor;i--)
if(E.CallCar[i]||E.CallDown[i]||E.CallUp[i]) return 1;
return 0;
}
//返回电梯状态
enum EleStage UpOrDown()
{
if(UpCheck())return E.stage=up;
else if(DownCheck()) return E.stage=down;
else return E.stage=stop;
}
uint32_t TEST_ctr_dcmotor(void)
{
uint32_t rtn;
ICETEK_CTR_init();
ICETEK_CTR_DCMOTOR_init();
ICETEK_CTR_LCD_init();
ICETEK_CTR_LCD_enable(true);
rtn = ICETEK_CTR_KEYPAD_init();
if (rtn != ERR_NO_ERROR)
{
printf("error initializing keypad: %u\r\n", rtn);
return (rtn);
}
//ICETEK_CPLD_init();
LED_init();
DIP_init();
EVMOMAPL138_int_enable((uint32_t)intcVectorTable);
USTIMER_delay(1000);
USTIMER_int_enable(VECTOR_ENTRY_04, TEST_CTR_int_period, (DSPINTC_func)TEST_ctr_dcmotor_isr);
ICETEK_CTR_DCMOTOR_direct(DCMOTOR_DIRECTION_CLOCK);
GPIO_int_enable(VECTOR_ENTRY_05, 4, 1, GPIO_INT_ON_BOTH_EDGE, TEST_ctr_keypad_isr);
ICETEK_CTR_KEYPAD_enable(true);
// ICETEK_CTR_DCMOTOR_enable(true);
//ICETEK_CTR_DCMOTOR_drive(DCMOTOR_DRIVE_LOW);
InitLift(); //初始化电梯
while(1)
{
Key(); //按键扫描
switch(UpOrDown()) //检查电梯状态
{
case stop: Stop();break; //停
case up: Up();break; //上升
case down:Down();break; //下降
}
ICETEK_CTR_DCMOTOR_drive(DCMOTOR_DRIVE_LOW); //停电机
if(ICETEK_CTR_KEYPAD_getkey() == KEYCODE_9) //按下9退出循环
break;
}
ICETEK_CTR_DCMOTOR_enable(false);
USTIMER_int_disable();
EVMOMAPL138_int_disable();
ICETEK_CTR_LCD_enable(false);
ICETEK_CTR_close();
return (ERR_NO_ERROR);
}
void TEST_ctr_dcmotor_isr(void)
{
TEST_CTR_count++;
if(TEST_CTR_count%100 == TEST_CTR_duty)
{
//TEST_CTR_toggle = 0;
ICETEK_CTR_DCMOTOR_drive(DCMOTOR_DRIVE_LOW);
return;
}
if(TEST_CTR_count%100 == 0)
{
//TEST_CTR_toggle = 1;
ICETEK_CTR_DCMOTOR_drive(DCMOTOR_DRIVE_HIGHT);
return;
}
}
//-----------------------------------------------------------------------------
// Private Function Definitions
//-----------------------------------------------------------------------------
void TEST_ctr_keypad_isr(void)
{
key_code = ICETEK_CTR_KEYPAD_getkey();
if(in)
{
switch(key_code)
{
case KEYCODE_1:E.CallUp[1]=1;break;
case KEYCODE_2:E.CallDown[2]=1;break;
case KEYCODE_3:E.CallUp[2]=1;break;
case KEYCODE_4:E.CallDown[3]=1;break;
case KEYCODE_5:E.CallUp[3]=1;break;
case KEYCODE_6:E.CallDown[4]=1;break;
default:break;
}
}
}
相关的头文件和环境依赖自行看程序和自己的实现。这个课程设计的一大遗憾是没有用上类似链表或者队列的数据结构,因为我们C语言学习的时候没有学指针之类的(借口而已)。碍于当时的时间紧迫,用上链表之类的驱动和代码量难度都会加大,为了省事也就这样了。当然也没有实现教授所说的平滑的电梯上升和下降速度(毫无思路)。