Предлагаю вам, уважаемые читатели GeekTimes, следующую статью из цикла (надеюсь, что не последнюю) по использованию микросхемы ESP8266 в качестве беспроводного моста для AVR микроконтроллеров, на примере аппаратной платформы Arduino Uno (Nano).

После первой статьи на эту тематику я получил множество дружелюбных откликов как-то: “А на кой чёрт ты взял ардуину, если всё можно было сделать исключительно на ESP8266” или “Почему ты, болван, не использовал esp-link ”. “Действительно почему?” — подумал я и накатал уже эту статью и обновил несколько своих программ в качестве новых аргументов.

Итак, встречайте беспроводной программатор для AVR микроконтроллеров BABUINO version 0.9



Подробности под катом:

Исходная версия программы была опубликована в прошлой статье и в принципе, делала почти то же самое, что и новая версия. Но отличалась крайним неудобством в работе. Как, впрочем, и конкурирующая esp-link. Поэтому, вздохнув, я привинтил GUI на JAVA. Теперь вы можете спокойно выбирать нужный вам для загрузки файл через оконный менеджер, а также редактировать IP адрес целевого устройства. Номер TCP порта я все-таки вшил намертво (он редактируется только в коде), но по идее, его нужно изменять только, если этот порт используется где-то у вас ещё (но тогда придется менять его номер и в прошивке ESP8266).

Микроконтроллер используется тоже пока один с размером FLASH памяти 32 кбайт, это, к примеру, всем известный Mega328P. Как, я уже упоминал в прошлой статье, теоретически мой программатор шьет версии и в 16 кбайт, а может даже и 8 кбайт. Ну и естественно в 64 кбайт и 128 кбайт версиях AVR он даже может, вероятно, прошить первые 32 кбайт памяти. Но таких микроконтроллеров у меня на руках нет и как оно на самом деле, сказать не могу. Там все дело в том, что 16 бит адреса в стандартных командах программирования по SPI настолько хитро делятся и режутся (битик сюда, битик туда), что понять, как всё будет при другом размере памяти отличном от 32 кбайт, совсем непросто.

Да, программа после записи не верифицируется, специальные регистры AVR не читаются, EEPROM тоже не пишет. Но все это теоретически возможно сделать без проблем (в отличие от принципиальных ограничений загрузки кода через UART, как в esp-link). Можете дописать, я не возражаю, продукт не коммерческий.

Здесь исполняемый файл для 64 бит Windows. Из него же можно выдрать код на Java. Или взять на Гитхабе

Итак, запускаем.

Дальше всё просто, открываете нужный вам HEX файл (да, программка научилась преобразовывать формат BIN в HEX, ура!) вписываете IP адрес ESP8266, которая вам нужна и жмёте “Upload” (как найти IP адрес ESP модуля — история отдельная). Если программатор находит ESP8266, то он быстренько (намного быстрее, чем esp-link), запихивает в неё ваш код, а та уже сама отправляет его дальше в AVR микроконтроллер по интерфейсу SPI. Программатор подробно описывает свои действия в окне и ему даже можно верить, за исключением того, что программа записалась в AVR. Как я уже говорил, верификации записи нет, а интерфейс SPI чисто синхронный, ему вообще по барабану, есть ли кто на втором конце линии или нет. Он закидывает данные, а ответа вообще не ждёт.

После закрытия программы (через “Stop” или просто через закрытие окна) ввёденные вами данные (если вы жали кнопку Upload до этого) сохраняются в файле tcp_dat.txt в корневом каталоге диска C, чтобы при последующем открытии вам не надо было долго мучиться, снова набирать. А вообще, окошко программы можно и не закрывать. По опыту, оно никому не мешает.

Теперь же обратимся в сторону ESP модуля и снова вспомним, теперь уже подробно, каким образом его подключить к AVR и каким манером прошить, дабы иметь возможность пользоваться вышеупомянутым программатором, а также просто гонять данные по WI-FI без проводов.

Итак, первым делом схема подключения. Обращаем внимание, что нам нужны ESP8266 в версиях с достаточным количество GPIO. Нам будут необходимы свободные выводы под RESET, MOSI и SLK для программирования по SPI интерфейсу, не считая того, что для обмена данными мы будем использовать ещё и обычный UART с его RX и TX. Для этого удобнее всего по цене и качеству мне показались ESP8266-07.

Берём её и сразу припаиваем два резистора номиналом 5-10 кОм. Первый к EN (CH-PD) и питанию, второй к GPIO15 и земле



Теперь можно цеплять её к адаптеру, через который мы будем заливать прошивку NodeMCU, а затем и нашу программу-загрузчик на LUA.



Адаптеров миллион, берите любой. Соединяем, как водится, RX c TX и наоборот. Землю делаем общей. Питание на ESP8266 подаем отдельное, а адаптеру хватит и своего с USB порта. Кидаем на GPIO0 ноль и заливаем свежую прошивку NodeMCU (взять её можно здесь, или собрать свою) через программку NODE MCU PyFlasher.



Всё это в принципе, описано в предыдущей статье и много раз в интернете. Далее, убираем ноль с GPIO0 (можно просто оставить висячим, ничего страшного) и открываем среду ESPlorer для отладки и загрузки программ на Lua. Правда, эта зараза без среды JAVA не работает. Так что эту штуку (Загрузите Java на свой настольный компьютер сейчас!) ставить предварительно придётся все равно.

После подключения к ESPlorer, тот немножко поформатирует ESP модуль, информируя вас соответствующими сообщениями. (главное в этот момент ничего не трогать), а затем ребутнет ESP. Можно начинать работу по загрузке LUA программ.



А программа будет у нас следующая:

Загрузчик для AVR на Lua в ESP8266
function InstrProgrammingEnable () -- instruction for MC "enable programming"

p=0
while p<31 do
p=p+1

pin=8  
gpio.write(pin, gpio.LOW)
spi.send(1, 0xAC,0x53)
read = spi.recv( 1, 8)
spi.send(1,0,0)
gpio.write(pin, gpio.HIGH)

     if (string.byte(read)== 83) 
        then     
        --print("connection established") 
        p=33
            if(p==31)
            then 
            --print("no connection")
            end
        end
    end
end



function ProgrammingDisable ()
pin=2--END OF RESET FOR MK GPIO4
gpio.mode(pin, gpio.INPUT)

pin=8  
gpio.mode(pin, gpio.INPUT) -- CE chip enable not used GPIO15

pin=5--CLK MASTER for SPI GPIO14 used
gpio.mode(pin, gpio.INPUT)

pin=6--MISO MASTER  for SPI GPIO 12 may not used
gpio.mode(pin, gpio.INPUT)

pin=7--MOSI MASTER for SPI //GPIO13 used
gpio.mode(pin, gpio.INPUT)
end



--PROGRAMMING ENABLE

function ProgrammingEnable ()
pin=2-- RESET FOR MK
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.LOW)

pin=2--POZITIV FOR 4MSEC RESET FOR MK
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)

tmr.delay(4)
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.LOW)

tmr.delay(25000)
end





function InstrFlashErase() 
pin=8  
gpio.write(pin, gpio.LOW)
spi.send(1,0xAC,0x80,0,0)
gpio.write(pin, gpio.HIGH)
tmr.delay(15000)

pin=2--RESET FOR MK
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
tmr.delay(20000)
gpio.write(pin, gpio.LOW)

--print( "FLASH is erased")
InstrProgrammingEnable () 
end




function InstrStorePAGE(H, address, data)
pin=8  
gpio.write(pin, gpio.LOW)
spi.send(1,H,0,address,data)
gpio.write(pin, gpio.HIGH)
tmr.delay(500)
end




function InstrWriteFLASH(page_address_low,page_address_high)
pin=8  
gpio.write(pin, gpio.LOW)
spi.send(1,0x4C,page_address_high,page_address_low,0)
gpio.write(pin, gpio.HIGH)
tmr.delay(5000)-- иногда не прописываются флэш при малых задержках
end




function Programming (payload)

pin=8--CS MASTER for SPI
gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP)
pin=4--LED LIGHTS ON LOW
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.LOW)
--print(string.len(payload))
page_count = 7 -- пишем 1 килобайт 

for k =0  ,page_count ,1 do--quantity of pages

    for i=0 , 127, 2 do-- -1
    address = i/2
    data=payload:byte(i+1+128*k)
        if data == nil 
        then
        data = 0xff
        end
    InstrStorePAGE(0x40,address,data)
  --  tmr.delay(100)--  otherwise not in time write
    data =payload:byte(i+1+1+128*k)
        if data == nil then
        data = 0xff
        end
    InstrStorePAGE(0x48,address,data)
--    tmr.delay(100)
    end

page_address_low=bit.band(k ,3)*64 -- 3 это двоичное 11
page_address_high=k/4+frame1024*2

tmr.delay(1000)
InstrWriteFLASH(page_address_low,page_address_high)
tmr.wdclr()
end

pin=4--LED
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
end



--MAIN BLOCK



wifi.setmode(wifi.STATION)
--wifi.sta.config("SSID","password ") -- set SSID and password of your access point
station_cfg={}
tmr.delay(30000)
station_cfg.ssid="SSID"
tmr.delay(30000)
station_cfg.pwd="Password"
tmr.delay(30000)
wifi.sta.config(station_cfg)
tmr.delay(30000)
wifi.sta.connect()
tmr.delay(1000000)
--print(wifi.sta.status())
--print(wifi.sta.getip())



while ( wifi.sta.status()~=1 ) do
if( wifi.sta.status()==5)
then
break
end
end



prog_address="";

sv=net.createServer(net.TCP,30)
tmr.delay(100) 
--print("SERVER READY")

sv:listen(40000,function(c)--Главный сервер, работает всегда
    c:on("receive", function(c, payload)
        --print(payload)
        if (payload =="program\r\n")
        then
            c:send("ready\r\n")
             --print("ready for program\r\n")

            tmr.wdclr()
            spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8,80,spi.FULLDUPLEX) -- настройка SPI 320 примерно 115 000 кБод
--на 80 еще работает это 1 мбит
            ProgrammingEnable ()
            tmr.delay(100)
            InstrProgrammingEnable ()
            tmr.delay(100)
            InstrFlashErase()
            tmr.delay(100)
            frame1024=0--номер переданного фрейма


        
            st=net.createServer(net.TCP,30)--Сервер для приема файла программы и трансляции ее в AWR, выключается командой stop program
            st:listen(40001,function(c)
        
            c:on("receive", function(c, payload)
            tmr.wdclr()
       
            Programming (payload)
            frame1024=frame1024+1
             
            end)
            end)
        end

          
        if (payload =="data\r\n")
        then
            
            tmr.wdclr()
            c:send("ready\r\n")
            --  print("ready for data\r\n")


    
        
            c:on("receive", function(c, prog_address_payload)

            prog_address=prog_address_payload--получаем IP адрес UDP хоста для отправки к нему данных
            --  print(prog_address)
            c:send(prog_address) 

     
            
            srv=net.createUDPSocket()-- Сервер для приема данных , выключается командой data stop
       
            srv:listen(50000)
            
            uart.setup(0,9600,8,0,1,0) 
              
            srv:on("receive", function(srv, pl) -- принимаем данные с компьютера по UDP
            pl=pl*1
            --     print(pl)
                 
            
            uart.write(0,pl) -- отправляем их по UART на AVR
            end)
          
            uart.on("data", 1, function(data) -- принимаем данные по UART из AVR

            srv:send(50000,prog_address,data) -- отправляем их по UDP на компьютер
                 
            end, 0)

            tmr.wdclr()   

            end)
            
       end

     
       if (payload =="stop data\r\n") -- здесь закрываем ненужные уже сервера
       then

             ready = false
             if(srv~=nil) 
             then
                srv:close()
                 --  print("stop data")
             end
                collectgarbage()   
       end


       if (payload =="stop program\r\n") 
       then 
            if(st~=nil)
            then
                st:close()
                frame1024=0
                ProgrammingDisable ()
                -- print("stop program")
            end

            collectgarbage()

           
       end

                
    end)
    
end)


Она почти такая же, как и описанная в первой части, но теперь умеет не только транслировать поток данных с компьютера на AVR микроконтроллер, но и делать теперь это в обратном направлении.

В процессе написания пришлось разрешить интересную загвоздку. Когда мы по протоколу UDP сыпем данные с компьютера на ESP8266, то проблем никаких нет. IP адрес ESP модуля известен (мы его сами вбиваем в начале, если что), порт известен, всё хорошо. Но когда мы пытаемся отправить данные в обратном направлении, то сделать мы этого не можем, так как ESP модуль не знает IP адрес компьютера, на котором запущен программатор. Вернее, он его знает, поскольку до этого мы устанавливаем контакт по TCP протоколу для пересылки управляющих команд (program, data, stop). А при использовании этого протокола устройства обмениваются своими адресами, ибо он двунаправленный. Но вот нам он его не скажет. Во всяком случае, я не нашел в API NodeMCU функции для его вытаскивания. Можно конечно, вбить IP компьютера прямо в загрузчик на ESP8266, но и это не выход. Вдруг мы запускаем программу для обмена данными на другом компьютере. Или у него не одна сетевая карта.

Поэтому я сделал костыль. Мы передаем IP компьютера, на котором запущена программа явно перед началом обмена данными. В API JAVA к счастью есть функция определения сетевого адреса хоста, на котором работает программа. ESP8266, получив этот адрес, теперь спокойно может слать данные не только в AVR, но и из него. Что касается программы на LUA, то она очень дубова, наивна и проста, а связано это с тем, что в этом языке я ориентируюсь пока еще очень плохо.

Итак, с помощью ESPlorer мы прописываем обновленный загрузчик в ESP8266. Не забудьте либо изначально обозвать файл, как init.lua или переименуйте его через ESPlorer, а то не взлетит. Ну, и естественно, забейте в тело (там, где MAIN BLOCK) загрузчика имя вашей сети и пароль.

Дальше нам надо определить и зафиксировать IP адрес ESP модуля в нашей внутренней сети. Заходим в местный роутер под правами админа и видим что-то в этом роде.



Это адрес пока динамический (то есть после переподключения может быть назначен другой) поэтому мы делаем его связывание с MAC-адресом ESP8266 там же в роутере.



Его можно даже написать (последние цифры) на самом модуле, если у вас склероз.



ESP модуль готов к работе, можно коннектить его с AVR микроконтроллером.



Запускаем BABUINO, пишем IP адрес ESP модуля, выбираем HEX файл (какой-нибудь BLINK), жмём «Upload» и наслаждаемся миганием светодиода. Программатор напишет в своём окошке, что-то вроде этого:



Но иногда может быть и такое, если ESP модуль по какой-то причине помалкивает:



Теперь посмотрим, как наш загрузчик зашитый в ESP8266 может обмениваться данными в обе стороны. Для этого мы будем управлять робо-тележкой с клавиатуры компьютера, а она будет отправлять нам свой пройденный путь. Первая моя четырехколесная робо-тележка погибла смертью храбрых, получив сигнал из Космоса и упав со стола (этот астральный факт будет объяснен позже). Поэтому пока не придет новая акриловая рама из Китая, эксперименты будут проводиться над двухколесной робо-тележкой, которую, к слову, уже как с год я периодически пытаюсь заставить балансировать на двух колесах, но пока безуспешно. По схеме подключения электроники и программе для AVR, тележки эти не отличаются, чем мы и воспользуемся.



Программа для работы телеги написана на С и больших затруднений в понимании вызывать не должна. Пишем постоянно новое значение скорости в регистры ШИМ регулятора, а он выдает сигналы на моторы. Есть цепь обратной связи на внутреннем АЦП микроконтроллера. При снижении напряжения батарей скорость программно увеличивается. Благодаря этому вплоть до полной просадки, тележка катается с постоянной скоростью. Суть в том, что чем плотнее заполнение ШИМ, тем быстрее крутятся моторы, но поскольку напряжение батареи со временем падает, то они крутятся медленнее. Тогда увеличивается заполнение ШИМ и они снова крутятся быстрее. И так пока заполнение ШИМ не будет 100%, то есть на выходе будет постоянно логическая “1”. Тут уж ничего поделать нельзя. На зарядку!

Программа на С для микроконтроллера AVRmega328P
/*
 * TWO_WEELS_ROBOT_NEW.c
 *
 * Created: 22.09.2017 23:48:49
 * Author : User
 */ 

#define F_CPU 16000000

#include <avr/io.h>
#include <stdint.h>// стандартные целые числа

#include <avr/interrupt.h>
#include <math.h>	// математика
#include <stdio.h> //стандартный ввод-вывод
#include <setjmp.h>
#include <stdlib.h> //стандартные возможности


volatile uint8_t Speed_of_ADC_conversion=0;
volatile uint8_t U_BATTERY; //среднее напряжение  подаваемое на моторы деленное на три

volatile uint8_t avr_speed=30;// граница скорости, к которой сводится обратная связь с напряжения
// при 8 вольтах батареи макс скорость равна где-то 110
// средняя , берите 53. На 10 еле ползет

volatile uint8_t komanda_s_kompa = 0;

volatile uint8_t transmition_ready = 0;
volatile uint8_t wheel_counter=0;





#define Left_Speed  OCR0A	// скорость левых моторов
#define Right_Speed  OCR0B  // скорость правых моторов


	void time_delay(long dell)// передается время в миллисекундах
							//   функция для временных задержек
					
	{ long i;
		cli();
		sei();
		dell=dell*1500;
		for(i=0;i<dell;i++){;;};

	}


ISR(USART_RX_vect)  //получаем команды управления через UART
{

	komanda_s_kompa=UDR0;

}



ISR(PCINT1_vect )//PC2 int 10 //вход счетчика оборотов колеса
{
		
	transmition_ready=1;
	wheel_counter++;
	
}



ISR(TIMER0_OVF_vect)// старт цикла запускаем ацп каждые 30 мс, 
	// на первом цикле запускается АЦП, на втором корректируется скорость раз в 90 мс
{
	
	Speed_of_ADC_conversion++;
		if (Speed_of_ADC_conversion<2)
	
		{ADCSRA |=(1<<ADSC);}// запускаем АЦП
	
	
		if(Speed_of_ADC_conversion>2)// запускаем коррекцию скорости 
	{
		ADCSRA &=~(1<<ADSC);
		Speed_of_ADC_conversion=0;
		U_BATTERY = ADCH;////регистр данных с ацп
						// в него заносится напряжение с моторов, через делитель 1/3 и
						// и интегрирующий конденсатор поскольку напряжение с ШИМ импульсное 
						//т.е макс U = 8 вольт (2 литиев батарейки - LN298 1 вольт)   = 7 вольт / 2
						// равно 3,5 т.к. вокруг нуля и еще делитель ,то на вход АЦП попадет  около 1 вольт 
			if(U_BATTERY<=avr_speed)// коррекция скорости
				
				{Right_Speed++;// если притормозили из-за расхода батарей, то увеличиваем скорость
				Left_Speed++;}
				else
				{Right_Speed--;// если разогнались, то притормаживаем
				Left_Speed--;}
	
	}

}



void stop()

{
	
	PORTD|=(1<<PORTD3);
	PORTD|=(1<<PORTD2);
	PORTD|=(1<<PORTD4);
	PORTD|=(1<<PORTD7);
	
}



void go_left()
{
	
	PORTD|=(1<<PORTD3);// правый вперед
	PORTD&=~(1<<PORTD2);
	PORTD|=(1<<PORTD4);// левый  назад
	PORTD&=~(1<<PORTD7);
	
}



void go_right()
{	
	
	PORTD|=(1<<PORTD2);// правый назад
	PORTD&=~(1<<PORTD3);
	PORTD|=(1<<PORTD7);//левый вперед
	PORTD&=~(1<<PORTD4);
	
}



void go_ahead()// движение вперед  
{
	
	PORTD|=(1<<PORTD3);// вперед
	PORTD&=~(1<<PORTD2);
	PORTD|=(1<<PORTD7);//вперед
	PORTD&=~(1<<PORTD4);
	
}



void go_back()// движение назад
{
		
	PORTD|=(1<<PORTD2);// правый назад
	PORTD&=~(1<<PORTD3);
	PORTD|=(1<<PORTD4);// левый  назад
	PORTD&=~(1<<PORTD7);
	
}








int main(void)




{ cli();
	//инициализация UART на 9600
	UCSR0A=0;
	UCSR0B=0b10011000;
	UCSR0C=0b00000110;
		
	UBRR0L=103;
	UBRR0H=0;
	
	//инициаализация внешнего прерывания INT0 на порту С2 номер прерывания 10
 

	PCICR|=(1<<PCIE1);// разрешение группы прерываниС14-8
	PCMSK1|=(1<<PCINT10);// разрешение конкретного прерывания INT10
	DDRC&=~(1<<PORTC2); // порт на вход для прерывания от  геркона
	PORTC|=(1<<PORTC2);
		
	
	
	
	
	
	// инициализация АЦП напряжение подаем на ADC1, 
	
	ADMUX= 0b01100001;  // V ref питание 5 в, сдвигаем результат ADC1  преобразования влево в старший регистр, канал 2
	ADCSRA=0b10010110;// прерывания от ацп запрещены опрашиваем программно
	ADCSRB=0;
	DDRC&=~(1<<PORTC1);//порт ацп/

	
	// инициализация счетчика Т0 для ШИМ модуляции регистр А левые моторы, регистр B правые
	
	
	TCCR0A |=(1<<COM0A1)|(1<<COM0B1);//внешние выводы включены
	TCCR0A &=~(1<<COM0A0)&~(1<<COM0B0);
	TCCR0A |=(1<<WGM00);
	TCCR0B &=~(1<<WGM02)&~(1<<WGM01);// режим ШИМ c точной фазой
	TCCR0B|=0b00000101; // частота переполнения 30 гц
	// CS02 CS01 CS00 - 000 - отключен; 001  без делителя; 010 c делителем 8; 
	// 011 -64; 100 -256; 101 -1024
	TIMSK0|=(1<<TOIE0);// разрешаем прерывание от Т0 по переполнению
	

	
	DDRB|=(1<<5);// зеленый светодиодный выход
	DDRD=0b11111110; // порты для моторов и ТХ на выход, RX на вход
	PORTD&=~(1<<PORTD5)&~(1<<PORTD6); // останов моторов после сброса
	
	
	Left_Speed=10;// начальная скорость моторов маленькая для плавного разгона
	Right_Speed=10;//максимальная скорость моторов определяется напряжением батареи ( 8-12 в)
	
	sei();
	
	PORTB |=(1<<5);//помигаем после сброса
	time_delay(500);
	PORTB &=~(1<<5);
	time_delay(500);
	PORTB |=(1<<5);
	time_delay(500);
	PORTB &=~(1<<5);
	time_delay(500);
	PORTB |=(1<<5);
	
	while (1)
		


				{	
	
				
				
				if( (UDRE0)){
				if(transmition_ready==1)// отправляем данные если путь увеличился
					{
					
					UDR0=wheel_counter;	
					
					
					transmition_ready=0;
				
					}
				}
				
		
		
	
			
				switch (komanda_s_kompa)
				{
				
				
				case 2:
				go_right();
				break;
				
				case 1:
				go_left();
				break;
				
				case 3:
				go_ahead();
				break;
					
				case 4:
				go_back();
				break;
				
				case 5:
				avr_speed++;
				if (avr_speed>100)
				{
					avr_speed=100;
				}
				time_delay(200); // газуем
				
				break;
				
				case 6:
				avr_speed--;
				if (avr_speed<0)
				{
					avr_speed=0;
				}
				time_delay(200);// тормозим
				break;
				
				case 0:
				stop();
				break;
		
					
				
				}
		
				}
		
}	


Пройденный путь считается герконом, который выдает внешнее прерывание INT10. Как только путь инкрементируется, то данные сразу сыпятся в UART. Соответственно сигналы управления (вперед, назад, влево, вправо, газ, тормоз, стоп) поступают из UART в обратном направлении.

Обратите внимание, что китайские моторы фонят с жуткой силой, так что не помогают никакие конденсаторы по питанию. В цепи геркона наводятся такие помехи, что создается впечатление, что ваша тележка участвует в Формуле 1 по скорости прохождения трассы. Спасает, только конденсатор 22 нФ на входе внешнего прерывания глотающий эти помехи.

Сама программа руления телегой взята из предыдущей статьи, где она ранее управляла механической рукой. Сделаны лишь небольшие дополнения: два текстовых окошка, где можно видеть в режиме реального времени, получаемые и отправляемые данные (1,2,3,4,5,6,0 — вперед, вправо, влево, назад, газ, тормоз, стоп), а также возможность редактирования и сохранения IP адреса ESP модуля через GUI и кнопка «Connect». Управляем тележкой при помощи стрелок либо с клавиатуры, либо мышкой в окне. Правда поскольку все кнопки в одном цикле, изменять скорость и направление одновременно не получится, только поочередно. Но понятное дело, это только из-за того что программа демонстрационная.



Исполняемый файл для 64 бит Windows. Из него же можно выдрать код на Java. Или взять на Гитхабе.

Теперь, когда программатор и обмен данными протестированы (вообще, наверное, я не меньше сотни раз прошивал AVR по WI-FI таким макаром), то можно вернуться к вопросу, почему я выбрал для себя этот путь, а не esp-link.

Итак, начнём с инсталляции.

Прошивка ESP модуля у меня чуть сложнее, чем у конкурента. Сначала шьем NodeMCU, потом заливаем загрузчик на LUA. В esp-link шьём только одну прошивку. Но затраты времени здесь однократные. В дальнейшем мы ESP модуль не трогаем. С другой стороны, в нашем случае мы можем допиливать мою дубовую программу на LUA, как нам хочется, добавлять свои модули и т.д. и т.п. С esp-link это сложнее. Там знанием азов LUA и API NodeMCU уже не отделаешься.

На стороне компьютера преимущества полностью у BABUINO. Просто запускаем исполняемый файл и работаем. Даже среды JAVA не надо, если у вас 64-разрядная версия Windows (но зато тогда надо 200 Мбайт диска). А если у вас Линух или МакОсь, то тогда вообще можете проверить слоган компании Oracle про свою Java, «Написано в одном месте, работает везде», ибо виртуальная машина Java и байт-код же. Но, если честно, не проверял, не знаю.

С esp-link вас ждут знатные танцы с бубнами, по установке Tibbo manager (знаю по опыту). Это такая программа для поддержки виртуального COM порта. Требует настройки кучи параметров и постоянного присутствия в системе. Сразу вряд ли заработает, крепитесь. Потом через браузер надо настроить сам ESP модуль. Важно везде, в том числе и в Tibbo выставить правильные скорости обмена данными и всяких битов стоп и четности.

После чего, уже через стандартный Arduino Uploader (с которого я спи… взял дизайн) или через среду Arduino IDE (опять таки настроив COM), начинаем очень до-о-олго грузить программу в AVR. Нет, правда, она реально грузиться вечность. Даже, если маленькая. Можно чай сходить заварить за это время. Минус, периодически отваливается, оставляя вас в полном недоумении, почему загрузка не состоялась. И тут выход один — сброс, перезапуск, сброс, перезапуск…

А BABUINO закидывает намного быстрее, как и обычный SPI программатор (а файлы, умещающиеся в один пакет 1024 байт, вообще мгновенно). Правда, не верифицирует. Но это поправимо и много времени все равно занимать не будет, так как будет вестись одновременно с прошивкой (хорошая особенность протокола SPI). Плюс нам доступны все SPI команды программирования: фьюзовые и локовые биты, прошивка EEPROM и т.д. А если запись не получается, то вы все причины видите в текстовом окне. Примечание. Команды-то доступны, но реализации пока нет. Упс.

Это то, что касается беспроводного программирования. Теперь перейдем к пересылке данных. В этом плане я esp-link не пользовался, поэтому рассуждения мои будут чисто теоретическими.

Итак, esp-link использует, насколько мне теперь известно MQTT протокол. По сути это всего лишь абстракция следующего уровня над TCP.



Не вдаваясь в тонкости, посмотрим, зачем он вообще нужен.

Ну, к примеру, когда у вас много устройств в каком-нибудь умном доме, которые работают на этом протоколе. Когда у вас что-то там уходит в облако и обратно. Когда вы интегрируетесь в какую-то сеть, работающую на MQTT. Когда у вас совместный проект, чтобы не выдумывать что-то свое, а пользоваться чем-то готовым и известным коллегам.

А если вам просто надо отправить байтовый поток туда обратно без проводов, то нафига вам такие сложности? Зачем громоздить ещё один протокол сверху?

Хотя, я естественно, не отрицаю полезности MQTT протоколов вообще и даже попробую интегрировать его поддержку в свой загрузчик-обменщик в следующих наработках и статьях. Но пока он мне не нужен, дальше поглядим. А нужен ли он вам, решайте сами.

Тем временем тележка моя послушно крутит колёсами в нужную сторону и высылает телеметрию пройденного пути на компьютер (обратите внимание, брандмауэр компьютера может не пущать пакеты с ESP). В следующий раз попробуем поуправлять ею с мобильного телефона. Я пробовал балансировать её на двух колесах с клавиатуры, но опыт оказался неудачным. Есть мысль использовать для этого акселерометры смартфона (пробовал использовать и отдельную плату с гироскопом и акселерометром, но не взлетело).

Вернемся теперь ко второму вопросу, неоднократно поднимавшемуся в ходе обсуждения статьи в комментариях. «А почему не сделать всё на ESP? Она же может! А AVR пусть будет как расширитель портов и хватит с него».

Конечно, может! Хотя все равно, как видим без AVR не обойтись.

Да, она может, если:

1. Вы потомственный объектно-ориентированный программист обожающий заворачиваться во всякие обёртки, делать колбэки, и не мыслящий жизнь без мета таблиц.

2. Вы неплохо знаете детали работы разных ОС. И вам раз плюнуть изучить новую ОС теперь уже RT (реального времени) её системные вызовы и библиотеки, написанные китайцами за миску риса.

3. В университете ваше знакомство с микроконтроллерами ограничилось одной-двумя лабораторными работами, и вы даже знать не желаете какие-сякие там биты и периферийные устройства. И вообще, вам для ШИМ, например, проще взять программную библиотеку, чем чего-то там использовать аппаратно.

4. Вам не нужна реакция устройства в микросекунды. Нет, конечно, RTOS может попробовать вам её обеспечить, на то она и операционная система реального времени. Но не факт, что обеспечит.

5. У вас нет сотен килобайт уже написанного кода, а главное уже работающего без глюков на AVR и вам не надо соответственно его портировать и отлаживать, а проще писать на нативном SDK (который тоже вам, раз плюнуть изучить по английским источникам) с нуля.

Тогда, да. Не читайте эту статью. А главное, не пишите комменты.

Но если:

1. Вы много лет ковыряетесь с микроконтроллерами и знаете их архитектуру наизусть.

2. Вам не нужны непонятного китайского происхождения баги.

3. Вы написали и отладили уже мегабайты кода за свою долгую жизнь разработчика, и вам совершенно не хочется заново всё переписывать и отлаживать.

4. У вас нет времени или желания изучать на языке вероятного противника нативный SDK и RTOS не очень широко известной в миру компании (это ж все-таки не Микрософт), а также ждать и верить в их патчи и апдейты.

5. Программируя, вы никуда особо за «begin if then do while switch end» не вылазили, а слова лямбда-функция и корутина считаете матерной латынью.

6. Вам, по сути, к вашему и так прекрасно работающему устройству, но в соответствии с веяниями новых времён, нужен просто беспроводной мост для идентификации, программирования и обмена данными.

Ну и используйте для этого ESP8266. Просто, как беспроводной мост. Они, понимаешь, используют AVR как расширитель портов для ESP. А мы сделаем наоборот!



На самом деле, прошу не относиться к последним моим высказываниям слишком серьезно. По сути это всего лишь шутка. Любой достаточно опытный разработчик делает свой выбор на основании многих факторов как-то: параметры быстродействия и энергопотребления, жизненный цикл устройства, преёмственность с прошлыми наработками, стоимость самого изделия и стоимость перевода на новую платформу, надёжность, время требующееся на изучение новых архитектур, SDK, операционных систем, наличие сотрудников с таким опытом работы в совместном проекте и так далее.

Поэтому лучше когда:



Буду рад, если статья вам понравилась. Библиографии не привожу, она та же, что и в предыдущей статье.

P.S.

А напоследок про сигналы из Космоса. Весь секрет в том, что ESP модуль с прошивкой NodeMCU очень любит отправлять всякую информацию на консоль. К примеру, после аварийной перезагрузки (а она у ESP случается иногда, уже поверьте, глюкоза ещё та). Или, например, если вы забыли убрать print («чего-то там») из самой программы на Luа после отладки. Или когда у вас вылазит Deprecated (устаревший) API (вы сменили прошивку и должны теперь использовать новое написание, к примеру, при запуске UDP сервера) и ESP теперь будет всегда напоминать вам об этом. Пока не перепишете код.

И вот проблема в том, что всё это аккуратно и методично отправляется на консоль, то есть в порт UART. Ну, а если ваш порт UART ждет в это время команду или данные, чтобы указать вашей тележке поехать вперёд? То тогда ваша тележка может упасть со стола.
Так, что этот момент тоже стоит учитывать.

Комментарии (43)


  1. igrushkin
    18.10.2017 10:48

    Круто! а просто как UART мост можно использовать? Или только для прошивки?


    1. Tarson Автор
      18.10.2017 12:23

      Здесь получается, что UART под UDP лежит. Комп гоняет данные туда обратно по UDP. А UART валяется под ним на стороне микроконтроллера.


      1. igrushkin
        18.10.2017 12:25

        меня практический вопрос интересует: можно ли читать данные с UARTа?


        1. Tarson Автор
          18.10.2017 12:30

          конечно можно. программка по рулению телегой прямо и получает данные с uart по пройденному расстоянию. Как только AVR кидает байт в UART, он тут же появляется в виде UDP пакета на выходе c ESP и отправляется на комп.


          1. Tarson Автор
            18.10.2017 12:43

            А как только комп бросает байт в виде пакета UDP в сторону ESP, он тут же появляется уже снова в виде байта на входе UART микроконтроллера и тот может его прочесть.
            Так да. Двусторонняя передача.


          1. igrushkin
            18.10.2017 12:43

            ОК, спасибо, просто недавно на esp8266.ru была заруба на тему возможности создания такого моста.


            1. Tarson Автор
              18.10.2017 12:48

              Интересно о чём там можно рубиться? Киньте ссылку пжлст, если есть.


              1. igrushkin
                18.10.2017 12:52

                esp8266.ru/forum/threads/transparent-most-uart-wifi.2857/page-2#post-42236

                Осторожно, там есть местный сумасшедший, не пытайтесь с ним дискутировать.


                1. Tarson Автор
                  18.10.2017 13:05

                  А, я читал. Там немножко другое. Они хотели прозрачный мост, да еще дуплексный, да еще быстрый.
                  Я согласен, что ESP тогда заикаться начнет.

                  Если внешний сервер, то ESP8266 не справится — нема RAM для буферизации UART потоков и адаптации скоростей TCP стека уже на 115200. Будут дыры и нарушения синхронизации дуплексных потоков RX/TX на UART.


                  Просто, обычно с такой скоростью бегать не требуется, да еще за пределы внутренней сети. Мне наоборот, допустим, пришлось делать задержку в 200 милисекунд, когда я на «газ» нажимал на телеге, ибо он сразу зашкаливал.
                  Но, если надо совсем быстро, то упс…


                  1. igrushkin
                    18.10.2017 13:07

                    а я ведь предупреждал не слушать сумасшедшего :-)) в изначальной задаче топикстартера этих требований не было


                    1. Tarson Автор
                      18.10.2017 13:11

                      Да, не, он нормальный. Только дотошный.


                1. A__D
                  19.10.2017 12:48

                  Хах. «сумашедший»… видимо ардуиноголовногомозга мешает здраво мыслить и воспринимать толково, пусть и дотошного, но реально разбирающегося человека. Иногда он конечно перегибает палку, но и выкладывает наработок и материалов больше, чем все остальные…


                  1. igrushkin
                    19.10.2017 12:50

                    пэвэвэха, перелогиньтесь


                    1. A__D
                      19.10.2017 12:54

                      Если не знаете, то он тут тоже есть и не под моим ником. ванга фейл.


                  1. Tarson Автор
                    19.10.2017 12:53

                    Так это ж комплимент.
                    Дотошный — придирчиво, пытливо, настойчиво вникающий в каждую мелочь; въедливый.
                    Не, лично я pvvx всегда с интересом читаю.


                    1. A__D
                      19.10.2017 12:58

                      Я то как раз и не в плохом смысле имею в виду, да он иногда прям слишком бросается в дискуссии и поучение других, но в тоже время в разборе кухни RTL871x это очень полезно. Многих это бесит (есть там пара товарищей, у которых судя по постам регулярно бомбит в дискуссиях, АК даже на мат переходил), я же научился на это не обращать внимания и дискутировать по делу, и так дискуссия проходит продуктивно и по делу.


                      1. igrushkin
                        19.10.2017 16:15

                        возмжно, в дискуссиях о RTL871x он и полезен, жаль, что в дискуссиях о ESp8266 он бесполезн чуть более, чем полностью
                        А RTL871x, кстати мертв, так и родившись.


                        1. A__D
                          19.10.2017 17:25

                          На WEB свалке от него не мало чего основано, по тому же форуму можно увидеть… ну как бы, это дело долгой полемики.
                          Если народу нравится копеешные ESP, с их глюковатостью и в одной сети если их 5-6, то wi-fi просто ужасный становится — то это выбор народа, не всегда общественное мнение выбирает лучший вариант. (как пример — допотопные AVR8 в ардуино и противовес им более дешевые STM32F0 — с головой их превосходят по периферии и возможностям, только чуть сложнее, но видимо порог вхождения решает)


                          1. igrushkin
                            19.10.2017 17:28

                            ага, именно поэтому Arduino (компания) реализовала wifi именно на esp8266 в своей последней флагманской плате.
                            Как думаете, у них был выбор?
                            я не испытываю иллюзий по поводу esp8266, но он далеко не так плох, как пытаются представить такие, как вы и пэвэвэха


                            1. A__D
                              19.10.2017 18:39

                              хм… ок, открываем Официальный сайт: www.arduino.cc/en/Main/Products
                              Где тут ESP?
                              Есть с WiFi, но он на Атмеловском чипе
                              store.arduino.cc/usa/arduino-wifi-101-shield
                              ну и
                              store.arduino.cc/usa/arduino-iot-mkr1000-bundle
                              на АРМ ядре всё.

                              Не вводите в заблуждению других людей, выдавая поделку Espressif Systems за официальный ардуино шилд.
                              А про глюковатость ESP8266 я пишу не с чужих слов, а на своём опыте общения с ним, для быстро-поделок пойдет, для серьезных проектов и на перспективу — никак нет.


                              1. igrushkin
                                19.10.2017 19:19

                                Вы отстали от жизни. Самые последняя плата Arduino — Primo.
                                Погуглите. Сильно удивитесь.
                                Кстати, в esp8266 там прошивка, которую Ваш друг пэвээвэха облил дерьмом, но это мелочи


                                1. A__D
                                  19.10.2017 19:29

                                  Уж ардуиной не занимаюсь, извиняюсь, что не слежу за трендами в этой теме для хоуммейкеров…
                                  И ссылки видимо не комильфо приводить, ок, приведу за вас:
                                  store.arduino.cc/usa/arduino-primo

                                  Мда, 3 МК на одной плате и цена добротная (а все почему то ESP-01 юзают, странно...), норм, хомячки схавают.

                                  И ванговать у вас плохо получается, завязывайте… мы не дружим…


                                  1. igrushkin
                                    19.10.2017 19:31

                                    Слушайте, ну нельзя так позорно сливаться :-)) хомячки, три Мк :-)))
                                    Тезис был другой


                                    1. A__D
                                      19.10.2017 19:39

                                      И в чём слив? Первое моё сообщение было о pvvx и вы до сих пор ничего толком не привели для его «очернения» так скажем по факту. А только и обливаете его грязью просто так и еще в друзья другим записываете… прям как на форуме определённые товарищи-тролли, которые ничего своего не выкладывают, да только тыкают всех носом и рассказывают как же правильно то делать надо. Так что, спорить с обиженным на pvvx не вижу смысла, сами знаете что возят на обиженных… удачи в проектах!


                              1. igrushkin
                                19.10.2017 19:20

                                Ответил ниже


  1. izzholtik
    18.10.2017 11:05

    Что у NodeMCU с реалтаймом?


    1. Tarson Автор
      18.10.2017 12:28

      Сложно сказать. Глубоко я его не знаю. Если для передачи данных, то за TCP и UDP поспевает, Но там что, в крайнем случае миллисекунды же.
      А так надо в RTOS ковыряться, смотреть, какие возможности она обеспечивает. Это на форум по ESP
      esp8266.ru/forum


      1. Barnaby
        18.10.2017 15:15

        Не обязательно RTOS https://github.com/esp8266/Arduino


        1. igrushkin
          19.10.2017 16:48

          это к чему?


          1. vvzvlad
            21.10.2017 03:02

            Это к тому, что не обязательно писать под rtos, можно взять любимый вами суперцикл.


            1. Tarson Автор
              21.10.2017 13:18

              Так это только кажется, что будет любимый нами суперцикл. А что там будет в реальности знает только ужасная rtos. Если я правильно понимаю, там ардуино обертка, под ней API NodeMCU или API rtos и все это работает в итоге все равно под управлением rtos?
              Тогда у вас там сегодня будут одни тайминги, завтра другие, потому, что параллельно другая задача запустится, про которую только rtos знает, а послезавтра она вообще килнет ваш процесс, потому что у нее где-то утечка и памяти не хватает. А атмел, за что купил, за то продал. под программой голое железо.


              1. vvzvlad
                21.10.2017 20:03

                Простите, я даже потерялся, что ответить на эту яростную тираду. Смешались в кучу кони, люди, RTOS, NodeMCU и ардуино. Что значит «это только кажется, что будет суперцикл»?

                Там нет никакого API внизу. Там просто подключенные Arduino-библиотеки к родному SDK, дабы не изучать его функции, а писать в привычной среде привычными функциями(и то, и то говно, но не будем об этом).
                API NodeMCU — это что вообще за зверь? Системные луашные функции? Каким они боком к си вообще? Что такое «API rtos»? Функции для управления процессами в ртосе? Опять же, каким они боком к си и суперциклу?

                Все проще. Для ESP8266 есть два официальных SDK: NON-OS SDK и RTOS SDK. Первое — это как раз таки голое железо. Разве что только там запускается системный таймер, который периодически передает управление на часть кода, который управляет работой WiFi. Но так как там 80 МГц и 32 бита, оно на порядок-два быстрее атмела с его 8 МГц и 8 битами, поэтому то, что периодически управление куда-то передается, заметно не будет. Если у вас есть задачи, где на 80 МГц нельзя даже отвлечься — есть запрет прерываний для критичных участков, некоторое время оно может подождать. В остальном, там точно такой же микроконтроллер, как и у атмела, на котором выполняется та же самая программа, которая пишется на таком же си, и которая оборачивается в while(1) после инициализации периферии. Какие утечки, там 100 килобайт памяти, вы что, собрались там что-то динамически выделять? Там все статично в начале выделяется(за редким исключением), и никаких утечек быть не может.

                RTOS SDK — уже интереснее. Там уже есть некая простая операционка, которая позволяет реализовывать многозадачность. В сочетании с нормальной скоростью контроллера, это уже позволяет нафигачить туда кучу процессов, которые будут выполняться вместе, и получить очень удобную среду для разработки.
                Что вы понимаете под «изучением ртос»? Они же все одинаковые. Десять функций для управления процессами(старт, стоп, пауза, послать сообщение, принять сообщение и так далее), пара-тройка видов таймеров, все. Ужасного ноль, разработку ускоряет. И там тоже выделение памяти статичное.


                1. Tarson Автор
                  21.10.2017 21:24

                  Ну, API ОС вроде общее понятие.

                  набор готовых классов, процедур, функций, структур и констант, предоставляемых операционной системой для использования во внешних программных продуктах. Используется программистами при написании всевозможных приложений.


                  API NodeMCU — я так понимаю абстракция следующего уровня от энтузиастов, позволяющая быстро создавать кучу функционала, типа тех же серверов, PWM, ну и там куча всего чуть ли не сотня наименований. Но она же не на железе по идее стоит, а пользуется сервисами RTOS, то же создание потоков и т.д. Так же как и ваш проект, Ардуино обертка, о котором вы говорили.

                  Это о конях и людях.


                  1. Tarson Автор
                    21.10.2017 21:34

                    Но, когда у вас сервер и несколько потоков, вы же не на голом железе NoN OS SDK их же не напишите? Значит надо брать RTOS SDK?

                    А ОС есть ОС, может для вас она и простая, но операционные системы вообще как таковые к классу простых программ никогда не относилась, даже со времен CP/M. Можно в них лезть разбираться, но жизнь коротка. А насчет быстродействия, ну у меня проц 3 ГГЦ и памяти терабайты, а зависнуть «на подумать» для Windows легче легкого. Она конечно не реального времени, но и там не 3 ГГц процессор. Да, ресурсов больше, чем у атмел и скорость выше, но при работе под ОС, не факт что быстрее получится в итоге.


  1. vvzvlad
    21.10.2017 02:57

    После подключения к ESPlorer, тот немножко поформатирует ESP модуль, информируя вас соответствующими сообщениями. (главное в этот момент ничего не трогать), а затем ребутнет ESP. Можно начинать работу по загрузке LUA программ.

    Ничего ESPlorer подобного не делает. Это делает сама прошивка — при первом запуске она форматирует флешку под spiffs, а потом перезагружается. Трогать можно — модулю пофиг в этом время на все. Даже если ему питание обрубить, он просто не запишет флаг «форматировано» и при следующем старте начнет форматировать заново.


    1. Tarson Автор
      21.10.2017 03:28

      А ну, да, скорее оно и так. Просто пишет на консоль своё.
      Но ни один вменяемый человек конечно трогать во время «чего-то там formatting» не будет.


  1. vvzvlad
    21.10.2017 03:00

    4. У вас нет времени или желания изучать на языке вероятного противника нативный SDK и RTOS не очень широко известной в миру компании (это ж все-таки не Микрософт), а также ждать и верить в их патчи и апдейты.

    Простите, а у вас на avr тоже ртос? Нет? Тогда что вам мешало писать все это на арудиновской обертке над стандартным sdk с суперциклом?


    1. Tarson Автор
      21.10.2017 03:30

      А зачем мне писать на ардуиновской обертке над стандартным sdk с суперциклом???


      1. vvzvlad
        21.10.2017 04:13

        Чтобы не изучать страшную RTOS, конечно же!


        1. Tarson Автор
          21.10.2017 13:09

          Спасибо за участие… Но я и так её не изучаю.


        1. Tarson Автор
          21.10.2017 13:27

          А как мне в ESP программу загрузить, кстати, без проводов? Если я напишу, допустим скетч на этой обертке.


          1. vvzvlad
            21.10.2017 20:11

            Что значит «без проводов»? Вы имеете ввиду OTA-обновление?
            Вот готовые приложения для sming(тоже суперцикл, но без ардуины): github.com/SmingHub/Sming/wiki/rBoot-and-OTA-updating и для esp8266-arduino: esp8266.github.io/Arduino/versions/2.0.0/doc/ota_updates/ota_updates.html


  1. Tarson Автор
    21.10.2017 21:05

    Я имел в виду, прошивку своего кода во flash память ESP. Есть там вариант беспроводной загрузки?