标题:
单片机控制4电机循环测试(数码管显示)构思与实现源代码
[打印本页]
作者:
miaoxiaobaiqaq
时间:
2019-4-12 23:56
标题:
单片机控制4电机循环测试(数码管显示)构思与实现源代码
实验构思:
一, 两位共阴数码管4个,要求显示范围0.0~9.9 分别对应4个电机运行时间; 开机无显示,
当电机运行时,对应的数码管从0开始计时,设定的时间到电机停止运行,数码管保持停止时间上.当下个电机运行时熄灭.
二 按键加减范围1~99 ,按设置键3秒进入电机1时间设置 ,(K_SET) 进入设置后,上次设置的数字闪烁, 用 K_UP和K_DN进行数字加减; 步进1,相当于时间0.1秒, 步数100个(0~99);进入设置后,再按设置键,每按一次,进行电机1,2,3,4,1.....循环,同时对应的数码管闪烁,分别显示AA,BB,CC,DD来区分,按下设置键,或者设置完成后3秒无任何按键操作;保存当前数据并退出设置状态. ,在设置的时候不得影响程序的正常运行,设置保存后,程序立即运行新设置的数据.
P0 P0 P0 P0
P1^1 P1^0 P1^3 P1^2 P1^5 P1^4 P1^7 P1^6
数码显示1 数码显示2 数码显示3 数码显示4
开始----------->电机1-------------->电机2---------->电机3-------------电机4-------------->挡杆
PIN_POW PIN_DJA PIN_DJB PIN_DJC PIN_DJD PIN_STOP
P2^2 P2^3 P2^4 P2^5 P2^6 P2^7
控制1 控制2 控制3
PA1 P3^0 PA2 P3^1 PA3^2
K_POW按一次开机,再按一次停机. K_POW=P3^4, K_SET=P3^5, K_UP=P3^6, K_DN=P3^7,
控制触发是低电平有效 输出为低电平 单片机STC89C52 程序C,不要汇编等.
工作过程:
开始(PIN_POW=0,其他=1),等待控制1触发,
控制1触发 (PIN_POW=1,PIN_STOP=0, PIN_DJA =0)
电机1运转时间到,PIN_DJA =1,等待控制2触发.
控制2触发.PIN_DJB =0,
电机2运转时间到 PIN_DJB =1,PIN_DJC =0,电机3接着运行
电机3运转时间到 PIN_DJC =1,PIN_DJD =0,电机4接着运行
电机4运转时间到 PIN_DJD =1,等待控制3触发.
控制3触发.PIN_STOP=1,PIN_POW=0,.
整个过程无限循环,只有有开关机键控制;
按关机键后,等运行到PIN_POW=0时关机,不得在工作过程中途停机.
要求主程序和子程序分类;建立单独的.h文件.此设计中需要设置的数据保存,断电重新开机运行的是上次修改的参数.不得每次开机重新设定.
脚位功能在程序中直接定义,除数码管P0口外,其他单个脚位不得使用代码代替;
以上是题目,贴出全部单片机代码
main.c
#include<STC15F2K60S2.H>
#include"delay.h"
#include"dj.h"
#include"key.h"
#include "eeprom.h"
uint time_DJA=3000;
uint time_DJB=3000;
uint time_DJC=3000;
uint time_DJD=3000;
extern bit flag_DJA1;
extern bit flag_DJB1;
extern bit flag_DJC1;
extern bit flag_DJD1;
extern bit flag_kaiguan;
sbit PA1=P2^0;
sbit PA2=P3^6;
sbit PA3=P3^7;
void main()
{
Init_Timer0();
PA1=1; //测试的时候用的
PA2=1; //测试的时候用的
PA3=1; //测试的时候用的
/*初始值从EEPROM 中读取*/
time_DJA=iap_READ(iap_ADDRESS)*1000+iap_READ(iap_ADDRESS+1)*100+iap_READ(iap_ADDRESS+2)*10+iap_READ(iap_ADDRESS+3);
time_DJB=iap_READ(iap_ADDRESS+4)*1000+iap_READ(iap_ADDRESS+5)*100+iap_READ(iap_ADDRESS+6)*10+iap_READ(iap_ADDRESS+7);
time_DJC=iap_READ(iap_ADDRESS+8)*1000+iap_READ(iap_ADDRESS+9)*100+iap_READ(iap_ADDRESS+10)*10+iap_READ(iap_ADDRESS+11);
time_DJD=iap_READ(iap_ADDRESS+12)*1000+iap_READ(iap_ADDRESS+13)*100+iap_READ(iap_ADDRESS+14)*10+iap_READ(iap_ADDRESS+15);
while(1)
{
Key(); // 检测开关是否按下,开关打开,开始执行下面的代码
if(flag_kaiguan==1)
{
PIN_STOP=1; //停止指示灯
PIN_POW=0; //开始指示灯
delay_ms(50);//延时程序时间定义50ms,
if(PA1==1) //PA1触发来到执行下面的代码,相当于开门
{
PIN_POW=1;
PIN_STOP=0;
DJA(); //电机1开始执行
while(flag_DJA1==0)Key(); //等待电机1执行完毕
// delay_ms(1000); //测试的时候用的,假设1秒后触发信号2来到了
while(PA2==0); //等待触发信号2来
if(PA2==1)
{
DJB(); //电机B开始执行
while(flag_DJB1==0)Key(); //等待电机B执行结束
DJC(); //同理
while(flag_DJC1==0)Key();
DJD();
while(flag_DJD1==0)Key();
// delay_ms(1000); //测试的时候用的假设1秒后触发信号3来到
while(PA3==0);
if(PA3==1)
{
PIN_STOP=1;
PIN_POW=0;
// PA1=0;
}
}
}
}
else TR0=0;P0=0X00; //开关关闭的时候把定时器关闭,数码管再清空
}
///*下面的代码可以用来第一次向EEPROM中写入数据,以后都不会用到所以注释掉*/
// iap_ERASE(iap_ADDRESS);
// iap_PROGRAM(iap_ADDRESS,3000/1000);
// iap_PROGRAM(iap_ADDRESS+1,3000/100%10);
// iap_PROGRAM(iap_ADDRESS+2,3000/10%10);
// iap_PROGRAM(iap_ADDRESS+3,3000%10);
//
// iap_PROGRAM(iap_ADDRESS+4,3000/1000);
// iap_PROGRAM(iap_ADDRESS+5,3000/100%10);
// iap_PROGRAM(iap_ADDRESS+6,3000/10%10);
// iap_PROGRAM(iap_ADDRESS+7,3000%10);
//
// iap_PROGRAM(iap_ADDRESS+8,3000/1000);
// iap_PROGRAM(iap_ADDRESS+9,3000/100%10);
// iap_PROGRAM(iap_ADDRESS+10,3000/10%10);
// iap_PROGRAM(iap_ADDRESS+11,3000%10);
//
// iap_PROGRAM(iap_ADDRESS+12,3000/1000);
// iap_PROGRAM(iap_ADDRESS+13,3000/100%10);
// iap_PROGRAM(iap_ADDRESS+14,3000/10%10);
// iap_PROGRAM(iap_ADDRESS+15,3000%10);
// while(1);
}
key.c
#include"key.h"
extern uint time_DJA;
extern uint time_DJB;
extern uint time_DJC;
extern uint time_DJD;
bit flag_key1=0; //设置键被按下三秒
bit flag_anjian=0; // 用于标记有按键按下,三秒无按键按下则退出设置界面
bit flag_kaiguan=0; //开关键1是开机,0是关机
uint key_num=1;
void Key()
{
if(K_SET ==0 && flag_key1==0) //检查P3.7端口是否为低电平,即检测S17是否被按下
{
delay_ms(2000); //再次检测S17是否被按下
if(K_SET ==0)
{
while(K_SET == 0); //等待按键释放
flag_key1=1;
}
}
if(flag_key1==1)
{
if(K_SET == 0) //检查P3.7端口是否为低电平,即检测S17是否被按下
{ //延时一定时间,去抖
delay_ms(10); //再次检测S17是否被按下
if(K_SET == 0)
{
while(K_SET == 0); //等待按键释放
key_num++;
flag_anjian=1;
if(key_num==5)
{
key_num=1;
}
}
}
}
if(flag_key1==1)
{
if(K_UP == 0) //检查P3.7端口是否为低电平,即检测S17是否被按下
{ //延时一定时间,去抖
delay_ms(10); //再次检测S17是否被按下
if(K_UP == 0)
{
while(K_UP == 0); //等待按键释放
flag_anjian=1;
switch(key_num)
{
case 1:
time_DJA+=100;
break;
case 2:
time_DJB+=100;
break;
case 3:
time_DJC+=100;
break;
case 4:
time_DJD+=100;
break;
}
}
}
if(K_DN == 0) //检查P3.7端口是否为低电平,即检测S17是否被按下
{ //延时一定时间,去抖
delay_ms(10); //再次检测S17是否被按下
if(K_DN == 0)
{
while(K_DN == 0); //等待按键释放
flag_anjian=1;
switch(key_num)
{
case 1:
time_DJA-=100;
break;
case 2:
time_DJB-=100;
break;
case 3:
time_DJC-=100;
break;
case 4:
time_DJD-=100;
break;
}
}
}
}
/*开关按键代码*/
if(K_POW ==0 ) //检查P3.7端口是否为低电平,即检测S17是否被按下
{
delay_ms(10); //再次检测S17是否被按下
if(K_POW ==0)
{
while(K_POW == 0); //等待按键释放
flag_kaiguan=~flag_kaiguan;
}
}
}
delay.c
#include"delay.h"
/*==========================================================
函数名称:void delayms(void)
形 参:无
返回值 :无
功能描述:1ms延时
时 间:2015-11-19
使 用:delayms();
==========================================================*/
void delayms(void) //@11.0592MHz
{
unsigned char i,j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
}
while (--i);
}
void delay_ms(unsigned int time)
{
unsigned int i;
for(i=0;i<time;i++)
delayms();
}
dj.c
#include"dj.h"
#include"key.h"
#include "eeprom.h"
extern uint key_num;
extern bit flag_key1;
extern uint key_num;
extern bit flag_anjian;
extern uint time_DJA;
extern uint time_DJB;
extern uint time_DJC;
extern uint time_DJD;
bit flag_DJA=0; //定时器运行电机A的代码
bit flag_DJA1=0; //电机进入一次DJA()后主模块就不第二次进去了
bit flag_DJB=0; //定时器运行电机B的代码
bit flag_DJB1=0; //电机进入一次DJB()后主模块就不第二次进去了
bit flag_DJC=0; //定时器运行电机C的代码
bit flag_DJC1=0; //电机进入一次DJC()后主模块就不第二次进去了
bit flag_DJD=0; //定时器运行电机D的代码
bit flag_DJD1=0; //电机进入一次DJD()后主模块就不第二次进去了
uint num=0;
uint num1=0;
uint num2=0; //用于在设置模式定时三秒,没有操作则退出设置模式
uchar SMG_N[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; // 共阴极数码管
uchar shu_1,shu_2,shu_3,shu_4,shu_5,shu_6,shu_7,shu_8;
void DJA()
{
TR0=1;// 定时器0打开
num=0;
PIN_DJA=0;
flag_DJD=0;
flag_DJD1=0;
flag_DJA=1;
}
void DJB()
{
TR0=0;// 定时器0关闭 //还原定时器0
TH0=(65536-45872)/256; //11.0592 晶振定时50ms还原定时器0
TL0=(65536-45872)%256; //还原定时器0
num=0; //还原定时器0
flag_DJA=0; //还原A的标志位
flag_DJA1=0; //还原A的标志位
PIN_DJB=0;
flag_DJB=1;
TR0=1;
}
void DJC()
{
TR0=0;// 定时器0关闭
TH0=(65536-45872)/256; //11.0592 晶振定时50ms
TL0=(65536-45872)%256;
num=0;
flag_DJB=0; //还原B的标志位
flag_DJB1=0; //还原B的标志位
PIN_DJC=0;
flag_DJC=1;
TR0=1;
}
void DJD()
{
TR0=0;// 定时器0关闭
TH0=(65536-45872)/256; //11.0592 晶振定时50ms
TL0=(65536-45872)%256;
num=0;
flag_DJC=0; //还原C的标志位
flag_DJC1=0; //还原C的标志位
PIN_DJD=0;
flag_DJD=1;
TR0=1;
}
void time0() interrupt 1
{
TH0=(65536-9216)/256; //11.0592 晶振定时50ms
TL0=(65536-9216)%256;
num++;num1++; //num1控制数码管显示num控制电机什么时候停止
/*电机A的代码******************************************************************/
if(flag_DJA==1)
{
if(num>=(time_DJA/10)) //time_DJA是电机A转动的时间,单位为ms
{
PIN_DJA=1;
flag_DJA1=1;
num=0;
}
if(PIN_DJA==0) //如果电机在运行则说明数码管数子还在跳动
{
shu_1=(num/10)/10;
shu_2=(num/10)%10;
}
else
{
shu_1=(time_DJA/100)/10;
shu_2=(time_DJA/100)%10;
}
if(num1==1 && flag_key1==0)
{
P0=0X00;
P1=0xfe;
P0=SMG_N[shu_1]+128;
}
if(num1==2 && flag_key1==0 )
{
num1=0;
P0=0X00;
P1=0xfd;
P0=SMG_N[shu_2];
}
}
/******************************************************************************/
/*********************************************************************************/
/*d电机B的代码 *******************************************************************/
if(flag_DJB==1)
{
if(num>=(time_DJB/10)) //time_DJA是电机A转动的时间,单位为ms
{
PIN_DJB=1;
flag_DJB1=1;
num=0;
}
if(PIN_DJB==0) //如果电机在运行则说明数码管数子还在跳动
{
shu_3=(num/10)/10;
shu_4=(num/10)%10;
}
else
{
shu_1=(time_DJB/100)/10;
shu_2=(time_DJB/100)%10;
}
if(num1==1 && flag_key1==0 )
{
P0=0X00;
P1=0xfb;
P0=SMG_N[shu_3]+128;
}
if(num1==2 && flag_key1==0 )
{
num1=0;
P0=0X00;
P1=0xf7;
P0=SMG_N[shu_4];
}
}
/****************************************************************************/
/*d电机C的代码 *******************************************************************/
if(flag_DJC==1)
{
if(num>=(time_DJC/10)) //time_DJA是电机A转动的时间,单位为ms
{
PIN_DJC=1;
flag_DJC1=1;
num=0;
}
if(PIN_DJC==0) //如果电机在运行则说明数码管数子还在跳动
{
shu_5=(num/10)/10;
shu_6=(num/10)%10;
}
else
{
shu_5=(time_DJC/100)/10;
shu_6=(time_DJC/100)%10;
}
if(num1==1 && flag_key1==0 )
{
P0=0X00;
P1=0xef;
P0=SMG_N[shu_5]+128;
}
if(num1==2 && flag_key1==0 )
{
num1=0;
P0=0X00;
P1=0xdf;
P0=SMG_N[shu_6];
}
}
/****************************************************************************/
/*d电机D的代码 *******************************************************************/
if(flag_DJD==1)
{
if(num>=(time_DJD/10)) //time_DJA是电机A转动的时间,单位为ms
{
PIN_DJD=1;
flag_DJD1=1;
num=0;
}
if(PIN_DJD==0) //如果电机在运行则说明数码管数子还在跳动
{
shu_7=(num/10)/10;
shu_8=(num/10)%10;
}
else
{
shu_7=(time_DJD/100)/10;
shu_8=(time_DJD/100)%10;
}
if(num1==1 && flag_key1==0 )
{
P0=0X00;
P1=0xBf;
P0=SMG_N[shu_7]+128;
}
if(num1==2 && flag_key1==0 )
{
num1=0;
P0=0X00;
P1=0x7f;
P0=SMG_N[shu_8];
}
}
/****************************************************************************/
/*按下设置键后数码管显示的代码*/
if(flag_key1==1)
{
switch(key_num)
{
case 1:
if(num1==1)
{
P0=0X00;
P1=0xfe;
P0=SMG_N[(time_DJA/100)/10]+128;
}
if(num1==2)
{
num1=0;
P0=0X00;
P1=0xfd;
P0=SMG_N[(time_DJA/100)%10];
}break;
case 2:
if(num1==1)
{
P0=0X00;
P1=0xfb;
P0=SMG_N[(time_DJB/100)/10]+128;
}
if(num1==2)
{
num1=0;
P0=0X00;
P1=0xf7;
P0=SMG_N[(time_DJB/100)%10];
}break;
case 3:
if(num1==1)
{
P0=0X00;
P1=0xef;
P0=SMG_N[(time_DJC/100)/10]+128;
}
if(num1==2)
{
num1=0;
P0=0X00;
P1=0xdf;
P0=SMG_N[(time_DJC/100)%10];
}break;
case 4:
if(num1==1)
{
P0=0X00;
P1=0xbf;
P0=SMG_N[(time_DJD/100)/10]+128;
}
if(num1==2)
{
num1=0;
P0=0X00;
P1=0x7f;
P0=SMG_N[(time_DJD/100)%10];
}break;
}
}
/* 进入设置后三秒没有操作自动退出并且把数据保存到EEPROM*/
if(flag_key1==1)
{
num2++;
if(num2==300)
{
flag_key1=0;
iap_ERASE(iap_ADDRESS);
iap_PROGRAM(iap_ADDRESS,time_DJA/1000);
iap_PROGRAM(iap_ADDRESS+1,time_DJA/100%10);
iap_PROGRAM(iap_ADDRESS+2,time_DJA/10%10);
iap_PROGRAM(iap_ADDRESS+3,time_DJA%10);
iap_PROGRAM(iap_ADDRESS+4,time_DJB/1000);
iap_PROGRAM(iap_ADDRESS+5,time_DJB/100%10);
iap_PROGRAM(iap_ADDRESS+6,time_DJB/10%10);
iap_PROGRAM(iap_ADDRESS+7,time_DJB%10);
iap_PROGRAM(iap_ADDRESS+8,time_DJC/1000);
iap_PROGRAM(iap_ADDRESS+9,time_DJC/100%10);
iap_PROGRAM(iap_ADDRESS+10,time_DJC/10%10);
iap_PROGRAM(iap_ADDRESS+11,time_DJC%10);
iap_PROGRAM(iap_ADDRESS+12,time_DJD/1000);
iap_PROGRAM(iap_ADDRESS+13,time_DJD/100%10);
iap_PROGRAM(iap_ADDRESS+14,time_DJD/10%10);
iap_PROGRAM(iap_ADDRESS+15,time_DJD%10);
}
if(flag_anjian==1)
{
flag_anjian=0;
num2=0;
}
}
}
void Init_Timer0(void)
{
AUXR=0X00; //定时器0 定时器 1工作在12分频 即1T
TMOD=0x11; //定时器0 和定时器1 不可自动重装载模式
TH0=(65536-9216)/256; //11.0592 晶振定时50ms
TL0=(65536-9216)%256;
TL1 = (65536-46080)/256; // 11.0592 晶振定时20ms
TH1 = (65536-46080)%256;
TR0=0; //定时器0关闭
TR1 = 0; //定时器1关闭
ET0=1; //允许定时器0中断
ET1=1; //允许定时器1中断
EA=1; //开启总中断
}
eeprom.c
#include "eeprom.h"
//使硬件或软件操作停止
void iap_IDLE()
{
IAP_CONTR=0; //禁止IAP读写擦除
IAP_CMD=0; //等待
IAP_TRIG=0; //命令未触发
IAP_ADDRH=0x80; //高位数据地址
IAP_ADDRL=0; //低位
}
//从数据里面读取数据
uchar iap_READ(uint addr)
{ uchar datas;
IAP_CONTR=IAP_EN; //控制允许位
IAP_CMD=CMD_READ; //写入读命令
IAP_ADDRL=addr; //自定义地址
IAP_ADDRH=addr>>8;
IAP_TRIG=0x5a; //命令有效
IAP_TRIG=0xa5;
_nop_();
datas=IAP_DATA;
iap_IDLE();
return datas; //返回读出的数据
}
//写一个比特ISP写到某个地方
void iap_PROGRAM(uint addr,uchar datas)
{
IAP_CONTR=IAP_EN;
IAP_CMD=CMD_PROGRAM;
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_DATA=datas;
IAP_TRIG=0x5a;
IAP_TRIG=0xa5;
_nop_();
iap_IDLE();
}
//擦掉某个区域
void iap_ERASE(uint addr)
{
IAP_CONTR=IAP_EN;
IAP_CMD=CMD_ERASE;
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_TRIG=0x5a;
IAP_TRIG=0xa5;
_nop_();
iap_IDLE();
}
复制代码
作者:
miaoxiaobaiqaq
时间:
2019-4-12 23:58
新手,有更好的实现方式可以一起交流,一起进步
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1