正文之前
感觉自己老老实实的写技术类文章还是上个世纪了。本学期开学了,每天沉迷于课设和写小说的节奏中,有点不可自拔。今天待会还要去发大四的补考证。真是忧伤。实在想不明白,挂科这么难的事情,怎么那么多人一门都能挂两次呢???百思不得其解!
正文
一、系统要实现的功能
-
主机从机串口通讯
-
主机向从机发送指定的速度差值
- 数据差值由 预设速度-实际速度 获得
- 差值在一定范围内的时候就算稳定,不传输
-
从机负责接收来自主机的速度差值,并且通过PWM转化为占空比的变化量
-
-
光电门测速
-
通过光电门获取直流电机的转速,传入主机之后加以利用
-
-
按键
-
设置两个功能按钮,一个加速一个减速
-
-
显示屏
-
四块七段LED显示屏,两块显示预设速度,两块显示实际速度!
-
-
直流电机
-
与从机连接,根据从机给定的占空比实现不同的转速
-
二、 硬件准备
内容如下图,就不转化为文字了。从PPT复制过来直接就是图片了,不知道咋消除格式~
三、流程设计
四、系统架构
五、系统设计
其实系统设计跟系统架构接近,就是一个是硬件的架构,一个是软件的模块分析,不同的软件模块对应不同的硬件设备。
六、模块关系设计
这个是我准备用来当流程图用的东西,但是答辩的时候没想到这茬,结果就瞎鸡儿一说了。瞎了我画的这张好图!
七、电路图设计
这图对于电气这方面的同学来说肯定弱的一屁。但是我们毕竟是机械,没学那么多电学,而且也不是大头。所以担待下啦!还有不少没写的呢
八、细节电路设计
光电门因为仿真软件上没有合适的型号,所以我室友用的按键代替高低电平信号输入单片机
九、系统软件设计
代码上一波(这一波我是主力):
#include<reg51.h>
#include<intrins.h>
// #define TIMS=3306
#define FOSC 18432000L //当前主时钟频率
#define BAUD 115200 //声明当前波特率常数
#define uchar unsigned char
#define uint unsigned int
#define sdint signed int
//从0~9 的晶体管显示方式
uchar table[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x71};
uint times=0;
uint sendtimes=0;
sbit P31=P3^1; //串口通信口 RXD1(主机) 注意主机的RXD1要接从机的TXD1
sbit P30=P3^0; //串口通信口 TXD1(主机)
sbit P32=P3^2; //用于接受按键的外部输入 增速指令 设置于主循环中,不另外设置外部中断了
sbit P33=P3^3; //用于接受按键的外部输入 降速指令
sbit P34=P3^4;
sbit P35=P3^5;
sbit P36=P3^6;
sbit P37=P3^7;
sdint Speed_Want=0; //根据键盘的输入,确定预设速度 初始值为0
sdint Speed_Now=0; // 根据光电门获得的速度存储地
uint Pulse=0; //Pulse 是脉冲的意思!这里用这个全局变量来接受光电门的脉冲信号,采用外部中断计数。
//发送数据函数,用于主机,查询TI(发送中断请求标志位)
void SendDate(uchar date)
{
SBUF=date; //将数据写入串口缓存区
while(!TI);
TI=0; //此处应该由软件清零
}
//接受数据函数,用于从机,查询RI(接收中断请求标志位)
uchar ReciveDate(void )
{
RI=0;
while(!RI);
RI=0;
return SBUF;
}
//延时子程序,常用的
void delay(uint z)
{
uint x,y;
for(x=z;x>0;--x)
for(y=110;y>0;y--);
}
//定时器0中断服务程序,用于累计时间,发送数据
void timer_0() interrupt 1
{
++sendtimes;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
if (sendtimes==4)
{
sendtimes=0;
SendDate(0x7f+(Speed_Want-Speed_Now));
}
}
//定时器1中断服务程序,用于定时去获取光电门的脉冲数据。
void timer_1() interrupt 3
{
++times;
//计数重新赋值。每次定时器定时50ms
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
if(times==4) //当定时4次的时候,时延0.2s,此时再次读取数据,并且计算电机速度。
{
times=0;
Speed_Now=(Pulse)*5/4;
}
}
// 键盘扫描函数,每次主循环中都要扫描一次,只检测两个独立按键即可。
uint kscan(void)
{
uint keyboard;
if (P36==0)
{
delay(2);
if(P36==0)
{
keyboard=1;
}
}
else if(P37==0)
{
delay(2);
if (P37==0)
{
keyboard=2;
}
}
else
{
keyboard=0;
}
return keyboard;
}
void Change_Speed_Want(keyboard)
{
if (keyboard==1)
{
Speed_Want+=10;
}
else if(keyboard==2)
{
if (Speed_Want>=10)
Speed_Want-=10;
else
Speed_Want=0;
}
}
// 7/8段LCD数码显示管显示程序。 P0负责个位数,P1负责十位数
void show(uint num)
{
if (num<10 && num>=0)
{
P0=table[0];
P1=table[num];
}
else if( num>=10 && num<100)
{
P0=table[num/10];
P1=table[num%10];
}
else
{
//如果数值不合法,直接显示FF
P0=table[10];
P1=table[10];
}
}
void main()
{
P0=P1=0x00; //初始化显示器
TMOD=0x11; //定时器工作方式寄存器设置
SCON=0x50; //设置串口1方式1工作,允许接收数据 SM0=0 SM1=1 REN=1
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
while(1)
{
uint keyboard=0;
delay(150);
keyboard=kscan();
Change_Speed_Want(keyboard);
show(Speed_Want);
}
}
//因为SBUF传递八位数据,而我们的速度定义是uint 也就是16位的无符号数,那么二者无法兼容。
// 所以我想了个办法,用C语言的隐式类型转换,通过16进制uchar类型的0x00与 10进制的uint数做加法
//强制转换为uchar之后,再在从机上进行解码!代码如下:
// uint s=5;
// uchar s1=0x09;
// uchar s2=0x04;
// if((s1-s2)==s)
// {
// P0=table[1];
// }
// else
// P0=table[3];
// Output:1
// 又因为我们的差值可能是负数,所以特地定义了sdint这个类型
//事实证明,十六进制的加减后得到的也是sdsint
// sdint s=25;
// sdint xs=30;
// uchar s1=0x7f;
// uchar s2=0x84;
// if((s1-s2)==(s-xs))
// {
// P0=table[1];
// }
// else
// P0=table[3];
// Output: 1
十、欠缺部分
正文之后
其实今天老师说我们这个要实现的话定时器和中断可能不够用,而且串口通信的设计还不够。所以后面这些天可能就好好好地学一波通信协议 RS-232C这个东西了。然后再重新规划下我们的硬件设计妥
一犬得道现在居然在简书有个连载的东西了。但是我过几天估计就要跟起点签约了啊。。免费章节放到简书来会不会有版权问题?貌似签约就类似于卖版权??