Сообщество - TECHNO BROTHER
Добавить пост

TECHNO BROTHER

1 636 постов 12 517 подписчиков

Популярные теги в сообществе:

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE)

AD7706 — это сигма-дельта 16 битные АЦП, гарантирующие отсутствие потери кодов. Выбранный входной сигнал поступает на усилитель с программируемым коэффициентом усиления, а с его выхода на аналоговый модулятор. Сигнал с выхода модулятора поступает на внутренний цифровой фильтр. Предыдущее значение фильтра может быть перенесено из внутреннего управляющего регистра, что позволяет регулировать порог отсечки фильтра и частоту обновления.

AD7706 работают от однополярного питания от 4.75 В до 5.25. AD7706 имеет три канала с псевдо дифференциальными входами.  Диапазон биполярного входного сигнала при питании 5 В и опорном напряжении 2,5 В может изменяться от 0 … 20 мВ до 0 … 2.5 В. При измерении биполярного сигнала может изменяться в диапазоне от ± 20 мВ до ± 2,5 В.

Отличительные особенности:

  • AD7706: трехканальный АЦП с псевдо-дифференциальными входами

  • 16 битное разрешение

  • Коэффициент нелинейности 0.003 %

  • Программируемый коэффициент усиления от 1 до 128

  • Трехпроводный последовательный SPI, QSPI, MICROWIRE и DSP совместимый интерфейс

  • Однополярное питание от 2.7 В до 3.3 В или от 4.75 В до 5.25 В

  • Рассеиваемая мощность при 3 В питании — менее 1 мВт

  • Ток потребления в дежурном режиме — не более 8 мкА

АЦП управляется при помощи нескольких регистров:

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Регистр Communications

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Communications Register 8 бит, содержит биты настройки выбора входа CH1 CH0, активация режима STANDBY STBY.

Так как это коммуникационный регистр, то он содержит адрес регистра который необходимо активировать RS0 RS1 RS2, то есть коммуникационном регистре указываем адрес регистра в который необходимо записать или прочитать данные (бит RW), так же указываем номер канала настойки которого необходимо поменять.

Например необходимо записать данные в регистр SETUP, то в коммуникационном регистре записываем адрес регистра SETUP, номер канала, бит записи или чтения:

Communications Register (пример записи в регистр SETUP)

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

RS0 RS1 RS2 = [001] — адрес регистра SETUP

RW = [0] — запись

CH1 CH0 = [01] — выбран канал №2

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Регистр Setup

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Регистр SETUP содержит биты настройки коэффициента усиления G2 G1 G0 (от 1 до 128), режимы калибровки MD1 MD0, тип входного сигнала B/U (униполярный\биполярный).

Биты G2 G1 G0

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Режимы калибровки:

MD1 MD0 = [00] — рабочий режим, калибровка не проводится

MD1 MD0 = [01] — калибровка нуля и опорного напряжения

MD1 MD0 = [10] — калибровка нуля

MD1 MD0 = [11] — калибровка опорного напряжения

После процедуры калибровки биты MD1 MD0 возвращаются в рабочий режим [00].

Регистр Clock

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Регистр Clock содержит делитель тактовых импульсов на 2 (бит CLKDIS), бит выбора частоты кварцевого резонатора (бит CLKDIV) и биты CLK FS1 FS0 определяющие скорость опроса АЦП (частота дискретизации).

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

*Бит CLK доступен при использовании кварцевого резонатора 4.9152 MHz

Регистр данных (Data Register)

16 — и бытный регистр, содержит результат измерения.

Ниже показаны эпюры сигналов в режиме чтения и записи регистров.

Запись

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Чтение

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

При записи данных в регистр сигнал CS служит сигналом начала и конца записи данных, запись бита производится на возрастающем фронте сигнала синхронизации SCLK.

При чтении главным условием для начала чтения данных служит сигнал готовности АЦП к передаче данных DRDY, в данном примере сигнал готовности DRDY снимается в выхода АЦП, но можно и не использовать выход DRDY, а брать состояние готовности с бита DRDY коммуникационного регистра. Далее после сигнала CS, на каждом возрастающем фронте сигнала синхронизации SCLK происходит считывание 1 бита данных с выхода DOUT. Запись как и чтение начинается со старшего разряда.

Как ранее отмечалось AD7706 имеет 3 псевдо дифференциальных входа, поэтому общим входом для всех каналов служит вход COMMON. В зависимости от подключения входа COMMON АЦП может измерять биполярное или униполярное напряжение.

Схема включения при измерении униполярного напряжения

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

Тестовый скетч

// AD7706

#define SCLK 2

#define CS 3

#define DIN 4

#define DOUT 5

#define DRDY 6 

#define REF 2.500  

#define AIN1 0b00

#define AIN2 0b01

#define AIN3 0b11  

#define GAIN_1 0b000000

#define GAIN_2 0b001000

#define GAIN_4 0b010000

#define GAIN_8 0b011000

#define GAIN_16 0b100000

#define GAIN_32 0b101000

#define GAIN_64 0b110000

#define GAIN_128 0b111000 

#define F20 0b000 // 5.24 Hz

#define F25 0b001 // 6.55 Hz

#define F100 0b010 // 26.2 Hz

#define F200 0b011 // 52.4 Hz 

unsigned long times; 

void setup() {

Serial.begin(9600);

pinMode(SCLK,OUTPUT);

pinMode(CS,OUTPUT);

pinMode(DIN,OUTPUT);

pinMode(DOUT,INPUT);

pinMode(DRDY,INPUT);

digitalWrite(SCLK,HIGH);

digitalWrite(CS,HIGH);

digitalWrite(DIN,HIGH);

reset(); 

write_byte(0x20|AIN2);

write_byte(0x00|F20); // Clock | 2.4576 MHz

delay(100);

void loop() {

times=millis();

write_byte(0x10|AIN2);

write_byte(0b01000100|GAIN_1); // Setup | Self-Calibration  // Измеренное напряжение от 0 до +2,5 В

write_byte(0x38|AIN2);

unsigned int u_data = read_byte();

Serial.println(REF/65535 * (u_data),5 );  // Цифровое значение от 0(0,0В) до 65535(+2,5В)

Serial.println(u_data);  /// Частота опроса

Serial.print("F = ");

Serial.print(1/ ((float(millis()-times))/1000));

Serial.println(" Hz");

Serial.println();

delay(1000);

void write_byte(byte data){

digitalWrite(CS,LOW);

for(int i = 7; i >= 0; i--){

digitalWrite(SCLK,LOW);

digitalWrite(DIN, (data >> i) & 1);

digitalWrite(SCLK,HIGH); }

digitalWrite(CS,HIGH);

unsigned int read_byte(){

unsigned int data_out=0;

unsigned int dat;

while(digitalRead(DRDY)!=LOW);

digitalWrite(CS,LOW);

for(int i = 15; i >= 0; i--){

digitalWrite(SCLK,LOW);

digitalWrite(SCLK,HIGH);

dat = digitalRead(DOUT);

data_out |= (dat<<i); }

digitalWrite(CS,HIGH);

return data_out;

void reset(){

digitalWrite(CS,LOW);

for(int i = 31; i >= 0; i--){

digitalWrite(SCLK,LOW);

digitalWrite(DIN, HIGH);

digitalWrite(SCLK,HIGH); }

digitalWrite(CS,HIGH); }

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

На вход №2 подано напряжение в 1,8 В. В мониторе порта отображается частота опроса, измеренное напряжение и его цифровое значение которое может находится в пределах от 0 до 65535 (16 бит).

Схема включения при измерении биполярного напряжения

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост


При измерении биполярного напряжения на вход COMMON подается опорное напряжение для создания средней точки, при этом источник входного сигнала не должен иметь соединения с GND АЦП.

Тестовый скетч

// AD7706

#define SCLK 2

#define CS 3

#define DIN 4

#define DOUT 5

#define DRDY 6 

#define REF 2.500  

#define AIN1 0b00

#define AIN2 0b01

#define AIN3 0b11  

#define GAIN_1 0b000000

#define GAIN_2 0b001000

#define GAIN_4 0b010000

#define GAIN_8 0b011000

#define GAIN_16 0b100000

#define GAIN_32 0b101000

#define GAIN_64 0b110000

#define GAIN_128 0b111000 

#define F20 0b000 // 5.24 Hz

#define F25 0b001 // 6.55 Hz

#define F100 0b010 // 26.2 Hz

#define F200 0b011 // 52.4 Hz 

unsigned long times; 

void setup() {

Serial.begin(9600);

pinMode(SCLK,OUTPUT);

pinMode(CS,OUTPUT);

pinMode(DIN,OUTPUT);

pinMode(DOUT,INPUT);

pinMode(DRDY,INPUT);

digitalWrite(SCLK,HIGH);

digitalWrite(CS,HIGH);

digitalWrite(DIN,HIGH);

reset(); 

write_byte(0x20|AIN2);

write_byte(0x00|F100); // Clock | 2.4576 MHz

delay(100);

void loop() {

times=millis();

write_byte(0x10|AIN2);

write_byte(0b01000000|GAIN_1); // Setup | Self-Calibration  // Измеренное напряжение от 0 до +/-2,5 В

write_byte(0x38|AIN2);

unsigned int u_data = read_byte();

Serial.println(REF/32768 * (u_data-32768),5 );  // Цифровое значение от 0(-2,5В) до 65535(+2,5В), середина шкалы 32768(0,0В)

Serial.println(u_data);  /// Частота опроса

Serial.print("F = ");

Serial.print(1/ ((float(millis()-times))/1000));

Serial.println(" Hz");

Serial.println();

delay(1000);

void write_byte(byte data){

digitalWrite(CS,LOW);

for(int i = 7; i >= 0; i--){

digitalWrite(SCLK,LOW);

digitalWrite(DIN, (data >> i) & 1);

digitalWrite(SCLK,HIGH);

}

digitalWrite(CS,HIGH);

unsigned int read_byte(){

unsigned int data_out=0;

unsigned int dat;

while(digitalRead(DRDY)!=LOW);

digitalWrite(CS,LOW);

for(int i = 15; i >= 0; i--){

digitalWrite(SCLK,LOW);

digitalWrite(SCLK,HIGH);

dat = digitalRead(DOUT);

data_out |= (dat<<i); }

digitalWrite(CS,HIGH); r

eturn data_out;

void reset(){

digitalWrite(CS,LOW);

for(int i = 31; i >= 0; i--){

digitalWrite(SCLK,LOW);

digitalWrite(DIN, HIGH);

digitalWrite(SCLK,HIGH);

}

digitalWrite(CS,HIGH);

}

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

На вход №2 подано напряжение в +1,48 В. В мониторе порта отображается частота опроса, измеренное напряжение и его цифровое значение которое может находится в пределах от 32768 (0 В) до 65535 (+2,5 В) (15 бит).

AD7706 3-х канальный 16 битный сигма-дельта АЦП (Arduino IDE) Arduino, Электроника, Самоделки, Программирование, Длиннопост

На вход №2 подано напряжение в -1,48 В. В мониторе порта отображается частота опроса, измеренное напряжение и его цифровое значение которое может находится в пределах от 0 (-2,5 В) до 32768 (0 В) (15 бит).

Даташит — ad7706.pdf

http://rcl-radio.ru/?p=129749

Показать полностью 15

ATtiny26 (Arduino IDE)

ATtiny26/L низкопотребляющий 8 битный КМОП микроконтроллер с AVR RISC архитектурой. Выполняя команды за один цикл, ATtiny26/L достигает производительности 1 MIPS при частоте задающего генератора 1 МГц, что позволяет разработчику оптимизировать отношение потребления к производительности.

Характеристики:

  • Высокая производительность при малом потреблении

  • RISC архитектура

  • 118- команд, большинство исполняемых за один машинный такт

  • 328 рабочих регистра общего назначения

  • Полностью статический режим

  • 16 MIPS производительность при 16 МГц

  • Память

    • 2К байтов FLASH памяти программ с внутрисистемным программированием

    • 1000 циклов записи- стирания

    • 128 байтов EEPROM c внутрисистемным программированием

    • 100 000 циклов записи- стирания

    • 128 байтов внутренней SRAM

    • Программируемый ключ доступа к программам и памяти данных

  • Периферия

    • 8- битный таймер/счётчик с программируемым предделителем

    • 8- битный скоростной делитель с программируемым предделителем

    • 2 скоростных ШИМ выхода с отдельным выходным регистром сравнения не совмещённый выход инверсной ШИМ

  • Универсальный последовательный интерфейс с детектором старта

  • 10- бит АЦП

    • 11 простых униполярных входа

    • 8 дифференциальных входа

    • 7 дифференциальных входа с программируемым усилением ( 1, 10 )

  • Встроенный аналоговый компаратор

  • Внешние прерывания

  • 11 прерываний по изменению потенциала вывода

  • Программируемый Watchdog с переключаемымим генераторами

  • Специальные функции контроллера

  • Режим экономии энергии, режим подавления шума, режим Выкл.

  • Сброс при включении и понижению напряжения питания

  • Внешние и внутренние источники прерывания

  • Внутрисистеммное программирование через SPI порт

  • Внутренний калиброванный RC генератор

  • 20- выводной корпус PDIP или SOIC

  • 16 программируемых входа-выхода

  • Рабочее напряжение питания:

    • 2.7 В до 5.5 В ATtiny26L

    • 4.5 В до 5.5 В ATtiny26

  • Рабочая тактовая частота:

    • 0- 8 МГц ATtiny26L

    • 0-16 МГЦ ATtiny26

ATtiny26 (Arduino IDE) Arduino, Программирование, Самоделки, Электроника, Длиннопост

Микроконтроллер ATtiny26 отлично подходит для маленьких и дешевых проектов, а поддержка средой программирования Arduino IDE заметно упрощает работу с микроконтроллером.

Для поддержки ATtiny26 в Arduino IDE необходимо выполнить несколько простых операций:

  • Добавление поддержки платы

Откройте в Arduino IDE вкладку Файл > Настройки и добавьте ссылку для менеджера плат

https://nich1con.github.io/tiny26.json

ATtiny26 (Arduino IDE) Arduino, Программирование, Самоделки, Электроника, Длиннопост

Далее перейдите во вкладку Инструменты > Плата > Менеджер плат

ATtiny26 (Arduino IDE) Arduino, Программирование, Самоделки, Электроника, Длиннопост

Далее в Инструменты > Плата выберите плату ATtiny26.

Установите параметры платы как показано на скриншоте:

ATtiny26 (Arduino IDE) Arduino, Программирование, Самоделки, Электроника, Длиннопост
  • Для прошивки скетча  Вам понадобится программатор USBAsp

ATtiny26 (Arduino IDE) Arduino, Программирование, Самоделки, Электроника, Длиннопост

Схемы подключения

ATtiny26 (Arduino IDE) Arduino, Программирование, Самоделки, Электроника, Длиннопост

Распиновка программатора USBAsp

ATtiny26 (Arduino IDE) Arduino, Программирование, Самоделки, Электроника, Длиннопост

Далее необходимо выставить нужные фьюзы для микроконтроллера, чтобы он всегда работал на выбранной Вами частоте. Для этого в настройках Arduino IDE выберите программатор USBasb и нажмите Инструменты > Записать загрузчик. Эту операцию необходимо проводить всего один и снова повторить если Вы будете менять частоту работы микроконтроллера.

Для загрузки скетча в настройках Arduino IDE выберите программатор USBasb и во вкладке Скетч нажмите на Загрузить через программатор.

Для примера, можно загрузить простой скетч мигания светодиода, к выводу 13(PB5) контроллера подключите светодиод через резистор 200 Ом.

#include <avr/io.h>

#include <util/delay.h>

int main(){  DDRB |=(1<<PB5); 

while(1){  PORTB |=(1<<PB5);  

_delay_ms(1000);  

PORTB &=~(1<<PB5);  

_delay_ms(1000);  

}}

Для нормальной работы микроконтроллера необходимо подать напряжение VCC через резистор 10 кОм на вход RST микроконтроллера.

Ошибка компиляции (проверялось в Linux Ununtu 20.04 | Arduino IDE 1.8.15)

chmod: невозможно получить доступ к ‘/root/.arduino15/packages/ATtiny26/hardware/avr/1.1.0/scripts/create_disassembler_listing.sh’: Нет такого файла или каталога
exit status 1
Ошибка компиляции для платы ATtiny26.

Загрузить файл — create_disassembler_listing.sh

Разместить файл по указанному пути: packages/ATtiny26/hardware/avr/1.1.0/scripts/create_disassembler_listing.sh

Ошибка компиляции (проверялось в Linux Ununtu 20.04 | Arduino IDE 1.8.15)

***failed;
avrdude: WARNING: invalid value for unused bits in fuse «hfuse», should be set to 1 according to datasheet
This behaviour is deprecated and will result in an error in future version
You probably want to use 0x12 instead of 0xf2 (double check with your datasheet first).

Открыть файл — packages/ATtiny26/hardware/avr/1.1.0/boards.txt

Найти строки:

t26.menu.bod.2V7=2.7V
t26.menu.bod.2V7.bootloader.high_fuses=0b11110{bootloader.eesave_bit}10
t26.menu.bod.4V=4.0V
t26.menu.bod.4V.bootloader.high_fuses=0b11110{bootloader.eesave_bit}00
t26.menu.bod.OFF=Disable
t26.menu.bod.OFF.bootloader.high_fuses=0b11110{bootloader.eesave_bit}01

заменить на:

t26.menu.bod.2V7=2.7V
t26.menu.bod.2V7.bootloader.high_fuses=0b00010{bootloader.eesave_bit}10
t26.menu.bod.4V=4.0V
t26.menu.bod.4V.bootloader.high_fuses=0b00010{bootloader.eesave_bit}00
t26.menu.bod.OFF=Disable
t26.menu.bod.OFF.bootloader.high_fuses=0b00010{bootloader.eesave_bit}01

Перезапустить Arduino IDE.

Исходник — https://github.com/Nich1con/ATtiny26-Core

http://rcl-radio.ru/?p=129787

Показать полностью 7

LGT8F328P-LQFP32 MiniEVB в Arduino IDE

Плата LGT8F328P-LQFP32 MiniEVB основана на китайском микроконтроллер LGT8F328p и является клоном популярной AVR ATmega328p (Arduino NANO). Микроконтроллер LGT8F328p практически полностью совместим с микроконтроллером ATmega328p и обладает рядом дополнительных функций и возможностей превышающих ATmega328p.

Плата LGT8F328P-LQFP32 MiniEVB прошивается через USB кабель, так как на плате установлен контроллер СОМ порта и прошит загрузчик.

LGT8F328P-LQFP32 MiniEVB в Arduino IDE Arduino, Электроника, Программирование, Самоделки, Длиннопост

Основные характеристики LGT8F328P

  • FLASH (ПЗУ): 32 Кбайт

  • SRAM (ОЗУ): 2 Кбайт

  • E2PROM (EEPROM): 0K / 1K / 2K / 4K / 8K (эмуляция)

  • PWM (ШИМ): 8

  • Частота: 32 МГц

  • АЦП: 9 пинов, 12 бит

  • ЦАП: 1 пин, 8 бит

  • Силовые пины: 4 (до 80 мА)

  • Таймеры 2x 8bit, 2x 16bit

  • UART: 1

  • SPI: 1

  • I2C: 1

  • PLL: 1

  • Опорное напряжение: 1.024В / 2.048В / 4.09В ± 0,5%

  • Логический уровень: 5В

Для прошивки LGT8F328P-LQFP32 MiniEVB необходимо поэтапно выполнить несколько простых действий:

  1. Добавим поддержку платы LGT8F328P-LQFP32 MiniEVB в Arduino IDE, для этого добавим ссылку в менеджер плат

https://raw.githubusercontent.com/dbuezas/lgt8fx/master/pack...

LGT8F328P-LQFP32 MiniEVB в Arduino IDE Arduino, Электроника, Программирование, Самоделки, Длиннопост
LGT8F328P-LQFP32 MiniEVB в Arduino IDE Arduino, Электроника, Программирование, Самоделки, Длиннопост

Далее в менеджере плат находим плату lgt8fx выбрав версию платы 2.0.0 (и выше) и устанавливаем ее:

LGT8F328P-LQFP32 MiniEVB в Arduino IDE Arduino, Электроника, Программирование, Самоделки, Длиннопост

Далее во вкладке инструменты находим нужную нам плату:

LGT8F328P-LQFP32 MiniEVB в Arduino IDE Arduino, Электроника, Программирование, Самоделки, Длиннопост

Установите настройки показанные на скриншоте:

LGT8F328P-LQFP32 MiniEVB в Arduino IDE Arduino, Электроника, Программирование, Самоделки, Длиннопост

После установки настроек платы можно для примера загрузить скетч BLINK. На плате  LGT8F328P-LQFP32 MiniEVB установлен светодиод подключенные к выходу D13, после загрузки скетча светодиод должен начать мигать.

Для загрузки скетча

void setup() {  

pinMode(LED_BUILTIN, 13); }

void loop() {  

digitalWrite(13, HIGH); 

delay(1000); 

digitalWrite(13, LOW); 

delay(1000);  

}

Распиновка платы

LGT8F328P-LQFP32 MiniEVB в Arduino IDE Arduino, Электроника, Программирование, Самоделки, Длиннопост

http://rcl-radio.ru/?p=129966

Показать полностью 6

Sony найдет «приемных родителей» собакам-роботам, от которых отказались владельцы

Владельцы собак-роботов смогут вернуть своих питомцев в Sony. Компания проведет ремонт и передаст их больницам, домам престарелых и другим социальным учреждениям.

В Sony уверены, что собаки-роботы подходят для эмоциональной поддержки: реагируют на голос и прикосновения и «узнают» хозяина.

Источник : Будущее сейчас

Показать полностью

Робот, который может отобрать работу у простых рабочих, ведь он может как минимум сделать шкафчик


Источник : Первый научный

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб?

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



Многие программисты так или иначе имеют тягу и интерес к разработке игр. Немалое количество спецов было замечено за написанием маленьких и миленьких игрушек, которые были разработаны за короткое время «just for fun». Большинству разработчиков за счастье взять готовый игровой движок по типу Unity/UE и попытаться создать что-то своё с их помощью, особенно упорные изучают и пытаются что-то сделать в экзотических движках типа Godot/Urho, а совсем прожжённые ребята любят писать игрушки… с нуля. Таковым любителем писать все сам оказался и я. И в один день мне просто захотелось написать что-нибудь прикольное, мобильное и обязательно — двадэшное! В этой статье вы узнаете про: написание производительного 2D-рендерера с нуля на базе OpenGL ES, обработку «сырого» ввода в мобильных играх, организацию архитектуры и игровой логики и адаптация игры под любые устройства. Интересно? Тогда жду вас в статье!

❯ Как это работает?



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

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост


Один из прошлых проектов — 3D шутэмап под… коммуникаторы с Windows Mobile без видеоускорителей! Игра отлично работала и на HTC Gene, и на QTek S110!

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

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



Подобные инструменты включают в себя как довольно функциональныеконструкторы игр, которые обычно не требуют серьёзных навыков программирования и позволяют собирать игру из логических блоков, так и полноценных игровых движков на манер Unity или Unreal Engine, которые позволяют разработчикам писать игры и продумывать их архитектуру самим. Можно сказать что именно «благодаря» доступности подобных инструментов мы можем видеть текущую ситуацию на рынке мобильных игр, где балом правят очень простые и маленькие донатные игрушки, называемыегиперкежуалом.

Но у подобных инструментов есть несколько минусов, которые банально не позволяют их использовать в реализации некоторых проектов:

  • Большой вес приложения: При сборке, Unity и UE создают достаточно объёмные пакеты из-за большого количества зависимостей. Таким образом, даже пустой проект может спокойно весить 50-100 мегабайт.

  • Неоптимальная производительность: И у Unity, и у UE очень комплексные и сложные рендереры «под капотом». Если сейчас купить дешевый смартфон за 3-4 тысячи рублей и попытаться на него накатить какой-нибудь 3 в ряд, то нас ждут либо вылеты, либо дикие тормоза.



Лично я для себя приметил ещё один минус — невозможность деплоить игры на устройства с старыми версиями Android, но это, опять же, моя личная хотелка.

Поэтому когда мне в голову пришла мысль сделать игрушку, я решил написать её с нуля — не используя никаких готовых движков, а реализовав всё сам — и игровую логику, и сам «движок» (правильнее сказать фреймворк). Не сказать, что в этом есть что-то очень сложное — в геймдеве есть отдельная каста «отшельников», которые называют себя «движкописателями» и пишут либо движки, либо игры — правда, не всегда хотя-бы одна игра доходит до релиза.

❯ Определяемся с задачами



Перед тем, как садится и пилить игрушку, нужно сразу же определится с целями и поставить перед собой задачи — какой стек технологий мы будет использовать, как будем организовать игровую логику, на каких устройствах игра должна работать и.т.п. Я прикинул и решил реализовать что-то совсем несложное, но при этом достаточно динамичное и забавное… 2D-шутер с видом сверху!

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



Игра будет написана полностью на Java — родном языке для Android-приложений. Пустые пакеты без зависимостей весят всего около 20 килобайт — что только нам на руку! Ни AppCompat, ни какие либо ещё библиотеки мы использовать не будем — нам нужен минимальный размер из возможных!

Итак, что должно быть в нашей игре:

  • Основная суть: Вид сверху, человечком по центру экрана можно управлять и стрелять во вражин. Цель заключается в том, чтобы набрать как можно больше очков перед тем, как игрока загрызут. За каждого поверженного врага начисляются баксы, за которые можно купить новые пушки!

  • Оружие: Несколько видов вооружения, в том числе пистолеты, дробовики, автоматы и даже пулеметы! Всё оружие можно купить в внутриигровом магазине за валюту, которую игрок заработал во время игры

  • Враги: Два типа врагов — обычный зомби и «шустрик». Враги спавнятся в заранее предусмотренных точках и начинают идти (или бежать) в сторону игрока с целью побить его.

  • Уровни: Можно сказать, простые декорации — на момент написания статьи без какого либо интерактива.



Поскольку игра пишется с нуля, необходимо сразу продумать необходимые для реализации модули:

  • Графика: Аппаратно-ускоренный рендерер полупрозрачных 2D-спрайтов с возможность аффинных трансформаций (поворот/масштаб/искривление и.т.п). На мобильных устройствах нужно поддерживать число DIP'ов (вызовов отрисовки) как можно ниже — для этого используется техника батчинга. Сам рендерер работает на базе OpenGLES 1.1 — т.е чистый FFP.

  • Ввод: Обработка тачскрина и геймпадов. Оба способа ввода очень легко реализовать на Android — для тачскрина нам достаточно повесить onTouchListener на окно нашей игры, а для обработки кнопок — ловить события onKeyListener и сопоставлять коды кнопок с кнопками нашего виртуального геймпада.

  • Звук: Воспроизведение как «маленьких» звуков, которые можно загрузить целиком в память (выстрелы, звуки шагов и… т.п), так и музыки/эмбиента, которые нужно стримить из физического носителя. Тут практически всю работу делает за нас сам Android, для звуков есть класс — SoundPool (который, тем не менее, не умеет сообщать о статусе проигрывания звука), для музыки — MediaPlayer. Есть возможность проигрывать PCM-сэмплы напрямую, чем я и воспользовался изначально, но с ним есть проблемы.

  • «Физика»: Я не зря взял этот пункт в кавычки :) По сути, вся физика у нас — это один метод для определения AABB (пересечения прямоугольник с прямоугольником). Всё, ни о какой настоящей физике и речи не идет :)



Поэтому, с учетом требований описанных выше, наша игра будет работать практически на любых смартфонах/планшетах/тв-приставках кроме китайских смартфонов на базе чипсета MT6516 без GPU из 2010-2011 годов. На всех остальных устройствах, включая самый первый Android-смартфон, игра должна работать без проблем. А вот и парк устройств, на которых мы будем тестировать нашу игру:

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



С целями определились, самое время переходить к практической реализации игры! По сути, её разработка заняла у меня около дву-трех дней — это с учетом написания фреймворка. Но и сама игра совсем несложная :)

❯ Рендерер



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

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

По сути, в современном мире, 2D — это частный случай 3D, когда рисуются всё те же примитивы в виде треугольников, но вместо перспективной матрицы, используется ортографическая матрица определенных размеров. Во времена актуальности DirectDraw (середина-конец 90х) и Java-телефонов, графику обычно не делали адаптивной, из-за чего при смене разрешения, игровое поле могло растягиваться на всю площадь дисплея. Сейчас же, когда разброс разрешений стал колоссальным, чаще всего можно встретить два подхода к организацию проекции:

  • Установка ортографической матрицы в фиксированные размеры: Если координатная система уже была завязана на пиксели, или по какой-то причине хочется использовать именно её, то можно просто завязать игру на определенном разрешении (например, 480x320, или 480x800). Растеризатор формально не оперирует с пикселями — у него есть нормализованные координаты -1..1 (где -1 — начало экрана, 0 — середина, 1 — конец, это называется clip-space), а матрица проекции как раз и переводит координаты геометрии в camera-space координатах в clip-space — т.е в нашем случае, автоматически подгоняет размеры спрайтов из желаемого нами размера в физический. Обратите внимание, физические движки обычно рассчитаны на работу в метрических координатных системах. Попытки задавать ускорения в пикселях вызывают рывки и баги.

  • Перевод координатной системы с пиксельной на метрическую/абстрактную:
    Сейчас этот способ используется чаще всего, поскольку именно его используют самые популярные движки и фреймворки. Если говорить совсем просто — то мы задаем координаты объектов и их размеры не относительно пикселей, а относительно размеров этих объектов в метрах, или ещё какой-либо абстрактной системы координат. Этот подход близок к обычной 3D-графике и имеет свои плюшки: например, можно выпустить HD-пак для вашей игры и заменить все спрайты на варианты с более высоким разрешением, не переделывая половину игры.



Для совсем простых игр я выбираю обычно первый подход. Самое время реализовать главный метод всего рендерера — рисование спрайтов. В моём случае, спрайты не были упакованы в атласы (одна текстура, содержащая в себе целую анимацию или ещё что-то в этом духе), поэтому и возможность выборки тайла из текстуры я реализовывать не стал. В остальном, всё стандартно:

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост
Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

Всё более чем понятно — преобразуем координаты спрайта из world-space в camera-space, отсекаем спрайт, если он находится за пределами экрана, задаем стейты для GAPI (на данный момент, их всего два), заполняем вершинный буфер геометрией и рисуем на экран. Никакого смысла использовать VBO здесь нет, а на nio-буфферы можно получить прямой указатель без лишних копирований, так что никаких проблем с производительностью не будет. Обратите внимание — вершинный буфер выделяется заранее — аллокации каждый дравколл нам не нужны и вредны.

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

Обратите внимание на вызовы ByteBuffer.order — это важно, по умолчанию, Java создаёт все буферы в BIG_ENDIAN, в то время как большинство Android-устройств — LITTLE_ENDIAN, из-за этого можно запросто накосячить и долго думать «а почему у меня буферы заполнены правильно, но геометрии на экране нет!?».

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



В процессе разработки игры, при отрисовке относительно небольшой карты с большим количеством тайлов, количество вызовов отрисовки возросло аж до 600, из-за чего FPS в игре очень сильно просел. Связано это с тем, что на старых мобильных GPU каждый вызов отрисовки означал пересылку состояния сцены видеочипу, из-за чего мы получали лаги. Фиксится это довольно просто: реализацией батчинга — специальной техники, которая «сшивает» большое количество спрайтов с одной текстурой в один и позволяет отрисовать хоть 1000, хоть 100000 спрайтов в один проход! Есть два вида батчинга, статический — когда объекты «сшиваются» при загрузке карты/в процессе компиляции игры (привет Unity) и динамический — когда объекты сшиваются прямо на лету (тоже привет Unity). На более современных мобильных GPU с поддержкой GLES 3.0 есть также инстансинг — схожая технология, но реализуемая прямо на GPU. Суть её в том, что мы передаём в шейдер параметры объектов, которые мы хотим отрисовать (матрицу, настройки материала и.т.п) и просим видеочип отрисовать одну и ту же геометрию, допустим, 15 раз. Каждая итерация отрисовки геометрии будет увеличивать счетчик gl_InstanceID на один, благодаря чему мы сможем расставить все модельки на свои места! Но тут уж справедливости ради стоит сказать, что в D3D10+ можно вообще стейты передавать на видеокарту «пачками», что здорово снижает оверхед одного вызова отрисовки.

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



Для загрузки спрайтов используется встроенный в Android декодер изображений. Он умеет работать в нескольких режимах (ARGB/RGB565 и.т.п), декодировать кучу форматов — в том числе и jpeg, что положительно скажется на финальном размере игры.

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

На этом реализация рендерера закончена. Да, все вот так просто :)
Переходим к двум остальным модулям — звук и ввод.

❯ Звук и ввод



Как я уже говорил, звук я решитл реализовать на базе уже существующей звуковой подсистемы Android. Ничего сложного в её реализацир нет, можно сказать, нам остаётся лишь написать обёртку, необходимую для работы. Изначально я написал собственный загрузчик wav-файлов и хотел использовать AudioTrack — класс для воспрозизведения PCM-звука напрямую, но мне не понравилось, что в нём нет разделения на источники звука и буферы, из-за чего каждый источник вынужден заниматься копированием PCM-потока в новый и новый буфер…

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



Полная реализация звукового потока выглядит так. И да, с SoundPool нет возможности получить позицию проигрывания звука или узнать, когда проигрывание закончилось. Увы.

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

Да будет звук! Ну и про ввод не забываем (листинг получился слишком длинный, а на Пикабу нет тега для кода - так что как-то так):

public static final int TOUCH_IDLE = 0; public static final int TOUCH_PRESS - Pastebin.com

Сама реализация джойстика крайне простая — запоминаем координаты, куда пользователь поставил палец и затем считаем дистанцию положения пальца относительно центральной точки, параллельно нормализововая их относительно максимальной дистанции:

public class Joystick { private Sprite joySprite; public float Veloc - Pastebin.com

Кроме того, я добавил вспомогательный метод для вызова диалога ввода текста — это для таблицы рекордов и прочих фишек, которые требуют ввода текста пользователем. Ну не будем же мы сами клавиатуру костылить!

Основа для игры есть, теперь переходим к её реализации!

❯ Пишем игру

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



Писать игру я начал с создания первого уровня и реализации загрузчика уровней. В качестве редактора, я выбрал популярный и широко-известный TileEd — удобный редактор с возможностью экспорта карт в несколько разных форматов. Я лично выбрал Json, поскольку в Android уже есть удобный пакет для работы с этим форматом данных.

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

Карта делится на 3 базовые понятия: тайлы — фон, с изображением травы/асфальта/земли и.т.п, пропы — статичные объекты по типу деревьев и кустов и сущности — объекты, участвующие в игровом процессе, т.е игрок, зомби и летящие пули. Система сущностей реализована в виде абстрактного базового класса, который реализовывает логику апдейтов, просчитывает Forward-вектор и выполняет другие необходимые задачи:

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

После этого, я приступил к реализации игрока, оружия и механики стрельбы. В целом, практически всю логику игрока можно описать в виде одного метода update: обрабатываем ввод и ходьбу с джойстика, поворачиваем игрока в сторону пальца на экране и пока зажата какая-либо область на экране мы ходим и стреляем:

@Override public void update() { super.update(); joyInp - Pastebin.com

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост



Ну и не забываем про реализацию зомби. Она тоже очень простая: есть базовый класс Zombie, от которого наследуются все монстры и который реализует несколько необходимых методов — повернуться в сторону игрока, идти вперед и конечно же атака!

Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост
Сам написал, сам поиграл: Как я написал 2D-игру для Android полностью с нуля, весом менее 1мб? Gamedev, Инди, Инди игра, Unity, 2D, Android, Разработка, Программирование, Графика, Девайс, Гаджеты, Opengl, Gles, Видео, Без звука, Длиннопост

❯ Что у нас есть на данный момент?



Честно сказать, статья итак уже получилась слишком длинной. Я очень хотел написать игру, о разработке которой можно было бы рассказать в рамках одной не особо большой статьи, но с моим стилем написания текстов так сделать не выйдет. Придется разбивать на части!
Однако, некоторый прогресс уже есть и мы можем даже поиграть в игру на текущем ее этапе!


Как мы видим, игра (а пока что — proof of concept) работает довольно неплохо на всех устройствах, которые были выбраны для тестирования. Однако это ещё не всё — предстоит добавить конечную цель игры (набор очков), магазин стволов и разные типы мобов. Благо, это всё реализовать уже совсем несложно :)

❯ Заключение



Написать небольшую игрушку с нуля в одиночку вполне реально. Разработка достаточно больших проектов конечно же требует довольно больших человекочасов, однако реализовать что-то своё, маленькое может и самому!

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

Статья подготовлена при поддержке компании TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud, чтобы не пропускать новые статьи каждую неделю!
Но тут я даже чутка навру - на этой неделе вас ждёт сразу две статьи :) Следующая - в четверг, прошлую неделю я отдыхал и работал.

Показать полностью 19 3

LGT8F328P таймеры (Arduino)

Микроконтроллер LGT8F328P содержит 4-е таймера, Timer_1 и Timer_3 16 бит, а Timer_0 и Timer_2 8 бит.

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

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

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

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

Режим CTC (сброс при совпадении)

Режим работы таймера CTC (сброс при совпадении) это когда в регистр OCR микроконтроллера загружается число, а счетный регистр TCNT сравнивает свое значение с числом регистра OCR и при совпадении происходит прерывание и сброс счетного регистра TCNT. При этом в обработчик прерывания исполняет помещенный в него код.

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Для примера использования таймера выберем 16 битный таймер Timer_1.

Для настройки таймера в данном примере используется 3 регистра:

  • TCCR1B — Регистр управления B

  • OCR1A — Регистр сравнения А выходных данных

  • TIMSK1 — Регистр маски прерываний счетчика/таймера

Пример скетча:

void setup() {  

pinMode(12, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;  

byte n = 5;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1B = (1 << WGM12) | n;  

OCR1A = 9999;// 0-65535  

TIMSK1 |= (1 << OCIE1A); //

_ctc = f_sys / (2 * n * (1 + OCR1A)) // 32 000 000 / (2 * 1024 * (1 + 9999)) = 1.5625 Hz interrupts();

}

void loop() {}

ISR(TIMER1_COMPA_vect){digitalWrite(12, !digitalRead(12));}

Подключите светодиод (через резистор 200 Ом) к выходу D12. После загрузки скетча светодиод начнет мигать с частотой 1,5625 Гц.

TCCR1B

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

В регистре управления используем бит WGW12 и биты CS10:CS12.

WGW12 активирует режим СТС

CS10:CS12 предделитель который делит тактовую частоту микроконтроллера

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

OCR1A

16-и битный регистр сравнения, содержит два 8-и битных регистра: OCR1AL и OCR1AH объединены для
формирования 16-разрядного OCR1A.

TIMSK1

Бит регистра TIMSK1 OCIE1A  разрешают прерывания при совпадении с A (OCR1A).

ISR(TIMER1_COMPA_vect) — функция обработчика прерывания, в нее помещается код который необходимо исполнять в режиме прерывания.

Если имеется необходимость использовать таймер для генерации импульсов (меандр), в микроконтроллере имеются выходы таймера. Для Timer_1 это выходы D9 и D10.

При совпадении регистра сравнения OCIE1A и счетного регистра состояние выхода таймера меняется на противоположное, а счетный регистр TCNT1 сбрасывается.

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Ниже показан пример скетча генерации меандра, таймер работает в режиме CTC

void setup() {  

pinMode(9, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;  

byte n = 5;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1B = (1 << WGM12) | n;  

OCR1A = 9999;// 0-65535  

TCCR1A |= (1 << COM1A0);

// f_ctc = f_sys / (2 * n * (1 + OCR1A)) // 32 000 000 / (2 * 1024 * (1 + 9999)) = 1.5625 Hz interrupts();

}

void loop() {}

Бит COM1A0 регистра TCCR1A определяет режим работы таймера. Если установлен бит COM1A0 то состояние на выходе OC1A меняется на противоположное при совпадении.

В этом примере если подключить светодиод (через резистор 200 Ом) к выходу D9, то после загрузки скетча он начнет мигать с частотой 1,5625 Гц.

Нормальный режим работы таймера

В нормальном режиме работы таймера можно использовать регистр сравнения OCR1A, при равенстве счетного регистра TCNT1 и регистра сравнения OCR1A происходит прерывание, но в отличии от режима СТС счетный регистр TCNT1 не сбрасывается, а увеличивает свое значение до максимального 65535 и только после этого происходит его сброс и новое прерывание.

Для нормальной работы этого режима в регистре масок прерывания TIMSK1 используются биты OCIE1A и TOIE1.

Бит OCIE1A разрешает прерывание по совпадению, а бит TOIE1 разрешает прерывание по переполнению.

При этом прерывания происходят два раза за один цикл заполнения счетного регистра TCNT1.

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Пример скетча

void setup() {  

pinMode(12, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;  

byte n = 5;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1B = n;  

OCR1A = 9999;// 0-65535  

TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1);

interrupts();

}

void loop() {}

ISR(TIMER1_COMPA_vect){  digitalWrite(12, !digitalRead(12));  }

При обнулении счетного регистра светодиод подключенный к D12 (через резистор 200 Ом) загорается, как только значение счетного регистра станет равным значению регистра сравнения, светодиод погаснет и не будет светится пока значение счетного регистра не достигнет максимального значения.

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Период работы прерывания при переполнении счетного регистра равен:

Tпереполнения = 1/(f sys / (2 * N * 65536))

Период работы прерывания при совпадении равен:

Tсовпадения = 1/(f_sys / (2 * n * (1 + OCR1A)))

В скетче установлен предделитель на 1024, значит:

Tпереполнения = 1/(32 000 000 / (2 * 1024 * 65536)) = 4,19424 с

Период работы прерывания при совпадении при OCR1A = 9999:

Tсовпадения = 1/(32 000 000 / (2 * 1024 * (1 + 9999))) = 0,64 с

Если например не использовать режим работы таймера прерывание и сбор при переполнении, то подключенный светодиод к D12 (через резистор 200 Ом), будет загораться при совпадении значений счетного регистра и регистра сравнения, а после переполнения счетного регистра и новом совпадении значений счетного регистра и регистра сравнения гаснуть.

void setup() {  

pinMode(12, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;  

byte n = 5;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1B = n;  

OCR1A = 20000;// 0-65535  

TIMSK1 |= (1 << OCIE1A);

interrupts();

}

void loop() {}

ISR(TIMER1_COMPA_vect){  digitalWrite(12, !digitalRead(12));  }

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Если например не использовать режим работы таймера при совпадении значений счетного регистра и регистра сравнения, то подключенный светодиод к D12 (через резистор 200 Ом), будет загораться при переполнении счетного регистра, а после гаснуть при новом переполнении счетного регистра.

void setup() {  

pinMode(12, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;

byte n = 5;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1B = n;  

TIMSK1 |= (1 << TOIE1);

interrupts();

}

void loop() {}

ISR(TIMER1_OVF_vect){  digitalWrite(12, !digitalRead(12));  }

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

В нормальном режиме работы таймера можно использовать выход таймера, например если к D9 (через резистор 200 Ом) подключить светодиод, то при совпадении значений счетного регистра и регистра сравнения подключенный светодиод будет загораться и гаснуть при новом при совпадении значений счетного регистра и регистра сравнения.

Если установлен бит COM1A0 то состояние на выходе OC1A (D9) меняется на противоположное при совпадении.

void setup() {  

pinMode(D9, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;  

byte n = 5;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1A = (1 << COM1A0);  

TCCR1B = n;  

OCR1A = 9999;

interrupts();

}

void loop() {}

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Режим PWM (ШИМ)

Широтно-импульсная модуляция  (PWM) — процесс управления мощностью методом пульсирующего включения и выключения потребителя энергии.

Основной причиной применения ШИМ является стремление к повышению КПД при построении вторичных источников питания электронной аппаратуры и в других узлах, например, ШИМ используется для регулировки яркости подсветки LED-мониторов и дисплеев в телефонах, КПК и т. п.

По сути выходной PWM сигнал в LGT8F328P это импульсный сигнал с изменяемой длительностью импульсов. Если взять период следования импульсов за 100 %, то длительность импульсов может меняться от 0 до 100%, а так как Timer_1 16 бит, то заполнение длительности импульса периода следования импульса может меняться от 0 до 65535 значений, то есть от 0 до 100%.

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Режим FPWM

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Режим работы FPWM определяется несколькими регистрами, а в частности регистром захвата ICR1 и регистром сравнения OCR1A.

В регистр ICR1 записывается значение которое сравнивается с счетным регистром TCNT1 и при равенстве происходит изменение состояния  на выводе OC1A (D9), в данном случае появляется лог. 1, в регистре ICR1 указываем максимальное значение (зависит от разрядности).

В регистр OCR1A записывается значение которое сравнивается с счетным регистром TCNT1 и при равенстве происходит изменение состояния  на выводе OC1A (D9), в данном случае появляется лог. 0.

void setup() {  

pinMode(D9, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;  

byte n = 1;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1A = (1 << COM1A1) | (1 << WGM11);  

TCCR1B = (1 << WGM13) | (1 << WGM12) | n;  

ICR1 = 65535;  

OCR1A = 5000;

interrupts();

}

void loop() {}

Бит COM1A1 делает активным выход OC1A (D9), а биты WGM11 WGM12 WGM13 активируют режим FPWM.

Частота PWM в этом режиме определяется:

Fpwm = f sys / (N * (1 + ICR1))

Если предделитель установлен на 1, а регистр ICR1 имеет значение 65535, то:

Fpwm = 32 000 000 / (1 * (1 + 65535)) = 488,28125 Hz

Аналогично можно использовать выход Timer_1 OC1B (D10), использование которого определяет бит COM1B1, при этом используется регистр сравнения OCR1B.

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

void setup() {  

pinMode(D10, OUTPUT);  

noInterrupts();  

TCNT1 = 0;  

TCCR1A = 0;  

TCCR1C = 0;  

byte n = 1;  

// clksys / 1 = 1  

// clksys / 8 = 2  

// clksys / 64 = 3  

// clksys / 256 = 4  

// clksys / 1024 = 5  

// [CS12:CS10]  

TCCR1A = (1 << COM1B1) | (1 << WGM11);  

TCCR1B = (1 << WGM13) | (1 << WGM12) | n;  

ICR1 = 65535;  

OCR1B = 1000;

interrupts();

}

void loop() {}

Так же в этом режиме PWM имеется возможность инверсии выходного сигнала. Биты COM1A1 COM1A0 определяют режим работы выходного сигнала.

LGT8F328P таймеры (Arduino) Arduino, Электроника, Программирование, Длиннопост

Читать дальше...

Показать полностью 13

NTP8212 — цифровой усилитель 2х20 Вт (Arduino)

S/PDIF (Sony/Philips Digital Interface) – распространенный и стандартизированный интерфейс, предназначенный для передачи цифрового звука между доступными компонентами, звуковыми картами, ресиверами и аудиоаппаратурой.

I2S — стандарт интерфейса электрической последовательной шины, использующийся для соединения цифровых аудиоустройств. Применяется для передачи PCM-аудиоданных между интегральными схемами в электронном устройстве. Шина I2S передает по разным линиям сигналы синхронизации и сигналы данных, что приводит к снижению фазового дрожания, типичного для систем связи, восстанавливающих сигналы синхронизации из целого потока.

NTP8212 — полнофункциональный цифровой аудио усилитель (класса D), включающий силовой каскад для
системы стерео усилителей. В NTP8212G интегрирована система цифровой обработки аудиосигнала (ЦАП), высокоточный цифровой ШИМ-модулятор и два мощных полномостовых каскада питания МОП-транзисторов.

NTP8212G поддерживает формат передачи цифровых данных I2S (I²S — стандарт интерфейса электрической последовательной шины, использующийся для соединения цифровых аудиоустройств) с частотой дискретизации от 8 кГц до 192 кГц, с разрешением до 24 бит.

Усилитель выдает 2 x 20 Вт (при питании 24 В на нагрузке 8 Ом), оснащен цифровым регулятором громкости, баланса, имеет 5-и полосный эквалайзер, так же доступны функции MUTE и STANDBY.

Структурная схема усилителя

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

Основные параметры усилителя NTP8212:

  • Напряжение питания цифровое от 3,0 до 3,6 В (3,3 В рекомендуемое)

  • Аналоговое питание от 4,5 до 28 В

  • Отношение сигнал/шум 95 дБ

  • Коэффициент гармоник (THD+N 1W, 1kHz) не более 0,1 %

  • КПД усилителя 90 %

  • Частота PWM 384 кГц

  • Управление цифровое I2C

  • Ток потребления в режиме STANDBY не более 0.2 мкА

  • 5-и полосный эквалайзер 100 Гц, 300 Гц, 1 кГц, 3 кГц, 10 кГц с диапазоном регулировки от -12 до +12 дБ

Для правильной работы цифрового усилителя NTP8212, необходимо использовать ресивер, который преобразует сигнал S/PDIF в формат I2S. В данном примере использован ресивер CS8416.

Параметры ресивера CS8416:

  • Напряжение питания:

    • +3.3 V Analog Supply (VA)

    • +3.3 V Digital Supply (VD)

    • +3.3 V or +5.0 V Digital Interface Supply (VL)

  • Входной формат данных: S/PDIF

  • Выходной формат данных:

    • Left-Justified

    • Right-Justified

    • I2S (аппаратно настроен)

  • Разрядность 16 — 24 бит (аппаратно настроен на 24 бит)

  • Частота дискредитации 32 — 192 кГц (аппаратно настроен на 192 кГц)

  • Фильтр De-emphasis:

    • No De-emphasis (аппаратно настроен)

    • 32 kHz

    • 48 kHz

    • 44.1 kHz

  • Кол-во входов: 8 (аппаратно поддерживает 4)

Ресивер CS8416 имеет цифровой интерфейс управления, но может быть сконфигурирован аппаратно. В данном примере ресивер сконфигурирован аппаратно и имеет выходной формат I2S 24 бит с частотой дискредитации 192 кГц. При аппаратной настройке в ресивере доступно 4 входа S/PDIF (8 входов при программном управлении).

Коммутация входами осуществляется при помощи пинов RSEL1 и RSEL0 микросхемы ресивера , при этом лог. 1 подается с питания VL (+5 В), а логический ноль с DGND.

INPUT RSEL0 RSEL1

RXP0 00 RXP1 10

RXP2 01 RXP3 11

Ресивер работает независимо от Arduino, в схеме присутствует индикатор режима работы светодиод D1, при подключении коаксиального кабеля с источником цифрового сигнала светодиод гаснет, при отключении кабеля загорается.

Для управления работой усилителя и ресивера используется плата Arduino Nano, три кнопки и энкодер (модуль KY-040), так же управление полностью продублировано ИК пультом, информация о текущих настройка отображается на дисплее LCD1602 с платой I2C.

Схема ресивера

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

Схема усилителя

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

Схема управления

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

На дисплей выводится три меню, переключение меню осуществляется при помощи кнопки энкодера.

  • Меню индикаторов громкости (от 0 до 99) и коммутатора входов

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

Регулировка громкости осуществляется при помощи энкодера.

  • Меню эквалайзера, регулировка уровня усиления или ослабления выбранной полосы осуществляется при помощи энкодера, выбор полосы происходит при нажатии на кнопку INPUT/EQ_F. Меню эквалайзера содержит графический индикатор регулировки полос.

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост
  • Меню регулировки баланса

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост
  • Режим MUTE

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост
  • Режим STANDBY

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

Так как предусмотрена управляемая яркость подсветки дисплея, то можно установить яркость подсветки в основном  режиме и в режиме STANDBY (как правило с пониженной яркостью подсветки), регулировка яркости подсветки осуществляется через скетч:

#define BRIG_H 200 // Яркость 0…255 POWER ON
#define BRIG_L 50 // Яркость 0…255 POWER OFF

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

Подсветка — убрать перемычку с модуля I2C PCF8574 и подключить вывод модуля к цифровому выходу Arduino D6. Перед подключением замерить ток подсветки который не должен превышать 20 мА (у моего модуля ток не более 15 мА, замер производить между контактами перемычки).

Максимальный выходной ток одного выхода Arduino Nano не должен превышать 40 мА (рекомендуется не более 20 мА).

ИК пульт дублирует работу энкодера и кнопок. Для управления усилителем подойдет практически любой пульт ИК, для поддержки Вашего пульта необходимо прописать коды кнопок в скетч:

#define IR_1 0x2FDD02F // Кнопка вверх #define IR_2 0x2FD32CD // Кнопка вниз #define IR_3 0x2FD906F // Кнопка > #define IR_4 0x2FDF20D // Кнопка < #define IR_5 0x2FD6A95 // Кнопка IN #define IR_6 0x2FDEA15 // Кнопка MUTE #define IR_7 0x2FD00FF // Кнопка STANDBY (POWER)

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

NTP8212 — цифровой усилитель 2х20 Вт (Arduino) Arduino, Электроника, Самоделки, Усилитель звука, Длиннопост

Скетч - http://rcl-radio.ru/?p=129927

Показать полностью 11
Отличная работа, все прочитано!