/*Traffic_Light.ino        17 SEP 2015   Arduining.com
Implementing the traffic light controller using Finite State Machines modeling.
Using Direct Port Manipulation in the Arduino UNO.
Creating a Data Structure in C.
Port B pins 0 and 1 as inputs (Arduino pins 8 and 9):
Pin 8 = North Switch
Pin 9 = East Switch
Port D pins 2 to 7 as outputs (Arduino pins 2 to 7):
Pin 2 = North Red light
Pin 3 = North Yellow light
Pin 4 = North Green light
Pin 5 = East Red light
Pin 6 = East Yellow light
Pin 7 = East Green light
Based in: Finite State MachinesFrom:http://users.ece.utexas.edu/~valvano/Volume1/E-Book/
*/
#define SENSORS  PINB      // define the ATmega328 Port to read the switches
#define LIGHTS   PORTD     // define the ATmega328 Port to drive the lights
// Linked data structure
struct State {
  int Out; 
  int Time;  
  int Next[4];}; 
typedef const struct State STyp;//将 STyp 指代为名为 state 的恒定的结构体变量
#define goS   0
#define waitS 1
#define goW   2
#define waitW 3
STyp FSM[4]={
 {0x21,3000,{goS,waitS,goS,waitS}},       //State 0 (goS)   go South.
 {0x22, 500,{goW,goW,goW,goW}},       //State 1 (waitS) wait South.
 {0x0C,3000,{goW,goW,waitW,waitW}},    //State 2 (goW)   go West.
 {0x14, 500,{goS,goS,goS,goS}}};        //State 3 (waitW) wait West.
//0x21 = 00100001 ,取后六位为灯控状态

int State;  // index to the current state 
int Input; 

void setup(){
  DDRB &= B11111100;  // Port B pins 0 and 1 as inputs (Arduino pins 8 and 9)
  DDRD |= B11111100;  // Port D pins 2 to 7 as outputs (Arduino pins 2 to 7)
  //DDRB 控制 Port B 的引脚方向。每个位(bit)代表一个引脚,当位被设置为 1 时,对应的引脚为输出模式;
  //当位被设置为 0 时,对应的引脚为输入模式。
  //DDRD 控制 Port D 的引脚方向。同样,每个位代表一个引脚,设置方式与 DDRB 相同。
  //DDRB &= B11111100; 将Port B的引脚0和1设置为输入模式,即设置为0,其他引脚保持不变。
  //这里使用了位操作 &=,以及二进制数 B11111100 来设置引脚的方向。
  //这样做的目的是将Arduino的引脚8和9(对应Port B的引脚0和1)设置为输入模式,用作传感器的输入。
}

void loop(){
    LIGHTS = (FSM[State].Out)<<2;    // set lights
    delay(FSM[State].Time);
    Input = SENSORS & B00000011;     //这行代码的作用是只保留端口 B 上的两个最低位,忽略其他位的状态,然后将这个结果存储到 Input 变量中。
    State = FSM[State].Next[Input];  
}