注:昨天有同学指正说流水灯会影响脉冲输出,造成4s时间的延误。这里说明下,程序设计的初衷是让每个任务独立运行,意思就是当流水灯任务执行的时候脉冲输出任务就被挂起,不过实际上流水灯工作的时候脉冲输出引脚的确会一直维持一个电平,没考虑周详,多谢这位同学提出。最后附上了新的解决方案,中断方式,欢迎同道指正。
需求:通过按下不同的按键让STC89C52RC控制电机以不同的转速运行或者控制LED实现流水灯。
需求分析:
按下按键1流水灯开始工作,按下按键2电机以低转速运行,按下按键3电机以中转速运行,按下按键4电机以高转速运行。
总结下,程序可分为如下三块:
(1)扫描按键
(2)流水灯
(3)发出三种不同速度的脉冲信号(用以控制电机不同转速)
解决方案:
程序分为两层,应用层和底层,应用层实现各个任务,底层实现一些基本操作(例如延时程序)
(1)应用层函数:单片机运行三个任务,分别是:扫描键盘、控制LED、控制电机。
(2)底层函数:延时函数、流水灯函数、脉冲输出函数
代码实现:
#include<reg51.h>
sbit P24=P2^4;//脉冲输出口
sbit P20=P2^0;//按键
sbit P21=P2^1;
sbit P22=P2^2;
sbit P23=P2^3;
unsigned char flag=0x00;//按键标量(看懂这个变量是啥意思,整个程序的思路就能全部看懂了!!!)
//应用层函数(任务)
void LED_Mission(unsigned char flag);//LED任务
void Motor_Mission(unsigned char flag);//电机任务
void Key_Mission();//扫描键盘任务
//底层函数
void PWM(unsigned char time);
void LED();
void Delay(int ms);
void main()//主函数
{
while(1)
{
Key_Mission();
LED_Mission(flag);
Motor_Mission(flag);
}
}
/*####################################
Key_Mission,扫描键盘任务
#####################################*/
void Key_Mission()//根据键盘更改按键标量
{
if(P20==0)
{
Delay(3);//去抖动
if(P20==0)
flag=0x00;
}
if(P21==0)
{
Delay(3);
if(P21==0)
flag=0x01;
}
if(P22==0)
{
Delay(3);
if(P22==0)
flag=0x02;
}
if(P23==0)
{
Delay(3);
if(P23==0)
flag=0x03;
}
}
/*####################################
LED_Mission,控制LED流水灯任务
#####################################*/
void LED_Mission(unsigned char flag)
{
if(flag!=0x00)
return;
LED();
}
/*####################################
Motor_Mission,电机控制任务
#####################################*/
void Motor_Mission(unsigned char flag)
{
switch(flag)
{
case 0x01:
PWM(1);
break;
case 0x02:
PWM(5);
break;
case 0x03:
PWM(9);
break;
}
}
/*####################################
PWM,脉冲输出子函数,根据参数发送不同速度的脉冲
#####################################*/
void PWM(unsigned char num)//输出脉冲信号,根据参数不同脉冲速度不一样
{
P24=0;
Delay(num*50);//倍率待定,暂定50,根据实际情况更改
P24=1;
Delay(num*50);//倍率待定,暂定50,根据实际情况更改
}
/*####################################
LED,流水灯程序
#####################################*/
void LED()
{
//流水灯程序
P1=0xFE;
Delay(500);
P1=0xFD;
Delay(500);
P1=0xFB;
Delay(500);
P1=0xF7;
Delay(500);
P1=0xEF;
Delay(500);
P1=0xDF;
Delay(500);
P1=0xBF;
Delay(500);
P1=0x7F;
Delay(500);
P1=0xFF;
Delay(500);
}
/*####################################
Delay,延时程序
#####################################*/
void Delay(int ms)
{
//延时程序
unsigned char a,b,c,i;
for(i=0;i<ms;i++)
{
for(a=0;a<1;a++)
for(b=0;b<3;b++)
for(c=0;c<219;c++);
}
}
keil下编译无错无警告:
注:只是编译无错,没有烧录到单片机上实验。具体实现可能需要更改相应参数。
*************************************************************************************************
*************************************************************************************************
******************************************分割线*************************************************
*************************************************************************************************
*************************************************************************************************
中断方式
以上采用了查询方式,优点是思路简单,缺点是实时性能太差。
那么为了解决实时性差这个问题,这里采用中断方式
需求:通过按下不同的按键让STC89C52RC控制电机以不同的转速运行或者控制LED实现流水灯。
需求分析:
按下按键1,流水灯慢速工作,电机慢速工作。按下按键2,流水灯快速工作,电机慢快速工作。
总结下,程序大体思路如下:
按键1触发外部中断0,按键2触发外部中断1。定时器0用作脉冲输出。
外部中断0触发之后设置流水灯的延时时间的数值大一些(延时时间就会长一点),同时设置定时器0的预装值小一些(这样脉冲输出的频率会慢一些)。
外部中断1触发之后设置流水灯的延时时间的数值小一些(延时时间就会短一点),同时设置定时器0的预装值大一些(这样脉冲输出的频率会快一些)。
解决方案:
任务1:LED流水灯
任务2:三个中断处理程序
三个中断处理程序分别是,外部中断0、外部中断1、定时器0
代码实现:
#include<reg51.h>
sbit P24=P2^4;//脉冲输出口
unsigned int InitTL0=0x1111;//默认数值比较小,脉冲周期较长
unsigned int InitTH0=0x1111;
sbit P25=P2^5;//接IN1
sbit P26=P2^6;//接IN2
unsigned int DelayTime=0xC8;//默认200ms,流水灯速度较慢
//底层与各种初始化函数
void Delay(int ms);
void InitInt();//初始化外部中断0和外部中断1
void InitT0();//初始化定时器0
//流水灯任务
void LED_Mission();//led流水
//中断任务
void exint0() interrupt 0 //外部中断0
{
InitTL0=0xFFFF;
InitTH0=0xFFFF;
DelayTime=0x30;//48ms
}
void exint1() interrupt 2 //外部中断1
{
InitTL0=0x1111;
InitTH0=0x1111;
DelayTime=0xC8;//200ms
}
void tm0_isr() interrupt 1 using 1 //定时器0中断
{
P24=~P24;
TL0=InitTL0;
TH0=InitTH0;
}
//主函数
void main()
{
P24=0;
P25=0;
P26=1;
InitInt();
InitT0();
while(1)
{
LED_Mission();
}
}
/*####################################
LED,流水灯程序
#####################################*/
void LED_Mission()
{
//流水灯程序
P1=0xFE;
Delay(DelayTime);
P1=0xFD;
Delay(DelayTime);
P1=0xFB;
Delay(DelayTime);
P1=0xF7;
Delay(DelayTime);
P1=0xEF;
Delay(DelayTime);
P1=0xDF;
Delay(DelayTime);
P1=0xBF;
Delay(DelayTime);
P1=0x7F;
Delay(DelayTime);
P1=0xFF;
Delay(DelayTime);
}
/*####################################
Delay,延时程序
#####################################*/
void Delay(int ms)
{
//延时程序
unsigned char a,b,c,i;
for(i=0;i<ms;i++)
{
for(a=0;a<1;a++)
for(b=0;b<3;b++)
for(c=0;c<219;c++);
}
}
/*####################################
InitInt,初始化外部中断
#####################################*/
void InitInt()
{
IT0 = 1;
EX0 = 1;
IT1 = 1;
EX1 = 1;
EA = 1;
}
/*####################################
InitT0,初始化定时器0
#####################################*/
void InitT0()
{
TMOD=0x01;
TR0 = 1;
ET0 = 1;
}
第一段代码,只是编译无错,没烧写到单片机上具体实验。第二段代码,烧写到单片机上仅测试了流水灯正常工作,可调速,未测试脉冲输出。欢迎指正。