#include <Arduino_FreeRTOS.h>
#include <event_groups.h>
#include <MsTimer2.h>
#define LATCH 11
#define CLOCK 9
#define DATA 12
#define BUTTON_1 2
#define BUTTON_2 3
#define BUZZER 4
#define LIGHT_PIN 0
#define SIGNAL_TIME 2000
#define BLINK_TIME 300
const int FLAG_CAR = (1 << 0);
const int FLAG_PEDE = (1 << 1);
const int FLAG_SERIAL = (1 << 2);
const int FLAG_MELODY = (1 << 3);
volatile unsigned long currentTime = 0;
volatile unsigned long lastWakeTime = 0;
unsigned int debounceTime = 200;
int pedeGreenTime = 5000;
int inputable = 1;
int nightMode = 0;
byte data = 0b00000000;
TaskHandle_t carSignalTask;
TaskHandle_t pedestrainSignalTask;
TaskHandle_t serialInputTask;
EventGroupHandle_t eventGroup;
TickType_t xFrequency1 = pdMS_TO_TICKS(SIGNAL_TIME);
TickType_t xFrequency2 = pdMS_TO_TICKS(BLINK_TIME);
void setup() {
Serial.begin(115200);
pinMode(LATCH, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(BUTTON_1, INPUT_PULLUP);
pinMode(BUTTON_2, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
eventGroup = xEventGroupCreate();
xTaskCreate(carSignal, "car", 128, NULL, 2, &carSignalTask);
xTaskCreate(pedestrainSignal, "pedestrain", 128, NULL, 2, &pedestrainSignalTask);
xTaskCreate(serialInput, "serial", 128, NULL, 1, &serialInputTask);
attachInterrupt(digitalPinToInterrupt(BUTTON_1), pedestrain_button, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_2), pedestrain_button, FALLING);
initialize();
MsTimer2::set(2000, signalChange);
InputAccepting();
vTaskStartScheduler();
}
void loop() {
// put your main code here, to run repeatedly:
}
// 歩行者用ボタン押下時割り込み
void pedestrain_button() {
if (inputable == 1) {
currentTime = millis();
if (currentTime - lastWakeTime > debounceTime) {
MsTimer2::start();
lastWakeTime = currentTime;
inputable = 0;
}
}
}
void signalChange() {
xEventGroupSetBits(eventGroup, FLAG_CAR);
MsTimer2::stop();
}
void carSignal(void* p) {
int i, lightValue;
TickType_t xTimeCarSignal;
while(1){
xEventGroupSetBits(eventGroup, FLAG_SERIAL);
xEventGroupWaitBits(eventGroup, FLAG_CAR, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000));
inputable = 0;
lightValue = analogRead(LIGHT_PIN);
if ((nightMode == 0) ? 0 : (lightValue <= 300 ? 1 : 0)) {
// if (analogRead(LIGHT_PIN) <= 300 || nightMode == 1) {
xTimeCarSignal = xTaskGetTickCount();
data = 0b00000000;
updateLSBFIRST();
while ((nightMode == 0) ? 0 : (lightValue <= 300 ? 1 : 0)) {
// while (analogRead(LIGHT_PIN) <= 300 || nightMode == 1) {
lightValue = analogRead(LIGHT_PIN);
data = 0b00001000;
updateLSBFIRST();
vTaskDelayUntil(&xTimeCarSignal, xFrequency2);
data = 0b00000000;
updateLSBFIRST();
vTaskDelayUntil(&xTimeCarSignal, xFrequency2);
}
initialize();
inputable = 1;
} else {
xEventGroupClearBits(eventGroup, FLAG_SERIAL);
xTimeCarSignal = xTaskGetTickCount();
Serial.println("変更処理停止中...(入力は保存されます)");
// 黄信号(赤信号)
data = 0b00101001;
updateLSBFIRST();
vTaskDelayUntil(&xTimeCarSignal, xFrequency1);
// 赤信号(赤信号)
data = 0b00100101;
updateLSBFIRST();
vTaskDelayUntil(&xTimeCarSignal, xFrequency1);
// 赤信号(青信号)
xEventGroupSetBits(eventGroup, FLAG_PEDE);
// 赤信号(赤信号)
xEventGroupWaitBits(eventGroup, FLAG_CAR, pdTRUE, pdFALSE, portMAX_DELAY);
// 青信号(赤信号)
data = 0b0110001;
updateLSBFIRST();
xEventGroupSetBits(eventGroup, FLAG_SERIAL);
}
}
}
void pedestrainSignal(void* p) {
int i;
TickType_t xVariableFrequency, xTimePede;
while(1){
xEventGroupWaitBits(eventGroup, FLAG_PEDE, pdTRUE, pdFALSE, portMAX_DELAY);
xVariableFrequency = pdMS_TO_TICKS(pedeGreenTime);
xTimePede = xTaskGetTickCount();
// 赤信号(青信号)
data = 0b1000110;
updateLSBFIRST();
for (i = 0; i < 10; i++) {
tone(BUZZER, 392);
vTaskDelayUntil(&xTimePede, pdMS_TO_TICKS(pedeGreenTime/ 20));
noTone(BUZZER);
vTaskDelayUntil(&xTimePede, pdMS_TO_TICKS(pedeGreenTime/ 20));
}
// 赤信号(青信号点滅)
bitClear(data, 5);
for (i = 0; i < 3; i++) {
bitSet(data, 1);
bitSet(data, 6);
updateLSBFIRST();
vTaskDelayUntil(&xTimePede, xFrequency2);
bitClear(data, 1);
bitClear(data, 6);
updateLSBFIRST();
vTaskDelayUntil(&xTimePede, xFrequency2);
}
// 赤信号(赤信号)
data = 0b0100101;
updateLSBFIRST();
vTaskDelayUntil(&xTimePede, xFrequency1);
// 青信号(赤信号)
xEventGroupSetBits(eventGroup, FLAG_CAR);
inputable = 1;
InputAccepting();
}
}
void serialInput(void* p) {
int number;
while(1){
xEventGroupWaitBits(eventGroup, FLAG_SERIAL, pdFALSE, pdFALSE, portMAX_DELAY);
if (Serial.available() > 0) {
number = Serial.parseInt();
if (number >= 1 && number <= 15) {
pedeGreenTime = number * 1000;
Serial.print(number);
Serial.println("秒に設定しました");
} else if (number == 16) {
nightMode = nightMode == 1 ? 0 : 1;
if (nightMode == 1) {
Serial.println("夜間対応モードに設定しました");
} else {
Serial.println("夜間対応モードを解除しました");
}
}
}
}
}
void InputAccepting() {
Serial.println("受付中...");
Serial.println("1 ~ 15 : 歩行者信号(青信号)時間を入力秒に変更");
Serial.println("16 : 夜間モード ON/OFF切替");
}
void updateLSBFIRST(){
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, data);
digitalWrite(LATCH, HIGH);
}
void initialize(){
data = 0b00110001;
updateLSBFIRST();
}