Собственно данный проект развитие старой темы с танком. Возникла идея уменьшить размеры пульта, задействовав Digispark. А кроме того, сделать нормальное управление танком, так как в случае вертолета поворот осуществляется за счёт небольшого относительного замедления\ускорения винтов. В случае же танка для эффективного разворота одну из гусениц нужно стопорить полностью.
Исследования я начал с определения несущей частоты, она составила 39.4 кГц, период примерно 25.4 мкс.


Для управления танком я планировал использовать 4 кнопки, пин5 отпадает, так как при его замыкании на землю чип перезагружается. Таким образом пин 0 у меня отошёл светодиоду, а пины 1,2,3,4 я использовал для кнопок. И тут вылезла проблема пина 3. Чтобы понять причину, взглянем на схему Digispark:

Но и это ещё не всё. Свой пульт я решил запитать от павер банка. А как оказалось, павер банк держит на выводах данных постоянное напряжение, это пины 3 и 4 Digispark. И кнопки от этого не работали как надо. В итоге пришлось выпаять и резисторы на 68 Ом, маркировка 680. После этого все кнопки заработали идеально. Конечно, для перепрошивки придётся резисторы впаять на место.
Алгоритм борьбы с дребезгом контактов был описан в статье про PWM регулятор. Вкратце - постоянно считывается состояние кнопок и раз в 25 мс (переменная press_voting) подводятся итоги, если больше половины времени кнопка была нажата, значит она реально нажата.
Сперва стояла задача воспроизвести несущую частоту. Здесь без осциллографа не обойтись, нужно смотреть длительность импульса в оригинальном пульте и добиться такой же от Digispark. Программно можно устанавливать паузу только до микросекунды, а требуется установка периода с точностью до одной десятой. Эта проблема решена переменной popravka - каждый импульс она увеличивается на подобранный коэффициент, и при превышении порога длительность импульса увеличивается на микросекунду. Таким образом удалось добиться полного соответствия частоты несущей.
Следующая проблема, которую пришлось решить - сканирование кнопок. Оно занимает немалое количество процессорного времени. С одной стороны, и с другой кнопки надо опрашивать как можно чаще для отзывчивости системы управления. Как показали замеры осциллографом, сканирование состояния 4х кнопок как раз занимает длительность одного периода несущей - примерно 25.4 мкс. В итоге сканирование кнопок делается в период паузы между импульсами, когда не нужно излучать сигнал. То есть паузы 1 (35 импульсов) и 0 (15 импульсов) по факту после сканирования кнопок делаются 34 и 14 импульсов.
Также пришлось подобрать минимальную паузу между командами. Если слать команды без паузы, приёмник начинает их игнорировать. Скетч приведен ниже:
int popravka = 0;
const int naklad = 5;
const int flash_len = (15 - naklad);
const int after_len = (10 - naklad);
const byte cmd_max_stop[6] =
{ 0, 0, 104, 231, 14, 24}; //0000 0
const byte cmd_min_rigt[6] =
{ 0, 32, 186, 3, 0, 0}; //0001 1
const byte cmd_max_rigt[6] =
{ 0, 252, 3, 0, 0, 0}; //0010 2
const byte cmd_min_left[6] =
{ 16, 3, 182, 3, 0, 0}; //0100 4
const byte cmd_max_left[6] =
{ 254, 1, 0, 0, 0, 0}; //1000 8
const byte cmd_max_frwd[6] =
{ 255, 254, 1, 0, 0, 0}; //1010 10
const byte cmd_min_frwd[6] =
{ 16, 35, 116, 3, 0, 0}; //0101 5
const byte cmd_some0[6] = { 251, 7, 0, 0, 0, 0};
const byte cmd_some2[6] = { 245, 192, 59, 47, 5, 9};
const byte cmd_some3[6] = { 95, 88, 2, 110, 104, 10};
byte mode;
unsigned long votes1=0, votes2=0, votes3=0, votes4=0;
const unsigned long press_voting = 25000;
unsigned long loop_time = 0;
unsigned long last_loop_time = 0, last_election = 0;
void setup() {
pinMode(0, OUTPUT);
pinMode(1, INPUT);
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
digitalWrite(0, LOW);
mode = 0;
sendit(cmd_max_frwd); sendit(cmd_max_stop); delay(100);
sendit(cmd_max_frwd); sendit(cmd_max_stop); delay(100);
sendit(cmd_max_frwd); sendit(cmd_max_stop); delay(100);
sendit(cmd_max_left); sendit(cmd_max_stop); delay(100);
sendit(cmd_max_rigt); sendit(cmd_max_stop); delay(100);
}
void scan_button(){
loop_time = micros();
unsigned long cycle_length = (loop_time - last_loop_time);
if( digitalRead(1) == HIGH ) votes1 += cycle_length;
if( digitalRead(2) == HIGH ) votes2 += cycle_length;
if( digitalRead(3) == HIGH ) votes3 += cycle_length;
if( digitalRead(4) == HIGH ) votes4 += cycle_length;
if( (loop_time - last_election) >= press_voting ){
mode = 0;
if( votes1 >= (press_voting >> 1) ) mode += 1;
if( votes2 >= (press_voting >> 1) ) mode += 2;
if( votes3 >= (press_voting >> 1) ) mode += 4;
if( votes4 >= (press_voting >> 1) ) mode += 8;
votes1 = 0;
votes2 = 0;
votes3 = 0;
votes4 = 0;
last_election = loop_time;
}
last_loop_time = loop_time;
}
void seria(int how_much, int state){
if( state == LOW ){
scan_button();
how_much -= 1;
}
while(how_much > 0){
digitalWrite(0, state);
delayMicroseconds(flash_len);
digitalWrite(0, LOW);
popravka += 30;
if( popravka >= 100 ){
popravka -= 100;
delayMicroseconds(after_len + 1);
}else{
delayMicroseconds(after_len );
}
how_much--;
}
}
void sendit(const byte bytes[]){
byte c;
seria(69, HIGH);//const
seria(15, LOW);//const
for(c = 0; c < 6; c++){
if( (bytes[c] & B00000001) > 0 ) seria(35, HIGH);
else seria(15, HIGH);
if( (bytes[c] & B00000010) > 0 ) seria(35, LOW);
else seria(15, LOW);
if( (bytes[c] & B00000100) > 0 ) seria(35, HIGH);
else seria(15, HIGH);
if( (bytes[c] & B00001000) > 0 ) seria(35, LOW);
else seria(15, LOW);
if( (bytes[c] & B00010000) > 0 ) seria(35, HIGH);
else seria(15, HIGH);
if( (bytes[c] & B00100000) > 0 ) seria(35, LOW);
else seria(15, LOW);
if( (bytes[c] & B01000000) > 0 ) seria(35, HIGH);
else seria(15, HIGH);
if( (bytes[c] & B10000000) > 0 ) seria(35, LOW);
else seria(15, LOW);
}
}
void loop() {
switch(mode){
case 1:
sendit(cmd_min_rigt);
break;
case 2:
sendit(cmd_max_rigt);
break;
case 4:
sendit(cmd_min_left);
break;
case 8:
sendit(cmd_max_left);
break;
case 5:
sendit(cmd_min_frwd);
break;
case 10:
sendit(cmd_max_frwd);
break;
default:
sendit(cmd_max_stop);
}
for(byte c = 0; c < 32; c++){
seria(35, LOW);
}
}
//const long freq = 39400; 25.4 micros
//35 = 885 mcs; 15+15 = 745..760 mcs



Более интересным мне видится создание приёмника на Digispark. И создать пару приёмник\пульт. Это вполне реально, когда-нибудь наверно это реализую.