西电微机系统课程设计——步进电机开环控制系统设计


一、课程设计目的

1.掌握微机系统总线与各芯片管脚连接方法,提高接口扩展硬件电路的连接能力。

2.加深对 A/D 和并行接口芯片的工作方式和编程方法的理解。

3.搞懂步进电机的工作原理及控制方式,掌握开环控制系统的设计思路和实现方法。


二、课程设计的内容

手动调节电位器旋钮(0V~5V),通过 ADC0809 模拟输入水库水位 0 米~50 米,CPU收到水位信号后,根据水位高度控制步进电机(水闸)进行调节。


三、系统功能与设计要求

基本功能要求

手动调节电位器旋钮,步进电机根据水位实时调节水闸。设水闸全部打开需要逆时针旋转 10 圈 (10 x 360°)度。随着上游进入水库的水流量变化,水库水位不断变化(手动调节电位器旋钮),每到一定高度,步进电机顺时针(关)或逆时针(开)旋转一定的角度调节水闸开启程度,从而控制水库水位在 10~50 米之间。调节精度控制在±5%,调节规律如下:

步进电机采用四相八步控制,开关顺序如图:


步进电机不使用时要关闭,不可以停止在一个相位上时间过长,会导致发热;

发挥部分

1.增加速度调节功能。水位在 10~40 米期间,步进电机中速转动,水位低于 10 (水位过低)或高于 40 米(水位过高)时,步进电机高速转动。

2.增加实时水位显示。用数码管 DLED 高两位显示当前水位(00~50 米)。

3.增加水闸开启程度显示。用数码管 DLED 低两位实时显示水闸开启程度(00~10圈)。


四、操作步骤

  1. 首先根据题目要求选择合适的器件并参考示例代码了解各器件的操作方法:
器件名称 功能
电位器 获取0~5V的模拟量
ADC0809 模拟量转换为数字量
步进电机 模拟水闸转动
数码管 显示必要参数
LED 根据水位亮不同的灯
74HC273N 锁存器,锁存控制LED的信号
系统总线 控制其他器件
8255 将系统总线的命令传输到步进电机和数码管
  1. 阅读硬件接口手册,粗略连接各器件,并加部分的流程控制,画出大致的流程控制图:

  1. 对于一些实验要求的分析:

    • 由于水位可能下降也可能上升,所以步进电机要记录历史状态,根据上一次水位信息来判断正转和反转;
    • 步进电机的速度控制通过延时不同时间来实现,延时函数可以粗略地使用空循环;
    • 数码管水位信息应该随步进电机旋转动态变化,所以应该放入步进电机旋转的函数中不停得对数码管进行刷新以实现;
    • 步进电机的每次旋转停下之后的相位应该被记录,下一次旋转应该在上一次停下的相位进行继续驱动,否则会出现旋转开始时倒转的现象;
    • 步进电机正转就是根据控制图由上到下循环out给步进电机的控制端口,同样反转是由下到上循环out给步进电机的控制端口;由于步进角我们并不清楚,所以采用测验来大致确定步进角,测验结果为步进电机运行40步为旋转一圈,在代码实现中,可以通过acircle这个全局变量来修改旋转一圈的步数;

五、硬件连线图



六、代码实现

/*步进电机开环控制系统设计:电位器功能描述:调节电位器旋钮(0~5V)作为水位;动态获取模拟量并转换为数字量显示在数码管上;4s左右时间不旋转电位器则停止采样,进入控制水闸功能模块;8位数码管功能描述:数码管低2位显示水位(m);数码管高2位显示水闸开启程度,用百分比表示;数码管4(中间位置)显示旋转速度,1表示中速,2表示高速;步进电机功能描述:[0,10)m和[40,50]m水位时,高速旋转,每转一步60ms延时;[10,40)m时,中速旋转,每转一步160ms延时;可以根据历史水闸开启状态来关闸或开闸(即逆时针旋转和顺时针旋转);LED管功能描述:[0,10)m水位时,黄灯闪烁;[10,50)m水位时,绿灯常亮;50m水位时,红灯闪烁;
*/
#define u8 unsigned char
#define u16 unsigned int/* 接口地址定义 */
#define IO8255_PC   0x272           //8255 C口地址;
#define IO8255_Con  0x273           //8255 控制字地址;
#define addr0809    0x250           //0809 地址;
#define IO273       0x230           //74LS273地址;/* 库函数定义 */
extern void outportb( unsigned int, char);                      //写I/O;
extern char inportb( unsigned int );                            //读I/O;extern void cInitKeyDisplay();  //对键盘、数码管管理器初始化;//将pBuffer指向的8字节缓冲区内容显示于F5区数码管上;
extern void cDisplay8(u8* pBuffer);u8 buffer[8];            //用于显示数码管缓冲区,8个字节;
u8 SpeedNo;             //选择哪一级速度;
u8 StepDelay;           //转动一步后,延时常数;
u16 StepCount;          //转动步数;//传给步进电机的值(四相八步);
u8 StepControl[8]={0x11, 0x99, 0x88, 0xcc, 0x44, 0x66, 0x22, 0x33};        u8 WaterHight = 0xff;  //水位;
u8 WaterHight1 = 0xff; //WaterHight1的副本;
u16 adResult = 0;      //电位器读取的值;
u16 lastResult = 0xff; //电位器上次读取的值;
u8 Steptemp = 0; //步进电机的历史状态(上次旋转之后位于哪步);
u8 hight = 0; // 水闸开启程度为hight%;
u8 acircle = 40; //转1圈要步进电机需要走的总步数;
u8 adtemp;
u8 count = 0;
u8 i = 0;/* 刷新数码管,并延时 */
void delayBuffer()
{u16 count = 10;while (count--){cDisplay8(buffer); //刷新数码管1次;}
}/* 延时函数 */
void delay(u16 ms)
{u16 i; while(ms--){i = 100;do{;}while(--i);}
}/* 读AD0809数据 */
u8 ad0809()
{u8 i = 100;outportb(addr0809, 0x0);while (i--){;}                                 //延时,等待AD转换完成;return inportb(addr0809);
}/* 接收到电位器旋转角度变化,更新数码管 */
void display_data(u16 adResult)
{buffer[5] = 0x10;buffer[1] = adResult / 51;          //255/51 (16进制的1 = 1/51V) ,十位;adResult = (adResult % 51) * 10;buffer[0] = adResult / 51;           //个位;buffer[2] = 0x10;          buffer[3] = 0x10;                  //0x10用于消隐,即数码管不显示;
}/* 初始化8255 */
void Init8255()
{outportb(IO8255_Con,0x80);     //写8255控制字,无条件的数据传输方式,A、B、C口都单向输出;outportb(IO8255_PC, 0xff);       //0FFH->8255 PC,写C口;
}/*     刷新LED灯:当水位为[10,50)时,绿灯亮;当水位为[0,10)时黄灯闪烁;当水位为50时,红灯闪烁
*/
void Testled(){/*  此处用WaterHight的副本WaterHight1作为判断而不用WaterHight的原因是:WaterHight在电压器不变而水闸已经运动结束的情况下会被置为0xff,0xff并不能表示水位信息,即LED无法刷新;WaterHight1作为WaterHight被置为0xff之前的副本,可以一直记录当前水位用于LED刷新;*/if(WaterHight1>100){WaterHight1 = 0xff; //水位不正常,不显示LED;}else if(WaterHight1 >= 50){outportw(IO273, 0xef); //红灯;delay(20);outportw(IO273, 0xff); }else if(WaterHight1 >= 10){outportw(IO273, 0xbf); //绿灯;}else{outportw(IO273, 0xdf); //黄灯;delay(20);outportw(IO273, 0xff);}
}/* 实现步进电机旋转的函数,参数:需要转动的圈数 */
void StepCircle(u8 circleN){u8 rate = 1;       u8 htemp = 0;if(circleN >= 8){rate = 0;}        //需要转10圈,即水位到了40以上,需要快速转动;if(circleN == 0){rate = 0;}         //需要转0圈,即水位到了10以下,需要快速转动;/*    此处要解决步进电机的正转和反转问题;buffer[7]中存储的水闸的开启程度,而circleN代表假设水闸开启程度为0时,需要转多少圈;buffer[7]可以视作水闸已经转了多少圈;circleN减buffer[7]即代表还需要转多少圈;结果为负数代表需要关闸,步进电机逆时针转;结果为正数代表需要开闸,步进电机顺时针转;*/if(circleN <= buffer[7]){//关闸,逆时针转;circleN = buffer[7] - circleN;while(circleN){u8 control = 0;for(i = acircle; i > 0; i--){control = (Steptemp+i)%8;        //读取历史状态,根据历史状态旋转步进电机;delay(rate*100);                //速度控制;buffer[4] = 2 - rate;            //速度显示;outportb(IO8255_PC, StepControl[control]);  //步机旋转;if(i%(acircle/10) == 0){  //转1圈水闸变化10%,一圈要旋转acircle次,acircle/10次水闸开启1%;hight--;buffer[7]=hight/10;buffer[6]=hight%10;delayBuffer();    //刷新显示水闸开启程度;}htemp = i;Testled();delay(40); //前面最少delay(20),即最小总延时为delay(60);最大总延时为delay(160);}circleN--;   //需要转的圈数减一;}}else{//开闸,顺时针转;circleN = circleN - buffer[7];while(circleN){u8 control = 0;for(i = 0; i < acircle; i++){control = (Steptemp+i)%8;delay(rate*100);buffer[4] = 2 - rate;outportb(IO8255_PC, StepControl[control]);if(i%(acircle/10) == 0){hight++;buffer[7]=hight/10;buffer[6]=hight%10;delayBuffer(); }htemp = i;Testled();delay(40);}circleN--; }}Steptemp = htemp;
}void main()
{Init8255();        //8255初始化;cInitKeyDisplay(); //键盘,数码管初始化;while (1){count = 0;                 adtemp = 0;        buffer[4] = 0; //步进电机停止转动,速度为0,显示出来;//采样时长为4s,如果4s内电压值不变化,则采样结束;while(1){        adResult = ad0809();           //获取电压值;display_data(adResult);          //刷新数码管;if(adResult == adtemp){            //adResult不等于adtemp时,说明电压旋钮在旋转;count++  ;}else{adtemp = adResult;  }if(count == 4){break;                        //四次采样都相等时,认为电压不再改变,退出采样循环;}delayBuffer();         //电压旋钮旋转时数码管刷新水位,显示到数码管;Testled();                        delay(1000);                    //延时,保证采样过程不会太快;}if (lastResult != adResult)         //与历史版本比较,只有电压变化时才会重新设置水位;{lastResult = adResult;            //记录新电压值的副本作为历史版本;WaterHight = buffer[1]*10 + buffer[0]; //更新水位;if(WaterHight1 == WaterHight){WaterHight = 0xff;}else{WaterHight1 = WaterHight; //保存水位的副本作为历史版本;}}delayBuffer();Testled();//根据水位来调整水闸,一旦调整水闸完成,WaterHight将暂时失效(即如果电压值不变,则不能再用于控制水闸);if(WaterHight>100){WaterHight = 0xff;}else if(WaterHight>=50){StepCircle(10);              //水位等于50时,水闸需要开启到100%,转10圈;WaterHight = 0xff;}else if(WaterHight>=40){StepCircle(8);WaterHight = 0xff;}else if(WaterHight>=30){StepCircle(6);WaterHight = 0xff;}else if(WaterHight>=20){StepCircle(4);WaterHight = 0xff;}else if(WaterHight>=10){StepCircle(2);WaterHight = 0xff;}else{StepCircle(0);WaterHight = 0xff;}}
}

七、心得体会

通过本次课设,我了解了CPU如何控制各器件实现一个简单的系统;

在实验中也有一些不足:可能是由于各个分支的延时不同,也可能是对四相八步理解不到位,步进电机旋转的速度并不是恒定的;此外我们没有使用8259中断来使输入和步进电机的旋转互不干扰,而是采用了不停地定时检测来确保在旋转按钮时步进电机不会旋转,所以反应速度比较慢,延时比较长;

对于操作系统学习的OS通过读写文件控制硬件,以及微机原理学习的各种芯片功能使用等,都通过本次实验得到了更深刻的理解;


踩坑点:
星研软件编译链接完要点全速运行(一个小感叹号)才能在板子上运行;
步进电机的示例代码有误,中断处理函数TIMEROif(--StartStepDelay)应该改成--StartStepDelay; if(StartStepDelay)(老师说的,没验证),如果不改就会有一个警告,即使没错误只要有警告就无法在板子上下载运行;


西电微机系统课程设计——步进电机开环控制系统设计相关推荐

  1. 西电微机系统课程设计步进电机开环控制系统

    ** 微机系统与应用课程设计 课题二 步进电机开环控制系统设计** 一.程设计目的 掌握微机系统总线与各芯片管脚连接方法,提高接口扩展硬件电路的连接能力. 加深对 A/D 和并行接口芯片的工作方式和编 ...

  2. 微机原理课程设计——步进电机工作原理模拟程序设计

    步进电机工作原理模拟程序设计 摘  要 本次设计通过汇编程序,模拟混合两相步进电机工作原理.通过按键控制步进电机的启动.停止与电机工作方式的选择,并且在PC显示器上模拟显示电机按指定转速周而复始的转动 ...

  3. c语言报告西电,c语言课程设计报告西安电子科技大学.docx

    C语言课程设计 题目名称: 7组 姓 名 学 号 130403100 专 业 自动化专业 班 级 1304031 指导教师 冯兰胜 编写日期 2016.5.16 需求分析 4.19 递归反向输出字符串 ...

  4. 西电Pintos操作系统课程设计 实验二

    实验二:Alarm-Clock 一.实验目的 重新实现timer_sleep()函数,避免"忙等待"的发生.通过阅读Pintos部分源码,初步了解Pintos操作系统内核的关键函数 ...

  5. 微型计算机测控系统课程设计报告,微机原理课程设计实验报告--步进电机控制.docx...

    文档介绍: 2010-2011学年第一学期 微机原理课程设计实验报告 课题名:步进电机控制 一.课题内容和提示: 编程提示: (1)步进电机驱动原理是通过对每相线圈中的电流的顺序切换来使电机做步进式旋 ...

  6. 西安电子科技大学计算机微原课设,西安电子科技大学我机电院微机原理课程设计.doc...

    西安电子科技大学我机电院微机原理课程设计 微机原理课程设计 学 院 机电工程学院 专 业 自动化 姓 名 ******* 学 号 ******** 指导教师 千博 董瑞军 一.微元课程设计 课程设计的 ...

  7. 【嵌入式系统课程设计——纸张计数显示装置设计】

    一.简介 本项目分享的是一个嵌入式系统的课程设计,老师给了多个题目供我们选择.我们组选择的题目是纸张计数显示装置设计,也是2019年全国大学生电子设计竞赛的F题. 有关这个题目的经验分享,网上已经出现 ...

  8. 计算机课程设计步进电机8086,基于8086步进电机课程设计

    微机原理课程设计 皖西学院本科课程设计 步进电机电机控制设计 摘要:8255A是一种通用的可编程并行I/O接口芯片(Programmable Peripherial Interface,PPI),它是 ...

  9. 8255交通灯实验的微型计算机,微机原理课程设计——8255,8253交通灯模拟实验.doc...

    文档介绍: 微机原理课程设计 设计任务及要求: 交通信号灯的控制: 通过8255A并口来控制LED发光二极管的亮灭. A口控制红灯,B口控制黄灯,C口控制绿灯. 输出为0则亮,输出为1则灭. 用825 ...

最新文章

  1. [Django](1093, quot;You can#39;t specify target table #39;fee_details_invoices#39; for update in...
  2. windbg-奔溃生成的dump文件
  3. Python二分查找算法
  4. 浅谈面向对象的javascript几个特性
  5. 同事线上埋的这个坑,我整整找了3天3夜
  6. java中定义存放汉字的数组_Java中如何存储汉字
  7. 滚动电梯卡延期复制教学
  8. 高等数学课后答案上册同济大学第七版第一章答案
  9. 安装oracle提示javaw,为什么oracle 9i 安装时,setup exe javaw exe进程消失
  10. if、else、else if使用方法
  11. 【转载】MiniGUI输入法词库更新
  12. 水管工游戏(随机地图版)
  13. 泰坦尼克号python数据分析统计服_数据分析可视化——泰坦尼克号幸存者分析(上)...
  14. LNMP搭建HDwiki
  15. Win32显示隐藏任务栏
  16. VS2017中处理命令行参数的方法----C++语言 Windows系统
  17. php获得视频分辨率,php+ffmpeg 获取视频相关信息(缩略图、视频分辨率)
  18. 深入了解电容(二):电容的参数指标解释
  19. Provides transitive vulnerable dependency - Intellij IDEA
  20. 图片压缩-speedpdf免费无损在线压缩图片

热门文章

  1. 算法到底有没有价值观?快手给出了标准答案
  2. 同步时序逻辑电路分析——数电第六章学习
  3. 轻雀协作客户最佳实践之凯叔讲故事
  4. NTU-RGBD骨架数据分析
  5. 如何使用esp32从零制作一个ROS2的teleop遥控器(cmd_vel)
  6. N32G457VEL7移植FreeRTOS代码
  7. c语言找最大数字,C语言: 键盘输入任意10个整数,找出最大数及最大数的序号。...
  8. python数字加密资产_GitHub - ezpod/crypto-exchange-engine: 数字加密资产交易引擎的原理性实现代码,汇智网提供...
  9. 什么是商业智能BI,谈谈商业智能BI的定义与作用
  10. 即时通讯 视频会议开源技术选择