Скетч arduino для wifi радио.
Jan. 29th, 2014 06:12 pmВ предыдущих постах уже описал как программируется arduino, доработка библиотеки LCD и особенности подключения потенциометра.
ИМХО, для понимания работы скетча и переноса его в arduino этого достаточно. Остальное описано на сайте arduino.ru/.
Arduino для маршрутизатора является консолью с LCD экраном и клавиатурой в виде много оборотного потенциометра. Можно использовать одно оборотный потенциометр, но тогда будет тяжело задавать больше 10 опций, хотя стоить он будет в 10 раз меньше.
Алгоритм работы.
Сразу после включения ардуино ждет строку "TPL may play <число каналов> channal.", если оно этого не дождется за 10 минут (переменная cuTimeoutOpenWRT), то начинает слать в роутер строку о необходимости сброса маршрутизатора, ибо это говорит о том, что во время работы по непонятным причинам arduino перезагрузилось.
Когда оно этой строки дождется, то начинает принимать команды с роутера.
Он понимает следующие команды:
- Имя проигрываемой станции: "play:<номер канала>. <имя канала>".
- Сброс arduino: "reset arduino".
- Изменение числа доступных каналов: "TPL may play <число доступных каналов> channal.".
- Сообщение об ошибке роутера: "error:<число>. <имя ошибки>".
- Текущее время:"time:<текстовое сообщение о времени>".
ЖКИ поделен на 2 области.
- Верхняя строка, в которую выводится сведения о положении потенциометра. Сведения о положении потенциометра выводятся только когда он поворачивается, если после последнего сдвига придет сообщение с текущем временем, то сведения о положении потенциометра будут затерты строкой с текущем временем.
- Три нижних строки в которых индицируется имя текущего канала или ошибка проигрывателя. Они берутся из команд "play:<номер канала>. <имя канала>" и "error:<число>. <имя ошибки>", только слово "play" вырезается, а "error" нет.
По прошествии 0.1 секунды после последнего сдвига потенциометра (переменная SPTIME), с периодичностью в 3 секунды (переменная STPLTIME) посылается в роутер команда сменить канал: "Tuner: <номер канала>".
!!!ВНИМАНИЕ!!!
1. Компилятор с++ для arduino имеет ошибку: не умеет корректно сравнивать переменные типа unsigned long, поэтому для обработки длительных временных промежутков, я сначала милисекунды преобразовывал в секунды, а потом уже их сравнивал.
2. Если непрерывно слать данные в arduino по последовательному порту, то по непонятным причинам, оно превращается в пожирателя энергии, которому БП в 1A недостаточно. Поэтому, для предотвращения перегрева, зависаний и сбоев arduino, непрерывно слать данные ему нельзя.
#include "LCD.h"
#include <avr\wdt.h>
// initial LCD library LiquidCrystal(rs, rw, enable, d4, d5, d6, d7)
LCD lcd(6,7,8,9,10,11,12);
#define AVR 512
#define MIDDLE_ADC 41 // края ADC,
unsigned int iNumOut=0;
const char csRadioReady[] = "TPL may play %i channal.";
const char csTime[] = "time:";
String inputString="";
String OldInputString="";const unsigned long STPLTIME=3000; // время между отправками сообщений TPL
const unsigned long SPTIME=100; // time of stabilization state trimmer
const unsigned int cuTimeoutOpenWRT=10*60;
const int ciRes330k=5;
const int ciRes33k=4;
const int ciRes560=13;
const int ciTunerPin=0;
static int iNewTuner=-1;
boolean fSendNumCh=false;static int iNumStation;
static int iTuner=-1;void(* resetFunc) (void) = 0;//declare reset function at address 0
unsigned int secondsis(void);
void setup() {
// конфигурация входов/выходов
pinMode(ciTunerPin,INPUT);
pinMode(ciRes330k,INPUT);
pinMode(ciRes33k,INPUT);
pinMode(ciRes560,INPUT);
// Open serial communications and wait for port to open:
Serial.begin(9600);
lcd.begin(20,4);
lcd.clear();
lcd.printf("\fWiFi radio ver. 0.0\n\rWaiting TPL...\n\r");
unsigned int uStartTime=secondsis();
// ожидание приветствия со стороны wifi radio с числом каналов
do{
while(!Serial.available())
if(secondsis()-uStartTime>cuTimeoutOpenWRT)
Serial.println("Arduino waiting TPL");
char inChar = (char)Serial.read();
if(inChar!='\n')
{
if(inputString.length()>80)
inputString="";
inputString+=inChar;
continue;
}
if(!sscanf(inputString.c_str(),csRadioReady,&iNumStation))
{
inputString="";
continue;
}
inputString="";
} while(!iNumStation);
// конец
lcd.clear();
lcd.setCursor(0,1);
lcd.printf("Num station is %i",iNumStation);
}void loop() {
// чтение номера канала с усреднением
static word wNumRead=0;
static unsigned long sum;
static unsigned long dwSendTime;
static unsigned long dwNewTime=0xffffffff;
static unsigned long iADC=2048;
unsigned long dwReadTime=millis();
char v;
int i;
if(!wNumRead)
sum=0;
sum+=analogRead(ciTunerPin);
wNumRead+=1;
if(wNumRead==AVR)
{
// номер канала считан
wNumRead=0;
sum=sum/AVR;
// удаление помехи
if(abs(iADC-sum)<=1)
sum=iADC;
else
iADC=sum;
sum=sum/2;
// iNumOut+=1;
// lcd.setCursor(0,2);
// lcd.printf("numout=%u ",iNumOut);
if(iNewTuner!=sum)
{
// установка подтягивающих резистров для обеспечения не большой положительной связи
// требуется для устранения помех
if((2*sum-(int)(sum*(long)512/(long)iNumStation)-(int)((sum+1)*(long)512/(long)(iNumStation))+1)>0)
{
// ближе к верхней границе диапазона, значит надо притягивать к минусу
// проверка на размер уровня
if(sum<MIDDLE_ADC)
{
// нижний диапазон
pinMode(ciRes330k,INPUT);
pinMode(ciRes33k,INPUT);
pinMode(ciRes560,OUTPUT);
digitalWrite(ciRes560,LOW);
}
else
{
if(sum<511-MIDDLE_ADC)
{
// средний диапазон
pinMode(ciRes330k,OUTPUT);
pinMode(ciRes33k,INPUT);
pinMode(ciRes560,INPUT);
digitalWrite(ciRes330k,LOW);
}
else
{
pinMode(ciRes330k,OUTPUT);
pinMode(ciRes33k,INPUT);
pinMode(ciRes560,INPUT);
digitalWrite(ciRes33k,LOW);
}
}
}
else
{
// ближе к нижней границе диапазона, значит надо притягивать к плюсу
if(sum<MIDDLE_ADC)
{
// нижний диапазон
pinMode(ciRes330k,INPUT);
pinMode(ciRes33k,OUTPUT);
pinMode(ciRes560,INPUT);
digitalWrite(ciRes33k,HIGH);
}
else
{
if(sum<511-MIDDLE_ADC)
{
// средний диапазон
pinMode(ciRes330k,OUTPUT);
pinMode(ciRes33k,INPUT);
pinMode(ciRes560,INPUT);
digitalWrite(ciRes330k,HIGH);
}
else
{
pinMode(ciRes330k,INPUT);
pinMode(ciRes33k,INPUT);
pinMode(ciRes560,OUTPUT);
digitalWrite(ciRes560,HIGH);
}
}
}
iNewTuner=sum;
dwNewTime=dwReadTime;
// отображение на экране этой информации
lcd.setCursor(0,0);
lcd.printf("\t\t%3d ",(int)sum);
sum=sum*(unsigned long)iNumStation;
sum=sum/512;
lcd.setCursor(0,0);
lcd.printf("%3i %3i \t%3i ",
(int)sum+1,
(int)(sum*(long)512/(long)iNumStation),
(int)((sum+1)*(long)512/(long)(iNumStation)));
}
else if(dwReadTime-dwNewTime>SPTIME)
{
sum=sum*(unsigned long)iNumStation;
sum=sum/512;
if(sum!=iTuner)
{
// взвод флага вывода на TPL нового номера канала
iTuner=sum;
fSendNumCh=true;
dwSendTime=0xffffffff;
}
}
}
// отправка номера канала на TPL
if(fSendNumCh)
{
if(dwReadTime-dwSendTime>STPLTIME)
{
// отправка номиера канала TPL
Serial.print("Tuner: ");
Serial.print(iTuner);
Serial.print("\r");
dwSendTime=dwReadTime;
}
}
// lcd.setCursor(0,1);
// lcd.printf("dt=%lu ",dwReadTime-dwSendTime);
// прием с TPL
while (Serial.available())
{
// get the new byte:
v = (char)Serial.read();
// add it to the inputString:
if(inputString.length()>160)
inputString="";
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if ((v=='\n') || (v=='\r'))
{
// если строка с именем канала
if(!inputString.length())
continue;
if(inputString!=OldInputString)
{
if(sscanf(inputString.c_str(),"play:%d. %*s",&i)==1)
{
i-=1;
if(i==iTuner)
{
// тогда бросать принимать строки
fSendNumCh=false;
lcd.setCursor(0,1);
for(v=60;v;v--)
lcd.CharOut_noscroll(' ');
// вывод полученной строки
lcd.setCursor(0,1);
lcd.printf_noscroll((inputString.c_str())+5);
}
}
else if(!inputString.compareTo("reset arduino"))
{
lcd.setCursor(0,0);
lcd.clear();
lcd.printf("reset");
resetFunc();
}
else if(sscanf(inputString.c_str(),csRadioReady,&i)==1)
{
iNumStation=i; // число каналов
lcd.setCursor(0,0);
lcd.clear();
inputString=""; // строку с именем канала не принимали
OldInputString="";
fSendNumCh=true; // выводить новую строку
lcd.clear();
lcd.setCursor(0,1);
lcd.printf("Num station is %i",iNumStation);
}
else if(sscanf(inputString.c_str(),"error:%d. %*s",&i)==1)
{
OldInputString=inputString;
// очищение нижней части экрана
lcd.setCursor(0,1);
for(v=60;v;v--)
lcd.CharOut_noscroll(' ');
// вывод полученной строки
lcd.setCursor(0,1);
lcd.printf_noscroll(inputString.c_str());
}
else if(!strncmp(inputString.c_str(),csTime,sizeof(csTime)-1))
{
// очищение верхней строки
lcd.setCursor(0,0);
for(v=20;v;v--)
lcd.CharOut_noscroll(' ');
lcd.setCursor(0,0);
lcd.printf_noscroll("%-20.20s",inputString.c_str()+sizeof(csTime)-1);
}
OldInputString=inputString;
}
inputString="";
continue;
}
inputString+=v;
}
}unsigned int secondsis(void)
{
return millis()/1000;
}