(物联网)智能车制作全过
程(飞思卡尔)
智能车制作全过程(飞思卡尔)
如果我写得好,请顶我一下,我将再接再厉!
(本人在很久以前做的一辆用来比赛的智能车--获得华北一等奖,全国二等奖,有许多可改进
地方.)
下面我们来立即开始我们的智能车之旅:
首先,一个系统中,传感器至关重要.
"不管你的 CPU 的速度如何的快,通信机制如何的优越,系统的精度永远无法超越传感器的精
度".是的,在这个系统中,传感器的精度,其准确性就显得至关重要.如果你问我传感器的电路,
呵呵,我早就和大家分享了,在我发表的日志中,有一篇<<基于反射式距离传感器>>的文章
就详细的说明了传感器的硬件电路以及可以采取的信号采样方式.
传感器安装成一排,如上面排列.(就是个一字排列,没有什么特别)
接下来,看看我们如何处理传感器得到的信息:
大家看到了.结构很简单,我们已经搞定了传感器通路.下面我们来看看多机的控制方面的问
题:
其实,不管是便宜还是比较贵的舵机,都是一样的用法.舵机的特点就是不同的占空比方波就
对应着舵机的不同转角.当然不同的舵机有不同的频率要求.比如我用的这个舵机:方波频率
50HZ.怎么改变占空比?这个不就是PWM模块的功能嘛.PWM模块可以输出任意占空比的方
波.只要你控制其中的占空比寄存器,就可以直接控制舵机的转角.你只要将传感器的状态和
这个占空比对应上,不就 OK 了?就这么简单,做到这里,你就可以让你的车在跑道上跑了!
接下来,我们的工作是让智能车更加完善:速度要稳定.
在当前的系统结构中,要使一个系统更稳定更可靠,闭环系统是一个选择.(如果你不知道什么
是闭环系统,可以参照我的文章里面的一篇"基于单片机的 PID 电机调速"),既然是一个闭环系
统,速度传感器是必不可少的,用什么样的传感器做为速度反馈呢:
仔细看,和后轮之间有一条皮带的这个貌似电机的东西,就是我的速度传感器,它的学名叫"旋
转编码器".这个器件的特点就是:每转一圈,就会从输出端输出一定的脉冲,比如我这个旋转编
码器是 500 线的,就是转一圈输出 500 个脉冲.因此,我只要在单位时间内计数输出端输出的
脉冲数,我就可以计算出车辆的速度.显然,这个速度可以用来作为 PID 速度调节的反馈.
现在有了反馈,我们需要的是调节智能车驱动电机的速度了,如何来调速,就成了必须解决的
问题了.我用的是驱动芯片 MC33886.其实,这个芯片就是一个功率放大的模块.
我们知道,单片机输出的PWM信号还是TTL信号,是不能直接用来驱动电机的.非要通过功率
模块的放大不可.这个道理其实很简单,就像上次我给大家画的哪个电子琴电路的放大电路
一样:
看上面的那个三极管,就是将 TTL 电路的电流放大,才能够来驱动蜂鸣器.其实这里的这个
MC33886 就是这样的一个作用.而且我们自己也完全可以用三极管自己搭建一个这样的功
率放大电路,当然,驱动能力肯定不如这里的这个 MC33886(如我们用三极管就搭建了超过
MC33886 的电路,摩托罗拉就不会卖几十块钱一个了.呵呵.)知道了这个 MC33886 的工作
原理,就好说了,一句话,通过 PWM 来调节电机的速度.当方波中高电平占的比例大,电机的平
均电压肯定高,转速肯定快.也就是说,PWM 的占空比越大,电机转速越高.
看,就这么简单,这个智能车就做好了.接下来,我们就把我们知道的 PID 知识放到舵机和直流
驱动电机的控制中去.就可以达到一个比较好的控制效果.
如果要达到更高的水平,肯定机械方面的改造也少不了.当然,这不属于本文的讨论范围.呵呵.
智能车制作全过程(飞思卡尔---舵机篇
发表于 2008/11/2810:00:55
感谢大家的支持!如果我写得好,请顶我一下!
智能车的制作中,看经验来说,舵机的控制是个关键.相比驱动电机的调速,舵机的控制对于智
能车的整体速度来说要重要的多.
PID 算法是个经典的算法,一定要将舵机的 PID 调好,这样来说即使不进行驱动电机的调速(匀
速),也能跑出一个很好的成绩.
机械方面:
从我们的测试上来看,舵机的力矩比较大,完全足以驱动前轮的转向.因此舵机的相应速度就
成了关键.怎么增加舵机的响应速度呢?更改舵机的电路?不行,组委会不允许.一个非常有效的
办法是更改舵机连接件的长度.我们来看看示意图:
从上图我们能看到,当舵机转动时,左右轮子就发生偏转.很明显,连接件长度增加,就会使舵
机转动更小的转角而达到同样的效果.舵机的特点是转动一定的角度需要一定的时间.不如
说(只是比喻,没有数据),舵机转动 10 度需要 2ms,那么要使轮子转动同样的角度,增长连接件
后就只需要转动 5 度,那么时间是 1ms,就能反应更快了.据经验,这个舵机的连接件还有必要
修改.大约增长 倍~2 倍.
在今年中,有人使用了两个舵机分别控制两个轮子.想法很好.但今年不允许使用了.
接下来就是软件上面的问题了.
这里的软件问题不单单是软件上的问题,因为我们要牵涉到传感器的布局问题.其实,没有人
说自己的传感器布局是最好的,但是肯定有最适合你的算法的.比如说,常规的传感器布局是
如下图:
这里好像说到了传感器,我们只是略微的一提.上图只是个示意图,意思就是在中心的地方传
感器比较的密集,在两边的地方传感器比较的稀疏.这样做是有好处的,大家看车辆在行驶到
转弯处的情况:
相信看到这里,大家应该是一目了然了,在转弯的时候,车是偏离跑道的,所以两边比较稀
疏还是比较科学的,关于这个,我们将在传感器中在仔细讨论。
在说到接下来的舵机的控制问题,方法比较的多,有人是根据传感器的状态,运用查表法差
出舵机应该的转角,这个做法简单,而且具有较好的滤波"效果",能够将错误的传感器状态滤掉;
还有人根据计算出来的传感器的中心点(比如第四个和第五个传感器检测到黑线,中心点就是
),计算出舵机需要的转角,这个做法也比较的简单,但是必须有一个滤波的过程,必须要滤
掉错误的传感器状态.比如说:现在传感器第四个,第五个和第 11 个检测到了黑线,显然第 11
个应该是个传感器检测错误.应该把它滤掉.关于这个如何滤波,我们待会在后面将进行讨论.
还有人的做法就是采用 PID 算法,这个方法比较的好,其实也不是很难,就是 PID 参数整定的
时候有些麻烦.
大家可以自己选择喜欢的方法.
关于滤波,有些许的方法:
1.平均值排序法.
这个方法大家肯定一听就知道是怎么回事.就是不急于执行,先多次检测被测传感器,累加,求
平均值.这个方法不错,特别在单片机中.比如:你如果连续采集 8 次,累加,最后你只要右移三
位(value=value>>3;)就是 value=value/8 的结果.毕竟,在单片机中,右移比除法要快嘛.
2.中间值算法.
这个算法也简单,顾名思义,就是取不大不小的中间的值.这个算法就需要把几次采集的值排
序,然后使用中间的那个值.
3.递推滤波.
这个滤波方法比较的受认可,但是执行起来也有风险所在.先说这个算法,就是根据当前值(传
感器的中心点所在值),推算接下来的传感器中心点的量,如果发现前后变化剧烈,就视为干扰
因素,忽略.这个算法看起来比较的好.但是风险就在于:如果出现了错误,并且错误的中心点成
为的当前值,那么以错误的中心点为基准,正确的中心点就成了干扰.这样就会出现极端情况.
为了避免这个情况,我们应该有一个检查的模块,检查当前的中心点是否有效.这个检查,我们
也许可以结合前面两种方法,在一定时间对中心点的有效性进行检查.
4.限幅滤波.
这个在舵机的控制中,特别是使用计算的方法获得 PWM 信号占空比的(用来控制舵机的转角),
更是尤为重要.这个滤波的思路就是规定一个最大值和一个最小值,当计算出的值低于最小
值时,令其等于最小值;大于最大值时,令其等于最大值.
智能车制作全过程(飞思卡尔)
发表于 2008/11/1522:28:01
如果我写得好,请顶我一下,我将再接再厉!
(本人在很久以前做的一辆用来比赛的智能车--获得华北一等奖,全国二等奖,有许多可改进
地方.)
下面我们来立即开始我们的智能车之旅:
首先,一个系统中,传感器至关重要.
"不管你的 CPU 的速度如何的快,通信机制如何的优越,系统的精度永远无法超越传感器的精
度".是的,在这个系统中,传感器的精度,其准确性就显得至关重要.如果你问我传感器的电路,
呵呵,我早就和大家分享了,在我发表的日志中,有一篇<<基于反射式距离传感器>>的文章
就详细的说明了传感器的硬件电路以及可以采取的信号采样方式.
传感器安装成一排,如上面排列.(就是个一字排列,没有什么特别)
接下来,看看我们如何处理传感器得到的信息:
大家看到了.结构很简单,我们已经搞定了传感器通路.下面我们来看看多机的控制方面的问
题:
其实,不管是便宜还是比较贵的舵机,都是一样的用法.舵机的特点就是不同的占空比方波就
对应着舵机的不同转角.当然不同的舵机有不同的频率要求.比如我用的这个舵机:方波频率
50HZ.怎么改变占空比?这个不就是PWM模块的功能嘛.PWM模块可以输出任意占空比的方
波.只要你控制其中的占空比寄存器,就可以直接控制舵机的转角.你只要将传感器的状态和
这个占空比对应上,不就 OK 了?就这么简单,做到这里,你就可以让你的车在跑道上跑了!
接下来,我们的工作是让智能车更加完善:速度要稳定.
在当前的系统结构中,要使一个系统更稳定更可靠,闭环系统是一个选择.(如果你不知道什么
是闭环系统,可以参照我的文章里面的一篇"基于单片机的 PID 电机调速"),既然是一个闭环系
统,速度传感器是必不可少的,用什么样的传感器做为速度反馈呢:
仔细看,和后轮之间有一条皮带的这个貌似电机的东西,就是我的速度传感器,它的学名叫"旋
转编码器".这个器件的特点就是:每转一圈,就会从输出端输出一定的脉冲,比如我这个旋转编
码器是 500 线的,就是转一圈输出 500 个脉冲.因此,我只要在单位时间内计数输出端输出的
脉冲数,我就可以计算出车辆的速度.显然,这个速度可以用来作为 PID 速度调节的反馈.
现在有了反馈,我们需要的是调节智能车驱动电机的速度了,如何来调速,就成了必须解决的
问题了.我用的是驱动芯片 MC33886.
其实,这个芯片就是一个功率放大的模块.我们知道,单片机输出的 PWM 信号还是 TTL 信号,
是不能直接用来驱动电机的.非要通过功率模块的放大不可.这个道理其实很简单,就像上次
我给大家画的哪个电子琴电路的放大电路一样:
看上面的那个三极管,就是将 TTL 电路的电流放大,才能够来驱动蜂鸣器.其实这里的这个
MC33886 就是这样的一个作用.而且我们自己也完全可以用三极管自己搭建一个这样的功
率放大电路,当然,驱动能力肯定不如这里的这个 MC33886(如我们用三极管就搭建了超过
MC33886 的电路,摩托罗拉就不会卖几十块钱一个了.呵呵.)知道了这个 MC33886 的工作
原理,就好说了,一句话,通过 PWM 来调节电机的速度.当方波中高电平占的比例大,电机的平
均电压肯定高,转速肯定快.也就是说,PWM 的占空比越大,电机转速越高.
看,就这么简单,这个智能车就做好了.接下来,我们就把我们知道的 PID 知识放到舵机和直流
驱动电机的控制中去.就可以达到一个比较好的控制效果.
如果要达到更高的水平,肯定机械方面的改造也少不了.当然,这不属于本文的讨论范围.呵呵.
基于单片机的电子琴设计
发表于 2008/11/1411:02:11
如果我写得好,请顶我一下,我将再接再厉
很多朋友喜欢搞一些声光的东西,因为能看到,能听到,比搞个什么通信滤波要好玩多了.好!我
们就开始做个电子琴.甚至做一个简单的"MP3",呵呵,从简单开始.我们先做电子琴,下一节再
做"MP3".
首先,因为是发声装置,我们得先了解发声的原理是什么,这有助于我们接下来的编程:
1.声音是由于物体震动产生的.
2.电流的变化通过线圈就可以使磁场发声变化.
上图是一个喇叭的工作原理.不知道大家看明白了没有.喇叭的电磁铁的电源是接到我们的
发声电路上.当电路中的电路发生变化时,电磁铁的吸引力也发生变化.因此就会吸合铁皮.吸
合铁皮的时候也带动了薄膜的运动.如果这个吸合过程非常的快.那么薄膜就会发生高频的
震动.这个震动就会发出声音.
上面只是一个示意图.实际上的喇叭并不是磁铁吸音铁框的问题,铁框往往也会换成一个磁
铁,不过是永磁铁,这样不但可以吸引,还可以排斥.声音幅度更大.
好了,总而言之一句话,就是来来回回的震动就会产生声音.
接下来,我们开始制作吧:电路相当的简单:
看到了吧,电路非常的简单.下面是四个键盘的按键开关.上面就是一个三极管的放大.有人说,
我直接接到单片机上就不行.完全可以!我为什么说是个电流放大呢,就是要发生的功率大,声
音大.如果你将蜂鸣器直接接到单片机的 IO 口上,当然是可以的.但是只是用来验证用的,声
音太小,实际中是没有用处的.
不过,我可得提醒你:
你如果这样接,那就不对了.为什么?问题就在于,单片机的 IO 口的驱动能力是绝对有限的,你
现在让它直接驱动一个功率比较大(比较 LED 而言)蜂鸣器,是比较吃力的.但是你却可以这样
设计:
什么?没有发现有什么不同?呵呵,看看,蜂鸣器的电压方向变了.为什么这样做,这就是一个开
发经验问题了:单片机的 IO 口吸收电流的能力要远远大于其提供电流的能力.所以不管是驱
动蜂鸣器还是驱动 LED 发光二极管,都要做成低电平有效的这种形式,切实有效!
(本人的实验板,具备上述模块,其原理图和上述完全一致.有实验板的朋友可以接着往下做了)
好了,硬件连接 OK 了,我们赶紧开始我们的编程吧:
我先说说算法,要实现一定频率的震动,不就是将 IO 端口进行一定频率的开和关就是了.要进
行一定频率的开和关,就必须有一个计数.在这里,定时计数器就比较合适了.自动重装载模式
显然比较合适.我们来看看程序吧(鉴于 c 语言良好的可阅读性,我们先用 c 语言来编写):
#include<>
#defineuintunsignedint
#defineucharunsignedchar
#defineSOUNDERP0_BIT2//用宏定义端口,直观.如以后更改,方便
#defineS1P2_BIT4
#defineS2P2_BIT5
#defineS3P2_BIT6
#defineS4P2_BIT7
#defineYES0
#defineNO1
intYIN[7][2];//定义一个音阶数组,存放计数器的计数初始值.
intDir="3",i;
voidTimerInit()//计数器初始化函数.
{
TMOD="0x21";
TL0=0;
TH0=0;
TH1=0xE8;
TL1=0xE8;
PCON=0x00;
TR0=1;
TR1=1;
SCON=0x50;
}
voidmain()
{
//2611//低音叨频率 261
YIN[0][0]=(65536-10000/261/2*100)%256;
YIN[0][1]=(65536-10000/261/2*100)/256;
//2942
YIN[1][0]=(65536-10000/294/2*100)%256;
YIN[1][1]=(65536-10000/294/2*100)/256;
//3303
YIN[2][0]=(65536-10000/330/2*100)%256;
YIN[2][1]=(65536-10000/330/2*100)/256;
//3494
YIN[3][0]=(65536-10000/349/2*100)%256;
YIN[3][1]=(65536-10000/349/2*100)/256;
//3925
YIN[4][0]=(65536-10000/392/2*100)%256;
YIN[4][1]=(65536-10000/392/2*100)/256;
//4406
YIN[5][0]=(65536-10000/440/2*100)%256;
YIN[5][1]=(65536-10000/440/2*100)/256;
//4947
YIN[6][0]=(65536-10000/492/2*100)%256;
YIN[6][1]=(65536-10000/492/2*100)/256;
EA="1";//开 CPU 中断
ET0=1;//开定时计数器中断
TimerInit();//调用初始化计数器函数
for(;;){}
///////////////////////////////////////////////////////////////////////////
//////////////////
voidTimerOverFlow()interrupt1//定时器中段函数
{
if(S1==YES)
{
SOUNDER=!SOUNDER;
TL0=YIN[0][0];
TH0=YIN[0][1];
}
if(S2==YES)
{
SOUNDER=!SOUNDER;
TL0=YIN[1][0];
TH0=YIN[1][1];
}
if(S3==YES)
{
SOUNDER=!SOUNDER;
TL0=YIN[2][0];
TH0=YIN[2][1];
}
if(S4==YES)
{
SOUNDER=!SOUNDER;
TL0=YIN[3][0];
TH0=YIN[3][1];
}
//Cleartheflag
TF0=0;
}
相信大家看得明白程序,很简单.下载到单片机上以后,按 S1 键,蜂鸣器发出低音 1(叨)的声音.
按 S2 发 2(ruan)的声音...
基于单片机的数字 PID 实现直流电机调速(智能车)
发表于 2008/11/129:45:33
现在做很多的智能车,都需要对车速进行控制.或匀速或变速,在调速算法中,PID 的经典永垂
不朽.
其实,简单的 51 单片机尚能轻易的实现平滑良好的调速,更不用说性能优良的单片机.然而,要
做到最好,是需要很高的专业水平和动手能力.但是,工程上能达到我们的目标即可.
抱着"够用就好"的思想,我们来开始我们的调速旅程:
所谓的 PID 是肯定基于一个闭环系统而言的,什么是闭环系统呢,我简单的介绍一下:
看上面的这个系统,就不是一个闭环系统,而是一个开环系统.再看下面的这个就是闭环系统:
上图这个系统就是典型的闭环系统.大家也许看出来了,"开环"系统,就是系统没有反馈,是个"
打开的环",而闭环系统,是有反馈的,是一个完整的环形.
正是这个反馈,就可以将当前电机的转速传递给系统控制端,如果电机转速快了,控制器就让
它慢点(比如可以降低电机两端的电压),同样,如果速度传感器检测到转速低了,就应该让电机
两端的电压提高一点.就是在这样的不断矫正中,电机的速度会保持恒定.当然,这个矫正的周
期是非常短的,矫正的速度是很快的.
有人说,不就是多了就少点,少了就多点嘛,干嘛使用什么玄乎的 PID?
对,你说对了,"多了就少点,少了就多点"这本身就是 PID 里面的一种:P 控制--只使用了 P 算
法.
接下来我们就看看到底什么是 PID,为什么要使用 PID,怎么样使用 PID:
P--比例
I--积分
D--微分
我们来一条一条的讲解 P,I,D 的含义及其意义:
P--比例部分
这个很好理解.比如说,速度传感器发现,当前速度是 1200(每分钟).而我们设定的速度值为
1000,那 么 就 差 别 了 200,这 时 ,如 果 我 设 定 P 为 ,如 果 输 入 的 电 压 就 应 该 是
.看到了没有,这里的比例的意思就是"倍数",就是你要把这个偏差放大多少倍."
放大"本身就是一个比例嘛.知道了这个,你就可以写一个 PID 控制里面的 P 控制了.很多时候,
不需要 I 和 D 控制,单单一个 P 控制就足够了.到了这里你就可以控制电机的速度了.
I--积分部分.
这个积分其实也很好理解.它是一个积分运算.有的时候偏差不是很大,所以继续运行下去,会
使系统存在一个偏差.但是你如果使用 I 运算将这个偏差累加起来,到了一定大小的时候就进
行处理.这样就能防止系统的误差累计.其实,在程序中,这个过程就是对一个小偏差的连续累
加罢了.
D--微分部分.
这个部分也比较好理解.所谓的微分就是对变量求导呗,意思就是一个量的变化率呗.所以,微
分部分就是能够将变量变化率放入计算中.这个量在边城中其实就是求上次的偏差和这次的
偏差的差罢了.
其实,在温度控制中 PID 还是比较有效的,但是在于电机控制这种速度经常变化的场合,一个
参数整定好的 P 控制就能完成任务.为了便于大家的理解,我给大家举一个例子吧:
关于对 51 单片机端口上拉电阻的讨论
发表于 2008/11/1122:28:33
前一段时间,看到实验室有个学弟设计了一个电路,其中还有一个键盘电路,取其原理是这样
子的:
据这位师弟的意思是:在没有按下按键的时候,端口上是低电平,按下按键的时候端口上接上
了高电平.
事实上,电路是不工作的.
问题比较多:
首先,将电源直接接到端口上是绝对不可以的.当按下按键的时候,会有很大的电流进入单片
机.在工程上,这种往往应该加限流电阻的.一般选择 1K 的就可以.如果选择太大的电阻也不
好,因为电阻上面压降太大,造成输入比应有的高电平低,造成错误.
其次,就算加了限流,这个电路也是不能工作的.检查 AT89C51 的 DataSheet 就会发现.技术
手册中说:P0 口是没有上拉电阻的端口;P1,P2,P3 口带有上拉电阻.问题就出在这里,什么是
上拉电阻,来看看图:
上面这个图,是红外线接收的电路图,看上面的这个电阻,就是上拉电阻.我们可以试图理解一
下 51 单片机 P2 口的这个上拉电阻为这种形式:
其中的 R 就是上拉电阻.如果像我的那个师弟那样设计电路,电路就成了以下这种形式了:
看,从这个电路上,我们可以清晰的看出,不管你按键是否按下,IO 端口上都是高电平.问题就
在这里,我让我的这个师弟测测 IO 端口的电平在按下按键前后的变化,结果果然不出所料:不
管他是否按下按键,都是高电平!!
从这里我们可以看出:DataSheet 还是有用的,在设计的时候,有很多细节,需要注意,否则,可
能功亏一篑.
基于或门的超级简单的液位传感器
发表于 2008/11/1116:29:04
前一阵子,在实验室,看到一个朋友在那里拿着一个盒子钻,敲,打...满头大汗,嘴里还嘀咕着...
"你在做什么呢?"
"我在做一个液位传感器,这个杠杆浮漂真不好弄!"
"你最近不是做液位控制,你如果用机械杠杆,你怎么采集数字信号到单片机?"
"我会在杠杆上安装一个角度传感器...".
看来真是个麻烦的事情...
回头突然想起,我小学的时候,给我妈妈做了一个检测下雨的东西.好像是五年级的时候,就是
那种平板,下上雨了以后,就会触发相关的电路(当年我是接上了一张生日贺卡里面的音乐芯
片).
要说,当初,我还记得,书上好像是叫那种电路为"或门",当初我怎么都不理解,但是现在看来,原
理是多么的简单.
看看电路:
当年的电路是这样子的,就是在板子上有水,就会接通两端的电路.很好理解,只有有一处接通,
整个电路就是通的,是一个逻辑上"或"的关系,所以叫或门.当然除了或门,肯定还有"与门".
既然能够检测到雨水,那怎么就不能检测液位呢(这里的液体也是水.),当然我们需要的是要将
电路进行些许的改装.我就为我这个朋友设计了一个:
你看,我分开处理,大不了我挨着扫描一次看看 1 到 11 的引脚,哪里检测到了水位(检测到电
压),我不就可以方便的检测到液位了.
你可能要说:这个占用 IO 口也太多了吧...不要紧!来,实用一个 138 译码器不就可以了,有选
择的读取其中的某个引脚.
就这么小的一个小东西,做出来,拿到现场一试--"屡试不爽",试验多次,没有出现过一次误报,
简单但是好用.
由这个问题我们看出来了:小学教育是多么的重要啊...
基于反射式红外线的测距传感器
发表于 2008/11/923:14:13
如果我写得好,请顶我一下,我将再接再厉!
前阵子做个小车玩,是走迷宫的那种.苦于没有所谓的距离传感器,就自己做个吧.结果也犯了
不少错误.现和大家分享.
买了几个两毛钱一个的发射管(注意,不是发光二极管,虽然长得一样,但是这个是发射红外线,
你可能肉眼看不出它再发光,但是你若是用手机或数码相机的摄像头看,你就会看到它的光).
(发射管)(接收管)
看来比较简单,一个发射,一个接受.发射管发射红外线,遇到遮挡就会反射回来(遮挡是黑色的
除外,因为黑色吸收了红外线),接收管接收到红外线以后阻值发生了变化,因此可以利用电阻
分压改变输出电压.看看电路:
发射电路,一开始我就是这样,一个限流电阻直接发射管(红外线发光管).后来发现一个随之而
来的问题,就是多个传感器工作时电流比较的大,达到 左右.而且传感器发热严重.要知
道,发热严重,性能就会严重的降低.于是想到,是不是可以在需要的时候开通,不需要的时候
关闭.形成这种扫描式的.结果衍生出了以下的电路:
这个电路的原理也是一目了然的:当单片机的 IO 口输出高电平时,R1 所在的支路有电流 I1,
因此 R2 所在的支路就有 I1*E(E 为三极管的放大倍数,比如我用的是 30).这样,三极管就相当
于一个电子开关.单片机输出 1 的时候,发光管接通,单片机输出 0 的时候,发光管截止.这样就
起到了用单片机来控制发光管关闭的效果.
经过实验,发现该电路效果非常的明显.在大多数情况下,电流表几乎检测不到电流的所在.用
精密的电流表,发现电流在 5MA 左右.而且整个电路的检测距离更远,更准确.具体分析其原
因是:长时间处于发光状态,发热严重,发光管效率降低,电阻增大,发射功率降低.而间歇发射,
发光管发光效率更高,更省电.
至于接受电路,我使用的就比较的简单.
其中,Sout为信号的输出.其实这个电路就太简单了,你看.红外线使着接收管的电阻发生了很
大的变化,所以两个电阻的比值就发生了变化,根据分压原理,输出的电压值也就改变了.
接下来的问题就是对现在的这个高电压和低电压进行处理.有人说,直接接到单片机上进行
编程不就可以了?不是的!注意,这里的输出电压虽然也有高和低,但是这里的电压是个"模拟量
",不是标准的 TTL 电平.举个例子,我测得有反射(前方有障碍物)的时候,电压是 4V,没有发射
(前方没有障碍物)的时候,电压是 .显然,你如果直接接到单片机上,单片机收到的都是高
电平.
处理的办法有两个:使用 AD 转换或是使用电压比较器.
这两个方法各有各自的优缺点,我们来分析一下:
一.AD 转换
大家都知道,就是将输出的电压值,用 AD 芯片进行数字化,比如 5V 转换成了 1200.等等...这
样做的好处是显而易见的,我们能够方便的对数据进行处理.比如,我们令数值小于 300 的表
示没有检测到障碍物或是障碍物比较的远.数值大于 300 的表示检测到障碍物.而且硬件上
也比较的简单,直接将输出接到 AD 的输入引脚即可(现在的许多 MCU 内部都自带 ADC,所以
根本就不需要外围电路,直接接上即可).这样做的不足也有,就是你需要编写 AD 检测的程序,
而且占用 CPU 时间.
二.比较器
所谓的比较器,就是电压比较器,看电路:
看,就是这么个简单的电路,当 Ui>U 时,Uo 一直是低电平;当 Ui<U 时,Uo 就是高电平.因此,
我们只要调节一下参考电压,就可以使着输出符合我们的要求--低于这个阀值的时候是高电
平,高于这个阀值的时候是低电平.这就实现了模拟量转换为数字量.看看电路图:
这个电路就很简单了,可以看出多了下面的那块电路,是用来调节基准电压的嘛.也是一个电
阻分压的原理,这样你设置不同的阀值,就可以控制输出了.比如:我们刚才说的低电压是
,高电压是 4V,我们要把这个电平转变成 TTL,因此我们可以把基准电压设置成 3V,因此
经过电压比较器, 就输出高--5V,4V 就输出低--<1V.这不就是 TTL 嘛.
电路中的比较器可以使用便宜的 LM324 来搭建.LM324 是四运放集成块.
PID 系统整定工程实践
发表于 2009/6/289:01:53
【如果我写的好,请顶一下】
参加比赛或是做项目也好,PID 的应用非常的广,不但可以用在运动控制的电机调速,更可
以用在温度控制、电流控制、电压控制等等动态变量的控制。
PID 其实没有多么神秘,还是那句话:被控量比我们的预期量(输入量)大,CPU 就控制其
小点;被控量比我们的预期量小,CPU 就控制其大些。在这其中在引入被控量信号的变化
率和误差累积,就成了真正的 PID,可以达到非常好的控制效果。
直流伺服系统的系统结构
图 一个伺服系统结构的例子
由图 可以看出来,一个基本的伺服系统由控制器、功率放大单元、执行机构、反馈传
感器组成。控制器是按照一定的控制策略,综合输入量和反馈量,输出控制信号的逻辑装置,
一般情况下使用工业计算机或是微型计算机系统(DSP、MCU 等)来作为伺服系统的逻辑
中枢;功率放大单元是将计算机输出的控制信号,转变成一定的功率信号来驱动执行机构;
执行机构(图 中是电动机)是将控制器的控制信号转变为相应的物理量,可以是电动
机(用于运动控制)、加热器(用于温度控制)、功率开关管(用于电流或电压控制)等等;
反馈传感器(图 中是位置检测传感器)是将执行机构的状态转变为相应的电气信号,
并反馈给控制器的装置,它可以是位置传感器(位置伺服系统)、速度传感器(速度伺服系
统)、温度传感器(温度伺服系统)、电流传感器(电流伺服系统)、电压传感器(电压伺服
系统)等等。
直流伺服系统的工作原理简述
由伺服系统的原理框图 就可以看出,伺服系统通常是一个闭环系统。其工作流程可以
简单的描述为:控制器接收外界的输入,计算相应的输出值给功率放大单元,功率放大单元
将控制器的信号放大,驱动执行机构动作。反馈传感器采集执行机构或被控对象的状态,将
状态信息反馈给控制器,控制器根据接收到的输入值和传感器反馈回来的反馈值,根据一定
得控制策略(本论文中使用的是 PID 算法),进一步调整输出,使输出达到目标值(输入值)。
其中,控制器--CPU/MCU
功率放大--MOSFET/MCS33886/各种电机驱动芯片
反馈传感器--角度传感器(位置伺服系统)/旋转编码器(速度伺服系统)/温度传感器(温
度伺服系统)/电流传感器(电流伺服系统)
为了便于讨论,我编写了一个上位机软件,实时对伺服系统的工作状态进行采集,而且还可
以绘制出伺服系统的工作曲线。
第 3 章直流伺服系统参数及其整定
数字 PID 的参数
根据偏差的比例(P)、积分(I)、微分(D)进行控制(简称 PID 控制),是控制系统中应
用最为广泛的一种控制规律。实际运行的经验和理论分析都表明,这种控制规律对许多工业
过程进行控制时,都能得到满意的效果。不过,用计算机实现 PID 控制,不是简单的将模
拟 PID 控制数字化,而是进一步与计算机的逻辑判断功能结合,使 PID 控制更加灵活,更
能满足生产过程提出的要求。
采样频率的选择
(1)采样周期应远小于过程的扰动信号的周期。
根据香农采样定理:采样频率应该大于或是等于信号最高频率成分的两倍。这个定理给出了
采样频率选择的最底线。
(2)执行机构的类型。
在执行器的响应速度比较慢时,过小的采样周期将失去意义,因此可适当选大一点。在计算
机运算速度允许的条件下,采样周期短,则控制品质好。当过程的纯滞后时间较长时,一般
选取采样周期为纯滞后时间的 1/4~1/8。
(3)给定值的变化频率。
加到被控对象上的给定值变化频率越高,采样频率也应该越高,这样给定值的改变可以迅速
得到反应。
(4)被控对象的特性
若被控对象是慢速的热工业或是化工对象时,采样周期一般取的比较的大;若被控对象是较
快速的系统,采样周期应取得比较小。
(5)控制算法的类型
采用 PID 控制算法,积分(I)和微分(D)作用都与采样周期 T 的选择有关系。采样周期 T
太小,将使微分作用不明显。
比例--P
一般来说,增加控制系统的比例增益,可以提高系统的响应速度,同时也会降低稳态误差。
尽管如此,如果比例增益太大,系统超调就会增大,如果 Kp 再进一步增加,震荡就会加大,
系统就会变得不稳定。
积分--I
为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差进行累加,随着时间的增
加,积分项会逐渐增大。这样,即便误差很小,积分项也会随着时间的增加而加大,它推动
控制器的输出增大使稳态误差进一步减小,直到等于零。因此,比例+积分(PI)控制器,可
以使系统在进入稳态后无稳态误差。但积分过强同样影响系统的稳定性。
微分--D
自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大
惯性组件(环节)或有滞后(delay)组件,具有抑制误差的作用,其变化总是落后于误差的
变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用
就应该是零。这就是说,在控制器中仅引入“比例”项往往是不够的,比例项的作用仅是放大
误差的幅值,而目前需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+
微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量
的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在调
节过程中的动态特性。但是,如果反馈回来的过程变量代表的噪声,微分参数就会引起系统
的不稳定。
数字 PID 的控制算法
位置型 PID 控制算法
图 位置型 PID 控制流程
在控制系统中,这种控制量确定了执行机构的位置,例如在阀门控制中,这种算法的输出对
应了阀门的位置(开度)。所以,将这种算法称为“位置算法”。
增量型 PID 控制算法
图 增量型 PID 控制流程图
如上图,当执行机构需要的不是控制量的绝对值,而是控制量的增量(例如去驱动步进电动
机)时,需要用 PID 的“增量算法”。
数字 PID 控制算法实现方式比较
在控制系统中,如果执行机构采用调节阀,则控制量对应阀门的开度,表征了执行机构的位
置,此时控制器采用数字 PID 位置式控制算法;如果执行机构采用步进电机,每个采样周
期,控制器的输出的控制量是相对于上次控制的增量,此时控制器应该采用数字 PID 增量
式控制法。
虽然增量式控制法和位置式控制法更有应用领域,但是增量式控制法相对于位置式控制法,
具有诸多的优势:
(1)增量式控制法不需要做累加,控制量增量的去定仅与近几次误差采样值有关,计算误
差或计算精度等问题对控制量的影响比较的小。相比之下,位置控制法要用过去的误差的累
加值,容易产生较大的累加误差。
(2)增量式算法得到的是控制量的增量。例如在阀门的控制中,只输出阀门开度的变化部
分,误动作影响小,必要时通过逻辑判断限制或禁止本次输出,不会严重影响系统的工作。
相比之下,位置式控制算法的输出是控制量的全量输出,误动作影响比较大。
(3)采用增量算法,容易实现手动到自动的无冲击切换。
数字 PID 控制算法流程
下图给出了数字 PID 控制算法的控制流程图。增量式的控制流程和位置式的控制流程很相
似。
图 程序流程
数字 PID 参数整定
1 工程法整定 PID 参数的方法
在工程上,PID 参数整定的方法比较的多,分别有:凑试法、扩充曲线法、优选法、自整定
法等等。由于研究采用的标定系统采样频率有限,不能绘制出非常精确响应曲线,所以使用
扩充曲线法误差较大。下面的参数整定使用凑试法。
(1)首先整定比例环节
将比例系数由小到大的变化,并观察相应的系统响应,直到得到一个反应速度快、超调小的
响应曲线。如果系统静差已经达到允许的范围,并且响应曲线已经令人满意,那么只是用比
例控制器即可。这里确定的是最优比例系数。
(2)再加入积分环节
如果在比例部分不能有效地消除静差,需要加入积分环节。积分系数 P 的整定应该从大到
小。并且应该将第一步整定的比例环节缩小(可以缩小为原来的 倍)。然后慢慢的减小
积分常数,直到系统具有良好的动态性能,并且静差得以消除。
(3)最后加入微分环节
如果在使用比例积分控制器时,动态特性仍达不到要求,可以加入微分环节。在整定微分环
节时,微分系数从小到大变化,在同时小范围改变比例、积分系数的同时,多次试凑,直到
达到理想的控制效果。
2 数字 PID 参数整定过程
由于机器人手臂定位属于绝对位置式定位,这里首先讨论位置式 PID 伺服系统的 PID 参数
整定。
(1)采样周期的选择
首先,选择一个合适的采样周期。采样周期应该综合各方面考虑,首先研究的是一个位置伺
服系统,要求响应快,精度高。因此采样周期不能太大。同时,电机带有减速机构,转动惯
量比较的大,因此采样周期又不能太小。关于采样周期的选择,虽然有“香农定理”这样的规
律,但是并没有给出实质的选择方法,大多是在规律的指导下探索。这里,本人总结了一个
根据工程试验选择采样频率的方法。
图 电机在额定电压下转动,传感器的输出电压曲线
如图 ,是电机在额定电压下,连续旋转的位置传感器输出电压曲线。可以根据这个图大
体的估算合适的采样频率。从这个图上的周期可见,电机(带减速机构)的额定转速为
转/秒,即约为 430 度/秒。假设我们的伺服系统要求分辨率在 度,那么可以计算出来,
伺服系统要转过这 度最快需要 度看成是系统的
一个“标准单位”,那么 就是系统控制的“标准时间”。假设,采样周期比这个“标准时
间”还要大,就可能出现伺服系统转过了“目标点”,但是系统还没有检测到得现象。当然,这
个假设中没有考虑系统的静摩擦、启动惯量等。但无论如何,不排除极限情况下,系统稳定
性要求系统达到及时响应。因此,本人认为采样周期在一般情况下不要大于这个“标准时间”。
接下来再综合考虑电机本体的转动惯量和静摩擦的存在,转动惯量和静摩擦越大,采样周期
可以相应的越大一些;反馈传感器的精度越高,采样周期可以选的越小一些,这样有利于提
高系统的控制精度。综上所述,采样周期可以选择稍小于“标准时间”,为 1ms,即采样频率
1KHZ。
(2)比例系数的整定
在选择了采样周期的情况下,开始整定比例(P)系数。比例系数从小到大变化。
P 控制源代码:
#definek1
E[k]=TargetValue-ADValue;//计算当前偏差。
Uk=KP*E[k];//计算比例部分。
Turn(Uk);//输出。
由以上的数据可以看出,增大比例系数 Kp 可以加快系统的响应,在有静差的时候有助于减
小静差。但是过大的比例系数会使系统有较大的超调,并可能产生振荡。经过多次的试验,
最终选择 Kp=3。
(3)积分项的整定
如上图所示,在只使用积分(P)控制的时候,存在一定的静差,因此很有必要加入积分项,
来消除这个静差。积分项的整定是从大到小整定,但是需要提前注意几个问题:
1.长时间的积分会造成积分饱和。
解决这个问题的办法是采用“积分分离”的办法,在误差较大的时候积分项不起作用,当误差
范围在一定范围内以后积分才起作用。本人认为应该根据计算机的字长和传感器精度分析,
计算出不会造成积分饱和的“积分时间”,来确定误差在多大的值时开始投入积分。
2.由于计算机精度问题,较小的误差将被舍掉,而不能输出。
解决这个问题的方法除了使用更加精确地 AD/DA 外,还可以采用误差累计的方法,当误差
累计到一定程度,进行一次积分输出,而不是将小误差舍弃掉。为了避免小误差的浮点累计
运算,本人使用了一个方法:“倍乘法”。即将小数误差乘以一定得倍数,比如 10 倍。这样,
小数被转换成了整数,积分项的运算也转换成了整数运算。最后在输出之前,将 Uk 的值再
除以 10。
PI 控制源代码:
#definek1
E[k]=TargetValue-ADValue;//计算当前偏差。
if(abs(E[k])<50)//在一定范围内才投入积分
{
SumErr+=E[k];
SumErr=SumErr>20000?20000:SumErr;
}
ElseSumErr=0;//清除积分累加。
Uk=KP*E[k]+SumErr/KI;//计算比例+积分。其实 1/KI 才是积分常数。
Turn(Uk);//输出。
如上面的组图所示,积分作用有助于消除系统误差,但是过大或过小的积分系数都将使系统
品质降低。经过反复试凑,最终选取积分常数 KI=。
(4)微分项的整定
以上的 PI 控制器,从图 的响应曲线上来看,已经达到了令人满意的效果。系统的静差
已经基本消除,系统运行已经基本满足要求。但是系统仍然存在不能忽略的超调,有时候这
种超调会让机器人手臂的定位感觉非常的僵硬,因此需要进一步将其去掉。
PID 控制源代码:
#definek1
E[k]=TargetValue-ADValue;//计算当前偏差。
if(abs(E[k])<50)//在一定范围内才投入积分
{
SumErr+=E[k];
SumErr=SumErr>20000?20000:SumErr;
}
ElseSumErr=0;//清除积分累加。
Uk=KP*E[k]+E[k]/KI+KD*(E[k]-E[k-1]);//计算比例+积分+微分。
Turn(Uk);//输出。
E[k-1]=E[k];//更新 E[k-1]
从图 中的图像对比中,可以发现微分作用避免了被控量的严重超调,合适的微分项使
得系统超调变小,改善了系统在调节过程中的动态特性。经过多次试凑,确定 PID 的参数
为 KP=3,KI=,KD=40。
单片机基础教程(AT89C51)--串行通信
发表于 2008/12/121:35:24
今天我们来开始单片机的通信实验。我们知道,单片机的通信接口是 RXD(接收端)和 TXD
(发送端),要实现两个单片机的通信,只要将两个单片机的 RXD 和 TXD 交叉连接就可以
了(一个单片机的 RXD 接另一个单片机的 TXD,TXD 接另一个单片机的 RXD)。
好了,硬件连接就这么简单。现在我们开始写程序吧。要完成个什么任务呢?就用一个单片
机做主机向另一个单片机发信息,用主机单片机控制从机的发光二极管亮吧。
首先必须规定一下:当主机的按键 1 按下的时候,发送 0x41 给从机(刚然,你爱规定成
什么就规定成什么),而从机呢,只要收到 0x41 就让第一个发光二极管亮;当主机的按键 2
按下是,就发送 0x42 给从机,从机只要收到 0x42 就使第二个放光二极管亮;以此类推,
总共四个按键,控制从机的四个二极管。
下面开始编程吧,先写主机(发送方)的程序,当然也是从查询开始:
#include<>
#defineS1P2^4
#defineS2P2^5
#defineS3P2^6
#defineS4P2^7
voidSCI_Init()
{
TMOD="0x20";
TH1=0xE8;
TL1=0xE8;
PCON="0x00";
TR1=1;
SCON="0x50";
}
voidmain()
{
SCI_Init();
for(;;)
{
if(S1==0)
{
SBUF=0x41;
while(TI==0);
TI="0";
}
elseif(S2==0)
{
SBUF="0x42";
while(TI==0);
TI=0;
}
elseif(S3==0)
{
SBUF="0x43";
while(TI==0);
TI="0";
}
elseif(S4==0)
{
SBUF=0x44;
while(TI==0);
TI="0";
}
else
{
SBUF="0x45";
while(TI==0);
TI=0;
}
}
}
单片机基础教程(2)--定时/计数器
发表于 2008/11/2816:48:34
如果你觉得我写得好,一定要顶我一下吆!
今天,我们来做霓虹灯.什么是霓虹灯,就是一个灯闪来闪去就是了.有人说,我会做我会做:
for(;;)
{
P0^0=!P0^0;
delay();
}
这样就解决了嘛.对,你说的对,这样的确就达到霓虹灯的效果了.不过,我们今天的霓虹灯可
不要用延时(以上程序中的 delay()函数)来完成,今天的霓虹灯我们要用定时计数器来完成.
对于很多地方,定时/计数器还是作用巨大的.可以说,定时计数器是单片机的精华之一.比如
说计数,定时,甚至 PWM,串行通信等等.都来不开定时计数器.
相信大家看这方面的东西都看烦了,那剩下的,就把课本扔掉,我们开始做吧!
首先,我们来看看查询模式下的定时计数器使用:
#include<>
voidmain()
{
TMOD=0x01;//定时器 0 工作在方式 1--16 位计数器
TL0=0;//定时器初值设定为 0
TH0=0;
TR0=1;//定时器 0 开始运行--Timer0Run.
for(;;)
{
if(TF0==1)//如果定时器 0 发生溢出
{
P0=~P0;
TF0=0;
}
}
}
上面这个是采用的查询方式,就是在主循环里面不断的查询,计数器从 0 开始计数,有没有超
过 65536 而溢出,一旦溢出,溢出标志位 TF0 就会被置 1,通过这样的方法,可以起到定时作
用.有人问,如果我要定时的时间更短,我怎么设定呢,很简单,51 单片机的定时计数器是累加
计数器.你给他一个初值,他就会一直作累加运算.现在的初值是 0.那你如果把初值设置成
30000,那么,是不是计数器就从 30000 开始计数,到 65536 溢出,是不是时间就变了?你需
要多长时间你都可以算的出来.有人又有问题了,那如果我需要的时间比从0开始的计数时间
都要长,我怎么办?那怎么不好办?你把你的这个长时间分成多个小时间块,让计数器计数这些
小时间块,你只要数到规定的个数就触发一次自己的事件不就 OK.给你举个例子:
unsignedcharCount;//申请一个变量用来计数.
for(;;)
{
if(TF0==1)//如果定时器 0 发生溢出
{
Count++;
if(Count==10)
{
//在这里放置你的代码.
Count="0";//不要忘了清零 Count,继续下一个周期.
}
TF0=0;
}
}
好了,相信到这里,大家对计数器有了一点了解了.我们再继续吧,开始中断模式下的霓虹灯:
#include<>
voidmain()
{
TMOD="0x01";//定时器 0 工作在方式 1--16 位计数器
TL0=0;//定时器初值设定为 0
TH0=0;
EA=1;//CPU 开中断,CPU 允许中断.
ET0=1;//定时器 0 允许中断
TR0=1;//定时器 0 开始运行--Timer0Run.
for(;;){}
}
voidTimerOverflow()interrupt1//中断处理子程序
{
P0=~P0;
TF0=0;//不要忘了清除标志位.
}
相信这个程序大家看起来也不会难,就是有一点可能有疑问,就是中断处理子程序的格式:
voideTimer()interrupt1
前面和普通的函数一样的写 ,没有任何区别 ,爱起什么名字就什么名字 .但是后面的
interrupt1 确实固定的.1 是中断号,代表着定时计数器 0 的中断:
0 外部中断 0
1 定时器 0 溢出
2 外部中断 1
3 定时器 1 溢出
4 串行口中断
5 定时器 2 溢出
在写不同的中断函数时候,只要在 interrupt 后面写上不同的中断号就可以实现不同功能中
段函数的编写.
由于运行后的结果太简单了,就是和 P0 接口连接的发光二极管不停的闪烁,所以就不做视频
了.祝大家好运吧!
单片机基础教程(1)--流水灯
发表于 2008/11/2122:12:39
好了,单片机的实验板终于做好了,现在我们开始我们的试验教程吧.如果你觉得这款 20 元的
实验板不错,你可以到这里购买:
g_of_wind
下面我们来开始基础教程,你使用别的实验板或是仿真软件都一样.
所谓的流水灯,就是控制数码管按照一定的顺序流动就是了.比如,你先让第一个亮,一段时间
后让第二个亮,再过一段时间让第三个亮.就这样连续起来,我们就会发现灯的亮暗就像流水
一样,来来去去.
下面我们就开始程序吧:
#include<>
sbitS1=0xA4;
voiddelay()
{
inti;
for(i=0;i<10000;i++);
}
voidmain()
{
charMode[]={
0x7F,//第一个灯亮.低电平有效.=0b01111111;
0XBF,//0b10111111
0xDF,//0b11011111
0xEF,//0b11101111
0xF7,//0b11110111
0xFB,//0b11111011
0xFD,//0b11111101
0xFE//0b11111110
};
charCount="0";
for(;;)
{
if(S1==0)
{
P0=Mode[Count++];
if(Count>7)
Count="0";
delay();
}
}
}
注意:上面代码里面的两行 Count="0";的零上面没有引号,是因为网站的问题,所以自动在零
上面加了引号.请大家注意.
好了,就这么简单的一个程序,我们下载到实验板上面看看结果吧,视频结果你们可以看这里:
看来很成功嘛,我们那就再来一个复杂一点的,不是有四个按键嘛,我们就来个四个模式,不同
的流水:
#include<>
sbitS1=0xA4;
sbitS2=0xA5;
sbitS3=0xA6;
sbitS4=0xA7;
voiddelay()
{
inti;
for(i=0;i<10000;i++);
}
voidmain()
{
charMode1[]={0x7F,0XBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE};
charMode2[]={0x77,0xBB,0xDD,0xEE};
charMode3[]={0x7E,0xBD,0xDB,0xE7};
charMode4[]={0xE7,0xDB,0xBD,0x7E};
charCount="0";
for(;;)
{
if(S1==0)
{
P0=Mode1[Count++];
if(Count>7)
Count="0";
delay();
}
if(S2==0)
{
P0=Mode2[Count++];
if(Count>3)
Count=0;
delay();
delay();
delay();
delay();
}
if(S3==0)
{
P0=Mode3[Count++];
if(Count>3)
Count=0;
delay();
delay();
delay();
delay();
}
if(S4==0)
{
P0=Mode4[Count++];
if(Count>3)
Count=0;
delay();
delay();
delay();
delay();
}
if(S1==1&&S2==1&&S3==1&&S4==1)
P0=0xFF;
}
}
好了,没有什么新玩意,就是刚才的程序换了的就是每个灯的开通顺序,我们来看看效果吧: