基于51单片机的步进电机控制(电机正转、电机反转、电机停止、电机正转加速、电机正转减速,电机反转加速、电机反转减速、汉字显示12864)原理图、流程图、物料清单、仿真图、源代码
基于51单片机的步进电机控制(12864)
单片机控制步进电机
使用LCD显示汉字,不同工作模式对应不同内容:电机正转、电机反转、电机停止、电机正转加速、电机正转减速,电机反转加速、电机反转减速。
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit AA=P3^4;//电机
sbit BB=P3^5;
sbit CC=P3^6;
sbit DD=P3^7;
sbit k1=P1^0;//按钮
sbit k2=P1^1;
sbit k3=P1^2;
sbit k4=P1^3;
sbit k5=P1^4;
sbit RS =P0^5;//显示器引脚
sbit RW =P0^6;
sbit EN =P0^7;
sbit CS1=P0^3;
sbit CS2=P0^4;
uchar start=0;//开启
uchar speed=10,time=0;//速度
uchar fang=0,flag=0;//方向
uchar code str0[] =
{0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00,
0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00};/*"电",3*/
uchar code str1[] =
{0x10,0x10,0xD0,0xFF,0x90,0x10,0x00,0xFE,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,
0x04,0x03,0x00,0xFF,0x00,0x83,0x60,0x1F,0x00,0x00,0x00,0x3F,0x40,0x40,0x78,0x00};/*"机",4*/
uchar code str2[] =
{0x00,0x02,0x02,0xC2,0x02,0x02,0x02,0xFE,0x82,0x82,0x82,0x82,0x82,0x02,0x00,0x00,
0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00};/*"正",5*/
uchar code str3[] =
{0x00,0x00,0xFC,0x24,0x24,0xE4,0x24,0x24,0x22,0x22,0x22,0xA3,0x62,0x00,0x00,0x00,
0x40,0x30,0x8F,0x80,0x40,0x40,0x23,0x14,0x08,0x14,0x22,0x41,0x40,0x80,0x80,0x00};/*"反",6*/
uchar code str4[] =
{0xC8,0xB8,0x8F,0xE8,0x88,0x88,0x40,0x48,0x48,0xE8,0x5F,0x48,0x48,0x48,0x40,0x00,
0x08,0x18,0x08,0xFF,0x04,0x04,0x00,0x02,0x0B,0x12,0x22,0xD2,0x0A,0x06,0x00,0x00};/*"转",7*/
uchar code str5[] =
{0x10,0x10,0x10,0xFF,0x10,0x10,0xF0,0x00,0x00,0xF8,0x08,0x08,0x08,0xF8,0x00,0x00,
0x80,0x40,0x30,0x0F,0x40,0x80,0x7F,0x00,0x00,0x7F,0x20,0x20,0x20,0x7F,0x00,0x00};/*"加",8*/
uchar code str6[] =
{0x00,0x02,0x0C,0xC0,0x00,0xF8,0x08,0x48,0x48,0x48,0x08,0xFF,0x08,0x09,0x8A,0x00,
0x02,0x02,0x7F,0x80,0x40,0x3F,0x00,0x1E,0x92,0x5E,0x20,0x17,0x38,0x46,0xF1,0x00};/*"减",9*/
uchar code str7[] =
{0x40,0x40,0x42,0xCC,0x00,0x04,0xF4,0x94,0x94,0xFF,0x94,0x94,0xF4,0x04,0x00,0x00,
0x00,0x40,0x20,0x1F,0x20,0x48,0x44,0x42,0x41,0x5F,0x41,0x42,0x44,0x48,0x40,0x00};/*"速",10*/
uchar code str8[] =
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//空
uchar code str9[] =
{0x80,0x60,0xF8,0x07,0x00,0x04,0x74,0x54,0x55,0x56,0x54,0x54,0x74,0x04,0x00,0x00,
0x00,0x00,0xFF,0x00,0x03,0x01,0x05,0x45,0x85,0x7D,0x05,0x05,0x05,0x01,0x03,0x00};/*"停",0*/
uchar code str10[] =
{0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00,
0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00};/*"止",1*/
/************** 判忙函数 **************/
void lcd_r_busy()
{
P2 = 0x00;
RS = 0;
RW = 1;
EN = 1;
while (P2 & 0x80); // 最高位DB7==1,则busy
EN = 0;
}
/************* LCD写命令函数 *************/
void lcd_w_cmd(uchar value)
{
lcd_r_busy(); // 每次读写操作前都要忙判断
RS = 0;
RW = 0;
P2 = value;
EN = 1; // 下降沿锁存写入的数据/命令
_nop_();
_nop_();
EN = 0;
}
/************* LCD写数据 **************/
void lcd_w_data(uchar value)
{
lcd_r_busy();
RS = 1;
RW = 0;
P2 = value;
EN = 1; // 下降沿锁存写入的数据/命令
_nop_();
_nop_();
EN = 0;
}
/***************页设置:显示在哪一页******************/
/*************共8页,一页是8行像素点*****************/
void lcd_set_page(uchar page)
{
page = 0xb8 | page; // 页的首地址为0xb8:page或上0xb8=选择page页
lcd_w_cmd(page);
}
/************行设置:起始在哪一行********************/
/**********每页共8行,一般从0行开始******************/
void lcd_set_line(uchar sline)
{
sline = 0xc0 | sline; // 起始行地址为0xc0:sline或上0xc0=选择行
lcd_w_cmd(sline);
}
/*************起始列设置+像素点选择********************/
/***********每半片共64列,列值不得大于63***************/
void lcd_set_column(uchar column)
{
column = 0x3f & column; // 与上列的最大值63:0x3f 可得所选列值<63
column = 0x40 | column; // 得列的首地址
lcd_w_cmd(column);
}
/*************设置显示的开关********************/
/**********0为关闭显示;1为 开启显示************/
void lcd_on_off(uchar set)
{
set = 0x3e | set; // =0011 111x----0x3e为关闭显示;0x3f为开启显示
lcd_w_cmd(set);
}
/*************选择左右半屏显示********************/
/********0-全屏显示;1-左;2-右********************/
/************cs片选端低电平有效********************/
void lcd_cs(uchar sel)
{
switch (sel)
{
case 0:CS1 = 0; CS2 = 0; break; // 全屏显示
case 1:CS1 = 0; CS2 = 1; break; // 左显示
case 2:CS1 = 1; CS2 = 0; break; // 右显示
default:break;
}
}
/*************清屏:选择半屏********************/
/********0-清全屏;1-清左;2-清右***************/
void lcd_clear(uchar sel)
{
uchar i, j;
lcd_cs(sel);
for (i = 0; i < 8; i++)
{
lcd_set_page(i);
lcd_set_column(0);
for (j = 0; j < 64; j++)
{
lcd_w_data(0x00); // 每列全部写0,列地址指针自动+1
}
}
}
/****************LCD的初始化********************/
void lcd_init()
{
lcd_r_busy();
lcd_cs(0);
lcd_on_off(0); // 关显示
lcd_cs(0);
lcd_on_off(1); // 开显示
lcd_cs(0);
lcd_clear(0); // 清全屏
lcd_set_line(0); // 起始行设为0
}
/****************16*16像素的汉字显示程序********************/
//CS左右半屏1,2
//page 页
void display(uchar cs, uchar page, uchar column, uchar* p)
{
uchar i;
lcd_cs(cs);
lcd_set_page(page); // 要在本页写上半个汉字8*16
lcd_set_column(column); // 选择起始列
for (i = 0; i < 16; i++)
{
lcd_w_data(p[i]); // 按列输入上半个汉字的编码8*16
}
lcd_set_page(page + 1); // 要在下一页写下半个汉字8*16
lcd_set_column(column); // 选择起始列
for (i = 0; i < 16; i++)
{
lcd_w_data(p[i + 16]); // 按列输入下半个汉字的编码8*16
}
}
void state1()//状态1,电机正转
{
lcd_set_line(0); // 设置起始行为0
display(1, 2, 1 * 16, str8);
display(1, 2, 2 * 16, str0);
display(1, 2, 3 * 16, str1);
display(2, 2, 4 * 16, str2);
display(2, 2, 5 * 16, str4);
display(2, 2, 6 * 16, str8);
}
void state2()//状态2,电机反转
{
lcd_set_line(0); // 设置起始行为0
display(1, 2, 1 * 16, str8);
display(1, 2, 2 * 16, str0);
display(1, 2, 3 * 16, str1);
display(2, 2, 4 * 16, str3);
display(2, 2, 5 * 16, str4);
display(2, 2, 6 * 16, str8);
}
void state3()//状态3,电机停止
{
lcd_set_line(0); // 设置起始行为0
display(1, 2, 1 * 16, str8);
display(1, 2, 2 * 16, str0);
display(1, 2, 3 * 16, str1);
display(2, 2, 4 * 16, str9);
display(2, 2, 5 * 16, str10);
display(2, 2, 6 * 16, str8);
}
void state4()//状态4,电机正转加速
{
lcd_set_line(0); // 设置起始行为0
display(1, 2, 1 * 16, str0);
display(1, 2, 2 * 16, str1);
display(1, 2, 3 * 16, str2);
display(2, 2, 4 * 16, str4);
display(2, 2, 5 * 16, str5);
display(2, 2, 6 * 16, str7);
}
void state5()//状态5,电机反转加速
{
lcd_set_line(0); // 设置起始行为0
display(1, 2, 1 * 16, str0);
display(1, 2, 2 * 16, str1);
display(1, 2, 3 * 16, str3);
display(2, 2, 4 * 16, str4);
display(2, 2, 5 * 16, str5);
display(2, 2, 6 * 16, str7);
}
void state6()//状态6,电机正转减速
{
lcd_set_line(0); // 设置起始行为0
display(1, 2, 1 * 16, str0);
display(1, 2, 2 * 16, str1);
display(1, 2, 3 * 16, str2);
display(2, 2, 4 * 16, str4);
display(2, 2, 5 * 16, str6);
display(2, 2, 6 * 16, str7);
}
void state7()//状态7,电机反转减速
{
lcd_set_line(0); // 设置起始行为0
display(1, 2, 1 * 16, str0);
display(1, 2, 2 * 16, str1);
display(1, 2, 3 * 16, str3);
display(2, 2, 4 * 16, str4);
display(2, 2, 5 * 16, str6);
display(2, 2, 6 * 16, str7);
}
void main()
{
//设置INT1
IT1=1;//跳变沿出发方式(下降沿)
EX1=1;//打开INT1的中断允许。
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0XD8; //10ms
TL0=0XF0;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
P0=0xfe;
lcd_init(); // 初始化
lcd_clear(0); // 清屏
lcd_set_line(0); // 设置起始行为0
state3();
while (1)
{
}
}
void Timer0() interrupt 1//定时器中断
{
if(start)//开始
{
if(time<speed)
time++;
else
{
time=0;
if(fang==0)//正转
{
switch(flag)
{
case 0:BB=1;break;
case 1:AA=0;break;
case 2:CC=1;break;
case 3:BB=0;break;
case 4:DD=1;break;
case 5:CC=0;break;
case 6:AA=1;break;
case 7:DD=0;
}
if(flag<7)
flag++;
else
flag=0;
}
else//反转
{
switch(flag)
{
case 0:DD=1;break;
case 1:AA=0;break;
case 2:CC=1;break;
case 3:DD=0;break;
case 4:BB=1;break;
case 5:CC=0;break;
case 6:AA=1;break;
case 7:BB=0;
}
if(flag<7)
flag++;
else
flag=0;
}
}
}
TH0=0XD8; //10ms
TL0=0XF0;
}
void Int1() interrupt 2 //外部中断1的中断函数
{
TR0=0;
if(!k1)//正转
{
start=1;
fang=0;
state1();//显示状态
}
if(!k2)//停止
{
start=0;
state3();//显示状态
}
if(!k3)//反转
{
start=1;
fang=1;
state2();//显示状态
}
if(!k4)//加速
{
start=1;
if(speed>5)
speed--;
if(fang)
state5();//显示状态
else
state4();//显示状态
}
if(!k5)//减速
{
start=1;
if(speed<40)
speed++;
if(fang)
state7();//显示状态
else
state6();//显示状态
}
TR0=1;
}