Ну а кому нужны бессмысленные блинки, с тупыми задержками нопами, например. Как я понимаю, блинк должен не занимать время и память, иначе на кой он тогда нужен! Разве, если только проверить работоспособность платы?
Я бы уточнил: “для полезных примеров”. В число которых, очевидно, входят как самые короткие, так и самые понятные. В отличие от того, что было у Гайвера. У последнего - не более чем “занимательные”. Хотя бы потому, что почти все либо на delay(), либо на аналогах.
В данной же ветке кроме самой первой ссылки все остальные “без delay()”, т.е. имеют хоть какой практический смысл.
Я тут подумал, есть еще один момент, который в отдельных случаях может оказаться существенным.
const byte ledPin = LED_BUILTIN;
const long interval = 500;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
static byte ledState = LOW;
static unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
digitalWrite(ledPin, ledState = !ledState);
}
}
const byte ledPin = LED_BUILTIN;
const long interval = 500;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
static byte ledState = LOW;
static unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis += interval;
digitalWrite(ledPin, ledState = !ledState);
}
}
Варианты различаются 14-й строкой.
Если нам нужно переключать пин не чаще чем раз в interval мс, следует пользоваться первым вариантом.
Если нужно, чтобы переключения происходили в среднем через interval мс, следует предпочесть второй. Во втором варианте можно убрать 11-ю строку, а millis() использовать непосредственно в 13-й.
Естественно, для светодиода это в большинстве случаев не очень критично, но если мы вместо digitalWrite() вызываем какую-то функцию, я которой период опроса играет существенную роль, следует задуматься, который из вариантов нам нужен.
Для критикал тайминг ещё и миллис стоит брать после окончания основного действия, чтобы не получить интервал M-N, где M - минимально необходимый интервала опроса датчика, а N - фактическая продолжительность опроса.
Ну это уже третий вариант - когда необходимо выдержать не период, а интервал между окончанием предыдущего и началом следующего.
“Виртуальный светодиод” позволяет менять количество, расположение, цвет свечения, форму и вид элемента
const unsigned char ris_1[]PROGMEM = {//РИСУНОК СВЕТОДИОДА
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XE0,0X00,0X00,0X1F,0XF8,0X00,
0X00,0X30,0X0C,0X00,0X00,0X60,0X36,0X00,0X00,0XC0,0X1B,0X00,0X00,0XC0,0X0D,0X00,
0X01,0X80,0X05,0X80,0X01,0X80,0X06,0X80,0X01,0X80,0X06,0X80,0X01,0X80,0X06,0X80,
0X01,0X80,0X06,0X80,0X01,0X80,0X06,0X80,0X01,0X80,0X06,0X80,0X01,0X80,0X06,0X80,
0X01,0X80,0X02,0X80,0X01,0X80,0X00,0X80,0X07,0XFF,0XFF,0XE0,0X04,0X00,0X00,0X20,
0X04,0X00,0X00,0X20,0X04,0X00,0X00,0X20,0X07,0XFF,0XFF,0XE0,0X07,0XFF,0XFF,0XE0,
0X00,0X00,0X00,0X00,0X00,0X30,0X0C,0X00,0X00,0X30,0X0C,0X00,0X00,0X30,0X0C,0X00,
0X00,0X30,0X0C,0X00,0X00,0X30,0X0C,0X00,0X00,0X00,0X0C,0X00,0X00,0X00,0X00,0X00
};
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
// TFT_SCL 13
// TFT_SDA 11
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
void setup(void) {
tft.initR(INITR_BLACKTAB);
tft.setRotation(3);
tft.fillScreen(ST7735_BLACK);
}
void loop() {
drawBitmapFast(65, 50, ris_1, 32, 32,tft.Color565(0,255,0),tft.Color565(0,0,0) );// ВКЛЮЧАЕМ СВЕТОДИОД
delay(500);
drawBitmapFast(65, 50, ris_1, 32, 32,tft.Color565(127,127,127),tft.Color565(0,0,0) );// ВЫКЛЮЧАЕМ СВЕТОДИОД
delay(500);
}
///////////функция отрисовки картинки по заданным координатам,размерам и цветам
void drawBitmapFast(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h, uint16_t color, uint16_t bg) {
uint8_t b(0);
uint8_t bc(0);
uint16_t tc(0);
int16_t c = w * h;
// tft.startWrite();
tft.setAddrWindow(x, y, x+w-1, y+h-1);
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
asm volatile(
"mloop_%=: \n"
" LPM %[b],%a[bm]+ \n"
" LDI %[bc],1 \n"
"loop_%=: \n"
" SBRC %[b],7 \n"
" MOVW %[tc],%[color] \n"
" SBRS %[b],7 \n"
" MOVW %[tc],%[bg] \n"
" IN __tmp_reg__,%[spdr]-1 \n"
" OUT %[spdr],%B[tc] \n"
" RJMP .+0 \n"
" RJMP .+0 \n"
" RJMP .+0 \n"
" RJMP .+0 \n"
" RJMP .+0 \n"
" RJMP .+0 \n"
" RJMP .+0 \n"
" RJMP .+0 \n"
" IN __tmp_reg__,%[spdr]-1 \n"
" OUT %[spdr],%A[tc] \n"
" SBIW %[c],1 \n"
" BREQ exit_%= \n"
" NOP \n"
" LSL %[b] \n"
" LSL %[bc] \n"
" BRCS mloop_%= \n"
" RJMP .+0 \n"
" NOP \n"
" RJMP loop_%= \n"
"exit_%=: \n"
: [tc] "=&r" (tc)
: [b] "l" (b), [bm] "z" (bitmap), [bc] "d" (bc), [color] "w" (color), [bg] "w" (bg),
[spdr] "M" (_SFR_IO_ADDR(SPDR)), [c] "w" (c)
: );
// tft.endWrite();
digitalWrite(TFT_CS, HIGH);
SPI.endTransaction();
}
Вопроса два:
- Зачем это здесь вообще?
- Зачем в данном фрагменте нужен ассемблер?
Ассемблер для новичков самая тема - изучил и считай что можешь писать на любом языке !
Шоб блеснуть.
2.Ассемблер, как вариант мне предложенный, даёт самую быструю отрисовку - приближает виртуальные светодиоды к реальным.
- Мне показалось…, после реальных светодиодов можно попробовать блинк и на виртуальных. Всяких симуляторов тьма, а тут интерпретатор-толкователь блинка.
ИМХО, в “блинке” цель не светодиоТ™ освоить, а основополагающий алгоритм программирования МК
Он и есть его образ, как самый доступный и понятный из элем. РЭА. В моём примере можно нарисовать 20 светодиодов и их миллисить до умопомрачения, а макетка с 20 реальными будет ёжиком небритым.
Начинающего путает в мыслях обычный INPUT, а тут код, в котором сделать ошибку можно даже не стараться.
Ну это проба, а так в мыслях свести к двум командам led_1(red); led_1(off); через функцию и дефайны.
Это утверждение можно подкрепить цифрами?
Особенно с учетом последующего delay(500);
Да, в старой теме - выходило 46-48 миллисекунд на отрисовку полного экрана. 20 кадров за секунду, около.
Ты за спрайты чонить слышал? У этих экранчиков можно обновлять только необходимую, меняющуюся область памяти (правда с дискретностью по вертикали в 8 точек). Задаешь сначала адрес куда выводить (в терминах экрана) и выводишь только измененные данные, а не перерисовываешь весь экран.
Помница мне, когда я с этими экранами экспериментировал (давно было) ему можно было указать “окно вывода”, все записи в память не выходили за пределы ограниченной области, адресация была относительная, первая ячейка ограниченной области (не экрана), имела логический адрес 0.
Могу ашибацца, давно было.
В скетче так всё и написано. Весь экран это все 20 штук, для одного будет гораздо быстрее.
Если мы утверждаем “самая быстрая”, то одной цифры мало: цифру нельзя сравнивать саму с собой. Для сравнения нужно минимум две цифры.
Например, одна - для того, что написано на Ассемблере, а вторая - для того, что написано на Си.
Если мы говорим “самая быстрая”, то должны продемонстрировать другие варианты - которые медленнее.
И, кстати, какой здесь экран? 220х160? Тогда фрагмент 32х32 пикселя - это 3% площади и, соответственно, должен отрисовываться за 1.4 мс. По сравнению с delay(500);
это, конечно, очень существенно.