+
Hardware Profile Feed

Дребезг контактов побежден!

Итак, для начала немного матчасти

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

Так что же делать? 

Написать алгоритм, который будет отсеивать лишние импульсы!

Логика в трех словах примерно такая.

При первом входящем импульсе - замыкание клавиши программа переходит в режим фиксации, включает таймер и отсчитывает время и пока оно не достигнет нужного вменяемого интервала, все импульсы-РАЗМЫКАНИЯ клавиши игнорируются. Если подобрать интервал близкий к скоростной игре на пианино одним пальцем - 1/32 120bpm будет достаточно, то практически всегда левые импульсы и искры при замыкании клавиши будут  фильтроваться.

И наоборот. 

Первое входящее разрешенное размыкание тоже фиксируется, отсчитывается таймером и пока время не достигнет нужного вменяемого интервала и все импульсы-ЗАМЫКАНИЯ клавиши игнорируются. 

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

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

Задаем ваши ответы))

// _ASSERT_ENABLE_ is used for enabling assert, typical for debug purposes

#define _ASSERT_ENABLE_

#include <string.h>

#include "compiler.h"

#include "main.h"

/**

 * \def BUFFER_SIZE

 * \brief The size of the UART buffer

 */

#define BUFFER_SIZE 240

// set the correct BAUD and F_CPU defines before including setbaud.h

#include "conf_clock.h"

#include "conf_uart.h"

/**

 * \name avr_libc_inc avr libc include files

 * @{

 */

#include <util/setbaud.h>

#include <avr/interrupt.h>

//! @}

#include "ring_buffer.h"

#include "lcd.h"

// buffers for use with the ring buffer (belong to the UART)

uint8_t out_buffer[BUFFER_SIZE];

uint8_t in_buffer[BUFFER_SIZE];

uint8_t chan=0;

uint8_t onchan=0x90;

uint8_t offchan=0x80;

uint16_t timer[64];

uint8_t timer1[64];

uint8_t timer2[64];

uint16_t tmd=15625;

uint8_t timerof[64];

uint8_t maxt=7;

uint8_t ecount=1;

char timestr[] = "";

// the string we send and receive on UART

const char test_string[] = " Kingdom MIDI Board^^!";

//! ring buffer to use for the UART transmission

struct ring_buffer ring_buffer_out;

//! ring buffer to use for the UART reception

struct ring_buffer ring_buffer_in;

/**

 * \brief UART data register empty interrupt handler

 *

 * This handler is called each time the UART data register is available for

 * sending data.

 */

ISR(UART0_DATA_EMPTY_IRQ)

{

// if there is data in the ring buffer, fetch it and send it

if (!ring_buffer_is_empty(&ring_buffer_out)) {

UDR0 = ring_buffer_get(&ring_buffer_out);

}

else {

// no more data to send, turn off data ready interrupt

UCSR0B &= ~(1 << UDRIE0);

}

}

/**

 * \brief Data RX interrupt handler

 *

 * This is the handler for UART receive data

 */

ISR(UART0_RX_IRQ)

{

ring_buffer_put(&ring_buffer_in, UDR0);

}

/**

 * \brief Initialize the UART with correct baud rate settings

 *

 * This function will initialize the UART baud rate registers with the correct

 * values using the AVR libc setbaud utility. In addition set the UART to

 * 8-bit, 1 stop and no parity.

 */

ISR(TIMER1_OVF_vect)

{

if (ecount) {

for (int i = 0; i < 64; i++){

if (timer) {

if (timer1<maxt){ 

timer1++;

setpos(14,0);

sprintf(timestr, "%d", timer1);

str_lcd(timestr);

setpos(14,1);

sprintf(timestr, "%d", timer2);

str_lcd(timestr);

}

}

else

{

if ((timer2<maxt)){

timer2++;

setpos(14,0);

sprintf(timestr, "%d", timer1);

str_lcd(timestr);

setpos(14,1);

sprintf(timestr, "%d", timer2);

str_lcd(timestr);

}

}

}

}

}

/*ISR(TIMER1_OVF_vect)

{

for (int i = 0; i < 64; i++){

timerof = 1;

}

}

*/

static void timer_ini(void)

{

//TCCR1B |= (1<<WGM12); // устанавливаем режим СТС (сброс по совпадению)

//TIMSK |= (1<<OCIE1A); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)

//OCR1AH = 0b01111010; //записываем в регистр число для сравнения

//OCR1AL = 0b00010010;

//TCCR1B |= (1<<CS02)|(1<<CS00);//установим делитель.

//TIMSK0|=(1<<TOIE0);

TCCR1B |= /*(1<<CS11)|*/(1<<CS10);//установим делитель.

TIMSK1|=(1<<TOIE1);

//TCCR1B |= (1<<CS11);//установим делитель.

}

static void timer_stop(void)

{

TCCR1B = 0;//установим делитель.

}

static void timer_play(void)

{

TCCR1B |= /*(1<<CS11)|*/(1<<CS10);//установим делитель.

}

static void uart_init(void)

{

#if defined UBRR0H

// get the values from the setbaud tool

UBRR0H = UBRRH_VALUE;

UBRR0L = UBRRL_VALUE;

#else

#error "Device is not supported by the driver"

#endif

#if USE_2X

UCSR0A |= (1 << U2X0);

#endif

// enable RX and TX and set interrupts on rx complete

UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);

// 8-bit, 1 stop bit, no parity, asynchronous UART

UCSR0C = (1 << UCSZ01) | (1 << UCSZ00) | (0 << USBS0) |

(0 << UPM01) | (0 << UPM00) | (0 << UMSEL01) |

(0 << UMSEL00);

// initialize the in and out buffer for the UART

ring_buffer_out = ring_buffer_init(out_buffer, BUFFER_SIZE);

ring_buffer_in = ring_buffer_init(in_buffer, BUFFER_SIZE);

}

/**

 * \brief Function for putting a char in the UART buffer

 *

 * \param data the data to add to the UART buffer and send

 *

 */

static inline void uart_putchar(uint8_t data)

{

// Disable interrupts to get exclusive access to ring_buffer_out.

cli();

if (ring_buffer_is_empty(&ring_buffer_out)) {

// First data in buffer, enable data ready interrupt

UCSR0B |=  (1 << UDRIE0);

}

// Put data in buffer

ring_buffer_put(&ring_buffer_out, data);

// Re-enable interrupts

sei();

}

static inline void noteon(uint8_t data)

{

uart_putchar(onchan);

uart_putchar(data);

uart_putchar(0x7F);

}

static inline void noteoff(uint8_t data)

{

uart_putchar(offchan);

uart_putchar(data);

uart_putchar(0x7F);

}

/**

 * \brief Function for getting a char from the UART receive buffer

 *

 * \retval Next data byte in recieve buffer

 */

static inline uint8_t uart_getchar(void)

{

return ring_buffer_get(&ring_buffer_in);

}

/**

 * \brief Function to check if we have a char waiting in the UART receive buffer

 *

 * \retval true if data is waiting

 * \retval false if no data is waiting

 */

static inline bool uart_char_waiting(void)

{

return !ring_buffer_is_empty(&ring_buffer_in);

}

/**

 * \brief The main application

 *

 * This application will initialize the UART, send a character and then receive

 * it and check if it is the same character as was sent.

 *

 * \note The RX and TX pins should be externally connected in order to pass the

 * test.

 */

int main(void)

{

uint8_t data;

uint8_t cnt;

uint8_t i;

uint8_t note;

uint8_t sta[8];

uint8_t pra[8];

uint8_t rta[8];

uint8_t rnz[8];

uint8_t /*sta=0xFF, */stb=0xFF, stc=0xFF, std=0xFF, ste=0x00, stf=0xFF, stg=0xFF, sth=0xFF, stj=0xFF, stk=0xFF, stl=0x00; 

uint8_t /*pra=0xFF, */prb=0xFF, prc=0xFF, prd=0xFF, pre=0x00, prf=0xFF, prg=0xFF, prh=0xFF, prj=0xFF, prk=0xFF, prl=0x00;

uint8_t /*rta=0xFF, */rtb=0xFF, rtc=0xFF, rtd=0xFF, rte=0x00, rtf=0xFF, rtg=0xFF, rth=0xFF, rtj=0xFF, rtk=0xFF, rtl=0x00;

uint16_t timert=0, timerd=0;

char test_string1[] = "Hi1^^!";

char test_string2[] = "Hi2^^!";

char notestr[] = "";

PORTA=0xFF;

DDRA=0x00;//0

PORTB=0x00;

DDRB=0xFF;//1 out scan

PORTC=0xFF;

DDRC=0x00;//2

PORTD=0xFF;

DDRD=0x00;//3

PORTE=0x00;

DDRE=0xFF;//out USART and MIDI CHANNEL LED 

PORTF=0xFF;

DDRF=0x00;//4

PORTG=0xFF;

DDRG=0x00;//in control

PORTH=0xFF;

DDRH=0x00;//5

PORTJ=0xFF;

DDRJ=0x00;//6

PORTK=0xFF;

DDRK=0xFF;//7 out scan

PORTL=0x00;

DDRL=0xFF;//out LEDS

cli();

for (int i = 0; i < 64; i++){

timer1 = maxt;

timer2 = maxt;

timer = 0;

}

timer_ini();

for (int j = 0; j < 8; j++){

pra[j]=0xFF;

sta[j]=0xFF;

}

rnz[0]=0b11111110;

rnz[1]=0b11111101;

rnz[2]=0b11111011;

rnz[3]=0b11110111;

rnz[4]=0b11101111;

rnz[5]=0b11011111;

rnz[6]=0b10111111;

rnz[7]=0b01111111;

uart_init();

sei();

LCD_ini();  //Инициализируем дисплей

setpos(4,0);

str_lcd("Kingdom>");

setpos(0,1);

str_lcd("MIDI Board ^_^");

// Send the test string

for (cnt = 0; cnt < strlen(test_string); cnt++) {

uart_putchar(test_string[cnt]);

}

// Check if we have received the string we sent

cnt = 0;

do

{

for (uint8_t j = 0; j < 8; j++)

{

prk=rnz[j];

PORTK = prk;

PORTK = prk;

asm("nop");

asm("nop");

pra[j]=PINA;

rta[j]=pra[j]^sta[j];

for (int i = 0; i < 8; i++)

{

note = (j<<3)+i;

if (rta[j]&(1<<i))

{

if (sta[j]&(1<<i))

{

if (timer2[note]==maxt)

{

timer_stop();

noteon(note);

sta[j]=pra[j];

timer1[note] = 0;

timer[note] = 1;

clearlcd();

setpos(0,0);

str_lcd("Note ON");

setpos(0,1);

sprintf(notestr, "%d", note);

str_lcd(notestr);

timer_play();

}

}

else

{

if (timer1[note]==maxt)

{

timer_stop();

noteoff(note);

sta[j]=pra[j];

timer2[note] = 0;

timer[note] = 0;

clearlcd();

setpos(0,0);

str_lcd("Note OFF");

setpos(0,1);

sprintf(notestr, "%d", note);

str_lcd(notestr);

timer_play();

}

}

}

}

}

} while (1);

}


PgIj2N W3TE @ Kingdom

Гениальное
TRANSIENT PROGRAM FOR DRUMS AND MACHINERY
3 ▲
2 November 2019 17:12
Kingdom

Comments

Pinned comments
Kate Noizu 「ノイズ・ケイト」  4 November 2019 0:04
Kingdom  2 November 2019 22:25
TIME TO SWEEP
(Atatat was here)
Я нигде код для фильтрации не заимствовал, просто сел и придумал сам.
(Atatat was here)
Ты невнимательно читаешь статью. У меня полифония 64 независимых клавиши. И у каждой должен быть отдельный отсчёт времени
Я думаю его можно оптимизировать
(Atatat was here)
попробую обойтись таблицей 64 таймера, но это не точно
(Atatat was here)
Мелко плаваешь. Я хочу тру полифонию!
(Atatat was here)
Играю, есть иногда арпы наслойки 5-7 нот
И зачем очередь, если хватит простой таблицы
(Atatat was here)
Но не мудрее
Мечтаю упасть локтями на клавиши и все заиграло ^^3
(Atatat was here)
У меня все работает!
удалил свои комменты , какойто бред. неважно все
не хватает двух самых главных экспертов по полотнам текстовым с познаниями космической важности и космической же глупости (=
шоу Ваша Раша загнулось когда мне их Латвии прислали ссылку на радиошоу Наша Латыша. Тогда то я и поняла что всё тлен. И юморок провинциальный уже не катит.
(Atatat was here)
там юмор такой был, типа два гопаря пришли сдавать экзамен на историю и знание лат языка... один сдал, выходит довольный, ждёт второго, второй выходит - не сдал... а ты где пиджак покупал? ну как всегда в Московском Доме Моды! а, ну тогда понятно
мы кароч нагнули блог чила
ну там рядом в ленте блоог Чила про его деятельность "Я заканчиваю выпускать CHILL и ОФФТОП!"
честно вот я не в курсе кто это... типа сода что ли? новый ремувз?
ты у меня спрашиваешь ? незнаю кто это
ты сказал, у тебя и спрашиваю
да я хз , откуда то я знаю ?
нагнули, значит поделом нагнули!! (=
TIME TO SWEEP
Зачем столько сложностей? :)
Хотя всё равно похвально :) C++ рулит
это си с асмой , какое C++, на микрухи еще плюсы тянуть , ну виндузяны
Ну, я ламер в этом деле, могу и перепутать: C++ когда-то давно занимался, увидел знакомые строчки кода :) так что извиняюсь, если кого-то этим задел :D
но конечно свиду одно и тоже.
Затем. Проще сделать невозможно.
И да, интервал нужно другой, потому что на одной клавише пианино можно не только одним пальцем, но и двумя, и тремя, и четырьмя - и там уже скорость большая достигается :)
1/64 120 bpm - уже достаточно
Да и то, не факт :) но там уже мало кто эту скорость превысит
Я отдельный регулятор выведу))

Регулировка скорости.

В атмеге2560 портов столько что можно еще 64 клавиши подрубить - миди контроллеры и модуляции
делай как люди - 96 тиков на такт , это стандарт. а то вы тут запархаетесь еще и с этим , лол.
Скорость миди порта 31250 бод/с , ты знаешь это?
одна команда это 3 байта
посылка ноты - всегда
Не неси пургу^^
ты не так хардкорен как пытаещьса выглядеть 1
Я софткорен
96 тиков генерит секвенсор, а синтезатор у пофиг на эти тики
и мне тоже. Это не я, а ты все слишком усложняешь^_~
долго обьяснять , ты хочешь синхронизиронизацию по миди или нет ? или зачем тебе вообще миди-клок
Она примерно такой и будет, я тестировал 1/32 на 8 МГц, потом перепрошью на 16МГц и задержка поделиться на 2
А если готовую клаву взять и сразу за дело. В качестве альтернативы конечно. ;)
Ну, подари мне 10 тыщ грн. Мне с контроллерами нужна.
У меня куча долгов за квартиру, я не куплю клаву еще ооочень долго
А синтезатор тем более
Смотри ситуация. С моей невралгией я больше чем 5-7 тыщ грн не зарабатываю. Вопрос, сколько мне надо времени чтобы собрать на один синтезатор с миди клавой? (1500$)
Нахрена тебе именно синтезатор за 1500$. Можно в инете поискать поломанный, лишь бы миди порты работали.
Тот который мне подойдет, стоит 1500. Ты же не видел как я музыку делаю))
Мне надо полный набор - 3 осциллятора, adsr, питч, фильтр моды, lfo, FM, PM, ring mod, ARPS full controlled
Чем тебя VST не устраивают?
Задержка. мне на сцене надо выступать.
Ну тады ОЙ! :)
Меня никуда не зовут, поэтому я особо не заморачиваюсь.
Отож то й воно^^3
А звуковухи внешней нет? Она ж компенсирует задержки
Это миф, ничего она не компенсирует, если речь идёт о реальном программном синтезе. На vst хосте будет слишком много вычислений и большой буффер, чтобы звук не лагал и не скрипел. Синтез должен быть натурально аппаратным, чтобы задержка была ультра короткой
Миф, значит? Как раз купил себе звуковуху, надо будет проверить :)
Подключи миди клаву к вст хосту и поиграй на мэссиве, замеряй задержку генерации
20-50 мс на вст при условии что ПК очень скоростной. На бюджетном будет 0,1-0,3 секунды
Где можно будет позырить видео выступления, еси чо?
На Ютубе разумеется
сплошной фейспалм конечно
Модно и познавательно. Прям как музыка Электролитов. :)
В отличие от Электродов, всё что я делаю - настоящее
Я бы сказал больше - ты сам есть настоящий, в отличии от Электродов.)
Пасибке за поддержк))
стока многа букавак, уф... так сё слозно и непонятно... ну да ладно ... )))
Не расслабляйся))
Вот и наступил тот момент походу)
-Или .уй пополам! или писда вдребезги!!!)))
Это было непросто)))
Хоть виден был издалека)
Please, sign up (it's quick!) or sign in, to post comments and do more fun stuff.