本帖最后由 WXJPCY888 于 2012-12-21 10:00 编辑
各位大侠向你们请教一个小程序。。。控制小电机正反转的问题。
按SW0控制小电机前行,按SW1时电机停止运行,形成互锁。
按SW1控制小电机后退,按SW0时电机停止运行,形成互锁。
改用状态机加扫描是可以了,但只能控制正转,反转控制不到,因我把两个端口分开进行状态机扫描了。可能要把两个端口放在一起进行状态机扫描才会达到效果。只是不知怎样区分扫描状态机分离两个端口状态。。。 :L
本人新手,恳请各位大侠高手指点迷津。。。多谢!!!
#include <pic.h>
#include <timers.h>
#include "delay.h"
void init();
void scan();
void runinit();
//主程序
void main (void)
{
init(); //初始化
while(1)
{
scan(); // 按键扫描
}
}
//PWM调速程序
void runinit()
{
PR2 = 0xff;
CCPR4L = 0xdf;
TRISDbits.TRISD2= 0;
T2CONbits.T2OUTPS3=0;
T2CONbits.T2OUTPS2=0;
T2CONbits.T2OUTPS1=0;
T2CONbits.T2OUTPS0=0;
T2CONbits.T2CKPS1=0;
T2CONbits.T2CKPS0=0;
T2CONbits.TMR2ON = 1;
CCP4CON = 0x0c;
}
void scan()
{
if(SW0==0) //正转按钮
{
delayms(1);
if(SW0==0)
{
PORTBbits.RB2=1; //蜂鸣器响一声
delayms(150);
PORTBbits.RB2=0;
delayms(50);
while(!SW0)
{
PORTBbits.RB4=0;
PORTBbits.RB5=1; // 正转
runinit(); // PWM调速
}
if(SW0==0 && SW1==0‖SW1==0) //停止
{
PORTBbits.RB4=0;
PORTBbits.RB5=0;
TRISDbits.TRISD2= 1;
}
}
}
if(SW1==0) //反转按钮
{
delayms(1);
if(SW1==0)
{
PORTBbits.RB2=1; //蜂鸣器响一声
delayms(150);
PORTBbits.RB2=0;
delayms(50);
while(!SW1)
{
PORTBbits.RB4=1; //反转
PORTBbits.RB5=0;
runinit(); PWM调速
}
if(SW0==0 && SW1==0‖SW0==0) // 停止
{
PORTBbits.RB4=0;
PORTBbits.RB5=0;
TRISDbits.TRISD2= 1;
}
}
}
}
void init()
{
ADCON1=0x0f; //初始化IO端口
CMCON=0x07;
TRISBbits.TRISB2= 0;
TRISBbits.TRISB4= 0;
TRISBbits.TRISB5= 0;
TRISDbits.TRISD0= 1;
TRISDbits.TRISD1= 1;
PORTB= 0x00;
PORTC= 0x00;
}
使用状态机扫描修改后的程序如下:
#include <p18cxx.h>
#include <timers.h>
#include "delay.h"
#pragma config DEBUG = ON, XINST=OFF, STVR = ON, WDT=OFF, CP0 = OFF, FCMEN = ON, IESO = OFF, FOSC2=ON, FOSC=HSPLL, ETHLED=OFF
#define beep_dr PORTBbits.RB2 /* beep_dr *///蜂鸣器输出
#define TRIS_beep_dr DDRBbits.RB2
#define key_sr1 PORTDbits.RD0 /* key_sr1 *///正转
#define TRIS_key_sr1 DDRDbits.RD0
#define key_sr2 PORTDbits.RD1 /* key_sr2 *///反转
#define TRIS_key_sr2 DDRDbits.RD1
#define cnt_delay4us_cnt1 10
#define cnt_delay4us_cnt2 10 //按键去抖动延时阀值
#define cnt_voice_time 10 //蜂鸣器响的声音长短的延时阀值
#define delay4us_cnt1
#define delay4us_cnt2
#define KEY_LONG_PERIOD 150
#define KEY_STATE_INIT 0
#define KEY_STATE_WOBBLE 1
#define KEY_STATE_PRESS 2
#define KEY_STATE_LONG 3
#define KEY_INIT 0
#define KEY_WOBBLE 1
#define KEY_PRESS 2
#define KEY_LONG 3
#define KEY_sr1_1 0x01
#define KEY_sr2_2 0x02
#define KEY_NULL 0x03
void init();
void GetKey();
void KeyGet();
void runinit();
void key_scan(); //按键扫描函数,放在定时中断里
void key_service();
void PIC18F_High_isr(void);/*中断服务函数声明*/
unsigned char key_step=1; //扫描步骤变量
unsigned char key_lock1=0; //按键自锁标志
unsigned char key_lock2=0; //按键自锁标志
unsigned char Count=0; //延时计数器的变量
unsigned char key_sate;
unsigned char key_step;
unsigned char key_sec=0; //哪个按键被触发
#pragma code high_vector_section=0x8
void high_vector (void)
{
_asm goto PIC18F_High_isr _endasm //跳转到中断服务函数处*/
}
#pragma code
#pragma interrupt PIC18F_High_isr
void PIC18F_High_isr (void)
{
if(INTCONbits.TMR0IE==1&&INTCONbits.TMR0IF==1) //定时中断
{
INTCONbits.TMR0IF=0; //定时中断标志位关闭
T0CONbits.TMR0ON=0; //定时中断开关关闭
key_scan(); //按键扫描函数
TMR1H=0x0b;
TMR0L=0xec; //重新设置定时时间间隔
T0CONbits.TMR0ON=1; //定时中断开关打开
}
}
void main()
{
init();
INTCONbits.GIE=0;
//IPR1bits.TMR1IP=1;
T0CON=0x08; //定时器中断配置
//TMR1H=0x0b;
TMR0L=0xec;
INTCONbits.TMR0IF=0; //定时中断标志位关闭
INTCONbits.TMR0IE=1; //开中断
T0CONbits.TMR0ON=1; //打开定时
INTCONbits.GIE=1; //开总中断
beep_dr=0; //关蜂鸣器,
while(1)
{
key_service(); //按键服务
//key_scan();
GetKey(); 正转按键扫描函数
KeyGet(); 反转按键扫描函数
}
}
void key_scan()
{
if(key_sr1 == 0)return KEY_sr1_1 ;
if(key_sr2 == 0)return KEY_sr2_2 ;
return KEY_NULL ;
}
void GetKey() //正转按键扫描函数
{
switch(key_step) //按键服务状态切换
{
case KEY_STATE_INIT: //状态0
{
if(key_sr1==1) //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
key_lock1=0;
key_step=KEY_STATE_WOBBLE;
}
else
{
key_step = KEY_STATE_INIT ;
}
}
break;
case KEY_STATE_WOBBLE : //状态1
{
key_lock1=0; //按键自锁标志清零
Count=0; //按键去抖动延时计数器清零,
key_step = KEY_STATE_PRESS ;//消抖
}
break;
case KEY_STATE_PRESS : //状态2
{
if(key_sr1==0)
{
key_lock1=1;
++Count;
if(Count>cnt_delay4us_cnt1 )
{
Count = 0 ;
key_lock1=1; //自锁按键置位,避免一直触发
key_sec=1;
key_step = KEY_STATE_LONG ;
}
}
else
{
key_step = KEY_STATE_INIT ;
}
}
break ;
case KEY_STATE_LONG : //状态3
{
if(key_sr1==0)
{
++Count;
if(Count >= KEY_LONG_PERIOD)
{
Count = 0 ;
key_sec=3; //长按键事件发生
key_step = KEY_STATE_INIT ;
}
}
else
{
key_step = KEY_STATE_PRESS ;
}
}
break ;
// default : break ;
}
}
void KeyGet() //反转按键扫描函数
{
switch(key_sate) //按键服务状态切换
{
case KEY_INIT: //状态0
{
if(key_sr2==1) //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
key_sate=KEY_WOBBLE;
}
else
{
key_sate = KEY_INIT ;
}
}
break;
case KEY_WOBBLE : //状态1
{
key_lock2=0; //按键自锁标志清零
Count=0; //按键去抖动延时计数器清零,
key_sate = KEY_PRESS ;//消抖
}
break;
case KEY_PRESS : //状态2
{
if(key_sr2==0)
{
key_lock2=1;
++Count;
if(Count >= cnt_delay4us_cnt2)
{
Count = 0 ;
key_lock1=2; //自锁按键置位,避免一直触发
key_sec=2;
key_sate = KEY_LONG ;
}
}
else
{
key_sate = KEY_INIT ;
}
}
break ;
case KEY_LONG : //状态3
{
if(key_sr2==0)
{
++Count;
if(Count >= KEY_LONG_PERIOD)
{
Count = 0 ;
key_sec=4; //长按键事件发生
key_sate = KEY_INIT ;
}
}
else
{
key_sate = KEY_PRESS ;
}
}
break ;
}
}
void key_service() //按键服务函数
{
switch(key_sec) //按键服务状态切换
{
case 1:// 1号键
beep_dr=1; //蜂鸣器响
delayms(150);
beep_dr=0; //蜂鸣器停止
delayms(50);
key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发
PORTBbits.RB4=0;
PORTBbits.RB5=1; //电机正转置位
runinit(); //PWM 运行
break;
case 2:// 2号键
beep_dr=1; //蜂鸣器响
delayms(150);
beep_dr=0; //蜂鸣器停止
delayms(50);
key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发
PORTBbits.RB4=1; //电机反转置位
PORTBbits.RB5=0;
runinit(); //PWM 运行
break;
case 3:// 3号键
case 4://4号键
beep_dr=1; //蜂鸣器响
delayms(150);
beep_dr=0; //蜂鸣器停止
delayms(50);
key_sec=0;//相应完按键处理程序之后,把按键选择变量清零,避免一直触发
PORTBbits.RB4=0; //停止
PORTBbits.RB5=0; //停止
TRISDbits.TRISD2= 1; //停止
break;
default : break ;
}
}
void init() //初始化IO端口
{
ADCON1=0x0f;
CMCON=0x07;
TRISBbits.TRISB2= 0;
TRISBbits.TRISB4= 0;
TRISBbits.TRISB5= 0;
TRISDbits.TRISD0= 1;
TRISDbits.TRISD1= 1;
PORTB= 0x00;
}
void runinit()
{
PR2 = 0xff; //PWM的周期
CCPR4L = 0xdf; //PWM的占空比,不能大于PR2
TRISDbits.TRISD2= 0; //设定RC2/CCP1为输出
T2CONbits.T2OUTPS3=0; //后分频比
T2CONbits.T2OUTPS2=0; //后分频比
T2CONbits.T2OUTPS1=0; //后分频比
T2CONbits.T2OUTPS0=0; //后分频比
T2CONbits.T2CKPS1=0; //预分频比
T2CONbits.T2CKPS0=0; //预分频比
T2CONbits.TMR2ON = 1; //打开定时器2
CCP4CON = 0x0c; //CCP4选择PWM模式
}
|