就不说怎么组装了吧,一把辛酸泪。说程序,因为这有两把辛酸泪……一把给下位机的C代码一把为了VB.NET的图像处理……不过就上上一篇说的,它们可以正确运行了,并且今天克服了Arduino上电过程中步进电机没事瞎转悠的困难。

其实上位机和下位机的功能界定非常清晰:上位机解释图片为指令,下位机解释上位机指令为硬件动作——就俩步进和一个激光器。当然,如果有读卡器模块,完全可以把命令写成文件实现脱机打印。总体框架就是这样,那么下位机要实现的具体功能有哪些呢?

1、串口通讯:接收指令和发送请求。既然是通讯,校验是少不了的,我写了一点CRC8校验。

2、控制步进电机:这方面的文章很多,够学一会的。我修改了Stepper库,当然只是用它的大部分框架,这个框架么……哎

3、控制激光器:激光器这里调节亮度的时候使用了PWM,正好手头有若干L298N…………

4、X,Y轴限位:用外部中断来控制,需要注意的是,我用的Uno么有那么多中断口可以挥霍,所以全部的微动开关都是连接在一起的。我是并联的,所以未按下时应该时断开的;如果串联,那么未按下时应该是闭合的。

5、软复位功能:可以用软件控制Arduino重启,方法也搜了一些,有些看着高大上的却然并卵。所以用的看门狗。

大体就是这样吧,下面看一下部分代码:

void setup() {
Serial.begin(115200); AboveStepper.setSpeed(aSpeed); //设置上步进电机每分钟转数
BelowStepper.setSpeed(bSpeed); //设置下步进电机每分钟转数 AboveStepper.SetEnabled(true); //初始化完成完成其他初始化之后再开启步进电机
BelowStepper.SetEnabled(true); attachInterrupt(InterruptIntID, Interrupt, CHANGE); //高电平
DoxGoto0();
DoyGoto0(); while (!Serial) {}
Serial.println(r_Ready);
}

一、初始化函数:这个函数在板子重启后被运行一次。

a、首先初始化串口,需要注意的是,这个波特率在你的板子所支持的范围内,越高越好——速度差异很大的。在这种频繁收发数据的应用中,9600明显感觉非常慢。

b、设置步进电机的转速,然后开启步进电机。

c、附加外部中断,利用微动开关使x,y轴归零。需要注意的是,如果你的板子加电时有扰动,那么应该在附加外部中断之前使x,y轴倒退一定的安全距离。

d、等待串口就绪,发送准备就绪信号。

二、外部中断函数

void Interrupt() {
if (digitalRead(InterruptIntPin) == HIGH) {
CurState = 0;
}
else {
if (CurState == 0) { //发生不应有的中断
CurState = -1;
AboveStepper.steps_left = 0l; //清理各个电机剩余步数
BelowStepper.steps_left = 0l;
digitalWrite(LaserPin, 0); //关闭激光器
}
else if (CurState == c_xGoto0) {
CurState = -c_xGoto0;
}
else if (CurState == c_yGoto0) {
CurState = -c_yGoto0;
}
else if (CurState == c_lzGoto0) {
CurState = -c_lzGoto0;
}
else if (CurState == c_rzGoto0) {
CurState = -c_rzGoto0;
} }
}

  这个函数也非常清晰,当微动闭合时,证明某一个开关被触动,如果是程序控制的,那么更改当前状态以便退出正在运行的循环;如果是意外中断,那么关闭相应的硬件避免损坏。这个函数应该尽可能短,它在极为有限的时间内就应调用完成,所以一般采用全局变量进行控制,这里就是使用CurState。

三、运行时的“循环”函数——Loop

这个函数并不是一次运行的,它是被系统不断的反复调用。我的代码如下:

void loop() {
if (CurState == 0 || CurState == State_Stop) { //非中断状态
if (Serial.available()>=msgBuffSize) {
msgLen = Serial.readBytes(msgBuff, msgBuffSize); //读取消息
if (msgBuff[msgBuffSize - 1] == cal_crc_table(msgBuff)) {
CommandParsing(msgBuff); //处理消息
if (CurState != State_Stop) {
RequestData(); //请求数据
}
}else{
RerequestData();
}
}
}
}

  这里添加了暂停的功能,所以看起来可能有点乱。首先在正常状态或暂停状态下,尝试读取串口获取指令,当获取到数据后,进行Crc8验证,若未通过则重新申请数据;否则对命令进行解释并执行,随后当不处于暂停状态时再次申请指令。

命令解释器就不详细说了,无非是一个大的分支结构。这里简要说一下这个AxiDraw用的双电机结构是怎么移动x,y轴的,其实很简单,你装起来之后用手转转就知道了。两个电机不同时针方向运行控制一轴,两个电机同方向运行控制另一轴。我的是这样的(Y+,Y-代表Y轴正方向和负方向上的电机):

a、Y+顺时针Y-逆时针→X轴向负方向运行

b、Y+顺时针Y-顺时针→Y轴向负方向运行

所以代码是这样的:

void DoxMove(long dBeat) {
int dir, step;
if (dBeat < 0) {
dir = -1;
step = -dBeat;
}else{
dir = 1;
step = dBeat;
}
for (int i = 0; i < step; i++) {
AboveStepper.step(dir);
BelowStepper.step(-dir);
}
} void DoyMove(long dBeat) {
int dir, step;
if (dBeat < 0) {
dir = -1;
step = -dBeat;
}else{
dir = 1;
step = dBeat;
}
for (int i = 0; i < step; i++) {
AboveStepper.step(dir);
BelowStepper.step(dir);
}
} void Do13Move(long dBeat) {
AboveStepper.step(dBeat);
} void Do24Move(long dBeat) {
BelowStepper.step(dBeat);
}

  当然,完全可以不用For循环。但是走斜线的时候感官上好像“绕远”,看着有点矬。然后是激光器控制,直接用PWM就可以了。最后,是软重启,用看门狗最通用,很稳定,无接线:

#include <avr/wdt.h>

void Soft_ReStart(){
do{
wdt_enable(WDTO_15MS); //开启看门狗计时器,然后不喂狗……就重启了。
for (;;){ }
} while (0);
}

  就是这……

"废物利用"也抄袭——“完全”DIY"绘图仪"<二、下位机程序设计>的更多相关文章

  1. "废物利用"也抄袭——“完全”DIY"绘图仪"<三、上位机程序设计>

    上位机的程序主要是解析图片和生成较好的代码,现在实现的功能有灰度打印,二值打印,轮廓打印,骨骼打印.当然,必不可少的是打印大小的控制.测试了一些图片,总体来说,打印速度依次加快,因为打印的内容依次减少 ...

  2. "废物利用"也抄袭——“完全”DIY"绘图仪"<一、准备工作>

    上一个光驱造已经解体若干天了,因为事情很多arduino也不太熟悉,直到今天才做出了一个可以用的样本.当然,上位机和下位机代码都写好了,可以正常工作,但是由于电路知识还是中学那点没还给老师的,加以各种 ...

  3. "废物利用"也抄袭——废旧喷墨打印机和光驱DIY"绘图仪"

    很长时间没有写博客,因为各种各样的事情占去大块时间,只有零碎时间偶尔在CSDN逛逛也偶尔回几个帖子.很久以前就看到一些光驱DIY雕刻机之类的,很是向往,最近这几天得闲就TB了一套Arduino UNO ...

  4. [No0000CA]什么是“普瑞马法则”?以及 如何利用“普瑞马法则”,三步克服惰性

    一般在学习和生活中,我们都可能有这样的经验,就是当说想要作某件事情的时候,但过了好久发现还是没有做:或者觉得有力气使不出来:或者总觉得生活是灰色和抑郁的等等. 这类情况反映在生活中,就是生活好像总是被 ...

  5. Touch Bar 废物利用系列 | 在触控栏上显示 Dock 应用图标

    都说 Intel 第八代 CPU 对比上代是牙膏不小心挤多了,而配备第八代 CPU 的 MacBook Pro,只有 Touch Bar 版本,虽然贵了一点,但就一个字 -- 买! 收到电脑后,兴冲冲 ...

  6. [自娱自乐] 4、超声波测距模块DIY笔记(四)——终结篇·基于C#上位机软件开发

    前言 上一节我们已经基本上把超声波硬件的发射和接收模块全部做好了,接下来我们着手开发一个软硬结合的基于C#的平面定位软件! 目录 一.整体思路 二.效果提前展示 2-1.软件部分展示 2-2.硬件部分 ...

  7. 实验三 Java基本程序设计(2)

                                             实验三 Java基本程序设计(2)                                           ...

  8. 20145208 实验三 Java面向对象程序设计

    20145208 实验三 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验步 ...

  9. 利用lipo编译合并iPhone模拟器和真机通用的静态类

    利用lipo编译合并iPhone模拟器和真机通用的静态类 如何编译静态类库,而且现在网上也有很多的教程,现在问题时我们编译好了的静态类库会时两个版本的.a文件,分别用于模拟器和iPhone真迹,因此M ...

随机推荐

  1. What's the difference between SDK and Runtime in .NET Core?

    What's the difference between SDK and Runtime in .NET Core? Answer1 According to the .Net Core Guide ...

  2. 【P4语言学习】Parser解析器

    参考文章:王垠:谈谈Parser 簡單介紹 P4 語言(一)- Parser 什么是Parser 传统的parser,一般出现在编译器和编译原理课程中,援引<谈谈Parser>的定义: 首 ...

  3. POJ 1014 Dividing(多重背包+二进制优化)

    http://poj.org/problem?id=1014 题意:6个物品,每个物品都有其价值和数量,判断是否能价值平分. 思路: 多重背包.利用二进制来转化成0-1背包求解. #include&l ...

  4. centos 升级python26到python27

    由于开发库依赖于python27,而自己安装的centos6.8自带的python是2.6.6,因此打算简单的做一下升级. 因为centos的yum依赖于python26因此不打算覆盖26.步骤如下: ...

  5. msgsrvmgr.cpp:5:37: fatal error: kdl_conversions/kdl_msg.h: No such file or directory #include <kdl_conversions/kdl_msg.h>

    /home/xxx/ros_workspace/src/bp_protocol_bridge/protospot/src/msgsrvmgr.cpp::: fatal error: kdl_conve ...

  6. 动态规划-House Robber

    2018-04-29 20:20:56 House Robber问题是leetcode上经典的系列题,这里对其中的题目做一个讲解. 198. House Robber 问题描述: 问题求解: 本质上就 ...

  7. 在x86为arm 编译 httpd 2.2.31

    这个版本的httpd 已经自带 apr apr-util pcre , 不用额外下载源代码 1) 编写环境变量脚本,并执行 cross-env.sh : export ARMROOTFS=/h1roo ...

  8. [POI2012]ROZ-Fibonacci Representation (数学)

    大意:给定n, 求至少要多少个斐波那契数相加减后能得到n  (可以重复, 重复的算多次) 假设$dp(x)$为$x$的最小划分, 有$dp(x)=dp(x-F_k)+1$, 其中$F_k$为最接近$x ...

  9. Hadoop1.2.1完全分布模式安装教程

    假设有三台机器,它们的IP地址和对应的主机名为: 192.168.12.18           localhost.localdomain 192.168.2.215           rhel5 ...

  10. Asp.Net使用org.in2bits.MyXls.dll操作excel的应用

    首先下载org.in2bits.MyXls.dll(自己的在~\About ASP.Net\Asp.Net操作excel) 添加命名空间: using org.in2bits.MyXls;using ...