2019-06-09 17:29:45 weixin_38679924 阅读数 334
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

项目描述:
用单片机(STC89C52RC)控制两个直流电机,从而实现各种运动形式。
本例中实现功能为:前进 后退 右转 左转。
C语言程序如下:

/*------------------------------------
FileName: main.c
Function: MCU控制两个直流电机组合运动
Description: 向前 向后 右转 左转
Author: Zhang Kaizhou
Date: 2019-6-9 17:28:42
------------------------------------*/
#include "ZKZ.h"

bit dirFlag = 0; // 前进方向标志 0-向前 1-向后
bit turnFlag = 0; // 转向方向标志 0-向右 1-向左

void main(){
	while(1){
		keyScan();
		motorRun();
	}
}

/*软件延时xms函数*/
void delay(uchar xms){
	uchar i, j;
	for(i = xms; i > 0; i--)
		for(j = 110; j > 0; j--);
}

/*键盘扫描函数*/
void keyScan(){
	if(!goAhead){
		delay(5);
		if(!goAhead){
			while(!goAhead);
			dirFlag = 0;
		}
	}
	if(!goBack){
		delay(5);
		if(!goBack){
			while(!goBack);
			dirFlag = 1;
		}
	}
	if(!turnRight){
		delay(5);
		if(!turnRight){
			while(!turnRight);
			turnFlag = 0;
		}
	}
	if(!turnLeft){
		delay(5);
		if(!turnLeft){
			while(!turnLeft);
			turnFlag = 1;
		}
	}
}

/*直流电机运转函数*/
void motorRun(){
	if(!dirFlag){
		MLEn = 1;
		ML1 = 1;
		ML2 = 0;
		MREn = 1;
		MR1 = 1;
		MR2 = 0;
	}else{
		MLEn = 1;
		ML1 = 0;
		ML2 = 1;
		MREn = 1;
		MR1 = 0;
		MR2 = 1;
	}
	if(!turnFlag){
		MLEn = 1;
		MREn = 0;
	}else{
		MLEn = 0;
		MREn = 1;
	}
}
/*------------------------------------
FileName: ZKZ.h
Function: MCU控制两个直流电机组合运动
Description: 向前 向后 右转 左转
Author: Zhang Kaizhou
Date: 2019-6-9 17:28:42
------------------------------------*/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int

/*直流电机驱动模块端口定义*/
sbit MLEn = P1^4; // 左边电机驱动端口
sbit ML1 = P1^2;
sbit ML2 = P1^3;
sbit MREn = P1^5; // 右边电机驱动端口
sbit MR1 = P1^6;
sbit MR2 = P1^7;

/*独立按键端口定义*/
sbit goAhead = P3^4; // 向前
sbit goBack = P3^5; // 向后
sbit turnRight = P3^6; // 向右转
sbit turnLeft = P3^7; // 向左转

/*主模块函数声明*/
void delay(uchar xms);
void keyScan();
void motorRun();
2019-02-22 22:27:02 LuDanTongXue 阅读数 584
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

程序下载地址:
https://download.csdn.net/download/ludantongxue/10971448
对应硬件线路连接见上章:
https://blog.csdn.net/LuDanTongXue/article/details/87869557
对应单片机程序见上章:
https://blog.csdn.net/LuDanTongXue/article/details/87869806

程序界面:
上位机图片

程序参数说明:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

各个曲线段参数设置举例:
第一段S曲线加速30°:1转/秒启动,5转/秒结束
在这里插入图片描述

第二段匀速运动120°:5转/秒匀速
在这里插入图片描述

第三段S曲线减速30°:5转/秒启动,0.5转/秒结束
在这里插入图片描述

第四段S曲线反转加速30°:0.5转/秒启动,5转/秒结束
在这里插入图片描述

第五段匀速反转运动120°:5转/秒匀速
同第二段

第六段S曲线反转减速30°:5转/秒启动,1转/秒结束
在这里插入图片描述

至此各个曲线段对应的数组均已生成,将各数组复制到单片机程序即可(记得更改数组名称)。(微信ID:saskingku)

2014-04-10 15:14:57 huang20083200056 阅读数 4389
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

51单片机开发系列四

LED点阵扫描显示

象棋小子    1048272975

LED点阵屏发光亮度强,指示效果好,可以制作运动的发光图文,更容易吸引人的注意力,信息量大,随时更新,有着非常好的广告和告示效果。笔者此处就LED点阵屏动态扫描显示作一个简单的介绍。

1. LED点阵屏显示原理概述

图1-1为一种8x8的LED点阵单色行共阳模块的内部等效电路图,对于红光LED其工作正向电压约为1.8v,其持续工作的正向电流一般10ma左右,峰值电流可以更大。如下图,当某一行线为高电平而某一列线为低时,其行列交叉的点就被点亮,当某一行线为低电平时,无论列线如何,对应的这一行的点全部为暗。LED点阵屏显示就是通过一定的频率进行逐行扫描,数据端不断输入数据显示,只要扫描频率足够高,由于人眼的视觉残留效应,就可以看到完整的文字或图案信息。通常有4、8、16线扫描方式,扫描行数越少,点阵的显示亮度越好,但相应硬件数据寄存器需求也越多。


图1-1 点阵内部原理图

2. 硬件设计

微控制器的IO口均不能流过过大的电流,LED点亮时有约10ms的电流,因此LED点阵引脚不要直接接单片机IO口,应先经过一个缓冲器74HC573。单片机IO口只需很小的电流控制74HC573即可间接的控制LED点阵某一行(或某一列),而74HC573输出也能负载约10ms的电流。设置LED每点驱动电流为ID =15ma,这个电流点亮度好,并且有一定的裕度,即使电源输出电压偏高也不会烧毁LED,限流电阻值

R = (VCC- VCE – VOL – VLED) / ID

VCC为5v供电,VCE为三极管C、E间饱和电压,估为0.2v, VOL为74hc573输出低电平时电压,不同灌电流,此值不一样,估为0.2v,具体查看规格书,VLED为红光驱动电压,估为1.7v,根据上式可算出限流电阻为R = 200R。

LED点阵屏需接收逐个扫描信号,扫描到相应列(或行),对应的列(或行)数据有效,即显示这一列(或行)的信息。一般产生扫描信号是需要采用专门的译码器,如三线八线译码器74HC138,这样可硬件保证任意时刻只有一列(或一行)正在扫描,并且可减少微控制器的IO口占用。市面上的51开发板对于LED点阵屏的设计基本都没有采用译码器,直接用单片机IO产生扫描信号,为兼容软件,笔者此处也不加译码器,软件保证IO口产生相应的扫描信号。

当某一列(或一行)LED点均点亮时,电流约15max8=90ma流过这一列(或一行)公共端,微控制器IO口无法直接驱动这个电流,需加三极管驱动,由于51单片机低电平灌电流较大,因此适合采用PNP三极管作为驱动。三极管基极电流设为2ma即可让三极管饱和,最大驱动电流远大于90ma。基极偏置电阻阻值

Rb =(VCC - VEB – VOL) / IB

VCC为5v供电,VEB为三极管E、B间的导通电压0.7v,VOL为单片机IO口输出低电平时电压,可根据规格书估为0.2v,故Rb = 2k即可。


图2-1 8X8共阴LED点阵原理图

3. 驱动实现

LED点阵数据口接P0口,扫描选择线接P2口的0~7位。对于动态扫描,都是有一个扫描频率的,LED屏扫描频率下限为50HZ,低于一定的扫描频率,显示会闪烁。频率过高,则亮度较差且占用cpu资源。一般整个屏扫描一遍时间为约10ms较合适(即扫描频率100HZ),我们采用的是8线扫描方式,每一行点亮时间为1.5ms,扫描一遍为12ms。为保证这个刷新频率,通常是通过定时器来周期性进行点阵屏刷新。

显示屏显示往往会涉及到画点、画线、画图等复杂的运算,改变屏幕的信息,只需处理显存中的数据,因此对于显示屏,是需要开辟出一块内存空间作为显存使用的。8X8点阵每个点可用1 bit表示,一行1字节,显存8字节即可。由于点阵屏像素点太少,没有必要实现画线、画图等复杂操作,笔者此处仅对点阵屏画点、文字上下左右移动进行代码实现。

点阵屏动态显示功能模块文件Matrix.c内容如下:

#include"reg52.h"

#include"Matrix.h"

 

// 每个LED点需1位保存,8X8点阵需8字节显存

static unsigned char FrameBuffer[8];

 

// 外部模块通过该函数获得显存内存位置进行处理

unsigned char *MatrixGetBuffer()

{

    return FrameBuffer;

}

 

// 点阵刷新,保证以一定周期调用刷新

void MatrixScan()

{

    static unsigned char Select =0; // 记录扫描的选择线

    // 列数据输出到点阵数据端口

    MatrixOutputData(FrameBuffer[Select]);

    // 扫描信号输出到点阵扫描选择端口

    MatrixOutputSelect(Select);

    Select++; // 进入到下一行扫描

    if (Select >= 8) {

        Select= 0; // 所有行已扫描,回到第一行再次开始扫描

    }

}

 

// LED点阵屏打点函数,对(x, y)位置进行亮,灭,状态取反

voidMatrixSetPoint(unsigned char x, unsigned char y, unsigned char Operation)

{

    if (x>7 || y>7) { // 位置保证在点阵屏区域内

        return;

    }

    switch (Operation) {

    case SET: // (x, y)位置置位,灯灭

        FrameBuffer[x] |= 1<< y;

        break;

    case CLEAR: // (x, y)位置清零,灯亮

        FrameBuffer[x] &= ~(1<< y);

        break;

    case NEGATE: // (x, y)位置取反,灯状态改变

        FrameBuffer[x] ^= 1<< y;

        break;

    default:

        break;

    }

}

 

// LED点阵屏清屏,显存对应1的位置,灯灭,0相应的灯才点亮

voidMatrixClearScreen()

{

    unsigned char i;

    for (i=0; i<8; i++) {

        FrameBuffer[i] = 0xff;

    }

}

 

// 点阵平移,上下左右四个方向平移1,平移空缺位置用数据Filling填充

void MatrixMove(unsignedchar Direction, unsigned char Filling)

{

    unsigned char i;

    switch (Direction) { // 判断平衡的方向

    case MOVE_UP: // 向上平移1,每列数据第7位移到第6位,如此类推

        for (i=0; i<8; i++) {

            FrameBuffer[i] =(FrameBuffer[i]>>1) | ((Filling<<(7-i))&0x80);

        }

        break;

    case MOVE_DOWN: // 向下平移1,每列数据第0位移到第1位,如此类推

        for (i=0; i<8; i++) {

            FrameBuffer[i]= (FrameBuffer[i]<<1) | ((Filling>>i)&0x01);

        }

        break;

    case MOVE_LEFT: // 向左平移1,右一列的数据移到当前列中,如此类推

        for (i=0; i<7; i++) {

            FrameBuffer[i] = FrameBuffer[i+1];

        }

        FrameBuffer[i] = Filling;

        break;

    case MOVE_RIGHT: // 向右平移1,左一列的数据移到当前列中,如此类推

        for (i=7; i>=1; i--) {

            FrameBuffer[i] = FrameBuffer[i-1];

        }

        FrameBuffer[i] = Filling;

        break;

    default:

        break;

    }

}

 

我们在点阵屏模块头文件Matrix.h中实现模块的宏定义及接口访问宏实现,使之方便移植及修改接口配置。模块头文件同时也引出模块的接口函数,如MatrixScan()为点阵屏刷新函数,需周期性调用刷新点阵屏显示。点阵屏动态显示功能模块文件Matrix.h内容如下:

#ifndef__Matrix_H__

#define__Matrix_H__

 

#ifdef__cplusplus

extern"C" {

#endif

 

#define SET         0x1 //置1操作

#define CLEAR           0x2 // 清0操作

#define NEGATE      0x3 //取反操作

 

#defineMOVE_UP     0x1 // 向上平移1

#defineMOVE_DOWN   0x2 // 向下平移1

#defineMOVE_LEFT   0x3 // 向左平移1

#defineMOVE_RIGHT 0x4 // 向右平移1

 

// 列数据输出到P0口

#defineMatrixOutputData(Dat) {P0 = (Dat);}

// P2口输出对应列的扫描选择线,低有效

#defineMatrixOutputSelect(Select) {P2 = ~(1<<(Select));}

 

 

voidMatrixClearScreen(void);

voidMatrixMove(unsigned char Direction, unsigned char Filling);

unsigned char*MatrixGetBuffer(void);

voidMatrixScan(void);

voidMatrixSetPoint(unsigned char x, unsigned char y, unsigned char Operation);

 

#ifdef__cplusplus

}

#endif

 

#endif/*__Matrix_H__*/

 

外部应用通过引入点阵屏的模块头文件Matrix.h来实现调用点阵屏驱动函数,简单测试调用(心形在点阵屏内随机平移)实现如下:

#include"reg52.h"

#include"Matrix.h"

 

// 心形坐标数据

static unsigned charcode HeartShape[][2] = {

{3, 3}, {4, 2}, {5,3}, {5, 4}, {4, 5},

{3, 6}, {2, 5}, {1,4}, {1, 3}, {2, 2},

};

 

// 以定时器时间为计时标准,记录时间间隔

static volatileunsigned int SystemTick = 0;

 

// 定时器1.5ms中断处理进行数码管刷新

void T0_Interrupt()interrupt 1

{

    TH0 = (65536-1500) / 256;

    TL0 = (65536-1500) % 256;

    SystemTick++; // 记录时间间隔

    MatrixScan(); // 刷新数码管

}

 

void T0_Init()

{

    TMOD = 0x01; // 定时器0工作方式1

    // 1.5ms计时中断(12M)

    TH0 = (65536-1500) / 256;

    TL0 = (65536-1500) % 256;

    ET0 = 1; // 定时器T0中断允许

    EA = 1; // 总中断允许

}

 

 

void main()

{

    unsigned char *pBuffer;

    unsigned char State = 0;

    unsigned char Point;

    unsigned char Direction;

    unsigned char DataAnd;

    unsigned char i;

    // 定时器初始化

    T0_Init();

    // 获得点阵显存,以作数据处理

    pBuffer = MatrixGetBuffer();

    // 点阵屏清屏

    MatrixClearScreen();

    // 开启定时器进行计时以及点阵扫描

    TR0 = 1;

 

    Point = 0;

    while(1) {

       switch (State) {

       case 0:    //状态0为逐点打出心形

           if (SystemTick > 334) { // 500ms打心形的一个点

              SystemTick = 0;

           MatrixSetPoint(HeartShape[Point][0],HeartShape[Point][1], CLEAR);

              Point++;

              if (Point >sizeof(HeartShape)/sizeof(HeartShape[0])) {

                  State = 1; // 心形打完,进入状态1,是否到边界判断

                  Direction = TL0& 0x3; // 随机得出心形的移动方向

              }                

           }

           break;

 

       case 1:    // 状态1为心形是否移动到点阵屏边界的判断

           switch (Direction) { // 移动方向判断是否到相应方向的边界

           case 0:    // 左边界判断

              // 第一列的点有一个亮,则认为图形到了左边界

              if (pBuffer[0] !=0xff) {

                  Direction = TL0& 0x3; // 重新选择移动方向

              } else {

                  State = 2; // 未到左边界,进入状态2进行左平移

              }

              break;

           case 1:    // 右边界判断

              // 第八列的点有一个亮,则认为图形到了右边界

              if (pBuffer[7] !=0xff) {

                  Direction = TL0& 0x3; // 重新选择移动方向

              } else {

                  State = 2; // 未到右边界,进入状态2进行右平移

              }

              break;

           case 2:    // 上边界判断

              // 所有列的第一行点有一个亮,则认为图形到了上边界

              DataAnd = 0xff;

              for (i=0; i<8; i++) {

                  DataAnd &= pBuffer[i];

              }

              if (DataAnd & 0x1) {

                  State = 2; // 未到上边界,进入状态2进行上平移                           

              } else {

                  Direction = TL0& 0x3; // 重新选择移动方向

              }

              break;

           case 3:    // 下边界判断

              // 所有列的第八行点有一个亮,则认为图形到了下边界

              DataAnd = 0xff;

              for (i=0; i<8; i++) {

                  DataAnd &= pBuffer[i];

              }

              if (DataAnd & 0x80) {

                  State = 2; // 未到下边界,进入状态2进行下平移                           

              } else {

                  Direction = TL0& 0x3; // 重新选择移动方向

              }

              break;

           default:

              break;

           }

           break;

 

       case 2:    // 状态2为对点阵屏平移

           if (SystemTick < 667){  // 1s平移1次

              continue;

           }

           SystemTick = 0;

           switch (Direction) {

           case 0:    // 左平移,平移后的空缺位置灭

              MatrixMove(MOVE_LEFT, 0xff);

              break;

           case 1: // 右平移,平移后的空缺位置灭

              MatrixMove(MOVE_RIGHT,0xff);

              break;

           case 2:    // 上平移,平移后的空缺位置灭

              MatrixMove(MOVE_UP, 0xff);

              break;

           case 3:    // 下平移,平移后的空缺位置灭

              MatrixMove(MOVE_DOWN, 0xff);

              break;

           default:

              break;

           }

           State = 1; // 平移后再进入状态1进行边界检测

           break;

 

       default:

           break;

       }  

    }

}

附录:

此章节的Keil工程,包含源码,Preteus仿真,包含仿真电路,可直接查看效果,Matrix.rar。

http://pan.baidu.com/s/1dDchpYh

 

 

2011-11-25 10:34:05 xhyglh 阅读数 1215
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

        最近在做运动控制的项目,用到CC2430单片机,由于老师要求用汇编语言编写CC2430的程序,而现有的关于CC2430的例子基本上是用C语言编写的,因而我只能自己靠着手册和软件帮助自己摸索。这里写下这篇博文,希望能够对后来者有所帮助。

首先,CC2430是51内核的单片机,因而指令系统跟51单片机一样,写汇编程序的时候,用51系列单片机的指令就行(手册上面的指令系统跟51系列的是一样的)。写汇编程序的时候注意查手册看CC2430有哪些特殊的SFR,这些寄存器里面会有很多是2430专用的,说到这里,在写汇编程序时,记得用#include <ioCC2430.h>将CC2430的头文件包含到程序里,否则编译时会出错。

其次,在用IAR Embeded Workbench IDE调试和烧程序时,用汇编语言写的程序需要对IAR进行配置,这也是我纠结了很久的地方,因为没有找到这方面的书籍,我就只能看软件的纯英文帮助了。这里给大家具体介绍一下步骤:(我用的是IAR Embeded Workbench IDE for 8051 7.51A版)

1.建立一个新的工程(project):启动IAR时就会有一个Create New Project窗口提示是打开已有的工程还是创建新的工程,我们这里是建立新的工程。如果启动IAR时没有创建   工程,也可以在Project菜单下找到Create New Project。

2.设置工程属性:在workspace窗口中选择建立的工程右击->options,在General Options目录(Categories)下的Target选项卡选择Device,点击Device右边的浏览键就   可以在目录下选择自己所用的设备的*.i51文件,然后由于用的是汇编,在Library Configuration选项卡上把Library选成Custom DLIB(自定义),在下面的Library中选择\IAR   Systems\Embedded Workbench 5.3\8051\tutor\Debug\Obj\Tutor.r51作为Library; 下面设置Linker目录,在Config选项卡上把Linker command file下的Override default勾  上,在下面的目录下选择自己所用单片机对应的连接文件,如CC2430的就是$TOOLKIT_DIR$\config\lnk51ew_cc2430.xcl;前面的$TOOLKIT_DIR$代表IAR的安装目录。

  最后在Debug目录下的Driver选择成自己片子对应的驱动,如果想仿真,就选择Simulator。

3.新建文件,写入汇编码,记得声明一个公共变量__program_start作为程序进入点,代码示例如下:

#include <ioCC2430.h>

num equ 08h

public __program_start

__program_start:

org 0000h

ljmp start

start:......

这里要说明IAR的标号要顶格写,执行的语句不能顶格写!否则会出错,用伪指令equ声明时也要顶格,而且放到程序最前面。

好了,之后就是自己的程序了。

祝大家做单片机的都能够做成功。

For more information,please contact xhyglh@163.com

2019-04-14 10:43:53 LuDanTongXue 阅读数 416
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

程序功能:生成步进电机S曲线运动数组代码
程序语言:VB6.0

对应硬件线路连接见上章:
https://blog.csdn.net/LuDanTongXue/article/details/87869557
对应单片机程序见上章(PC端程序显示正常,手机端程序后半段显示不出来):
https://blog.csdn.net/LuDanTongXue/article/details/87869806
程序详细使用方法请见:
https://blog.csdn.net/LuDanTongXue/article/details/87886580
程序下载地址:
https://download.csdn.net/download/ludantongxue/11114203

程序界面如下:
步进电机S曲线+VB6
S曲线算法参照该博文:
https://blog.csdn.net/pengzhihui2012/article/details/52228822
源码如下:

Option Explicit
    Dim BuJuJiao As Double '步进电机步距角
    Dim F0 As Double '硬件频率
    Dim Nf As Double '定时器分频
    Dim v0 As Double '加速段启动速度
    Dim vt As Double '加速段最大速度
    Dim JSBuShu As Long '加速步数
    Dim JSJiaoDu As Double '加速段角度
    Dim XiFen As Double '驱动器细分
    Dim JSKuaiMan As Double '加速快慢,数值越大越慢
    Dim JSshijian As Double '加速时间
    Dim FenDuan As Double '将曲线分成梯形图
    Dim MCCiShu As Long '每个速断段脉冲次数
    Dim MCYuShu As Integer '分段不整除时最后的余数
    
    Dim Fmin As Double 'V0对应的脉冲频率
    Dim Fmax As Double 'Vt对应的脉冲频率
    Dim Fcurrent As Double '实时频率
    
    Dim DSChuZhi As Long '定时器1初值,采用溢出中断
    Dim i As Integer '计数
    Dim a0 As Long 'A0第一个脉冲的初值
    Dim DingShiQiFenPing As Integer '定时器1预分频数
    Dim ZhuanXiang As String '电机转动方向
    Public Function Max(a As Double, b As Double) As Double '求最大值
        If a < b Then
            Max = b
        ElseIf a >= b Then
            Max = a
        End If
    End Function
    Public Function ST(ax As Double, ay As Double, n As Double, m As Double) '图框初始化
    '图框初始化
        Dim Kuandanwei As Double
        Picture1.ScaleMode = 6 '设置图片框单位
        Kuandanwei = Picture1.Width / 400
        Picture1.ScaleTop = -Picture1.Height / 2 '定义坐标原点x
        Picture1.ScaleLeft = -Picture1.Width / 2 '-10 * Kuandanwei '定义坐标原点y
        Picture1.Circle (0, 0), 1000
    'X轴
        Picture1.Line (-8 * Kuandanwei, 0)-(380 * Kuandanwei, 0)
        Picture1.Line (380 * Kuandanwei, 0)-(370 * Kuandanwei, 10 * Kuandanwei)
        Picture1.Line (380 * Kuandanwei, 0)-(370 * Kuandanwei, -10 * Kuandanwei)
        Picture1.CurrentX = 380 * Kuandanwei
        Picture1.CurrentY = 0
        Picture1.Print "t"
    'Y轴
        Picture1.Line (0, 0.45 * Picture1.Height)-(0, -0.45 * Picture1.Height)
        Picture1.Line (0, -0.45 * Picture1.Height)-(-10 * Kuandanwei, -0.45 * Picture1.Height + 10 * Kuandanwei)
        Picture1.Line (0, -0.45 * Picture1.Height)-(10 * Kuandanwei, -0.45 * Picture1.Height + 10 * Kuandanwei)
        Picture1.CurrentX = 0
        Picture1.CurrentY = -0.5 * Picture1.Height
        Picture1.Print "S"
    '绘制坐标点
        Picture1.PSet (n * Kuandanwei, -ax * m / 3), vbRed
        Picture1.PSet (n * Kuandanwei, -ay * m / 3), vbBlue
        n = n + 1
        If n >= 360 Then
            n = n - 360
            Picture1.Cls
        End If
    End Function
    Public Function QuXian() '曲线图框初始化,BS步进电机步数为x轴,vt为Y轴
    '图框初始化
        
        Picture1.Cls
        Picture1.DrawWidth = 1
        Dim Bili As Double '绘图比例
        Bili = 0.7
        Dim Kuandanwei As Double 'x方向图片放缩比例
        Dim Gaodanwei As Double 'y方向图片放缩比例
        Form1.ScaleMode = 6 '设置FORM框单位
        Picture1.ScaleMode = 6 '设置图片框单位
        Kuandanwei = Picture1.Width / (JSBuShu) '根据步进电机总时间计算图片放缩比例
        Gaodanwei = Picture1.Height / Max(v0, vt)
        Picture1.ScaleTop = -Picture1.Height + 5 * Kuandanwei '定义坐标原点y
        Picture1.ScaleLeft = -5 * Kuandanwei '定义坐标原点x
        Picture1.CurrentX = 0
        Picture1.CurrentY = 0
        Picture1.Print "0"
    'X轴
        Dim x1 As Double
        Dim y1 As Double
        Dim x2 As Double
        Dim y2 As Double
        Dim x3 As Double
        Dim y3 As Double
        x1 = Bili * (JSBuShu * Kuandanwei)
        y1 = Bili * 0
        x2 = Bili * (x1 - 3) ' 5 * Kuandanwei)
        y2 = Bili * (y1 + 3) '5 * Kuandanwei)
        x3 = x2
        y3 = -y2
        Picture1.Line (0, 0)-(x1, y1)
        Picture1.Line (x1, y1)-(x2, y2)
        Picture1.Line (x1, y1)-(x3, y3)
        Picture1.CurrentX = x1
        Picture1.CurrentY = y1
        Picture1.Print Int(JSshijian * 1000) & "ms"
    'Y轴
        Dim x4 As Double
        Dim y4 As Double
        Dim x5 As Double
        Dim y5 As Double
        Dim x6 As Double
        Dim y6 As Double
        x4 = Bili * 0
        y4 = Bili * (-Max(v0, vt) * Gaodanwei)
        x5 = Bili * (x4 - 3) '-5* Kuandanwei)
        y5 = Bili * (y4 - 3) '-5* Kuandanwei)
        x6 = -x5
        y6 = y5
        Picture1.Line (0, 0)-(x4, y4)
        Picture1.Line (x4, y4)-(x5, y5)
        Picture1.Line (x4, y4)-(x6, y6)
        Picture1.CurrentX = x4 + Kuandanwei
        Picture1.CurrentY = y4
        Picture1.Print Max(v0, vt) & "r/s"
        
    '绘制坐标点
        Picture1.DrawWidth = 5
        Dim i As Integer
        For i = 1 To JSBuShu
            Picture1.PSet (Bili * i * Kuandanwei, Bili * -Gaodanwei * (v0 + (vt - v0) / (1 + Exp(-JSKuaiMan * (i - JSBuShu / 2) / (JSBuShu / 2))))), vbRed
        Next
    End Function
    Private Sub Command1_Click()
    BuJuJiao = Text2.Text
    F0 = Text3.Text
    Nf = Text4.Text
    v0 = Text5.Text
    vt = Text6.Text
    JSJiaoDu = Text7.Text
    XiFen = Text8.Text
    JSKuaiMan = Text9.Text
    If Text4.Text = 1 Then
    DingShiQiFenPing = 1
    ElseIf Text4.Text = 8 Then
    DingShiQiFenPing = 2
    ElseIf Text4.Text = 64 Then
    DingShiQiFenPing = 3
    ElseIf Text4.Text = 256 Then
    DingShiQiFenPing = 4
    ElseIf Text4.Text = 1024 Then
    DingShiQiFenPing = 5
    End If
    
    JSBuShu = JSJiaoDu / (BuJuJiao / XiFen)
    Fmin = v0 * 360 / (BuJuJiao / XiFen)
    Fmax = vt * 360 / (BuJuJiao / XiFen)
    
    Text1 = ""
    JSshijian = 0
    
    ''''''''''''''''''''''''''''加速段A0数组生成'''''''''''
        For i = 1 To JSBuShu
            Fcurrent = Fmin + (Fmax - Fmin) / (1 + Exp(-JSKuaiMan * (i - JSBuShu / 2) / (JSBuShu / 2)))
            DSChuZhi = 65535 - 1 / (Fcurrent * 2) * F0 / Nf '16位定时器
            If i <> JSBuShu Then
                Text1 = Text1 & "0X" & Hex(DSChuZhi) & ","
            Else
                Text1 = Text1 & "0X" & Hex(DSChuZhi)
            End If
            JSshijian = JSshijian + 1 / Fcurrent
        Next
    
    a0 = 65535 - 1 / ((Fmin + (Fmax - Fmin) / (1 + Exp(-JSKuaiMan * (1 - JSBuShu / 2) / (JSBuShu / 2)))) * 2) * F0 / Nf
    Text10 = JSBuShu
    Text12 = JSshijian * 1000
    Text1 = "A[" & JSBuShu & "]={" & Text1 & "};" & vbCrLf & vbCrLf
    
    ''''''''''''''''''''''''''''
    Text11.Text = (2 * F0 * BuJuJiao) / (65535 * Nf * 360 * XiFen) '计算最小启动速度
    
    QuXian '绘制速度曲线
    End Sub

微信ID:saskingku

没有更多推荐了,返回首页