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++)<>
;>
文章评论(0条评论)
登录后参与讨论