实验四 步进电机控制

一、实验目的

掌握步进电机的驱动原理和控制方式
掌握使用CH451进行数码管显示的原理和方法
 

二、实验设备

*单片机实验箱
    *步进电机模块
    *CH451显示模块
*Keil开发系统
 

三、实验原理

步进电机

140104ba9830a03e8d13467f35f9503e.png 4d9d72e229ec29c56e70ac81c963571b.png
d481270b7c3677ee7d3f9586fb64fd91.png
a9b33687a37f74b7dec516c1fcd25441.png
5ac807afff1d9e7e39d0911d4ee55574.png

 

CH451

CH451 的操作命令均为 12 位,下表列出了 CH451 的各个操作命令所对应的 12 位串行数据。其中, 标注为 x 的位表示该位可以是任意值;标有名称的位表示该位在 CH451 芯片内部具有相应的寄存器, 其数据根据操作命令的不同而变化。
3f086f745891952c456bf341067ef26d.png
*设定系统参数:0100000[CKHF][DPLR][WDOG][KEYB][DISP]B
设定系统参数命令用于设定 CH451 的系统级参数:输出高频时钟 CKHF(选择快速闪烁),字驱动输出极性 DPLR(选择 DIG 字驱动输出极性:0=低电平有效;1=高电平有效),看门狗使能 WDOG,键盘扫描使能 KEYB,显示驱动使能 DISP。各个参数均通过 1 位数据控制,将相应的数据位置为 1 则启用该功能,否则关闭该功能(默认值)。例如,命令数据 010000000011B 表示选择低频时钟、关闭看门狗的功能、启用键盘扫描的功能、启用显示扫描驱动的功能、字驱动为低电平有效。
*设定显示参数:0101[MODE][LIMIT][INTENSITY]B
设定显示参数命令用于设定 CH451 的显示参数:译码方式 MODE,扫描极限 LIMIT,显示亮度 INTENSITY。译码方式 MODE 通过 1 位数据控制,置 1 时选择 BCD 译码方式,置 0 时选择不译码方式(默认值)。扫描极限 LIMIT 通过 3 位数据控制,数据 001B~111B 和 000B 分别设定扫描极限为 1~7 和 8 (默认值)。显示亮度 INTENSITY 通过 4 位数据控制,数据 0001B~1111B 和 0000B 分别设定显示驱动占空比为 1/16~15/16 和 16/16(默认值)。例如,命令数据 010101110000B 表示选择不译码方式、 扫描极限为 7、显示驱动占空比为 16/16;命令数据 010110001010B 表示选择 BCD 译码方式、扫描极限为 8、显示驱动占空比为 10/16。
*加载字数据:1[DIG_ADDR][DIG_DATA]B
加载字数据命令用于将字数据 DIG_DATA 写入 DIG_ADDR 指定地址的数据寄存器中。DIG_ADDR 通过 3 位数据指定数据寄存器的地址,数据 000B~111B 分别指定地址 0~7,对应于 DIG0~DIG7 引脚驱动的 8 个数码管。DIG_DATA 是 8 位的字数据。例如,命令数据 100001111001B 表示将字数据 79H写入第 1 个数据寄存器,如果是不译码方式,则 DIG0 引脚驱动的数码管将显示 E;命令数据110010001000B 表示将字数据 88H 写入第 5 个数据寄存器,如果是 BCD 译码方式,则 DIG4 引脚驱动的数码管将显示 8.。
 

四、实验内容

使用C51编写程序,控制步进电机转动,并将状态显示到CH451控制的数码管上,具体要求如下:
*在SWITCH区使用两个开关,当开关1为0时,电机不运行,否则电机按一定速度旋转;当开关2为0时,电机顺时针旋转;当开关2为1时,电机逆时针旋转。
*同时在数码管的最左边显示转动方向的标识,右边使用十进制显示已转动的步数(顺时针每转一步加1,逆时针减1)。
 

五、实验步骤

1. 设计电路连接方案,进行设备连线
建议的接线如下: P0接口中的IO1--IO4分别连接到步进电机模块的ORANGE、YELLOW、PINK、BLUE,并连到LAMP区的发光管上。 连接CH451建议使用P1的引脚,不要和P0共用。
参考连接图中,CH451模块的DIN连接SDA(对应C51芯片管脚P1.1),DCLK连接SCL(对应C51芯片管脚P1.2),LOAD连接PWM0(对应C51芯片管脚P1.3)。SWITCH区中,一个开关连接SPICLK(对应C51芯片管脚P1.6),另一个开关连接到SPISTE(对应C51芯片管脚P1.7)。
096fa7470e2bdbe1a7c2ed3b4774dda7.png
参考连接图
2. 编程和调试
参考代码:
//ch451.h
#ifndef __CH451_H__
#define __CH451_H__
#include<reg51.h>
#define CH451_RESET     0x0201                //复位
#define CH451_LEFTMOV   0x0300		            //设置移动方式-作移
#define CH451_LEFTCYC   0x0301		            //设置移动方式-左循
#define CH451_RIGHTMOV  0x0302		            //设置移动方式-右移
#define CH451_RIGHTCYC  0x0303		            //设置移动方式-右循	
#define CH451_SYSOFF    0x0400                //关显示、键盘、看门狗
#define CH451_SYSON1    0x0401                //开显示
#define CH451_SYSON2    0x0403                //开显示、键盘
#define CH451_SYSON3    0x0407                //开显示、键盘、看门狗功能
#define CH451_DSP       0x0500                //设置默认显示方式
#define CH451_BCD       0x0580                //设置BCD译码方式
#define CH451_TWINKLE   0x0600		            //设置闪烁控制
#define CH451_DIG0      0x0800                //数码管位0显示
#define CH451_DIG1      0x0900		            //数码管位1显示 
#define CH451_DIG2      0x0a00		            //数码管位2显示
#define CH451_DIG3      0x0b00		            //数码管位3显示
#define CH451_DIG4      0x0c00		            //数码管位4显示
#define CH451_DIG5      0x0d00	              //数码管位5显示	
#define CH451_DIG6      0x0e00	              //数码管位6显示	
#define CH451_DIG7      0x0f00		            //数码管位7显示
 
#define  USE_KEY  1//如果使用键盘中断请定义
//以下四句:加extern后,错误为:syntax error near sbit,所以不把它作为外部变量且必须赋值
sbit ch451_load = P1^3;  //串行命令加载,上升延激活
sbit ch451_din = P1^1;   // 串行数据输出,接CH451的数据输入
sbit ch451_dclk = P1^2;  //串行数据时钟上升延激活
sbit ch451_dout = P3^2;  //INT0对应P3.2,键盘中断和键值数据输入,接CH451的数据输出
extern unsigned char  ch451_key;// 全局变量,存放键盘中断中读取的键值
void ch451_init();
void ch451_write(unsigned int command);
unsigned char ch451_read();
void ch451_inter();

#endif 
//ch451.c
#include "ch451.h"

//初始化子程序

void ch451_init()
{
  ch451_din=0;                                     //先低后高,选择4线输入
  ch451_din=1;
#ifdef USE_KEY
  IT1=0;			                  //设置下降沿触发
  IE1=0;			                  //清中断标志
  PX1=0;			                  //设置低优先级
  EX1=1;			                  //开中断
#endif

}
//*****************************************************

 //输出命令子程序
 //定义一无符号整型变量存储12字节的命令字。
 void ch451_write(unsigned int command)
{
  unsigned char i;
#ifdef USE_KEY
  EX1=0;			                 //禁止键盘中断
#endif	
  ch451_load=0;                                  //命令开始       
  for(i=0;i<12;i++){                             //送入12位数据,低位在前
    ch451_din=command&1;				
    ch451_dclk=0;
    command>>=1;
    ch451_dclk=1;                               //上升沿有效
  }
  ch451_load=1;                                 //加载数据
#ifdef USE_KEY
  EX1=1;
#endif
}

#ifdef USE_KEY

//*************************************************
//输入命令子程序,MCU从451读一字节
 unsigned char ch451_read()
{
  unsigned char i;
  unsigned char command,keycode;		//定义命令字,和数据存储器
  EX1=0;			               //关中段	
  command=0x07;			               //输入读451命令字	
  ch451_load=0;
  for(i=0;i<4;i++){
 
    ch451_din=command&1;		      //送入最低位
    ch451_dclk=0;			 
    command>>=1;			      //往右移一位
    ch451_dclk=1;			      //产生时钟上升沿锁通知CH451输入位数据
 }
  ch451_load=1;				      //产生加载上升沿通知CH451处理命令数据
  keycode=0;				      //清除keycode
  for(i=0;i<7;i++){
    keycode<<=1;			      //数据移入keycode,高位在前,低位在后
    keycode|=ch451_dout;		      //从高到低读入451的数据
    ch451_dclk=0;			      //产生时钟下升沿通知CH451输出下一位
    ch451_dclk=1;
 }
  IE1=0;				      //清中断标志
  EX1=1;
  return(keycode);			     //反回键值
}
//*************************************************
//中断子程序  使用中断0,寄存器组1

void ch451_inter() interrupt 0//外部中断0(INT0)对应interrupt 0 ,外部中断1(INT1)对应interrupt 2 
{
  unsigned char i;			      //定义循环变量
  unsigned char command,keycode;	      //定义控制字寄存器,和中间变量定时器
  command=0x07;				      //读取键值命令的高4位0111B
  ch451_load=0;				      //命令开始
  for(i=0;i<4;i++){
    ch451_din=command&1;		     //低位在前,高位在后
    ch451_dclk=0;
    command>>=1;			     //右移一位
    ch451_dclk=1;			     //产生时钟上升沿锁通知CH451输入位数据
 }
  ch451_load=1;				     //产生加载上升沿通知CH451处理命令数据
  keycode=0;				     //清除keycode
  for(i=0;i<7;i++){
    keycode<<=1;			     //数据作移一位,高位在前,低位在后
    keycode|=ch451_dout;		     //从高到低读入451的数据
    ch451_dclk=0;			     //产生时钟下升沿通知CH451输出下一位
    ch451_dclk=1;
 }
  ch451_key=keycode;			    //保存上次的键值,读取的按键代码与按键键值的关系需要测试
  IE0=0;				    //清中断标志
}

//***********************************************

#endif 
//main.c
#include <reg51.h>
#include "ch451.h"
unsigned int ch451_dig[8]={CH451_DIG0,CH451_DIG1,CH451_DIG2,CH451_DIG3,CH451_DIG4,CH451_DIG5,CH451_DIG6,CH451_DIG7};
sbit switch1 = P1^6;  // 开关1连接到P1.6,SPICLK
sbit switch2 = P1^7;  // 开关2连接到P1.7,SPISTE

sbit orange = P0^1;  // 步进电机ORANGE连接到P0.1
sbit yellow = P0^2;  // 步进电机YELLOW连接到P0.2
sbit pink = P0^3;    // 步进电机PINK连接到P0.3
sbit blue = P0^4;    // 步进电机BLUE连接到P0.4

unsigned char stepsClockwise[] = {0x06, 0x07, 0x04, 0x0b, 0x09, 0x0d, 0x0c, 0x0e};//顺时针
unsigned char stepsCounterclockwise[] = {0x0e, 0x0c, 0x0d, 0x09, 0x0b, 0x04, 0x07, 0x06};//逆时针

int stepCount = 0;  // 步数计数

//ch451展示步数
void display(int cnt){
    unsigned char a[5];
    unsigned char i;
    if(cnt<0){
	    ch451_write(CH451_DIG5|0X12); //DIG5显示负号
        cnt=-cnt;
	}else{
	    ch451_write(CH451_DIG5|0X10); //DIG5显示空格
	}
	//DIG0-DIG5展示数字
    for(i=0;i<5;i++){
	    a[i]=cnt%10;
        ch451_write(ch451_dig[i]|a[i]);
        cnt=cnt/10;
    }
}

void delay(int ms) {
    int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 110; j++);
    }
}

void rotateMotor(int clockwise) {
    int i;
    unsigned char* steps;
    if (clockwise) {// 方向为顺时针
	    steps = stepsClockwise;
        stepCount++;
        display(stepCount);
    } else {// 方向为逆时针
        steps = stepsCounterclockwise;
        stepCount--;
        display(stepCount);
    }
    for (i = 0; i < 8; i++) {
        P0 = steps[i];
        delay(10); 
    }
}

void main() {
    ch451_init();
	ch451_write(0x403);
    ch451_write(0x580);
	ch451_write(CH451_DIG5|0X10);  //DIG5显示空格   
    ch451_write(CH451_DIG6|0X10);  //DIG6显示空格     
    while (1) {
        if (switch1 == 0) {// 开关1为0,电机不运行
            P0 = 0x00;  // 停止步进电机
        } else {// 开关1为1,电机按一定速度旋转
            if (switch2 == 0) {
                // 开关2为0,电机顺时针旋转
				ch451_write(CH451_DIG7|0X14); //显示顺时针符号
                rotateMotor(1);
            } else {
                // 开关2为1,电机逆时针旋转
                ch451_write(CH451_DIG7|0X15); //显示逆时针符号
                rotateMotor(0);
            }
        }
    }
}


*代码说明:

ch451_write(0x403);表示向CH451写命令字010000000011B,表示选择低频时钟、关闭看门狗的功能、启用键盘扫描的功能、启用显示扫描驱动的功能、字驱动为低电平有效。
ch451_write(0x580);表示向CH451写命令字010110000000B,表示选择 BCD 译码方式、扫描极限为 8、显示驱动占空比为 16/16。
ch451_write(CH451_DIG5|0X10);  表示DIG5显示空格

ch451_write(CH451_DIG5|0X12); 表示DIG5显示负号

ch451_write(CH451_DIG7|0X14); 表示DIG7显示顺时针符号

ch451_write(CH451_DIG7|0X15); 表示DIG7显示逆时针符号

以上四条语句是采用BCD译码方式使相应数码管显示特定字符,字符对应的5位数据(数据寄存器中字数据的位 4~位 0)参照下表:

ac52e235f1dcadcdef19d6f7a23d7024.png
 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值