原创 步进电机做单指针时钟半成品

2015-7-6 18:01 1851 13 13 分类: MCU/ 嵌入式

http://player.youku.com/player.php/sid/XMTI3NzcxNjk0MA==/v.swf

闲来无事翻出个步进电机,插上个牙签想做个单指针表玩,C语言也是初学,并不熟练,目前程序只编了一半算半成品,只是实现了按键控制和串口命令控制,也算是指哪打哪吧哈哈!

计划是加个DS1302实时时钟,弄个光盘做盘面,加上几个按键可以设置时间,用开槽的光开关当指针位置检测,这样就不怕丢步了,如果能加上红外遥控或者人体红外感应开关当触发更好玩,程序计划是平常指针当时针用,触发后指示分针和秒针,想法挺多编程能力有限,如果感兴趣帮我进一步开发,附上初学编制程序供参考,如果感觉有意思可以一起完善它。

/********************************************************/
/* 步进电机做单指针时钟半成品
/* STC15W408AS控制ULN2803驱动5线1.8°步进角的步进电机,一根公共线接+,四线逐一接地电机可以单步运转的那种                                                 
/* 晶振11.0592M,下载参数全默认,STC下载工具设为串口115200自动打开串口
/* P1.0-1.3为步进电机四相控制输出,P3.2-P3.5是控制键盘,P3.6是蜂鸣器输出 
/* 键盘可以独立控制,也可以串口发送HEX数据指定运行到的位置
/* 功能描述:上电后按键盘正反转每次一步,每一步实际是两步为了可靠运转,按增减步数键可以调整每次转的步数
/* 上电初始默认每次转一圈200步,增减键最大200步,最小1步
/* 串口发送0意味着以当前位置为原点,下次以这个位置为零点
/* 串口发送不超过C8H的数据,则电机会运转到指定的位置,例如32H则运行到3点钟方向,64H运行到6点钟方向等等
/* 电机运行具有启动缓加速功能,根据电机不同可以单独设置启动转速和最高不丢步转速,加速率20%可以自己设定
/* 串口发送来的数据会判断与当前位置的偏差,以最低运行步数运转到要求的位置,也就是不会走大于半圈的
/* 运行末了有位置锁定功能,防止因惯性走过了,延时后会关闭电机输出实现节电的目的                                                     
/********************************************************/
#include "reg51.h"
#include "intrins.h"
#define uchar unsigned char
#define uint  unsigned int
uchar code FFW[10]={0xff,0xf9,0xf1,0xf3,0xf2,0xf6,0xf4,0xfc,0xf8,0xf9};  //四相8拍正转编码,为方便编程调整了一下顺序和插入了必要的编码
sbit  K1   = P3^2;       //正转数步
sbit  K2   = P3^3;       //反转数步
sbit  K3   = P3^4;       //每次按键增加一步
sbit  K4   = P3^5;       //每次按键增减一步
sbit  BEEP = P3^6;       //蜂鸣器
uchar INDEX =1;  //步码索引
uchar POSION = 200; //指针位置0-200步一圈 200=0位
uchar REQPOS = 200;//串口发来的要求运行到的位置
 
#define FOSC 11059200L          //系统频率
#define BAUD 115200             //串口波特率
 
#define NONE_PARITY     0       //无校验
#define ODD_PARITY      1       //奇校验
#define EVEN_PARITY     2       //偶校验
#define MARK_PARITY     3       //标记校验
#define SPACE_PARITY    4       //空白校验
 
#define PARITYBIT EVEN_PARITY   //定义校验位
 
sfr AUXR  = 0x8e;               //辅助寄存器
sfr T2H   = 0xd6;               //定时器2高8位
sfr T2L   = 0xd7;               //定时器2低8位
sfr P_SW1   = 0xA2;             //外设功能切换寄存器1
 
#define S1_S0 0x40              //P_SW1.6
#define S1_S1 0x80              //P_SW1.7
 
bit busy;
 
void SendData(uchar dat);
void SendString(uchar *s);
void uartint();
 
/********************************************************/
/*                                                  
/* 步进电机步间延时 
/*                                                      
/********************************************************/
void delay(uint t)
{                           
   uint k;
     for(k=0; k
}
 
/**********************************************************/
/*其它用途延时
/**********************************************************/
 
void delayB(uchar x)
 {
   uint k;
   while(x--)
   {
     for(k=0; k<10000; k++)
     { }
   }
 }
 
/**********************************************************/
void beep()
 {
BEEP=0;
delayB(5);
BEEP=1;                    //关闭蜂鸣器
 }
 
 
/********************************************************/
/*
/*步进电机正转
/*
/********************************************************/
void  motor_ffw(uchar N)
 {
 uchar r;//已运行步数计数器
 uint rate;//速率变量
 rate=3000;//初始启动速率
 for (r=0;r
{ INDEX=INDEX+1;//步进电机驱动编码加一
if(INDEX==5)//步进电机最大编码只能是4
{INDEX=1;//编码超过4必须回位到1
}
P1 = FFW[INDEX*2-1];//先输出一个半步
delay(rate);
P1 = FFW[INDEX*2];//再输出全步,这是正常的位置
    delay(rate);            //调节转速
POSION=POSION+1;//当前电机位置更新
if(POSION==201)//位置最大200
{POSION=1;//位置超过200回归1
}
rate=rate-rate/20;//每步提高速率20%
if (rate<1000)
{rate=1000;//最高速率限制
}
 }
delay(3000);//刹车锁位
SendData(POSION);//串口发送当前位置
  P1 = 0xf0;//撤除驱动电流
 
 }
 
/********************************************************/
/*
/*步进电机反转
/*
/********************************************************/
void  motor_rev(uchar N)
{ uchar r;//已运行步数计数器
 uint rate;//速率变量
 rate=3000;//初始启动速率
 for (r=0;r
{ INDEX=INDEX-1;//步进电机驱动编码减一
if(INDEX==0)//步进电机最小编码只能是1
{
INDEX=4;//编码小于1必须回位到4
}
 
P1 = FFW[INDEX*2+1];//先输出一个半步
delay(rate);
P1 = FFW[INDEX*2];//再输出全步,这是正常的位置
delay(rate);//调节转速
POSION=POSION-1;//当前电机位置更新
if(POSION==0)//位置最小1
{
POSION=200;//位置0=200
}
 
 rate=rate-rate/20;//每步提高速率20%
 if (rate<1000){rate=1000;}//最高速率限制
 }
delay(3000);//刹车锁位
SendData(POSION);//串口发送当前位置
  P1 = 0xf0;//撤除驱动电流
 
 }
/********************************************************
*                                                       
*  主程序                                               
*                                                      
*********************************************************/
 
main()
uchar N=200;             //N 步进电机运转步数
uartint();//串口初始化
beep();
P1 = FFW[INDEX*2-1];//电机位置初始化
delay(3000);
P1 = FFW[INDEX*2];
delay(3000);
  P1 = 0xf0;//撤除驱动电流
 
while(1)
{
if(K1==0)//正转按键按下
{
motor_ffw(N);//电机正转N步
delayB(5);//按键连续触发间隔
beep();
}
else if(K2==0)//反转转按键按下
{
motor_rev(N);//电机反转N步 
delayB(5);//按键连续触发间隔
beep();
}
else if(K3==0)//步数加一按键按下
{
N=N+1;//步数加一
if(N>200)//如果步数大于200
{
N=200;//步数最大设置到200
}
delayB(5);//按键连续触发间隔
beep();  
}
else if(K4==0)//步数减一按键按下
{
N=N-1;//步数减一
if(N<1)//如果步数小于1
{
N=1;//步数设置最少1
}
delayB(5);//按键连续触发间隔
beep();  
}
 
else if (POSION != REQPOS)//每时每刻检查要求的位置是否和当前位置一样
{
if (REQPOS>POSION)//判断要求位置是否大于当前位置
{if ((REQPOS-POSION)<100)//判断位置偏差是否超过半圈了
motor_ffw(REQPOS-POSION);//没超过半圈电机正转差的步数
else
motor_rev(200-(REQPOS-POSION));//超过半圈则反向转200-差,保障电机不会转超过半圈
beep();
}
else//若要求位置小于当前位置则:
{if ((POSION-REQPOS)<100)//判断位置偏差是否超过半圈了
motor_rev(POSION-REQPOS);//没超过半圈电机倒转差的步数
else
motor_ffw(200-(POSION-REQPOS));//超过半圈则反向转200-差,保障电机不会转超过半圈
beep();
}
 
};  
 
 
}
}
 
/*----------------------------
UART 中断服务程序
-----------------------------*/
void Uart() interrupt 4 using 1
{
uchar i;
    if (RI)
    {
        RI = 0;                 //清除RI位
        i = SBUF;
if (i==0)//如果上位机发来0,则赋值当前位置为200即0位
{POSION = 200;
REQPOS=200;
SendData(POSION);
}
else
REQPOS= i;//否则把上位机发来的数据作为要求的位置命令 
    }
    if (TI)
    {
        TI = 0;                 //清除TI位
        busy = 0;               //清忙标志
    }
}
 
/*----------------------------
发送串口数据
----------------------------*/
void SendData(uchar dat)
{
    while (busy);               //等待前面的数据发送完成
    ACC = dat;                  //获取校验位P (PSW.0)
    if (P)                      //根据P来设置校验位
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 0;                //设置校验位为0
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 1;                //设置校验位为1
#endif
    }
    else
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 1;                //设置校验位为1
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 0;                //设置校验位为0
#endif
    }
    busy = 1;
    SBUF = ACC;                 //写数据到UART数据寄存器
}
 
/*----------------------------
发送字符串
----------------------------*/
void SendString(uchar *s)
{
    while (*s)                  //检测字符串结束标志
    {
        SendData(*s++);         //发送当前字符
    }
}
 
void uartint()
{
    ACC = P_SW1;
    ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=0
    P_SW1 = ACC;                //(P3.0/RxD, P3.1/TxD)
    
//  ACC = P_SW1;
//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=1 S1_S1=0
//  ACC |= S1_S0;               //(P3.6/RxD_2, P3.7/TxD_2)
//  P_SW1 = ACC;  
//  
//  ACC = P_SW1;
//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=1
//  ACC |= S1_S1;               //(P1.6/RxD_3, P1.7/TxD_3)
//  P_SW1 = ACC;  
 
#if (PARITYBIT == NONE_PARITY)
    SCON = 0x50;                //8位可变波特率
#elif (PARITYBIT == ODD_PARITY) || (PARITYBIT == EVEN_PARITY) || (PARITYBIT == MARK_PARITY)
    SCON = 0xda;                //9位可变波特率,校验位初始为1
#elif (PARITYBIT == SPACE_PARITY)
    SCON = 0xd2;                //9位可变波特率,校验位初始为0
#endif
 
    T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值
    T2H = (65536 - (FOSC/4/BAUD))>>8;
    AUXR = 0x14;                //T2为1T模式, 并启动定时器2
    AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器
    ES = 1;                     //使能串口1中断
    EA = 1;
    SendString("STEP MOTER CLOCK\r\n");//上电后串口发送程序信息
}
;r++)<>
;r++)<>
;>
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
13
关闭 站长推荐上一条 /3 下一条