Дмитрий Кузьмичёв

BK8000L не соединяется по UART и не реагирует на AT-команды

6 сообщений в этой теме

Доброго времени суток!!! Я столкнулся с тем, что не работает UART и не реагирует на AT-команды. Пробовал с 2-мя переходниками: CH340 и FT232RL, тот, что в Arduino. Пробовал и менять контакты RX-TX местами, и скорость менял (должно быть 9600 бод) - терминал молчит от слова совсем. CH340 просто светит своим индикатором приема, а FT232 моргнет при включении и все. Должно выводиться в терминале при включении ON, но не выводится ничего и никак не реагирует. Проверял и обвязкой, и упрощенным подключением (4 провода - 2 питания и 2 UART), и напряжение то 3.3 делал, то 3.7, то питал с аккумулятора - молчание. Подумал, что UART нагнулся из-за моих кривых рук - махнулся с другом на свежую, проверить UART, но результат тот же, полагаю, что в моем даже и не сдох. А сам модуль работает, не считая злосчатного UART. Так в чем может быть проблема? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
--@lexxx--    2

Один в один, такая же история. Хотел переименовать его и пин назначить, но не реагирует на команды. Подозреваю что прошивка урезанная. Там есть на плате еепромка и ее можно перепрошить, вот только бы ее найти. 

  • Одобряю 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

пока нет нормальной прошивки с юартом для этого модуля, я одну из юарт линий кинул на сброс модуля, и опускаю на минус, когда модуль не нужен

  • Одобряю 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
--@lexxx--    2

Ясно. Хотя сам модуль мне понравился. Звучание не плохое. Встроил в колонки. Очень удобно теперь. Вот только бы пин установить, иначе если забыть отключить колонки то любой желающий сможет к ним подключиться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
BARS_    530
В 17.06.2017 в 00:48, Дмитрий Кузьмичёв сказал:

не работает UART и не реагирует на AT-команды

В каком формате шлете команду? Символ окончания строки присутствует?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
12 часа назад, BARS_ сказал:

В каком формате шлете команду? Символ окончания строки присутствует?

По-всякому пробовал: и через Putty, и через Arduino, в разных режимах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Похожие публикации

    • Автор: Aven
      Появилась необходимость собрать устройство на базе Arduino, которое работает с SD картой.
      Так как работа от аккумулятора, нужно максимально снизить ток потребления.
      Возникла проблема, если отключить питание SD карты, чтобы уйти в сон, после его возобновления работа с картой уже невозможна, при попытке пере инициализировать все виснет.
      Вопрос, как лучше реализовать отключение SD карты?
    • Автор: carlogulliani
      Добрый день!
      Столкнулся с такой проблемой, пытаюсь взаимодействовать с чипом AFE4300 по SPI. В дотащите указано, что уровень сигнала 2 - 3 вольта. Подключаю к nrf51 (использует уровень 3.3 вольта), ресетю и пытаюсь прочитать дефолтное значение регистра (0x01C3), в итоге получаю 0xFFFF.
      Перепроверил на Arduino Mega 2560, где уровень сигнала 5 вольт (подключил напрямую без level shifter) и считал свои дефолтные значения. Попробовал также считать другие 4 регистра, все также отлично считалось.
      Вот теперь не пойму, в дотащите указано не верно или у меня что-то не то.
      Еще вопрос про согласовать уровней TXB0108. Пытался через нее прокинуть сигнал от nrf51 (3.3v) на afe4300. Питание А - 3.3в, каналы А к nrf51, питание Б 5в, каналы Б к afe4300, OE к 3.3в. Не завелось, даже анализатор говорит, что MOSI шлет 0xFF, вместо реальных данных. Земля везде общая.
      Правда есть оговорка, как данный уровень ко мне приехал я мог по ошибке запитать Б 3 вольтами, а А 5 вольтами. Но даташит на него говорит, что когда А > Б, это не повреждает чип, хотя А должно быть до 3.6 вольт. Еще мог OE подключить к 5 вольтам. В общем, могли ли мои неразумные операции вывести его из строя???
       
      Еще в даташите указано, что неиспользуемые каналы надо подключить либо к питанию, либо к земле. Это может влиять на то, что я сейчас получаю?
    • Автор: mefi73
      Эта статья является логическим продолжением  вот этой статьи про монохромный OLED дисплей. На этот раз мне в руки достался цветной OLED дисплей, разрешением 96*64 пикселя от магазина Banggood (ссылка на дисплей) Пока не забыл, на странице товара есть ссылка на архив с документацией на дисплей.
      Кроме того достаточно информации по дисплею встречается в сети, так же есть готовые библиотеки для нетерпеливых (от Adafruit, Seeed-Studio и конечно же монстр среди библиотек для дисплеев U8Glib). Я же покажу работу с дисплеем безо всяких библиотек, покажу в среде программирования ArduinoIDE, что бы было понятно новичкам (матерые программисты наверняка разберутся).
      Итак, дисплей может подключаться при помощи параллельных интерфейсов (6800, 8080) и последовательного интерфейса SPI. В модуле, который попал мне в руки, реализован SPI протокол.

      Распиновка слева-направо: 2 вывода для питания, SCL - предназначен для тактового сигнала, SDA - по этому входу в контроллер дисплея поступают данные, RES - предназначен для сброса дисплея, DC (data/command) - логический сигнал на этом входе сообщает дисплею что в данный момент передается, данные или команда (об этом чуть позже подробнее), CS - обычный chip select протокола SPI, низкий уровень на этом входе сообщает дисплею, что данные, поступающие по нему, предназначены именно для дисплея. Подробно вдаваться в суть протока SPI я не буду, стоит только уточнить, что дисплей работает в режиме SPI_MODE3 (CPOL=1, CPHA=1).
      Вас могут смутить обозначения SDA и SCL, ведь они применяются для обозначения выводов устройств, работающих по протоколу I2C, но всё на самом деле не так плохо. Поскольку по линии SDA идут данные от микроконтроллера к дисплею - он подключается к выводу MOSI микроконтроллера (D11 на ардуино). По SCL идут тактовые сигналы, а значит он подключается к выводу SCK микроконтроллера (D13 на ардуино).
      Для выводов RES, DC и CS можно выбрать любые выводы (у меня D10 для CS, D8 для DC и  D9 для RES). Библиотека SPI не будет управлять этими выводами, это придется делать вручную. Разберемся для чего нужен каждый из этих выводов.
      CS - самое простое, логический 0 говорит дисплею о том, что данные предназначены для него, логическая 1 - о том что передача данных завершена.
      RES - служит для сброса дисплея, для этого надо на некоторое время подать на этот вывод логический 0. Это необходимо сделать один раз в начале программы перед инициализацией дисплея.
      DC - логический 0, подаваемый на этот вывод, сообщает дисплею о том, что передаются команды, логическая 1 - передаются данные.
      На основании этого создаем две функции для отправки команды и данных соответственно. 
      #include <SPI.h> const int ss = 10; //slave select const int dc = 8; // data/command data=1 command=0 const int reset = 9; //oled reset=0 void oledCommand(uint8_t val) //общая функция отправки команды дисплею {   digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI   digitalWrite(dc, LOW); //DC равен 0, это значит что отправляется команда   SPI.transfer(val); //отправляем команду стандартной функцией библиотеки SPI   digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена } void oledData(uint8_t val) //общая функция отправки данных дисплею {   digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI   digitalWrite(dc, HIGH); //DC равен 1, это значит что отправляются данные   SPI.transfer(val); //отправляем данные стандартной функцией библиотеки SPI   digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена } void setup() {  pinMode(ss, OUTPUT);  pinMode(dc, OUTPUT);  pinMode(reset, OUTPUT);  SPI.begin();  SPI.setDataMode(SPI_MODE3);  oledInit(); } void setup() {  pinMode(ss, OUTPUT);  pinMode(dc, OUTPUT);  pinMode(reset, OUTPUT);  SPI.begin();  SPI.setDataMode(SPI_MODE3);  oledInit(); } Обратите внимание на функция oledInit() в предпоследней строке кода. Прежде чем дисплей сможет что-либо выводить на экран, его необходимо настроить (инициализировать). Для этого посылаем команды, приведенные в следующей диаграмме.

      init.PNG
      В программе это будет выглядеть так:
      void oledInit() //функция инициализации дисплея {   digitalWrite(reset, HIGH); //процедура сброса дисплея   delay(100);   digitalWrite(reset, LOW);   delay(100);   digitalWrite(reset, HIGH);   delay(100);   //процедура инициализации дисплея   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0xAE); //display OFF   SPI.transfer(0xA0); //remap & color depth setting   SPI.transfer(0x72);          //b01110010 расшифровка ниже   /*   b01 - 65k format, (00 -256 color, 10 - 65k color format 2)   1 - enable COM split odd even (0 - disable)   1 - scan COM95 to COM0 (0 - COM0 to COM95) отражение по короткой стороне   0 - disable left-right swaping (1 - enable swaping)   0 - RGB color (1 - BGR color)   1 - RAM column 0 to 95 (0 - 95 to 0)   0 - horizontal address increment (1 - vertical)   */   SPI.transfer(0xA1); //set display start line (0-63)   SPI.transfer(0x0);   SPI.transfer(0xA2); //set vertical offset (0-63)   SPI.transfer(0x0);   SPI.transfer(0xA4); //normal display (A5 - all pixel ON, A6 - all pixel OFF, A7 - inverse display)   SPI.transfer(0xA8); //set MUX ratio N+1 mux   SPI.transfer(0x3F); //default 0x3F   SPI.transfer(0xAD); //select internal Vcc supply   SPI.transfer(0x8E); //default 0x8E   SPI.transfer(0xB0); //set power saving mode   SPI.transfer(0x0B); //default 0x0B (disable power saving mode) 0X1A - enable   SPI.transfer(0xB1); //set reset, pre-charge period   SPI.transfer(0x31); //default 0x31   SPI.transfer(0xB3); //oscillator frequency   SPI.transfer(0xF0); //default 0xF0   SPI.transfer(0x8A); //set second pre-charge color A   SPI.transfer(0x64); //default 0x64   SPI.transfer(0x8B); //set second pre-charge color B   SPI.transfer(0x78); //default 0x78   SPI.transfer(0x8C); //set second pre-charge color C   SPI.transfer(0x64); //default 0x64   SPI.transfer(0xBB); //set pre-charge voltage level   SPI.transfer(0x3A); //default 0x3A   SPI.transfer(0xBE); //set COM deselect voltage level   SPI.transfer(0x3E); //default 0x3E   SPI.transfer(0x87); //set master current   SPI.transfer(0x06); //default 0x06   SPI.transfer(0x81); //set contrast for color A   SPI.transfer(0x91); //default 0x91   SPI.transfer(0x82); //set contrast for color B   SPI.transfer(0x50); //default 0x50   SPI.transfer(0x83); //set contrast for color C   SPI.transfer(0x7D); //default 0x7D   SPI.transfer(0xAF); //display ON, normal mode   digitalWrite(ss, HIGH); } Теперь дисплей готов к выводу изображения. Но стоит рассмотреть некоторые команды. В частности очень важны следующие строки:
      SPI.transfer(0xA0); //remap & color depth setting
      SPI.transfer(0x72); //b01110010 расшифровка ниже
      /* b01 - 65k format, (00 -256 color, 10 - 65k color format 2) - здесь мы выбираем в каком формате будут задаваться цвета и сколько цветов будет возможно использовать
      Поскольку выбираем 65 тысяч цветов, то значение цвета в один байт не поместится, только в два байта.
      1 - enable COM split odd even (0 - disable)
      1 - scan COM95 to COM0 (0 - COM0 to COM95) отражение по короткой стороне
      0 - disable left-right swaping (1 - enable swaping) 0 - RGB color (1 - BGR color) задаем привычный нам формат RGB
      1 - RAM column 0 to 95 (0 - 95 to 0)
      0 - horizontal address increment (1 - vertical) */ Выбираем как будут выводиться данные на дисплей, слева-направо сверху-вниз (привычный нам способ, потому что и пишем так и массивы задаем) или сверху-вниз слева-направо. Эти методы адресации рассмотрены в предыдущей статье, лишь отмечу что мы будем использовать горизонтальную адресацию.
      Поскольку для задания цвета у нас есть всего 2 байта, а формат RGB предполагает 3, то необходимо произвести преобразование. Для красного цвета отводятся первые 5 бит, затем 6 бит зеленого цвета, замыкают 5 бит синего, поэтому функцию преобразования цвета я назвал color565
       
       uint16_t c;   c = r >> 3;   c <<= 6;   c |= g >> 2;   c <<= 5;   c |= b >> 3;   return c;// получаем 16-битное значение цвета и возвращаем его } Поскольку данными необходимо передавать только цвет, то функцию передачи данных можно переделать в функцию передачи цвета, но 16-битное значение цвета необходимо будет разбить на два 8-битных и послать их одно за другим.
      void oledDataColor(uint16_t color) //измененная функция для отправки 16-битного значения цвета {   digitalWrite(ss, LOW);   digitalWrite(dc, HIGH);   SPI.transfer(color >> 8); //разбиваем 16-битное значение на 2 8-битных   SPI.transfer(color);   digitalWrite(ss, HIGH); } Теперь можно рисовать, и начну я с базового элемента любого растрового изображения - пикселя. Для отображения графических примитивов предусмотрены готовые функции, но не для пикселя и окружности, поэтому будем изобретать велосипед.
      Я упоминал про горизонтальную адресацию, команды и данные, и сейчас я свяжу это всё воедино и поведаю как вывести изображение на дисплей (но делать я этого конечно же не буду).
      Представим, что необходимо вывести изображение размером N на N пикселей, левый верхний угол изображения должен находиться в координатах х=X, у=Y. Для этого необходимо выбрать прямоугольную область на дисплее, а затем передать значения цвета пикселей по очереди обходя каждый пиксель изображения слева-направо сверху-вниз. Полученные дисплеем значения цвета так же будут выводиться слева-направо сверху-вниз в пределах выбранной области, и обход пикселей будет таким, как представлен на изображении ниже.

      Для выбора области на дисплее необходимо передать команду 0x15,значения Х и У левого верхнего угла области, затем команду 0x75 и значения Х и У правого нижнего угла области. Все эти значения передаются командами, то есть вывод DC подтянут к нулю. Затем подаем на DC логическую единицу и посылаем значения цвета каждого пикселя. Функции отправки команд, данных и цвета я уже привел. Далее необходимо включить фантазию и принять факт что один пиксель - это изображение состоящее из одного пикселя, и процедуру вывода изображения применить к одному единственному пикселю. В итоге получается вот такая функция:
      //функция задает цвет выбранной точке void oledPixel(uint8_t x, uint8_t y, uint16_t color) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x15);   SPI.transfer(x);   SPI.transfer(95);   SPI.transfer(0x75);   SPI.transfer(y);   SPI.transfer(63);   delay(1);   digitalWrite(dc, HIGH);   SPI.transfer(color >> 8);   SPI.transfer(color);   delay(1);   digitalWrite(ss, HIGH); } Далее пойдут уже готовые функции для вывода линии, прямоугольника и залитого прямоугольника. 
      //функция отрисовывает линию определенного цвета между двумя указанными координатами void oledLine (uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x21);   SPI.transfer(x1); //x start   SPI.transfer(y1); //Y start   SPI.transfer(x2); //X end   SPI.transfer(y2); //Y end   delay(1);   //здесь синтезированный в формат 565 цвет разбирается отбратно   //я понимаю что это костыль, но во первых для задания цвета необходимо использовать один аргумент вместо трех   //а во вторых, я использовал именно такой способ для общего понимания работы с цветом при работе с данным дисплеем   SPI.transfer((color >> 11) & 0x1F); //R color   SPI.transfer((color >> 5) & 0x3F); //G color   SPI.transfer(color & 0x1F); //B color   delay(1);   digitalWrite(ss, HIGH); } //функция рисует прямоугольник заданной высоты ширины и цвета, левый верхний угол прямоугольника задается первыми двумя аргументами void oledRect (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x26); //настройка заливки прямоугольника   SPI.transfer(0x0); //отключаем заливку прямоугольника   SPI.transfer(0x22);   SPI.transfer(x); //x start   SPI.transfer(y); //Y start   SPI.transfer(x + w); //X end   SPI.transfer(y + h); //Y end   delay(1);   SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame   SPI.transfer((colorFrame >> 5) & 0x3F); //G color   SPI.transfer(colorFrame & 0x1F); //B color   delay(10);   digitalWrite(ss, HIGH); } //то же самое, но прямоугольникк залит определенным цветом (6 аргумент задает цвет заливки) void oledRectFill (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame, uint16_t colorFill) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x26); //настройка заливки прямоугольника   SPI.transfer(0x1);  //включаем заливку прямоугольника   SPI.transfer(0x22);   SPI.transfer(x); //x start   SPI.transfer(y); //Y start   SPI.transfer(x + w); //X end   SPI.transfer(y + h); //Y end   delay(1);   SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame   SPI.transfer((colorFrame >> 5) & 0x3F); //G color   SPI.transfer(colorFrame & 0x1F); //B color   SPI.transfer((colorFill >> 11) & 0x1F); //R color fill   SPI.transfer((colorFill >> 5) & 0x3F); //G color   SPI.transfer(colorFill & 0x1F); //B color   delay(10);   digitalWrite(ss, HIGH); } Так же предусмотрена функция очистки прямоугольной области дисплея и она же используется для очистки всего дисплея.
      void oledClear(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x25);   SPI.transfer(x1);   SPI.transfer(y1);   SPI.transfer(x2);   SPI.transfer(y2);   delay(1);   digitalWrite(ss, HIGH); } void oledClearAll() {   oledClear(0, 0, 95, 63); } И ещё команды скролинга дисплея. В них я глубоко не вникал, заставил картинку двигаться вертикально, но не смог заставить двигаться горизонтально. На том и хватит, я вряд ли буду использовать эти команды.
       
      //настройка скролинга дисплея void oledScrollSetup (uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x27);   SPI.transfer(a);   SPI.transfer(b);   SPI.transfer(c);   SPI.transfer(d);   SPI.transfer(e);   delay(1);   digitalWrite(ss, HIGH); } void oledScrollOn() {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x2F);   digitalWrite(ss, HIGH); } void oledScrollOff() {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x2E);   digitalWrite(ss, HIGH); } Приведу весь код "скетча".
      #include <SPI.h> const int ss = 10; //slave select const int dc = 8; // data/command data=1 command=0 const int reset = 9; //oled reset=0 void oledCommand(uint8_t val) //общая функция отправки команды дисплею {   digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI   digitalWrite(dc, LOW); //DC равен 0, это значит что отправляется команда   SPI.transfer(val); //отправляем команду стандартной функцией библиотеки SPI   digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена } void oledData(uint8_t val) //общая функция отправки данных дисплею {   digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI   digitalWrite(dc, HIGH); //DC равен 1, это значит что отправляются данные   SPI.transfer(val); //отправляем данные стандартной функцией библиотеки SPI   digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена } void oledDataColor(uint16_t color) //измененная функция для отправки 16-битного значения цвета {   digitalWrite(ss, LOW);   digitalWrite(dc, HIGH);   SPI.transfer(color >> 8); //разбиваем 16-битное значение на 2 8-битных   SPI.transfer(color);   digitalWrite(ss, HIGH); } void oledInit() //функция инициализации дисплея {   digitalWrite(reset, HIGH); //процедура сброса дисплея   delay(100);   digitalWrite(reset, LOW);   delay(100);   digitalWrite(reset, HIGH);   delay(100);   //процедура инициализации дисплея   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0xAE); //display OFF   SPI.transfer(0xA0); //remap & color depth setting   SPI.transfer(0x72);          //b01110010 расшифровка ниже   /*   b01 - 65k format, (00 -256 color, 10 - 65k color format 2)   1 - enable COM split odd even (0 - disable)   1 - scan COM95 to COM0 (0 - COM0 to COM95) отражение по короткой стороне   0 - disable left-right swaping (1 - enable swaping)   0 - RGB color (1 - BGR color)   1 - RAM column 0 to 95 (0 - 95 to 0)   0 - horizontal address increment (1 - vertical)   */   SPI.transfer(0xA1); //set display start line (0-63)   SPI.transfer(0x0);   SPI.transfer(0xA2); //set vertical offset (0-63)   SPI.transfer(0x0);   SPI.transfer(0xA4); //normal display (A5 - all pixel ON, A6 - all pixel OFF, A7 - inverse display)   SPI.transfer(0xA8); //set MUX ratio N+1 mux   SPI.transfer(0x3F); //default 0x3F   SPI.transfer(0xAD); //select internal Vcc supply   SPI.transfer(0x8E); //default 0x8E   SPI.transfer(0xB0); //set power saving mode   SPI.transfer(0x0B); //default 0x0B (disable power saving mode) 0X1A - enable   SPI.transfer(0xB1); //set reset, pre-charge period   SPI.transfer(0x31); //default 0x31   SPI.transfer(0xB3); //oscillator frequency   SPI.transfer(0xF0); //default 0xF0   SPI.transfer(0x8A); //set second pre-charge color A   SPI.transfer(0x64); //default 0x64   SPI.transfer(0x8B); //set second pre-charge color B   SPI.transfer(0x78); //default 0x78   SPI.transfer(0x8C); //set second pre-charge color C   SPI.transfer(0x64); //default 0x64   SPI.transfer(0xBB); //set pre-charge voltage level   SPI.transfer(0x3A); //default 0x3A   SPI.transfer(0xBE); //set COM deselect voltage level   SPI.transfer(0x3E); //default 0x3E   SPI.transfer(0x87); //set master current   SPI.transfer(0x06); //default 0x06   SPI.transfer(0x81); //set contrast for color A   SPI.transfer(0x91); //default 0x91   SPI.transfer(0x82); //set contrast for color B   SPI.transfer(0x50); //default 0x50   SPI.transfer(0x83); //set contrast for color C   SPI.transfer(0x7D); //default 0x7D   SPI.transfer(0xAF); //display ON, normal mode   digitalWrite(ss, HIGH); } uint16_t color565(uint8_t r, uint8_t g, uint8_t b) //функция преобразования цвета R8G8B8bit в формат R5G6B5bit {   uint16_t c;   c = r >> 3;   c <<= 6;   c |= g >> 2;   c <<= 5;   c |= b >> 3;   return c;// получаем 16-битное значение цвета и возвращаем его } //функция задает цвет выбранной точке void oledPixel(uint8_t x, uint8_t y, uint16_t color) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x15);   SPI.transfer(x);   SPI.transfer(95);   SPI.transfer(0x75);   SPI.transfer(y);   SPI.transfer(63);   delay(1);   digitalWrite(dc, HIGH);   SPI.transfer(color >> 8);   SPI.transfer(color);   delay(1);   digitalWrite(ss, HIGH); } void oledSetArea(uint8_t x, uint8_t y, uint8_t w, uint8_t h) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x15);   SPI.transfer(x);   SPI.transfer(y);   SPI.transfer(0x75);   SPI.transfer(x + w);   SPI.transfer(y + h);   delay(1);   digitalWrite(ss, HIGH); } //функция отрисовывает линию определенного цвета между двумя указанными координатами void oledLine (uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x21);   SPI.transfer(x1); //x start   SPI.transfer(y1); //Y start   SPI.transfer(x2); //X end   SPI.transfer(y2); //Y end   delay(1);   //здесь синтезированный в формат 565 цвет разбирается отбратно   //я понимаю что это костыль, но во первых для задания цвета необходимо использовать один аргумент вместо трех   //а во вторых, я использовал именно такой способ для общего понимания работы с цветом при работе с данным дисплеем   SPI.transfer((color >> 11) & 0x1F); //R color   SPI.transfer((color >> 5) & 0x3F); //G color   SPI.transfer(color & 0x1F); //B color   delay(1);   digitalWrite(ss, HIGH); } //функция рисует прямоугольник заданной высоты ширины и цвета, левый верхний угол прямоугольника задается первыми двумя аргументами void oledRect (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x26); //настройка заливки прямоугольника   SPI.transfer(0x0); //отключаем заливку прямоугольника   SPI.transfer(0x22);   SPI.transfer(x); //x start   SPI.transfer(y); //Y start   SPI.transfer(x + w); //X end   SPI.transfer(y + h); //Y end   delay(1);   SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame   SPI.transfer((colorFrame >> 5) & 0x3F); //G color   SPI.transfer(colorFrame & 0x1F); //B color   delay(10);   digitalWrite(ss, HIGH); } //то же самое, но прямоугольникк залит определенным цветом (6 аргумент задает цвет заливки) void oledRectFill (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame, uint16_t colorFill) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x26); //настройка заливки прямоугольника   SPI.transfer(0x1);  //включаем заливку прямоугольника   SPI.transfer(0x22);   SPI.transfer(x); //x start   SPI.transfer(y); //Y start   SPI.transfer(x + w); //X end   SPI.transfer(y + h); //Y end   delay(1);   SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame   SPI.transfer((colorFrame >> 5) & 0x3F); //G color   SPI.transfer(colorFrame & 0x1F); //B color   SPI.transfer((colorFill >> 11) & 0x1F); //R color fill   SPI.transfer((colorFill >> 5) & 0x3F); //G color   SPI.transfer(colorFill & 0x1F); //B color   delay(10);   digitalWrite(ss, HIGH); } void oledClear(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x25);   SPI.transfer(x1);   SPI.transfer(y1);   SPI.transfer(x2);   SPI.transfer(y2);   delay(1);   digitalWrite(ss, HIGH); } void oledClearAll() {   oledClear(0, 0, 95, 63); } //настройка скролинга дисплея void oledScrollSetup (uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e) {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x27);   SPI.transfer(a);   SPI.transfer(b);   SPI.transfer(c);   SPI.transfer(d);   SPI.transfer(e);   delay(1);   digitalWrite(ss, HIGH); } void oledScrollOn() {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x2F);   digitalWrite(ss, HIGH); } void oledScrollOff() {   digitalWrite(ss, LOW);   digitalWrite(dc, LOW);   SPI.transfer(0x2E);   digitalWrite(ss, HIGH); } void setup() {   pinMode(ss, OUTPUT);   pinMode(dc, OUTPUT);   pinMode(reset, OUTPUT);   SPI.begin();   SPI.setDataMode(SPI_MODE3);   oledInit();   oledClearAll();   randomSeed(millis); } void loop() {  oledClearAll();   oledPixel(10, 10, color565(255, 0, 0));   oledLine(45, 32, 40, 63, color565(0, 255, 0));   oledRectFill(60, 0, 10, 20, color565(0, 0, 255), color565(255, 255, 0));   oledRect(40, 0, 10, 20, color565(255, 255, 0));   int x = 20, y = 31, w = 10, h = 10;   oledSetArea(x, y, w, h);   for (int i = 0; i < (w*h); i++) {     oledDataColor(color565(random(0, 255), random(0, 255), random(0, 255)));   }      delay(5000); } Результат работы на фото (специально сдвинул экспозицию в минус): вывод точки, линии, залитого и пустого прямоугольника и массива из точек случайного цвета.

      Плюсы данного дисплея очевидны: малое потребление из-за отсутствия подсветки, малая толщина дисплея, большие углы обзора, ну и наконец он цветной. Чип SSD1331 позволяет обращаться к каждой точке напрямую ( в отличии от монохромного дисплея на чипе SSD1306), что намного упрощает работу с ним. Ну и библиотеки для этого дисплея уже написаны, а то я тут всё велосипеды изобретаю.
      P.S. В архиве скетч, библиотеки для ArduinoIDE и даташиты.
      SSD1331.rar
    • Автор: CasperReduct
      Заранее извиняюсь если вопрос для многих будет примитивным, но так как в радиотехнике 0  - прошу помощи.
      Итак: есть Arduino mini,  различные датчики, датчик MQ135(потребление ~150mA). Питание: к пинам +5,Gnd припаян Microusb для подключения зарядника от телефона (но также хочу дать возможность запитать от 3 батареек).
      вопрос:
      1. как сделать обвязку чтобы при подключении внешнего источника питания, питание от батареек не тратилось?
      2. MQ135 пишут везде нужно свое питание но если я запитаю от внешнего источника его и ардуино то никаких проблем не возникнет?
      3. надо датчик MQ135 включать периодически допустим раз в 10мин на 2 мин c помощю ардуино, какие элементы могут помочь в этом?(использовать реле мне кажеться как с ружья по воробьям) 
    • Автор: Atreides
      Добрый день. Мне требуется реализовать программный юарт на атмеге16. Он нужен для того, чтобы принятые по нему данные отправить на аппаратный юарт. В интернете нашел примеры кода, но понять его мне трудно. Прошу вас словами в общих чертах объяснить принцип реализации программного юарта. Буду рад примерам, которые, на ваш взгляд, являются наиболее простыми и понятными. Заранее спасибо.