基于8051系统控制步进电机28BYJ-48,并且通过LCD12864可选菜单选择步进电机运行模式
步进电机控制部分
28BYJ48.C
#include "28BYJ48.H"
#include "LCD12864.H"
unsigned char delay_ms(unsigned int ms, unsigned char Range)
{
unsigned int i;
unsigned char j, FSOC;
for(i = ms; i > 0; i--)
{
for(FSOC = 12; FSOC > 0; FSOC--)
{
for(j = 96; j > 0; j--)
{
switch(Range)
{
case 0: //Just Delay
{
} break;
case 1: //LimitSwitch
{
if(LimitSwitch == 0)
{
return 1;
}
}
break;
case 2://
{
if(!Start)
{
return 2;
}
if(!Back)
{
return 3;
}
}
break;
}
}
}
}
return 0;
}
void step_motor_28BYJ48_send_pulse(unsigned char Step, bit Dir)
{
if(Dir == 0) //如果为逆时针旋转
{
Step = 7 - Step; //调换节拍信号
}
switch(Step)//8个节拍控制:A->AB->B->BC->C->CD->D->DA
{
case 0:
IN1_A = 1;
IN2_B = 0;
IN3_C = 0;
IN4_D = 0;
break;
case 1:
IN1_A = 1;
IN2_B = 1;
IN3_C = 0;
IN4_D = 0;
break;
case 2:
IN1_A = 0;
IN2_B = 1;
IN3_C = 0;
IN4_D = 0;
break;
case 3:
IN1_A = 0;
IN2_B = 1;
IN3_C = 1;
IN4_D = 0;
break;
case 4:
IN1_A = 0;
IN2_B = 0;
IN3_C = 1;
IN4_D = 0;
break;
case 5:
IN1_A = 0;
IN2_B = 0;
IN3_C = 1;
IN4_D = 1;
break;
case 6:
IN1_A = 0;
IN2_B = 0;
IN3_C = 0;
IN4_D = 1;
break;
case 7:
IN1_A = 1;
IN2_B = 0;
IN3_C = 0;
IN4_D = 1;
break;
default:
IN1_A = 0;
IN2_B = 0;
IN3_C = 0;
IN4_D = 0;
break;//停止相序
}
}
//电机初始化
bit MOTOR28BYJ48Init(bit Dir)
{
unsigned char step;
unsigned char step1;
while(1)
{
step_motor_28BYJ48_send_pulse(step++, Dir);
if(step == 8)
{
step = 0;
step1++;
//转180度
if(step1 == 255)
{
return 1;
}
}
if(delay_ms(1, 1))
{
return 0;
}
}
}
28BYJ48.H
#include <STC8.H>
#ifndef __28BYJ48_H__
#define __28BYJ48_H__
//端口定义
sbit LimitSwitch = P4 ^ 3;
sbit IN1_A = P6 ^ 0;
sbit IN2_B = P6 ^ 1;
sbit IN3_C = P6 ^ 2;
sbit IN4_D = P6 ^ 3;
//端口定义
void step_motor_28BYJ48_send_pulse(unsigned char Step, bit Dir);
unsigned char delay_ms(unsigned int ms, unsigned char Range);
bit MOTOR28BYJ48Init(bit Dir);
#endif
LCD12864实现部分,可以切换为Oled12864以及其他屏幕
LCD12864.C
#include "LCD12864.H"
void DelayLCD()
{
unsigned char i, j;
for(i = 0; i < 12; i++)
{
for(j = 0; j < 32; j++)
{
}
}
}
//-->整数转换函数
char* itoa(int num, char* str, int radix)
{
char index[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //索引表
char temp;//临时变量,交换两个值时用到
unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数
int i = 0, j, k; //i用来指示设置字符串相应位,转换之后i其实就是字符串的长度;转换后顺序是逆序的,有正负的情况,k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。
//获取要转换的整数的绝对值
if(radix == 10 && num < 0) //要转换成十进制数并且是负数
{
unum = (unsigned) - num; //将num的绝对值赋给unum
str[i++] = '-'; //在字符串最前面设置为'-'号,并且索引加1
}
else unum = (unsigned)num; //若是num为正,直接赋值给unum
//转换部分,注意转换后是逆序的
do
{
str[i++] = index[unum % (unsigned)radix]; //取unum的最后一位,并设置为str对应位,指示索引加1
unum /= radix; //unum去掉最后一位
}
while(unum); //直至unum为0退出循环
str[i] = '\0'; //在字符串最后添加'\0'字符,c语言字符串以'\0'结束。
//将顺序调整过来
if(str[0] == '-') k = 1; //如果是负数,符号不用调整,从符号后面开始调整
else k = 0; //不是负数,全部都要调整
for(j = k; j <= (i - 1) / 2; j++) //头尾一一对称交换,i其实就是字符串的长度,索引最大值比长度少1
{
temp = str[j]; //头部赋值给临时变量
str[j] = str[i - 1 + k - j]; //尾部赋值给头部
str[i - 1 + k - j] = temp; //将临时变量的值(其实就是之前的头部值)赋给尾部
}
return str;//返回转换后的字符串
}
//-->读忙函数
void CheckBusy(void)
{
RS = 0;
RW = 1;
EN = 1;
while((DataPort & 0x80) == 0x80);
EN = 0;
}
//-->写指令
void WriteCmd(unsigned char CmdCode)
{
CheckBusy();
RS = 0;
RW = 0;
EN = 1;
DataPort = CmdCode;
DelayLCD();
EN = 0;
}
//-->写数据
void WriteData(unsigned char DataCode)
{
CheckBusy();
RS = 1;
RW = 0;
EN = 1;
DataPort = DataCode;
DelayLCD();
EN = 0;
}
//-->LCD12864初始化
void InitLCD(void)
{
RSB = 1;
RST = 0;
DelayLCD();
RST = 1;
WriteCmd(0x30);
WriteCmd(0x30);
WriteCmd(0x0c);
WriteCmd(0x02);
WriteCmd(0x01);
BLA = 0;
LCD_String(0, 0, "显示器显示无误!!");
LCD_String(0, 1, "显示器显示无误!!");
LCD_String(0, 2, "显示器显示无误!!");
LCD_String(0, 3, "显示器显示无误!!");
}
//-->发送字符串
void LCD_String(unsigned char x, unsigned char y, unsigned char *Str)
{
switch(y)
{
case 0:
WriteCmd(0x80 + x);
break;
case 1:
WriteCmd(0x90 + x);
break;
case 2:
WriteCmd(0x88 + x);
break;
case 3:
WriteCmd(0x98 + x);
break;
default:
break;
}
while(*Str > 0)
{
WriteData(*Str);
DelayLCD();
Str++;
}
}
LCD12864.H
#include <STC8.H>
#ifndef __LCD12864_H__
#define __LCD12864_H__
//端口定义
#define DataPort P7
sbit RS = P1 ^ 1;
sbit RW = P1 ^ 2;
sbit EN = P1 ^ 3;
sbit RSB = P4 ^ 4;
sbit NC = P1 ^ 5;
sbit RST = P1 ^ 0;
sbit BLA = P1 ^ 4;
sbit LED1 = P5 ^ 5;
sbit LED2 = P4 ^ 1;
sbit BUZZ = P2 ^ 1;
sbit Start = P6 ^ 7;
sbit Back = P6 ^ 6;
sbit Up = P6 ^ 5;
sbit Down = P6 ^ 4;
sbit Sure = P4 ^ 3;
//端口定义
/********************
******函数定义******/
//-->整数转换函数
char* itoa(int num, char* str, int radix);
//-->读忙函数
void CheckBusy(void);
//-->写指令
void WriteCmd(unsigned char CmdCode);
//-->写数据
void WriteData(unsigned char DataCode);
//-->LCD12864初始化
void InitLCD(void);
//-->发送字符串
void LCD_String(unsigned char x, unsigned char y, unsigned char *s);
//-->用于稳定时序的延时
void DelayLCD();
/********************
******函数定义******/
#endif
主函数部分
#include <STC8.H>
#include "28BYJ48.H"
#include "LCD12864.H"
bit StartFlag = 0;
bit Laout2Flag = 0;
//储存模式
bit Laout3FlagA;
bit Laout3FlagB;
bit Laout3FlagC;
//储存角度
bit Laout4FlagA;
bit Laout4FlagB;
bit Laout4FlagC;
//储存速度
bit Laout5FlagA;
bit Laout5FlagB;
bit Laout5FlagC;
void UI(unsigned char Layout, unsigned char Mode)
{
switch(Layout)
{
//开机界面
case 0:
{
WriteCmd(0x01);
LCD_String(0, 0, "->初始化未完成<0");
LCD_String(0, 1, "显示器显示无误!!");
LCD_String(0, 2, "限位开关检测异常");
LCD_String(0, 3, "当前状态循环自检");
}
break;
//自检完成待机界面
case 1:
{
WriteCmd(0x01);
LCD_String(0, 0, "->初始化已完成<1");
LCD_String(0, 1, "长按启动按钮开启");
LCD_String(0, 2, "限位开关检测无误");
LCD_String(0, 3, "自检完毕等侯操作");
}
break;
//选择模式开启电机
case 2:
{
if(!Laout2Flag)
{
WriteCmd(0x01);
WriteCmd(0x01);
LCD_String(0, 0, "->选择模式开机<2");
LCD_String(0, 1, "A>顺时针转动");
LCD_String(0, 2, "B>逆时针转动");
LCD_String(0, 3, "C>循环转动");
Laout2Flag = 1;
}
switch(Mode)
{
case 0:
{
LCD_String(0, 1, "+>顺时针转动");
LCD_String(0, 2, "B>");
LCD_String(0, 3, "C>");
}
break;
case 1:
{
LCD_String(0, 1, "A>");
LCD_String(0, 2, "+>逆时针转动");
LCD_String(0, 3, "C>");
}
break;
case 2:
{
LCD_String(0, 1, "A>");
LCD_String(0, 2, "B>");
LCD_String(0, 3, "+>循环转动");
}
break;
}
}
break;
//选择模式开启电机
case 3:
{
if(!Laout2Flag)
{
WriteCmd(0x01);
WriteCmd(0x01);
LCD_String(0, 0, "->选择转动模式<3");
LCD_String(0, 1, "->转动45度");
LCD_String(0, 2, "->转动90度");
LCD_String(0, 3, "->按下启动转动");
Laout2Flag = 1;
}
switch(Mode)
{
case 0:
{
LCD_String(0, 1, "+>");
LCD_String(0, 2, "->");
LCD_String(0, 3, "->");
}
break;
case 1:
{
LCD_String(0, 1, "->");
LCD_String(0, 2, "+>");
LCD_String(0, 3, "->");
}
break;
case 2:
{
LCD_String(0, 1, "->");
LCD_String(0, 2, "->");
LCD_String(0, 3, "+>");
}
break;
}
}
break;
//选择转速
case 4:
{
if(!Laout2Flag)
{
WriteCmd(0x01);
WriteCmd(0x01);
LCD_String(0, 0, "->选择转动速度<4");
LCD_String(0, 1, "->低速");
LCD_String(0, 2, "->中速");
LCD_String(0, 3, "->高速");
Laout2Flag = 1;
}
switch(Mode)
{
case 0:
{
LCD_String(0, 1, "+>");
LCD_String(0, 2, "->");
LCD_String(0, 3, "->");
}
break;
case 1:
{
LCD_String(0, 1, "->");
LCD_String(0, 2, "+>");
LCD_String(0, 3, "->");
}
break;
case 2:
{
LCD_String(0, 1, "->");
LCD_String(0, 2, "->");
LCD_String(0, 3, "+>");
}
break;
}
}
break;
case 5:
{
if(!Laout2Flag)
{
WriteCmd(0x01);
WriteCmd(0x01);
LCD_String(0, 0, "->按下启动开始<5");
LCD_String(0, 1, "模式:");
LCD_String(0, 2, "速度:");
LCD_String(0, 3, "状态:");
Laout2Flag = 1;
}
if(Laout3FlagA)
{
LCD_String(3, 1, "顺时");
}
if(Laout3FlagB)
{
LCD_String(3, 1, "逆时");
}
if(Laout3FlagC)
{
LCD_String(3, 1, "循环");
}
if(Laout4FlagA)
{
LCD_String(5, 1, "45度");
}
if(Laout4FlagB)
{
LCD_String(5, 1, "90度");
}
if(Laout4FlagC)
{
LCD_String(5, 1, "按键");
}
if(Laout5FlagA)
{
LCD_String(3, 2, "低速");
}
if(Laout5FlagB)
{
LCD_String(3, 2, "中速");
}
if(Laout5FlagC)
{
LCD_String(3, 2, "高速");
}
if(StartFlag)
{
LCD_String(3, 3, "开启");
}
else
{
LCD_String(3, 3, "关闭");
}
}
break;
}
}
void main(void)
{
unsigned char ModeFlag;
unsigned char Mode, Angle, Speed;
unsigned char Buff1, Buff2, Buff3;
RSTCFG = 0X10;
P1M0 = 0X1F;
P1M1 = 0X00;
P7M0 = 0XFF;
P7M1 = 0XFF;
InitLCD();
//显示开机界面
UI(0, ModeFlag);
//等待限位开关
//while(LimitSwitch);
while(MOTOR28BYJ48Init(LED2))
{
LED2 = !LED2;
}
//显示自检完成待机界面
UI(1, ModeFlag);
//等待按下启动按钮
while(Start);
Layout2:
{
//*****************************************
// Layout = 2;
Laout2Flag = 0;
//显示2菜单
UI(2, ModeFlag);
//等待确认
ModeFlag = 0;
while(Sure)
{
if(Up == 0)
{
while(!Up);
ModeFlag++;
}
if(Down == 0)
{
while(!Down);
ModeFlag--;
}
if(ModeFlag == 3)
{
ModeFlag = 0;
}
if(ModeFlag == 255)
{
ModeFlag = 2;
}
UI(2, ModeFlag);
}
//存储转动模式
switch(ModeFlag)
{
case 0:
{
Laout3FlagA = 1;
Laout3FlagB = 0;
Laout3FlagC = 0;
}
break;
case 1:
{
Laout3FlagA = 0;
Laout3FlagB = 1;
Laout3FlagC = 0;
}
break;
case 2:
{
Laout3FlagA = 0;
Laout3FlagB = 0;
Laout3FlagC = 1;
}
break;
}
}
Layout3:
{
//*****************************************
// Layout = 3;
Laout2Flag = 0;
//等待确认
ModeFlag = 0;
UI(3, ModeFlag);
while(!Sure);
while(Sure)
{
if(Up == 0)
{
while(!Up);
ModeFlag++;
}
if(Down == 0)
{
while(!Down);
ModeFlag--;
}
if(Back == 0)
{
while(!Back);
goto Layout2;
}
if(ModeFlag == 3)
{
ModeFlag = 0;
}
if(ModeFlag == 255)
{
ModeFlag = 2;
}
UI(3, ModeFlag);
}
//储存角度
switch(ModeFlag)
{
case 0:
{
Laout4FlagA = 1;
Laout4FlagB = 0;
Laout4FlagC = 0;
}
break;
case 1:
{
Laout4FlagA = 0;
Laout4FlagB = 1;
Laout4FlagC = 0;
}
break;
case 2:
{
Laout4FlagA = 0;
Laout4FlagB = 0;
Laout4FlagC = 1;
}
break;
}
}
Layout4:
{
//*****************************************
// Layout = 4;
Laout2Flag = 0;
//等待确认
ModeFlag = 0;
UI(4, ModeFlag);
while(!Sure);
while(Sure)
{
if(Up == 0)
{
while(!Up);
ModeFlag++;
}
if(Down == 0)
{
while(!Down);
ModeFlag--;
}
if(Back == 0)
{
while(!Back);
goto Layout3;
}
if(ModeFlag == 3)
{
ModeFlag = 0;
}
if(ModeFlag == 255)
{
ModeFlag = 2;
}
UI(4, ModeFlag);
}
//储存角度
switch(ModeFlag)
{
case 0:
{
Laout5FlagA = 1;
Laout5FlagB = 0;
Laout5FlagC = 0;
}
break;
case 1:
{
Laout5FlagA = 0;
Laout5FlagB = 1;
Laout5FlagC = 0;
}
break;
case 2:
{
Laout5FlagA = 0;
Laout5FlagB = 0;
Laout5FlagC = 1;
}
break;
}
}
Layout5:
{
//*****************************************
// Layout = 5;
Laout2Flag = 0;
StartFlag = 0;
//等待确认
ModeFlag = 0;
UI(5, ModeFlag);
while(Start)
{
if(Back == 0)
{
while(!Back);
goto Layout4;
}
}
while(!Start);
StartFlag = 1;
UI(5, ModeFlag);
}
//*****************************************
while(1)
{
if(!Back)
{
while(!Back);
goto Layout5;
}
if(!Start)
{
while(!Start);
goto Layout5;
}
Motor:
Mode = Angle = Speed = 0;
{
if(Laout3FlagA)
Mode = 1;
if(Laout3FlagB)
Mode = 2;
if(Laout3FlagC)
Mode = 3;
//
if(Laout4FlagA)
Angle = 64;
if(Laout4FlagB)
Angle = 128;
if(Laout4FlagC)
Angle = 255;
//
if(Laout5FlagA)
Speed = 15;
if(Laout5FlagB)
Speed = 10;
if(Laout5FlagC)
Speed = 1;
while(Start || Back)
{
if(!Back)
{
while(!Back);
goto Layout4;
}
//step_motor_28BYJ48_send_pulse(Buff1++, Buff2 );
if(Mode == 1)
{
Buff2 = 0;
}
if(Mode == 2)
{
Buff2 = 1;
}
if(Mode == 3)
{
if(Buff1 == Angle)
{
Buff2 = !Buff2;
Buff1 = 0;
}
}
if(Angle == Buff1)
{
Buff1 = 0;
goto Layout5;
}
if(Angle == 255)
{
while(Sure)
{
if(!Start)
{
while(!Start);
break;
}
if(!Back)
{
while(!Back);
goto Layout4;
}
}
}
if(Buff3 == 8)
{
Buff3 = 0;
Buff1++;
}
step_motor_28BYJ48_send_pulse(Buff3++, Buff2 );
if(delay_ms(Speed, 2) == 2)
{
while(!Start);
while(!Back);
goto Layout5;
}
// switch(delay_ms(Speed, 2)){
// case 2:
// {
// while(!Start);
// goto Motor;
// }break;
// case 3:
// {
// while(!Back);
// goto Layout5;
// }break;
// }
}
}
}
}
使用说明:
该代码为屎山代码,不保证移植能用,主函数与28BYJ48.C关联密切,其中按键未使用中断也能够快速跳出死循环代码段,具体实现详情看代码。