作者:mznewfacer (Wolf Geek) 时间:2012年 05月23日 转载需说明出处,谢谢
这两天想让arduino ethernet即做服务器又做客户端来完成我的一些需求,想了想单片机上可以这么搞么?这是我自己首先提出的问题。
经搜索,其实还是有并行实现方案的,我还没仔细研究,有时间了再详细讲,arduino 这里有提供 concurrency,它是基于occam-pi 并行语言写的,编译程序前需要先利用jedit插件导入firmware到arduino板子上。
语法基本形式与其他并行语言类似,同时点亮两个LED灯的程序如下所示:
PROC main ()
PAR //occam-π 语言形式
blink (12 , 500) //Plumbing library 函数 每500ms对12pin口的LED灯开关
blink (11 , 500)
:
如果不用此种方式,我们知道一般单片机没有多线程的概念,要能达到“同时”的效果,就需要任务调度来实现,先看一种简单实现两灯同时开关的程序,
#define ledPin1 11
#define ledPin2 12
#define led1Cycle 500U
#define led2Cycle 500U
unsigned long led1LastMillis = 0;
unsigned long led2LastMillis = 0;
boolean led1State = false;
boolean led2State = false;
boolean cycleCheck(unsigned long *lastMillis, unsigned int cycle) // 检查不使用中断方式每cycle时间是否可以执行动作
{
unsigned long currentMillis = millis();
if(currentMillis - *lastMillis >= cycle)
{
*lastMillis = currentMillis;
return true;
}
else
return false;
}
void setup()
{
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
}
void loop()
{
if(cycleCheck(&led1LastMillis, led1Cycle))
{
digitalWrite(ledPin1, led1State); //每cycle时间重置led灯状态
led1State = !led1State;
}
if(cycleCheck(&led2LastMillis, led2Cycle))
{
digitalWrite(ledPin2, led2State);
led2State = !led2State;
}
}
为了方便多任务调度,可以cycleCheck封装一下直接写成库导入libraries就可以方便的实现多任务了,将该库命名为TimeSched,以下是头文件,
#ifndef TIMESCHED_H
#define TIMESCHED_H
#include "WProgram.h"
#define NO_PREDELAY 0
class TimeSched{
public:
TimeSched(unsigned long interval,void (*function)()); //函数指针形式供调用
TimeSched(unsigned long prev,unsigned long interval,void (*function)());
void reset();
void disable();
void enable();
void check();
void setInterval( unsigned long interval );
private:
bool active;
unsigned long previous;
unsigned long interval;
void (*execute)();
};
#endif
具体实现源文件,TimeSched.cpp
#include "TimeSched.h"
TimeSched::TimeSched(unsigned long intervl,void (*function)()){
active = true;
previous = 0;
interval = intervl;
execute = function;
}
//构造函数
TimeSched::TimeSched(unsigned long prev,unsigned long intervl,void (*function)()){
active = true;
previous = prev;
interval = intervl;
execute = function;
}
void TimeSched::reset(){
previous = millis();
}
void TimeSched::disable(){
active = false;
}
void TimeSched::enable(){
active = true;
}
void TimeSched::check(){ //对应于小例子的cycleCheck函数
if ( active && (millis()-previous >= interval) )
{
previous = millis();
execute();
}
}
void TimeSched::setInterval( unsigned long intervl){
interval = intervl;
}
之后就是调用该库函数,写个pde吧,在增加个打印ASCII表的工作吧~一共三个任务,
#include "TimeSched.h"
TimeSched blinkLED1 = TimeSched(500,blink); //初始化执行函数指针
TimeSched blinkLED2 = TimeSched(500,blink);
TimeSched asciiTableAction = TimeSched(10000,asciiTable);
#define ledPin1 13
#define ledPin2 12
boolean ledState = false;
void setup(){
pinMode(ledPin1,OUTPUT);
pinMode(ledPin2,OUTPUT);
digitalWrite(ledPin,ledState);
digitalWrite(ledPin,ledState);
Serial.begin(9600);
}
void loop(){
blinkLED1.check();
blinkLED2.check();
asciiTableAction.check();
}
//执行函数
void blink(){
ledState ? ledState=false : ledState=true;
digitalWrite(ledPin,ledState);
}
//打印ASCII表到串口
void asciiTable()
{
byte number = 33; // '!' is #33
// 打印到 '~' #126 ...
while(number <= 126) {
Serial.print(number, BYTE);
Serial.print(", dec: ");
Serial.print(number);
Serial.print(", hex: ");
Serial.print(number, HEX); // 16进制
Serial.print(", oct: ");
Serial.print(number, OCT); // 8进制
Serial.print(", bin: ");
Serial.println(number, BIN); // 2进制
number++;
}
asciiTableAction.disable();
}
好了,编译后上传到板子,就可以实现“同时”闪烁两个LED灯并且在串口打印数据的任务调度程序了。