找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 17765|回复: 1
收起左侧

基于单片机的直流伺服电机控制系统设计论文

[复制链接]
ID:367315 发表于 2018-7-9 17:05 | 显示全部楼层 |阅读模式
这是一个直流伺服电机控制系统设计  有代码  大师搭建出来仿真有问题 大家帮忙看看
电子信息与电气工程系
课程设计报告

设计题目:    直流伺服电机控制系统设计     
系    别:电子信息与电气工程系
年级专业:
学    号:
学生姓名:
      
自动化专业《计算机控制技术》课程设计任务书
论文
题目
直流伺服电机控制系统设计
设计类型

导师姓名
丁健
干开峰
主要内容及目标
设计对象是直流伺服电机实验台,设计一个计算机控制的直流伺服电机控制系统。由测量元件(位移传感器)对被控制对象(电机)的被控参数(位移)进行测量,由变换发送单元(A/D转换器)将被控参数变成一定形式的信号 ,送给控制器CPU,控制器将测量信号(实际位移量)与给定信号(位移量)进行比较,若有误差则按预定的控制规律产生一控制信号驱动执行机构(伺服电机控制电源)工作,使被控参数(实际位移量)与给定信号(位移量)保持一致。其电机位置随动系统:
其中: =1.8,=0.035,=0.15,K =100,控制算法选用数字PID控制。
设计条件
  • PC机一台,教学实验箱一台;

计划学生数及任务
3人
(1):明确课题功能。
(2):把复杂问题分解为若干模块,确定各模块处理方法,画出流程图。
(3):存储器资源分配
(4):编制程序,根据流程图来编制源程序
(5):对程序进行汇编,调试和修改,直到程序运行结果正确为止。
计划设计进程
  • 总体方案设计
  • 控制系统的建模和数字控制器设计
  • 硬件的设计和实现
  • 选择计算机字长(选用 51内核的单片机)
  • 设计支持计算机工作的外围电路(EPROMRAMI/O端口、键盘、显示接口电路等)
  • 设计输入信号接口电路;
  • 设计输出控制电路;
  • 其它相关电路的设计或方案(电源、通信等)
  • 软件设计
  • 分配系统资源,编写系统初始化和主程序模块框图;
  • 编写A/D转换和位置检测子程序框图;
  • 编写控制程序和D/A转换控制子程序模块框图;
  • 其它程序模块(显示与键盘等处理程序)框图。
五、编写课程设计说明书,绘制完整的系统电路图(A3幅面)。
参考文献
1.于海生 计算机控制技术[M] 北京:机械工业出版社,2007.6
2、周荷琴等 微型计算机原理及接口技术[M]合肥:中国科技大学出版社,2008.6   
3、李刚民等 单片机原理及应用技术[M]北京:高等教育出版社
4、楼然苗  51系列单片机设计实例[M]北京:北京航空航天大学出版社
5、计算机控制技术实验指导书
摘要
随着集成电路技术的飞速发展,微控制器在伺服控制系统普遍应用,这种数字伺服系统的性能可以大大超过模拟伺服系统。数字伺服系统可以实现高精度的位置控制、速度跟踪,可以随意地改变控制方式。单片机和DSP在伺服电机控制中得到了广泛地应用,用单片机作为控制器的数字伺服控制系统,有体积小、可靠性高、经济性好等明显优点。。本设计研究的直流伺服电机控制系统即以单片机作为核心部件,主要是单片机为控制核心通过软硬件结合的方式对直流伺服电机转速实现开环控制。
对于伺服电机的闭环控制,采用PID控制,利用MATLAB软件对单位阶跃输入响应的PID校正动态模拟仿真,研究PID控制作用以及PID各参数值对控制系统的影响,通过试凑法得到最佳PID参数。同时能更深度地掌握在 自动控制领域应用极为广泛的MATLAB软件。
目   录
1.引言
2.单片机控制系统硬件组成
2.1 微控制器
2.2 DAC0808转换器
2.3运算放大器
2.4按键输入和显示模块
2.4.1 按键输入
2.4.2 显示模块
2.5 直流伺服电动机
3.单片机控制系统软件设计
3.1主程序
3.2键盘处理子程序
4.控制系统原理图及仿真
4.1控制系统方框图
4.2控制系统电路原理图
4.3 Proteus仿真结果
5.Simulink组件对直流伺服控制系统的仿真
5.1 MATLAB与Simulink简介
5.1.1 MATLAB简介
5.1.2 Simulink简介
5.2 直流伺服电机数学模型
5.3 系统Simulink模型及时域特性仿真
5.3.1 开环系统Simulink模型及仿真
5.3.2 单位负反馈系统Simulink模型及仿真
5.4 PID校正
5.4.1 PID参数的凑试法确定
5.4.2 比例控制器校正
5.4.3 比例积分控制器校正
5.4.4 PID控制器校正
6.小结
参考文献
附录
1.引言
本设计的单片机控制直流伺服电机系统是一个开环的自动控制系统控制系统。是以单片机为控制器, 通过按钮设置设定值输入到单片机,单片机对输入信号处理后输出控制信号,经D/A转换器DAC0808转换后把数字信号转变为模拟电压,再经放大器放大后,去控制伺服电机工作,进而控制电机向着预定的转速转动。同时单片机处理的数字信号通过LCD来显示,实时显示单片机的转速值。
另外本设计还利用了MATLAB软件,利用 Simulink构造直流电机控制系统模型,通过对各个单元部件的参数进行设定,进而对直流伺服电机系统控制进行仿真,就其仿真功能对系统进行时域分析。
2.单片机控制系统硬件组成
本系统是由一片单片机、矩阵式键盘,DAC0808转换器、运算放大器、显示模块和一台直流伺服电机组成,另外通过Proteus7.4软件进行仿真。
2.1 微控制器
选用AT89C52单片机。 AT89C52是51系列单片机的一个型号,它是ATMEL公司生产的。
  AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的AT89C52单片机可为您提供许多较复杂系统控制应用场合。
  AT89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线,AT89C52可以按照常规方法进行编程,但不可以在线编程(S系列的才支持在线编程)。其将通用的微处理器和Flash存储器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。
  AT89C52有PDIP、PQFP/TQFP及PLCC等三种封装形式,以适应不同产品的需求。
主要功能特性:
(1)兼容MCS51指令系统,8k可反复擦写(>1000次)Flash ROM
(2)32个双向I/O口,256x8bit内部RAM
(3)3个16位可编程定时/计数器中断,时钟频率0-24MHz
(4)2个串行中断,可编程UART串行通道
(5)2个外部中断源,共6个中断源
(6)2个读写中断口线,3级加密位
(7)低功耗空闲和掉电模式,软件设置睡眠和唤醒功能
图2-1 AT89C52
2.2 DAC0808转换器
设计中采用的芯片是DAC0808,它是一个8位DAC。图2是DAC0808典型应用电路。图2-1中输出的模拟量是一个正电压,当需要负电压时,在DAC的第4引脚直接接一个3KΩ左右的电阻即可。DAC的第4引脚的电流总是流入的,其最大值为1.992mA。当外接一个3KΩ的负载电阻RL时,输出的电压是通过RL上所加的电压,最大的电压为-3KΩ×1.922mA ≈-6V(当所有位输入都是高电平的时候),与实验中的数据相符合。需要指出的是,负载电阻的大小会影响转换时间,当负载电阻为2.5KΩ的时候,在最坏的情况下,会使转换时间增加1.2μs。

图2-2  DAC0808典型应用电路
2.3运算放大器
把D/A转换器的电流输出转换为电压输出,同时也是把微小的电流信号放大为较大的电压信号,以驱动电机转动。
2.4按键输入和显示模块2.4.1 按键输入
采用自己设计的形如3×4矩阵式按钮,按钮用于设定某一数值,即电机转速值。通过
程序设置延时环节来消除按钮的抖动问题,这样做使矩阵式按钮硬件连线简单,同时按钮的软件设计也不复杂。
2.4.2 显示模块
系统采用点阵式液晶显示器,显示电机的当前转速值,通过软件设计使得连线简单。
2.5 直流伺服电动机
直流伺服电动机在伺服系统中控制机械元件运转的发动机.是一种补助马达间接变速装置。又称执行电动机,在自动控制系统中,用作执行元件,把所收到的电信号转换成电动机轴上的角位移或角速度输出。其主要特点是,当信号电压为零时无自转现象,转速随着转矩的增加而匀速下降。其作用可使控制速度,位置精度非常准确。
直流伺服电动机的结构与直流电动机基本相同。只是为减小转动惯量,电机做得细长一些。所不同的是电枢电阻大,机械特性软、线性(电阻大,可弱磁起动、可直接起动)。供电方式是他励供电,即励磁绕组和电枢分别两个独立的电源供电。控制方式有.电枢控制和磁极控制,其中改变电枢电压U调速范围较大,直流伺服电机常用此方法调速
直流伺服电动机 转速的计算公式如下:
式中:n为转速;Φ为磁通;U为外加电压;I、R为电枢电流和电阻;Ke为电势系数。
3.单片机控制系统软件设计
软件设计采用模块化设计,由主程序模块和功能实现模块两大部分组成。主程序通过读取键值处理后送到D/A转换以达到控制电机的目的;功能实现模块主要由主函数模块、键盘处理子程序和D/A转换子程序等组成。
3.1主程序
主程序首先对键盘和显示模块的程序进行初始化,通过读取键值处理后送到D/A转换以达到控制电机的目的。主程序流程图如图2-1所示。
图2-1 主程序流程图
3.2键盘处理子程序
键盘采用程序扫描的工作方式,即在特定的程序位置段上安排键盘扫描程序读取键盘状态。键盘处理子程序的程序扫描法流程图如图2-2所示。
图2-2 键盘处理子程序的程序扫描法流程图
4.控制系统原理图及仿真4.1控制系统方框图
控制系统是以单片机为控制器 ,通过键盘设置输入转速值,经单片机处理后送到D/A转换器,模拟信号经功率放大后驱动电机,最终电机以设定的转速值稳定旋转。图4-1即为控制系统方框图
图4-1  控制系统方框图
4.2控制系统电路原理图
图4-2  控制系统电路原理图
4.3 Proteus仿真结果
图4-3 Proteus仿真图
利用Proteus 7.4a进行仿真,当通过键盘选择某一数值时,电机转速即为相应的设定值,并在仿真电路图中电机下方显示电机对应转速值的变化及最终稳定值。图4-3中仿真图是当通过按键设定值为158时,电机下方液晶显示器即显示158,表明电机转速为158 r/min。经多次仿真分析,某些时候与键盘输入值相比较得知当电机响应输入值时有很小的稳态误差存在,原因是没有加入反馈环节。以下利用MATLAB仿真软件研究PID反馈控制对直流伺服电机控制系统的作用。
5.Simulink组件对直流伺服控制系统的仿真5.1 MATLAB与Simulink简介5.1.1 MATLAB简介
MATLAB软件推出并应用到自动控制领域后,极大地改善了自动控制系统的动态仿真和性能分析环境。MATLAB(Matrix Laboratory,矩阵实验室)是一个适用于科学计算和工程应用的数学软件系统。自1982年由Mathworks软件公司推出后,经二十多年的发展,现已是IEEE
组织认可的最优化的科技应用软件,成为大学教学和科研中最常用的工具。掌握了MATLAB的应用,对直流伺服电机控制效果的改善,肯定有着意想不到的帮助。该软件具有以下特点:
(1)数值运算功能强大;
(2)编程环境简单;
(3)数据可视化功能强;
(4)丰富的程序工具箱;
(5)可扩展性能强等。
5.1.2 Simulink简介
Simulink是MATLAB软件的扩展,它是实现动态系统建模和仿真的一个软件包,他与MATLAB语言的主要区别在于,其与用户的交互接口是基于Windows模型化图形输入,使得用户可以把更多的精力投入到系统模型的构建,而非编程上。
使用Simulink进行仿真一般分为两步:用户首先需要在仿真模型编辑窗口中搭建好自己的仿真模型,设置好具体模型参数和仿真参数,然后就可以开始仿真,Simulink将根据用户搭建的模型,模拟系统在用户设定条件下的具体行为。下面将以直流伺服电机的自动控制为例,演示MATLAB中Simulink仿真的应用。
5.2 直流伺服电机数学模型
直流伺服电机开环系统结构图如图图5-1所示
  
图5-1  直流伺服电机开环系统结构图
其中直流伺服电机的传递函数为
5.3 系统Simulink模型及时域特性仿真
对于单输入单输出系统,在经典控制理论中可用传递函数来描述系统, 获得系统的动态响应。同样,S仿真软件也有传递函数模块,可方便地描述系统的特性,且简化了仿真模型。从模块库窗口创建系统模型如图1所示,选信号源模块组中的阶跃信号模块为输入信号,以输出模块组中的示波器模块作为显示器来观察系统阶跃响应。在模型窗口设置传递函数模块的参数和特性,运行仿真模型,得系统阶跃响应曲线。
5.3.1 开环系统Simulink模型及仿真
图5-2  直流伺服电机开环系统Simulink模型
端口Step为直流伺服电机的输入电压,输出端口为电机转速。
图5-3是开环系统的仿真结果,即开环系统的阶跃响应曲线,也即直流伺服电机输入1V单位阶跃电压时。电机的转轴输出呈线性变化。
图5-3  开环系统仿真图
由图5-3响应曲线可知,系统没有在可视范围内达到稳态值“1”,但从理论上分析知此系统属稳定系统,在足够时间内是能够达到稳定状态的。上述分析说明:系统的响应速度较慢,系统性能较差,从而可能不具备使用价值。这个分析结果表明,该系统没有达到预期的设计要求。
5.3.2 单位负反馈系统Simulink模型及仿真
图5-4是在图5-3的基础上加一个单位负反馈环节,构成直流伺服电机的单位负反馈系统,单位负反馈系统Simulink模型如图5-4所示
图5-4 直流伺服电机单位负反馈系统Simulink模型
图5-5是单位负反馈系统的仿真结果
图5-5 单位负反馈系统仿真图
系统超调:40%,调节时间:2 s。由图5-5和开环阶跃响应曲线相比较知:系统应经可以达到较快达到稳态值。说明闭环单位负反馈系统对系统性能有很大改善。
5.4 PID校正
为了使系统能够达到设计要求,我们可以在图5-4前向通道上设置一个控制器构成闭环系统来校正直流伺服电机。基于PID控制(闭环)的直流伺服电机系统框图如图5-6所示。
图5-6  基于PID控制(闭环)的直流伺服电机系统框图
其控制过程为由测速发电机输出电压得到直流电机输出量,即转速,通过转速反馈后与系统输入信号进行比较,得到偏差信号。偏差信号作为PID控制器的输入信号根据设定的PID控制规律计算后输出信号U,作为控制量输入给直流电机,从而实现整个直流电机调速系统的闭环负反馈PID控制。
5.4.1 PID参数的凑试法确定
增大比例系数KP一般系统响应利于减小静差,但是过大会增大超调,并产生震荡,是稳定性变坏。增大TI有减小超调,减小震荡,是系统更稳定,但静差消除变慢。增大微分TD利于加快系统响应时间,使超调减小,稳定性增加,但对扰动的抑制能力减弱,对扰动有较敏感的响应。
在凑试时,对参数实行下述先比例,后积分,再微分的整定步骤。
(1)首先只整定比例部分。即将比例部分由小变大,并观察相应的系统响应,直到得到反应快,超调小的响应曲线。如果系统没有静差或静差已小到允许范围内,并且响应曲线已属满意,那么只需用比例控制器即可,最优比例系数可由此确定。
(2)如果在比例调节的基础下系统的静差不能满足设计要求,则须加入积分环节。整定时首先置积分时间T1为一较大值,并将经第一步整定得到的比例系数略微缩小,然后减小积分时间,并在保持系统良好动态性能的情况下,静差得到消除。在此过程中,可根据响应曲线的好坏反复改变比例系数与积分时间,以期得到满意的控制过程与整定参数。
(3)若使用比例积分控制器消除了静差,但动态过程经反复调整仍不能满意,则可加入微分环节,构成比例积分微分控制器。在整定时,可先置微分时间Td为零。在第二步整定的基础上,增大Td,同时相应的改变比例系数和积分时间,逐步凑试,以获得满意的调节效果和控制参数。
5.4.2 比例控制器校正
为能要求系统在特别短的时间内达到设定的转速值,比例增益K 应尽可能大,以提高比例作用的强度,但必须同时考虑系统的稳定性。采用单纯的比例控制,其调整时间和超调量是一对矛盾,无法同时满足:要缩短调整时间,K 要加大;而K 加大,超调量也同时加大了。经过多次参数选择,当K。=10时,阶跃响应曲线较为理想,呈现接近0.75衰减率的振荡过程。
比例控制系统Simulink模型及仿真
图5-7 比例控制系统Simulink模型
Kp=1时仿真图
Kp=3时仿真图
Kp=5时仿真图
由以上三个比例控制的仿真图可知,增大比例系数KP一般系统响应利于减小静差,但是过大会增大超调,并产生震荡,是稳定性变坏。
5.4.3 比例积分控制器校正
积分控制的作用是只要系统存在误差,积分控制作用就不断地积累,输出控制量以消除误差,因而,只要有足够的时间,积分控制将能完全消除误差。在比例环节基础上加入积分环节,只要参数设置合适就能完全消除系统偏差。
比例积分控制系统Simulink模型
图5-8 比例积分控制系统Simulink模型
Kp=1、Ki=1时仿真图
Kp=1、Ki=3时仿真图
Kp=5、Ki=3时仿真图
由以上三个比例积分控制的仿真图可知,增大TI有减小超调,减小震荡,使系统更稳定,但静差消除变慢。PI控制参数设置适当可使系统静差为零。经多次试凑,选KI=1.
5.4.4 PID控制器校正
比例积分作用虽能是系统误差为零,但系统动态性能不能得到满足。积分作用太强可能会使系统出现震荡。微分控制具有超前控制能力,可抑制最大动态偏差,改善系统动态性能,提高系统的稳定性。为此,在PI作用基础上引入微分控制,构成PID控制器,以使系统满足稳、准、快的要求。
PID控制控制系统Simulink模型如图
图5-9 PID控制系统Simulink模型
Kp=1、Ki=1、Kd=0.1时仿真图
和PI控制闭环响应曲线相比较可知:系统响应时间变短,超调变小,但仍不符合要求;
Kp=5、Ki=1、Kd=0.1时仿真图
与KP=1、KI=1、KD=0.1时的仿真图相比,系统超调和调节时间都变小,仍然不符合要求,继续校正。需加大Kp及Ki。
Kp=12、Ki=1、Kd=0.5时仿真图
由上曲线知此时系统有微量的超调,进一步加大Ki时超调为零。
Kp=12、Ki=1、Kd=0.9时仿真图
经过多次校正参数,此时当 Kp=12、Ki=1、Kd=0.9时系统超调量为0,稳态误差为0,性能满足设计要求,稳定、准确、快速得到了完满的统一。
6.小结
控制系统特点是以单片机为控制器 ,通过键盘设置输入转速值,使得电机的转速设置方便快捷,另外又通过软件实现系统转速设置范围的保护。
    但在proteus中没能实现闭环系统的PID控制。此缺点通过软件弥补,在MATLAB软件中的SIMULINK中进行了直流伺服电机的开环控制系统仿真,单位闭环控制系统仿真,闭环PI控制系统仿真,闭环PD控制仿真,闭环PID控制仿真能够更好的测试和控制系统的性能,从而为设计事物提供了更准确的性能指标。

  1. #include "reg52.h"
  2. //#include "absacc.h"
  3. //#include "stdio.h"
  4. //#include "math.h"
  5. //#include "string.h"
  6. #define unchar unsigned char
  7. #define unint unsigned int
  8. void wdata(unchar dat);//write data function
  9. void wcom(unchar com);//write command function
  10. void delay(unchar t);//delay function
  11. sbit rw=P3^1;//rw
  12. sbit rs=P3^0;//rs
  13. sbit en=P3^2;//en
  14. #define MAX_LEN 16    // 数据最大长度
  15. #define count_M1 50000
  16. #define H_0 (65536-count_M1)/256
  17. #define L_0 (65536-count_M1)%256
  18. unchar code tab2[]={0x31,0x32,0x33,0x41,0x34,0x35,0x36,0x42,0x37,0x38,0x39,
  19.                     0x43,0x0e,0x30,0x0f,0x44};      //键盘求值表
  20. unchar code tab3[]={"Target Value:  "};
  21. unchar code tab4[]={" "};
  22. unchar code tab6[]={" input ERR "};
  23. unchar serial_data[MAX_LEN],serial_len=0,sure_flag=0;

  24. void wdata(unchar dat);//write data function
  25. void wcom(unchar com);//write command function
  26. void delay(unchar t);//delay function
  27. void keyscan(void);//键盘操作程序
  28. unchar scankey(void);//键盘求值程序
  29. void chushi(void);//初始化程序
  30. //void init_serial(void);//串口初始化
  31. //void uart_serial(void);//串口主程序
  32. void lcd_write(void);//液晶显示待发送指令
  33. unchar jisuan(void);//计算结果为十进制
  34. unint freq = 0;//频率变量
  35. sfr16 DPTR=0x82;//申明DPTR
  36. char times=0;//计算T0中断次数
  37. //delay function
  38. //P0=0x00;
  39. //中断初始化
  40. void init_interrup(void)
  41.               {
  42.                 IE=0x8a;//启用T0,T1中断
  43.                 TMOD=0x51;//T1为计数器,T2为定时器,都采用mode1
  44.                 TH0=H_0;
  45.                 TL0=L_0;
  46.                 TH1=0;
  47.                 TL1=0;
  48.                 TR0=1;
  49.                 TR1=1;            
  50.               }
  51. void delay(unchar t)
  52.      {
  53.      unchar a,b;
  54.      for(a=0;a<t;a++)
  55.      for(b=0;b<128;b++);
  56.      }
  57. //The function for write data to LCD screen
  58. void wdata(unchar dat)
  59.      {
  60.        P1=dat;
  61.        rs=1;
  62.        rw=0;
  63.        en=0;
  64.        delay(6);
  65.        en=1;
  66.      }
  67. //The function for write command to LCD screen
  68. void wcom(unchar com)
  69.      {
  70.      P1=com;
  71.      rs=0;
  72.      rw=0;
  73.      en=0;
  74.      delay(6);
  75.      en=1;
  76.      }
  77. //初始程序
  78. void chushi(void)
  79.      {
  80.               unchar i;
  81.      wcom(0x01);
  82.      wcom(0x38);
  83.      wcom(0x0c);
  84.      wcom(0x06);
  85.               delay(4);
  86.               wcom(0x80);
  87.               delay(4);
  88.      for(i=0;i<17;i++)
  89.          {
  90.          wdata(tab3[i]);
  91.          }
  92.      wcom(0xc0);
  93.      delay(2);
  94.      }
  95. //键盘求值程序
  96. unchar scankey(void)
  97.    {
  98.      unchar temp,c,d;
  99.               P2=0x0f;
  100.               temp=P2;
  101.      temp=temp&0x0f;//屏蔽高四位,取列值
  102.      temp=~(temp|0xf0);//将temp中的内容与0xf0进行相加,最后求反可得到是那列按下
  103.      if(temp==1)
  104.          c=0;//P2.0位低电平
  105.      else if(temp==2)
  106.          c=1;//P2.1位低电平
  107.      else if(temp==4)
  108.          c=2;//P2.2位低电平
  109.      else if(temp==8)
  110.          c=3;//P2.3位低电平
  111.      else
  112.          c=0;//否则给返回值C=0
  113.      P2=0xf0;//给P2的行为高电平,以来判断是高四为的那位为低电平
  114.      delay(1);
  115.      temp=P2;
  116.      temp=temp&0xf0;//屏蔽低四位
  117.      temp=~((temp>>4)|0xf0);//将temp中的高四位向右移动4位,与0xf0相加,最后求反可以得到是那行按下
  118.      if(temp==1)
  119.         c=c+0;//将行P2.4的值加上列的值
  120.      else if(temp==2)
  121.         c=c+4;//将行P2.5的值加上列的值
  122.      else if(temp==4)
  123.         c=c+8;//将行P2.6的值加上列的值
  124.      else if(temp==8)
  125.         c=c+12;//将行P2.7的值加上列的值
  126.      else
  127.         c=0;
  128.               d=tab2[c];
  129.     return (d);//最后返回行加列的值
  130.    }

  131. //lcd_write function
  132. void lcd_write(void)
  133.     {
  134.               unchar write_0,write_1,jian_zhi[MAX_LEN];
  135.               for(write_0=0;write_0<MAX_LEN;write_0++)
  136.                     {
  137.                                serial_data[write_0]=0;
  138.                               }   //清空发送缓冲数组
  139.               wcom(0x0f);   // 将光标置在oxc0处
  140.               serial_len=0;
  141.               delay(2);
  142.               while(1)     
  143.                 {
  144.               write_1=0xc0;   //光标地址
  145.               wcom(write_1);
  146.               for(write_0=0;write_0<MAX_LEN; )   //输入指令  最大为MAX_LEN
  147.                     {
  148.                        wcom(write_1);
  149.            P2=0x0f;                      //等待键盘值
  150.                                while((P2&0x0f)==0x0f);
  151.                                jian_zhi[write_0]=scankey();
  152.                                delay(1);
  153.                                P2=0x0f;
  154.                                while((P2&0x0f)!=0x0f);       //等待按键放松
  155.                                             if(jian_zhi[write_0]==0x0e)   //当按一下取消键时 清空所有发送缓冲数组,
  156.                                         {                      //当连续按下两次时则取消本次通讯,退出
  157.                                                           if(write_0==0)
  158.                                                               goto write_out;
  159.                                                           else if(write_0>=1)
  160.                                                               {
  161.                                                                         write_1-=1;
  162.                                                                         wcom(write_1);
  163.                                                                         write_0-=1;
  164.                                                                         wdata(tab4[0]);
  165.                                                                         serial_data[write_0]=0;
  166.                                                                         serial_len--;
  167.                                                                         }
  168.                                                         }
  169.                                             else if(jian_zhi[write_0]==0x0f)      //确定发送的指令
  170.                                                {
  171.                                                           if(serial_len==3)
  172.                                                                       {if(serial_data[0]<2)
  173.                                                                                     sure_flag++;
  174.                                                                       else if(serial_data[0]>2);
  175.                                                                       else
  176.                                                                           {
  177.                                                                             if(serial_data[1]<5)
  178.                                                                                       sure_flag++;
  179.                                                                                       else if(serial_data[1]>5);
  180.                                                                                       else
  181.                                                                                         {
  182.                                                                                                     if(serial_data[2]<6)
  183.                                                                                                     sure_flag++;
  184.                                                                                                     else ;
  185.                                                                                                   }
  186.                                                                           }
  187.                                                                         }
  188.                                                           else
  189.                                                                       sure_flag++;                      //确定的标志位
  190.                                                         goto write_out;                      //退出本次输入指令
  191.                                                         }
  192.                                             else
  193.                                                {
  194.                                                         wdata(jian_zhi[write_0]);
  195.                                                         if(jian_zhi[write_0]<=0x39)
  196.                                                              serial_data[write_0]=jian_zhi[write_0]-0x30;
  197.                                                         else
  198.                                                              serial_data[write_0]=jian_zhi[write_0]-0x37;
  199.                                                         write_1++;
  200.                                                         write_0++;
  201.                                                         serial_len++;
  202.                                                         }
  203.                     }
  204.                  }
  205.     write_out :
  206.                          delay(1);
  207.     }
  208. //合并数组
  209. void serial_and(void)
  210.     {
  211.               unchar and0,and1,and2=0;
  212.               and1=serial_len/2;
  213.               for(and0=0;and0<and1;and0++)
  214.                   {
  215.                             serial_data[and0]=(serial_data[and0+and2++]<<4)|serial_data[and0+and2];
  216.                             }
  217.               }                           
  218. //键盘操作
  219. void keyscan(void)
  220.    {
  221.      unchar ks_0,ks_1;
  222.      delay(2);//延时去抖动
  223.               P2=0x0f;
  224.      if((P2&0x0f)!=0x0f)//延时后在判断一次,去除抖动影响
  225.                   {
  226.                             ks_0=scankey(); //求键盘值
  227.                             P2=0x0f;
  228.                             while((P2&0x0f)!=0x0f);  //等待放松
  229.         while(ks_0==0x41)
  230.                                  {
  231.                                           switch(ks_0)
  232.                                               {
  233.                                              case 0x41 :
  234.                                                        {
  235.                                                                                     chushi();
  236.                                                                                     lcd_write();   //调用写指令程序
  237.                                                                            if((sure_flag==1)&&(serial_len<=3)&&(jisuan()<256))
  238. //发送指令的条为确认发送标志sure_flag=1&&本次发送指令的个数erial_len=6
  239.                                                 {
  240.                                        sure_flag=0;  //清除确定标志
  241.                                                                                                   //serial_and();//合并数组
  242.                                                                                     //              serial_len/=2;
  243.                                                 // uart_serial();//调用发送指令程序
  244.                                                                                     //              P0=serial_data[0];
  245.                                                                                                   P0=jisuan();
  246.                                                                                     //              P0=255;
  247.                                                                                                   }
  248.                                                                                       else
  249.                                                                                           {
  250.                                                                                           wcom(0xc0);
  251.                                for(ks_0=0;ks_0<10;ks_0++)
  252.                                  {
  253.                                   wdata(tab6[ks_0]);
  254.                                  }                           
  255.                                                                                                         for(ks_0=0;ks_0<10;ks_0++)
  256.                                            {
  257.                                  delay(250);
  258.                                            }
  259.                                                   }
  260.                                                                                       delay(1);
  261.                                                                                     }break;
  262.                default :
  263.                                                       break;
  264.                                               }
  265.                                           ks_0=0;
  266.                                 }
  267.          sure_flag=0;
  268.                             serial_len=0;
  269.                    chushi();        //初始化,等待下一次发送指令
  270.                             wcom(0xc0);  
  271.                    for(ks_1=0;ks_1<MAX_LEN;ks_1++)    //清空发送缓冲数组
  272.                        serial_data[ks_1]=0;
  273.        }
  274.    }
  275. // 求取输入值转换为十进制
  276. unchar jisuan(void)
  277. {
  278. unchar jieguo;
  279. if(serial_len==3)
  280. jieguo=serial_data[0]*100+serial_data[1]*10+serial_data[2];
  281. else if(serial_len==2)
  282. jieguo=serial_data[0]*10+serial_data[1];
  283. else if(serial_len==1)
  284. jieguo=serial_data[0];
  285. else ;
  286. ……………………

  287. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

完整的Word格式文档51黑下载地址:
直流伺服电机控制系统设计62701844.doc (605.31 KB, 下载次数: 138)
回复

使用道具 举报

ID:579411 发表于 2019-12-14 18:59 | 显示全部楼层
我来学习下,刚好做这个题目
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表