Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Опрос клавиатуры на С
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
Make_Pic
Опрос клавиатуры на С -> Как написать компактный и "красивый" код?
Дайте pls примеры опроса матрицы клавиш на С (C++ не надо).
Forger
Цитата(Make_Pic @ Jun 23 2018, 08:17) *
Опрос клавиатуры на С -> Как написать компактный и "красивый" код?
Дайте pls примеры опроса матрицы клавиш на С (C++ не надо).

В своих проектах разделяю опрос клавиатуры (неважно какая, матричная или обычная) на два разных этапа:
1) опрос существующего состояния кнопок с заданной периодичностью, обычно раз в 50мс, чтобы потом не "воевать" с дребезгом.
2) анализ (сравнение) текущего и предыдущего состояния клавиатуры, тем самым выделяя события отпускания и нажатия
далее в зависимости от проекта реализовывал систему подписки на различные события, если в двух словах, то речь про колбэки и их продвинутые аналоги.
Модули, которым нужно ждать события от клавиатуры, "подписываются" на нужные события и кнопки, "обращаясь" к модулю клавиатуры.
События всего два - отпускание и нажатие. Этого обычно вполне достаточно. Долгое удержание или т. п. реализуется уже в самом модуле.
Такая схема дает возможность напрочь отвязаться от способа реализации клавиатуры: будь то "примитивные" кнопки на пинах и внешние проводные или беспроводное клавиатуры (например, пульты оператора).

Т.е. я жестко разделяю опрос клавиатуры от тех модулей/блоков, которые ждут от нее реакцию.
Примеры приводить не буду, т. к. вы "запретили" тут использовать C++.
Однако, на голом С все описанное выше тоже реализуется, но уже несколько "топорно" и далеко не так "компактно и красиво".
К счастью (кому-то к сожалению) давно не использую подобный инструментарий и поэтому примеров на нем, увы, не сохранилось ((

Добавлю, что использую RTOS, т. к. под ней это реализуется значительно проще: не нужно "колдовать" с таймерами и самодельными генераторами/приемниками событий.

зы. В проектах с одной/двумя кнопками все реализую значительно проще, но аналогично - периодический опрос и сравнение двух состояний: предыдущего и текущего.
Make_Pic
Цитата(Forger @ Jun 23 2018, 09:38) *
...
Добавлю, что использую RTOS, т. к. под ней это реализуется значительно проще: не нужно "колдовать" с таймерами и самодельными генераторами/приемниками событий.

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

Я не запрещал, но понимаю, что на плюсах удобнее - приведите свой пример pls!
x893
Цитата(Forger @ Jun 23 2018, 09:38) *
...
далее в зависимости от проекта реализовывал систему подписки на различные события, если в двух словах, то речь про колбэки и их продвинутые аналоги.
Модули, которым нужно ждать события от клавиатуры, "подписываются" на нужные события и кнопки, "обращаясь" к модулю клавиатуры
....

То есть у Вас модули в runtime подписываются/отписываются от событий клавиатуры ?

Forger
Цитата(Make_Pic @ Jun 23 2018, 10:20) *
Я не запрещал, но понимаю, что на плюсах удобнее - приведите свой пример pls!

Честно говоря, мне влом "выдерать" его из кода, чтобы было понятно, что тут происходит laughing.gif
Поэтому выше я на словах довольно подробно описал сам принцип.
Имхо, так будет намного понятнее, особенно кто ни разу ничего подобного не делал.

Вообще, стараюсь документировать свой код визуально (использую для этого XMind). Не вдаваясь в нюансы и детали, но чтобы в целом все было все понятно сходу через энное время.
Однако, с клавиатурами пока этого не делал, пока в планах.

Пока копался в исходниках, нашел, что в одном из проектов делал чуть иначе: для работы с некой кнопкой нужно наследовать свой класс от шаблона Button<>,
потом реализовать пару виртуальных методов, где нужно обрабатывать реакцию на отпускание/нажатие. Если реакция, скажем, на отпускание не нужна, то можно вообще не реализовывать соотв. метод.
В моем случае функционал класса кнопки еще умеет и управлять собственной подсветкой: on/off/blink и т. п.
После этого нужно лишь "подключить" этот экземпляр класса к нужной клавиатуре (в одном проекте может быть не одна клавиатура, например, распределенная система).
Цитата(x893 @ Jun 23 2018, 11:03) *
То есть у Вас модули в runtime подписываются/отписываются от событий клавиатуры ?

В принципе, это возможно, но на практике мне пока не приходилось это использовать.
AlexandrY
Цитата(Make_Pic @ Jun 23 2018, 10:20) *
Я не запрещал, но понимаю, что на плюсах удобнее - приведите свой пример pls!

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

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

А вот код на C который сгенерился по этой модели
CODE

/*
* File: KeyboardScanModule.c
*
* Code generated for Simulink model 'KeyboardScanModule'.
*
* Model version : 1.5
* Simulink Coder version : 8.14 (R2018a) 06-Feb-2018
* C/C++ source code generated on : Sat Jun 23 17:02:12 2018
*
* Target selection: ert.tlc
* Embedded hardware selection: ARM Compatible->ARM Cortex
* Code generation objectives:
* 1. Execution efficiency
* 2. Traceability
* Validation result: Not run
*/

#include "KeyboardScanModule.h"

/* Block signals and states (default storage) */
DW rtDW;

/* External outputs (root outports fed by signals with default storage) */
ExtY rtY;

/* Real-time model */
RT_MODEL rtM_;
RT_MODEL *const rtM = &rtM_;
static void rate_scheduler(void);

/*
* This function updates active task flag for each subrate.
* The function is called at model base rate, hence the
* generated code self-manages all its subrates.
*/
static void rate_scheduler(void)
{
/* Compute which subrates run during the next base time step. Subrates
* are an integer multiple of the base rate counter. Therefore, the subtask
* counter is reset when it reaches its limit (zero means run).
*/
(rtM->Timing.TaskCounters.TID[1])++;
if ((rtM->Timing.TaskCounters.TID[1]) > 2) {/* Sample time: [3.0s, 0.0s] */
rtM->Timing.TaskCounters.TID[1] = 0;
}
}

/* Model step function */
void KeyboardScanModule_step(void)
{
int32_T uyIdx;
int32_T currentOffset;
int32_T nSampsAtBot;
int32_T rtb_Add[9];
boolean_T rtb_RelationalOperator[9];
boolean_T rtb_TmpSignalConversionAtDelayI[9];
boolean_T rtb_Delay[9];
int32_T rtb_Switch[9];
uint8_T rtb_FixPtSum1;
boolean_T rtb_Buffer2[3];
boolean_T rtb_Buffer1[3];
boolean_T rtb_Buffer[3];
int32_T i;
int32_T rtb_Add_d;
if (rtM->Timing.TaskCounters.TID[1] == 0) {
for (i = 0; i < 9; i++) {
/* Sum: '<S1>/Add' incorporates:
* Constant: '<S1>/Constant3'
* Delay: '<S1>/Delay1'
*/
rtb_Add_d = rtDW.Delay1_DSTATE[i] + 1;

/* RelationalOperator: '<S1>/Relational Operator' incorporates:
* Constant: '<S1>/Constant2'
*/
rtb_RelationalOperator[i] = (10 > rtb_Add_d);

/* Delay: '<S1>/Delay' */
rtb_Delay[i] = rtDW.Delay_DSTATE[i];

/* Sum: '<S1>/Add' */
rtb_Add[i] = rtb_Add_d;
}
}

/* Buffer: '<S1>/Buffer2' incorporates:
* Constant: '<S1>/Constant'
* MultiPortSwitch: '<S1>/Multiport Switch'
*/
rtb_Add_d = 6;
uyIdx = rtDW.Buffer2_inBufPtrIdx;
if (6 - rtDW.Buffer2_inBufPtrIdx <= 1) {
for (i = 0; i < 6 - rtDW.Buffer2_inBufPtrIdx; i++) {
rtDW.Buffer2_CircBuf[rtDW.Buffer2_inBufPtrIdx + i] = false;
}

uyIdx = 0;
rtb_Add_d = rtDW.Buffer2_inBufPtrIdx;
}

for (i = 0; i < rtb_Add_d - 5; i++) {
rtDW.Buffer2_CircBuf[uyIdx + i] = false;
}

rtDW.Buffer2_inBufPtrIdx++;
if (rtDW.Buffer2_inBufPtrIdx >= 6) {
rtDW.Buffer2_inBufPtrIdx -= 6;
}

rtDW.Buffer2_bufferLength++;
if (rtDW.Buffer2_bufferLength > 6) {
rtDW.Buffer2_outBufPtrIdx = (rtDW.Buffer2_outBufPtrIdx +
rtDW.Buffer2_bufferLength) - 6;
if (rtDW.Buffer2_outBufPtrIdx > 6) {
rtDW.Buffer2_outBufPtrIdx -= 6;
}

rtDW.Buffer2_bufferLength = 6;
}

if (rtM->Timing.TaskCounters.TID[1] == 0) {
rtDW.Buffer2_bufferLength -= 3;
if (rtDW.Buffer2_bufferLength < 0) {
rtDW.Buffer2_outBufPtrIdx += rtDW.Buffer2_bufferLength;
if (rtDW.Buffer2_outBufPtrIdx < 0) {
rtDW.Buffer2_outBufPtrIdx += 6;
}

rtDW.Buffer2_bufferLength = 0;
}

uyIdx = 0;
currentOffset = rtDW.Buffer2_outBufPtrIdx;
if (rtDW.Buffer2_outBufPtrIdx < 0) {
currentOffset = rtDW.Buffer2_outBufPtrIdx + 6;
}

nSampsAtBot = 6 - currentOffset;
rtb_Add_d = 3;
if (6 - currentOffset <= 3) {
for (i = 0; i < 6 - currentOffset; i++) {
rtb_Buffer2[i] = rtDW.Buffer2_CircBuf[currentOffset + i];
}

uyIdx = 6 - currentOffset;
currentOffset = 0;
rtb_Add_d = 3 - nSampsAtBot;
}

for (i = 0; i < rtb_Add_d; i++) {
rtb_Buffer2[uyIdx + i] = rtDW.Buffer2_CircBuf[currentOffset + i];
}

rtDW.Buffer2_outBufPtrIdx = currentOffset + rtb_Add_d;
}

/* End of Buffer: '<S1>/Buffer2' */

/* Buffer: '<S1>/Buffer1' incorporates:
* Constant: '<S1>/Constant'
* MultiPortSwitch: '<S1>/Multiport Switch2'
*/
rtb_Add_d = 6;
uyIdx = rtDW.Buffer1_inBufPtrIdx;
if (6 - rtDW.Buffer1_inBufPtrIdx <= 1) {
for (i = 0; i < 6 - rtDW.Buffer1_inBufPtrIdx; i++) {
rtDW.Buffer1_CircBuf[rtDW.Buffer1_inBufPtrIdx + i] = false;
}

uyIdx = 0;
rtb_Add_d = rtDW.Buffer1_inBufPtrIdx;
}

for (i = 0; i < rtb_Add_d - 5; i++) {
rtDW.Buffer1_CircBuf[uyIdx + i] = false;
}

rtDW.Buffer1_inBufPtrIdx++;
if (rtDW.Buffer1_inBufPtrIdx >= 6) {
rtDW.Buffer1_inBufPtrIdx -= 6;
}

rtDW.Buffer1_bufferLength++;
if (rtDW.Buffer1_bufferLength > 6) {
rtDW.Buffer1_outBufPtrIdx = (rtDW.Buffer1_outBufPtrIdx +
rtDW.Buffer1_bufferLength) - 6;
if (rtDW.Buffer1_outBufPtrIdx > 6) {
rtDW.Buffer1_outBufPtrIdx -= 6;
}

rtDW.Buffer1_bufferLength = 6;
}

if (rtM->Timing.TaskCounters.TID[1] == 0) {
rtDW.Buffer1_bufferLength -= 3;
if (rtDW.Buffer1_bufferLength < 0) {
rtDW.Buffer1_outBufPtrIdx += rtDW.Buffer1_bufferLength;
if (rtDW.Buffer1_outBufPtrIdx < 0) {
rtDW.Buffer1_outBufPtrIdx += 6;
}

rtDW.Buffer1_bufferLength = 0;
}

uyIdx = 0;
currentOffset = rtDW.Buffer1_outBufPtrIdx;
if (rtDW.Buffer1_outBufPtrIdx < 0) {
currentOffset = rtDW.Buffer1_outBufPtrIdx + 6;
}

nSampsAtBot = 6 - currentOffset;
rtb_Add_d = 3;
if (6 - currentOffset <= 3) {
for (i = 0; i < 6 - currentOffset; i++) {
rtb_Buffer1[i] = rtDW.Buffer1_CircBuf[currentOffset + i];
}

uyIdx = 6 - currentOffset;
currentOffset = 0;
rtb_Add_d = 3 - nSampsAtBot;
}

for (i = 0; i < rtb_Add_d; i++) {
rtb_Buffer1[uyIdx + i] = rtDW.Buffer1_CircBuf[currentOffset + i];
}

rtDW.Buffer1_outBufPtrIdx = currentOffset + rtb_Add_d;
}

/* End of Buffer: '<S1>/Buffer1' */

/* Buffer: '<S1>/Buffer' incorporates:
* Constant: '<S1>/Constant'
* MultiPortSwitch: '<S1>/Multiport Switch3'
*/
rtb_Add_d = 6;
uyIdx = rtDW.Buffer_inBufPtrIdx;
if (6 - rtDW.Buffer_inBufPtrIdx <= 1) {
for (i = 0; i < 6 - rtDW.Buffer_inBufPtrIdx; i++) {
rtDW.Buffer_CircBuf[rtDW.Buffer_inBufPtrIdx + i] = false;
}

uyIdx = 0;
rtb_Add_d = rtDW.Buffer_inBufPtrIdx;
}

for (i = 0; i < rtb_Add_d - 5; i++) {
rtDW.Buffer_CircBuf[uyIdx + i] = false;
}

rtDW.Buffer_inBufPtrIdx++;
if (rtDW.Buffer_inBufPtrIdx >= 6) {
rtDW.Buffer_inBufPtrIdx -= 6;
}

rtDW.Buffer_bufferLength++;
if (rtDW.Buffer_bufferLength > 6) {
rtDW.Buffer_outBufPtrIdx = (rtDW.Buffer_outBufPtrIdx +
rtDW.Buffer_bufferLength) - 6;
if (rtDW.Buffer_outBufPtrIdx > 6) {
rtDW.Buffer_outBufPtrIdx -= 6;
}

rtDW.Buffer_bufferLength = 6;
}

if (rtM->Timing.TaskCounters.TID[1] == 0) {
rtDW.Buffer_bufferLength -= 3;
if (rtDW.Buffer_bufferLength < 0) {
rtDW.Buffer_outBufPtrIdx += rtDW.Buffer_bufferLength;
if (rtDW.Buffer_outBufPtrIdx < 0) {
rtDW.Buffer_outBufPtrIdx += 6;
}

rtDW.Buffer_bufferLength = 0;
}

uyIdx = 0;
currentOffset = rtDW.Buffer_outBufPtrIdx;
if (rtDW.Buffer_outBufPtrIdx < 0) {
currentOffset = rtDW.Buffer_outBufPtrIdx + 6;
}

nSampsAtBot = 6 - currentOffset;
rtb_Add_d = 3;
if (6 - currentOffset <= 3) {
for (i = 0; i < 6 - currentOffset; i++) {
rtb_Buffer[i] = rtDW.Buffer_CircBuf[currentOffset + i];
}

uyIdx = 6 - currentOffset;
currentOffset = 0;
rtb_Add_d = 3 - nSampsAtBot;
}

for (i = 0; i < rtb_Add_d; i++) {
rtb_Buffer[uyIdx + i] = rtDW.Buffer_CircBuf[currentOffset + i];
}

rtDW.Buffer_outBufPtrIdx = currentOffset + rtb_Add_d;

/* SignalConversion: '<S1>/TmpSignal ConversionAtDelayInport1' */
rtb_TmpSignalConversionAtDelayI[0] = rtb_Buffer2[0];
rtb_TmpSignalConversionAtDelayI[3] = rtb_Buffer1[0];
rtb_TmpSignalConversionAtDelayI[6] = rtb_Buffer[0];
rtb_TmpSignalConversionAtDelayI[1] = rtb_Buffer2[1];
rtb_TmpSignalConversionAtDelayI[4] = rtb_Buffer1[1];
rtb_TmpSignalConversionAtDelayI[7] = rtb_Buffer[1];
rtb_TmpSignalConversionAtDelayI[2] = rtb_Buffer2[2];
rtb_TmpSignalConversionAtDelayI[5] = rtb_Buffer1[2];
rtb_TmpSignalConversionAtDelayI[8] = rtb_Buffer[2];
for (i = 0; i < 9; i++) {
/* Outport: '<Root>/PressFlags' incorporates:
* Logic: '<S1>/Logical Operator2'
*/
rtY.PressFlags[i] = (rtb_RelationalOperator[i] && rtb_Delay[i]);

/* Outport: '<Root>/ReleasFlags' incorporates:
* Logic: '<S1>/Logical Operator3'
* Logic: '<S1>/Logical Operator4'
*/
rtY.ReleasFlags[i] = (rtb_RelationalOperator[i] && (!rtb_Delay[i]));

/* Switch: '<S1>/Switch' incorporates:
* Constant: '<S1>/Constant4'
* Logic: '<S1>/Logical Operator'
*/
if ((boolean_T)(rtb_Delay[i] ^ rtb_TmpSignalConversionAtDelayI[i])) {
rtb_Switch[i] = rtb_Add[i];
} else {
rtb_Switch[i] = 0;
}

/* End of Switch: '<S1>/Switch' */
}

for (i = 0; i < 9; i++) {
/* Update for Delay: '<S1>/Delay1' */
rtDW.Delay1_DSTATE[i] = rtb_Switch[i];

/* Update for Delay: '<S1>/Delay' */
rtDW.Delay_DSTATE[i] = rtb_TmpSignalConversionAtDelayI[i];
}
}

/* End of Buffer: '<S1>/Buffer' */

/* Sum: '<S4>/FixPt Sum1' incorporates:
* Constant: '<S4>/FixPt Constant'
* UnitDelay: '<S3>/Output'
*/
rtb_FixPtSum1 = (uint8_T)(rtDW.Output_DSTATE + 1U);

/* Switch: '<S5>/FixPt Switch' */
if (rtb_FixPtSum1 > 2) {
/* Update for UnitDelay: '<S3>/Output' incorporates:
* Constant: '<S5>/Constant'
*/
rtDW.Output_DSTATE = 0U;
} else {
/* Update for UnitDelay: '<S3>/Output' */
rtDW.Output_DSTATE = rtb_FixPtSum1;
}

/* End of Switch: '<S5>/FixPt Switch' */
rate_scheduler();
}

/* Model initialize function */
void KeyboardScanModule_initialize(void)
{
{
int32_T i;

/* InitializeConditions for Delay: '<S1>/Delay1' */
for (i = 0; i < 9; i++) {
rtDW.Delay1_DSTATE[i] = 1;
}

/* End of InitializeConditions for Delay: '<S1>/Delay1' */

/* InitializeConditions for Buffer: '<S1>/Buffer2' */
rtDW.Buffer2_inBufPtrIdx = 3;
rtDW.Buffer2_bufferLength = 3;

/* InitializeConditions for Buffer: '<S1>/Buffer1' */
rtDW.Buffer1_inBufPtrIdx = 3;
rtDW.Buffer1_bufferLength = 3;

/* InitializeConditions for Buffer: '<S1>/Buffer' */
rtDW.Buffer_inBufPtrIdx = 3;
rtDW.Buffer_bufferLength = 3;
}
}

/*
* File trailer for generated code.
*
* [EOF]
*/


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

Предупреждение. Файл имеет зависимости. Типы и функция main объявлены в других файлах.
Forger
Цитата
B такая генерация спасает от рутины громоздить огромное количество счетчиков и создания длинный битовых масок.

Отличный пример "героизма": сначала создать проблему на пустом месте, а потом с ней героически бороться cool.gif
AlexandrY
Цитата(Forger @ Jun 23 2018, 16:54) *
Отличный пример "героизма": сначала создать проблему на пустом месте, а потом с ней героически бороться cool.gif

Возьмем тон чуть конструктивней. biggrin.gif

"Героизм" - это про счетчик на каждую кнопку?
Тогда жду альтернативы.
Forger
Цитата(AlexandrY @ Jun 23 2018, 17:09) *
Возьмем тон чуть конструктивней

Другой разговор!

Цитата
"Героизм" - это про счетчик на каждую кнопку?

Полагаю, что именно с этим вы и пытаетесь "бороться".

Но в моем решении таймер всего один, да и тот используется в виде соотв. сервиса RTOS.
Число кнопок, их принцип работы, размещение и т. п. никакого значения не имеют.
Именно так выглядит модульное построение проекта - зависимости минимизированы и предельно абстрактны.
AlexandrY
Цитата(Forger @ Jun 23 2018, 17:13) *
Другой разговор!


Полагаю, что именно с этим вы и пытаетесь "бороться".

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

Таймер то со счетчиком не путайте.
Я прекрасно знаю как вы используете таймер.
В вашем случае все так же надо хранить метки времени для каждой кнопки.
И все также делать каскад сравнений. Метод ничего не упрощающий и не экономящий. Плюсы тут ни к селу ни к городу.
Forger
Цитата(AlexandrY @ Jun 23 2018, 17:22) *
Таймер то со счетчиком не путайте.
Я прекрасно знаю как вы используете таймер.

Сильно сомневаюсь, что вы поняли мою реализацию.
Однако, распишите, как вы это поняли?

Цитата
В вашем случае все так же надо хранить метки времени для каждой кнопки.

Какие еще "временные метки"???
Перечитайте мой первый пост в этой теме.
Ведь очень простое и очевидное решение. Я не сам его придумал, а как обычно - подсмотрел у более опытных комрадов.

Цитата
И все также делать каскад сравнений. Метод ничего не упрощающий.

Да нут тут никаких "каскадов сравнений" (где вы берете такие архаичные термины? )
Есть один-два банальных цикла для сравнения двух "слепков" состояния кнопок - текущее и прежнее.
В целом все очень компактно и просто. Именно так, как я описал в первых постах.
Но конкретная реализация сильно зависит от программиста и его видения "проблемы".

Цитата
Плюсы тут ни к селу ни к городу.
Да спрячьте вы уже свой "баян" или хотя бы разучите новые мотивы! wink.gif
AlexandrY
Цитата(Forger @ Jun 23 2018, 17:29) *
Какие еще "временные метки"???
Перечитайте мой первый пост в этой теме.
Ведь очень простое и очевидное решение. Я не сам его придумал, а как обычно - подсмотрел у более опытных комрадов.

Че...? 50 мс?
Да не смешите. Скажите это геймерам которые за миллисекунды трясутся на своей клавиатуре.
Не, с такими упрощениями мне не интересно.
Факт только в том, что я свой алгоритм сделал и выложил элементарно, а вы свой даже частями показать не можете.
Он мне конечно не интересен, но мы же меряемся за принцип. smile3009.gif

Кста MATLAB может и на C++ сгенерить исходники, и под разные процессоры, и под RTOS и без RTOS.
Т.е. показанная модель реально универсальна.
Forger
Цитата(AlexandrY @ Jun 23 2018, 17:43) *
Че...? 50 мс? Да не смешите. Скажите это геймерам которые за миллисекунды трясутся на своей клавиатуре.

Вы точно остались где-то в 90-х и пишите на паскале в DOSе. biggrin.gif

Для геймеров можно поставить 10мс, 1мс, 100мкс. Это - не проблема. Но мои проекты рассчитаны на обычных рядовых юзеров.
А такой юзер не отличит реакции кнопки 50 мс от 100 мс. Можете сами убедиться.

Цитата
Не, с такими упрощениями мне не интересно.

Ну, разумеется! Ведь ваш конек - создавать из воздуха проблемы и героически с ними бороться lol.gif

Цитата
Факт только в том, что я свой алгоритм сделал и выложил элементарно, а вы свой даже частями показать не можете.

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

Цитата
но мы же меряемся за принцип. smile3009.gif
Говорите лучше за себя.

Цитата
Кста MATLAB может и на C++ сгенерить исходники, и под разные процессоры, и под RTOS и без RTOS.

Вы молодец - освоили MATLAB: теперь умеете "отрезать тонкие веточки" "промышленной бензопилой". Подравляю! sm.gif
x893
Цитата(AlexandrY @ Jun 23 2018, 16:40) *
...
Но я хочу показать еще один универсальный способ создания софта.
...

Но это же тихий ужас !
P.S. Но это личное дело конечно.
Сергей Борщ
QUOTE (x893 @ Jun 23 2018, 18:01) *
Но это же тихий ужас !
Ну почему же? Стильно, модно, молодежно. Следующим этапом будем искать кнопки с переключающими контактам, потому что только такие есть в модели.
iliusmaster
Обычно, чтобы ничего постояно не опрашивать, все сигналы с кнопок через диоды собираются в одну точку и с этой точки в порт с прерыванием. По нажатию возникает прерывание - а уже в обработчике анлизируете матрицу.
Вот тут можно время отклика до микросекунд уменьшить, осталось еще только триггеры повесить со сбросом, чтобы только передний фронт ловить, тогда можно с дребезгом не бороться.
AlexandrY
Цитата(Сергей Борщ @ Jun 23 2018, 19:01) *
Ну почему же? Стильно, модно, молодежно. Следующим этапом будем искать кнопки с переключающими контактам, потому что только такие есть в модели.

Да не проблема.
Нажмите для просмотра прикрепленного файла

Просто сегодня тестирую Matlab 2018а.
А так это конечно шутка. (Но рабочая!)
Forger
Цитата(iliusmaster @ Jun 23 2018, 20:17) *
Обычно, чтобы ничего постояно не опрашивать,

А в чем проблема периодического опроса, что его по-вашему следует избегать? Вот честно, не понимаю )

Обычно, чтобы избежать ненужной мгновенной реакции на очень медленное событие - реакция человека на различные действия, в т.ч. и действия его самого - делают как раз периодический опрос с такой частотой,
с которой среднестатистический индивидуум никак не увидит разницы.
А раз нет разницы, то зачем за это платить диким колхозом из нагромождений "временных меток", "каскадов сравнений" и подобной средневековой дикости? wink.gif

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

Ага, а вместе с таким сигналом прилетают множественные прерывания от дребезга.
Чтобы его побороть, нужно делать задержки, ставить "аппаратные" фильтры, короче, открывать целые "институты" по решению копеешной проблемы.... очередная игра в "донкихота" cranky.gif
По статистике реакция человека 100мс на визуальное событие - очень крутая реакция, доступная лишь очень крутым тренированным спортсменам.

Цитата
Вот тут можно время отклика до микросекунд уменьшить
Почитайте название темы : "Опрос клавиатуры...", не управление ключами драйвера двигателя для соотв. формирования ШИМ, а опрос клавиатуры!
Клавиатуру нажимает человек, а не робот. Именно из этой позиции и следует подходить к решению задачи с клавиатурой.
Роботы еще не скоро займут место человека, но, если и займут, то клавиатура им точно не понадобится wink.gif

Как-то в свое время ради интереса я собирал статистику: имеем задачу, которая занимается обработкой матричной клавиатуры 16х16, период - 50мс (дребезг в таких условия не грозит).
Так вот нагрузка на CPU (мерял под RTOS) составляла сотые доли процента. Речь тогда была про "бытовые" кортексы STM32F103 на 72Мгц.
Сокращая период до 25 мс, нагрузка на CPU соотв. удвоилась - но в итоге те же доли процента ...
Поскольку события возникают лишь при изменении состояния клавиатуры, то в расчете на 10 событий в секунду (таких индивидуумов еще найти нужно) нагрузка возрастала до 0.1%.
Вот и вся математика sm.gif
Повторюсь - постоянный опрос клавиатуры 256 кнопок и 10 отпусканий/нажатий в секунду. Конкретный пример и конкретные цифры.
Код простейший, построенный по алгоритму, как я описал во втором посте этой темы.
ArtemKAD
Ну развели... Проблема дребезга полностью освещена даже в Вики: https://ru.wikipedia.org/wiki/%D0%94%D1%80%...%82%D0%BE%D0%B2

В частности программные методы борьбы:
Цитата
При программном формировании очищенного от дребезга контакта сигнала наибольшее распространение получили три из них:

1.Путём установки временной задержки — программа, обнаружив замкнутое состояния контакта, игнорирует его состояние на время, заведомо большее длительности дребезга, и спустя это время снова проверяет состояние контакта. Если после этого времени состояние контакта замкнутое, то соответствующая переменная меняет значение.
2.Методом подсчёта числа совпадающих значений сигнала замкнутости — программа многократно считывает состояние контакта, и, если последовало определённое количество подтверждений замкнутости в течение заданного промежутка времени (определяется экспериментально и выбирается в пределах от 10 до 100), контакт считается устойчиво замкнутым.
3.Методом подсчёта времени устойчивого состояния — программа в течение заданного времени многократно считывает состояние контакта. Если в течение заданного времени не обнаружено ни одного изменения состояния на противоположное, то контакт считается устойчиво замкнутым. В противном случае, если было обнаружено изменение состояния в течение заданного времени, то подсчёт времени прерывается (или продолжается, но с установкой флага или подсчётом количества изменений состояния для оценки физического состояния механических контактов) и контакт считается разомкнутым или с неустойчивым состоянием (если такая информация используется в программе).


Время дребезга для контактов клавиатуры до нескольких миллисекунд (до 5). Forger по сути предложил метод №1 суть которого сравнить 2 измерения с временным промежутком времени завершения переходного процесса на контакте. Кстати, не обязательно постоянно опрашивать. Если есть необходимость глубоко дрыхнуть и просыпаться по сигналу нажатия, то никто не мешает в прерывании которое разбудило запустить таймер на те самые несколько мс в котором и принять решение чего это такого только что было...

ЗЫ. На самом деле есть еще более тупой метод борьбы с дребезгом - RC-цепочка после контакта плюс триггер Шмитта который есть на входах многих современных контроллеров...
Forger
Цитата(ArtemKAD @ Jun 23 2018, 22:56) *
Ну развели... Проблема дребезга полностью освещена даже в Вики

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

Цитата
Если есть необходимость глубоко дрыхнуть и просыпаться по сигналу нажатия,

В предложенном мной решении, для этого таймер периодического опроса клавиатуры можно временно перенастроить на период, скажем, в 1 сек.
Этот таймер будет периодически будить проц. Для полного пробуждения достаточно удерживать "правильную" кнопку соотв. более 1 сек.
Если же и это не годится, то кнопку пробуждения следует делать вообще отдельной от остальной части клавиатуры и заводить на соотв. пин проца.
Сергей Борщ
QUOTE (ArtemKAD @ Jun 23 2018, 22:56) *
Forger по сути предложил метод №1 суть которого сравнить 2 измерения с временным промежутком времени завершения переходного процесса на контакте.
Нет, у него другой метод, которым и я пользуюсь. Суть его в том, что от клавиатуры чисто электрически не может прийти ложный сигнал о нажатии (провода до кнопок короткие, подтяжки достаточно низкоомные). И если такой сигнал пришел - кнопку точно нажали. А проверять факт отпускания и/или повторного нажатия нужно не раньше, чем через время, заведомо большее времени дребезга, но меньшее времени возможного повторного нажатия. Если после нажатия считано разомкнутое состояние кнопки - значит ее или начали отпускать (попали в дребезг) или уже отпутили. Если в момент отпускания мы попали на дребезг и считали замкнутое сотояние кнопки - никакого криминала, в следующем цикле опроса считаем разомкнутое сотояние уже после окончания дребезга. Если кнопка дребезжит дольше 50 мс - ей место в помойке, поэтому 50 мс - вполне разумный компромисс между временем дребезга и временем реакции на изменение. А повторно нажать кнопку быстрее, чем через 100 мс не сможет даже неадекватный оператор (помешанных на играх опустим).

QUOTE (ArtemKAD @ Jun 23 2018, 22:56) *
ЗЫ. На самом деле есть еще более тупой метод борьбы с дребезгом - RC-цепочка после контакта плюс триггер Шмитта который есть на входах многих современных контроллеров...
С натяжкой подходит для одиночных кнопок и не годится для матричных клавиатур.
Forger
Цитата(Сергей Борщ @ Jun 24 2018, 00:07) *
...
Вы прям "разжевали все до молекул" sm.gif
Честно говоря, мне лень было расписывать такие, казалось бы, очевидные вещи. Но очевидность, видать, тоже - понятие субъективное ...
ArtemKAD
Цитата(Сергей Борщ @ Jun 24 2018, 00:07) *
Суть его в том, что от клавиатуры чисто электрически не может прийти ложный сигнал о нажатии (провода до кнопок короткие, подтяжки достаточно низкоомные). И если такой сигнал пришел - кнопку точно нажали.


Я б с таким подходом в автомобиле ноги бы точно протянул. Разве что провода действительно короткие.
Forger
Цитата(ArtemKAD @ Jun 24 2018, 02:20) *
Я б с таким подходом в автомобиле ноги бы точно протянул. Разве что провода действительно короткие.

В автомобилях подтяжки ставят достаточно низкоомные.
В одном из проектов для опроса такой кнопки мне пришлось ставить реально низкоомные резисторы, через которые при нажатии кнопки шел довольно немалый ток.
Чтобы не спалить эти резисторы, питание на них подавалось кратковременно (около 1мс) и непосредственно перед опросом кнопок. Опрос - периодический (50мс).

С "классической" постоянной подтяжкой (около 1мА) эти кнопки, которые находятся снаружи кабины камаза, через какое-то время эксплуатации переставали работать - постепенно окислялись контакты.
Но относительно большой ток подтяжки (около 0,15 А), видать, "выжигал" тонкий слой окисла и кнопки работали как ни в чем не бывало.

Глянул конкретные значения: 150 Ом (24В). А резисторы всего лишь в корпусе 1206.
Но, если бы оставил постоянную подтяжку, то пришлось бы ставить 5..10 Вт резисторы.

Один "минус" такой схемы - нужен доп. транзистор для программного управления подтяжкой.
ArtemKAD
Импульсную подтяжку еще и на кнопку - знаете вы толк в извращениях...
Forger
Цитата(ArtemKAD @ Jun 24 2018, 10:23) *
Импульсную подтяжку еще и на кнопку - знаете вы толк в извращениях...

Извращение как раз в противоположном - ставить 5 Вт резистор подтяжки для подобных кнопок. А если кнопок много, то ...
К вашему сведению, я не придумал ничего нового - в данном случае также "традиционно" позаимствовал идею, обернув ее в свою обертку.
Прочитайте мою подпись внизу каждого поста ... wink.gif
k155la3
Цитата(iliusmaster @ Jun 23 2018, 20:17) *
Обычно, чтобы ничего постояно не опрашивать, все сигналы с кнопок через диоды собираются в одну точку и с этой точки в порт с прерыванием. По нажатию возникает прерывание - а уже в обработчике анлизируете матрицу. . . .

Постоянный опрос не есть "явное зло". Если он происходит раз в 10-20-50-100 мс (можно и больше) то это скорее благо.
По предложенной Вами схеме на каждом дребезге контакта (если это обычный "сухой контакт" а не или матмодель или "через-триггер") на каждом нажатии-отжатии
в течение интервала дребезга будет дергаться вектор прерывания (если, конечно, не прописать соотв-ие EI DI разрешения прерывания).
Вопрос, так ли необходимо микросекундное "время отклика" системы при нажатии кнопки оператором ?
Экономить на опросе нет смысла, тк он (для матрицы) сводится к двум коротким операциям - записи в порт маски опроса (столбцов) и чтения из него (рядов).
чтения из него (рядов) и записи в порт маски опроса (столбцов).
Это делается в векторе имеющегося таймера RTC или "тиков" RTOS. Если этот таймер очень "быстрый" - делается условный вход по софт-делителю
с интервалом нескольких десятков мс. Дальнейшая обработка (по выставленному флагу интервала опроса клавиатуры и считанному скан-коду) выполняется вне вектора прерывания, с минимальным приоритетом.
---
ps
ООП имеет смысл применить для работы с очередью скан-кодов, полученных из драйвера клавиатуры.
iliusmaster
У музыкантов нужно точно отслеживать длительность нажатия, с разрешением не хуже 10 мс.
Forger
Цитата(iliusmaster @ Jun 24 2018, 12:30) *
а если клавиатура музыкального инструмента?

Решили повторить копеечный китайский детский синтезатор, которые раздают на сдачу в супермаркетах? Ведь именно такой вы и описали biggrin.gif

В нормальных музыкальных электронных инструментах клавиатура - это не просто нажатие/отпускание, а еще как минимум контроль скорости нажатия.
А в проф. инструментах еще и полная имитация "физики" клавиш настоящего механического рояля/пианины.
Такие клавиатуры составляют основную стоимость самого инструмента.
В эту область не пускают "простых смертных", коими мы практически все тут и являемся wink.gif
Herz
Цитата(ArtemKAD @ Jun 24 2018, 10:23) *
Импульсную подтяжку еще и на кнопку - знаете вы толк в извращениях...

Это как раз нормальный подход. Ибо для всяческих механических контактов (реле, кнопки, переключатели) существует минимальный ток, требующийся для разрушения окисной плёнки (если, конечно, это металлические контакты), иначе замыкание не будет надёжным.
Греть резисторы подтяжки таким током долго - не всегда разумно.
k155la3
Цитата(iliusmaster @ Jun 24 2018, 12:30) *
У музыкантов нужно точно отслеживать длительность нажатия, с разрешением не хуже 10 мс.

Это специфика. Там еще и амплитуду-форму сигнала нажатия клавиши надо отслеживать. Задача намного сложенее, чем HMI для оператора.
Forger
Цитата(Herz @ Jun 24 2018, 12:50) *
Греть резисторы подтяжки таким током долго - не всегда разумно.

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

iliusmaster
Ну раз музыканты это специфика, то вот еще один пример.
Есть у меня самодеятельный ЦАП с пультом управления. Пульт с многими кнопками, а питается для уменьшения габаритов от батареи типоразмера 2320. Так вот если мне каждые 100мс опрашивать кнопки, то батарейки придется часто менять. Можно даже придумать хитрый алгоритм, который будет увеличивать интервал между опросами, если длительное время отсутствует нажатие, но тогда я буду беситься от долгого времени отклика при первом нажатии.
Диоды же, повешенные на прерывание, позволяют МК спать все время, пока не произошло нажатия. Время работы от батареи значительно вырастает....
Эти примеры я для чего привожу, что каждой задаче - свое решение. И вопрос как лучше опрашивать клавиатуру на Си, требует уточнения, какую клавиатуру и в каких условиях.
Forger
Цитата(iliusmaster @ Jun 24 2018, 14:11) *
И вопрос как лучше опрашивать клавиатуру на Си, требует уточнения, какую клавиатуру и в каких условиях.

Логично ))
k155la3
Цитата(iliusmaster @ Jun 24 2018, 14:11) *
Ну раз музыканты это специфика, . . . .

Мой коллега по работе пламенный сторонник "прерывательной" клавиатуры. Да, если нужен глубокий LPM и в то же время - быстрая реакции на
нажатие - прерывания вне конкуренции.
Make_Pic
Цитата(k155la3 @ Jun 24 2018, 17:07) *
Мой коллега по работе пламенный сторонник "прерывательной" клавиатуры. Да, если нужен глубокий LPM и в то же время - быстрая реакции на
нажатие - прерывания вне конкуренции.

Тема ушла куда то "налево" sad.gif А хотелось просто увидеть код хорошего простого решения по клавиатуре...
AlexandrY
Цитата(Make_Pic @ Jun 25 2018, 05:06) *
Тема ушла куда то "налево" sad.gif А хотелось просто увидеть код хорошего простого решения по клавиатуре...

Так что за клавиатура?
Код сканирования вот такой клавиатуры устроит ?
k155la3
Цитата(Make_Pic @ Jun 25 2018, 05:06) *
Тема ушла куда то "налево" sad.gif А хотелось просто увидеть код хорошего простого решения по клавиатуре...
Нет, тема идет полностью так, как Вы ее задали в первом посте.
Цитата
Опрос клавиатуры на С -> Как написать компактный и "красивый" код?
Вот Вам и рекомендуют не сам код, а как его писать "красиво", те выбрать правильный алгоритм. Как его перенести на код - это уже дело техники.
т.е. Вы хотите увидить готовый код - драйвер клавиатуры ? Хотя это несколко противоречит цитате выше sm.gif
(я свой драйвер матрицы 4x4 выложу, позднее).
Вот реализация на С от Ti Low power keyb
PDF SLAA773
Herz
Цитата(Forger @ Jun 24 2018, 13:03) *
Например, в педали тормоза обычных рядовых машин стоит концевик-кнопка, а роль резисторов подтяжки которой играют лампы стоп-сигналов - "одним выстрелом двух зайцев"

А зачем в "рядовых" машинах подтяжка с кнопки педали тормоза?
AlexandrY
Цитата(k155la3 @ Jun 25 2018, 12:09) *
Вот реализация на С от Ti

Тут надо сразу предупредить, что такая клавиатура надежно дает определить только одно нажатие.
Если речь идет о клавиатуре скажем PC где надо обрабатывать несколько нажатий одновременно, то такая клавиатура не годится.
Надо добавить диоды как минимум.
А алгоритм соответственно не адаптирован к условиям сильных помех.
Forger
Цитата(Herz @ Jun 25 2018, 13:02) *
А зачем в "рядовых" машинах подтяжка с кнопки педали тормоза?

Под рядовыми я понимаю бюджетные ширпотребные авто не самых "бородатых" годов (скажем, до 10лет), где все же производится хотя бы какой-нить целостность стоп-ламп, тем более, если авто с коробкой-автомат.
Но это уже офф.
Цитата(AlexandrY @ Jun 25 2018, 13:35) *
Тут надо сразу предупредить, что такая клавиатура надежно дает определить только одно нажатие.
Если речь идет о клавиатуре скажем PC где надо обрабатывать несколько нажатий одновременно, то такая клавиатура не годится.
Надо добавить диоды как минимум.

Вы верны своей "традиции" - очередной "пук в лужу" biggrin.gif
Любая матричная клавиатура позволяет однозначно обрабатывать условия, когда даже ВСЕ кнопки нажаты и уж тем более в любом сочетании любого числа одновременно нажатых кнопок.
Никакие диоды тут не нужны. Достаточно лишь ряда резисторов подтяжки на столбцы или строки.
AlexandrY
Цитата(Forger @ Jun 25 2018, 15:13) *
Вы верны своей "традиции" - очередной "пук в лужу" biggrin.gif

За это вам предупреждение. Второго не будет.

Цитата(Forger @ Jun 25 2018, 15:13) *
Любая матричная клавиатура позволяет однозначно обрабатывать условия, когда даже ВСЕ кнопки нажаты и уж тем более в любом сочетании любого числа одновременно нажатых кнопок.
Никакие диоды тут не нужны. Достаточно лишь ряда резисторов подтяжки на столбцы или строки.

А над этим предлагаю вам подумать еще раз.
На матрице без диодов при одновременном нажатии в определенной конфигурации возможны фантомные определения нажатий.
Forger
Цитата(AlexandrY @ Jun 25 2018, 15:24) *
А над этим предлагаю вам подумать еще раз.

Согласен, поторопился с выводами. Без диодов в таком случае не обойтись.
Однако, в случае с клавиатурой, у которой сопротивление нажатых кнопок относительно большое (пленочные клавиатуры), это решаемо без диодов.
Но усложняется алгоритм опроса - нужен импульсный (ШИМ) или даже аналоговый способ измерений.
Судя по всему именно такой и применяется в клавиатурах ПК, для выявления подобных "коллизий".
ArtemKAD
Цитата(Forger @ Jun 24 2018, 11:10) *
Извращение как раз в противоположном - ставить 5 Вт резистор подтяжки для подобных кнопок. А если кнопок много, то ...
К вашему сведению, я не придумал ничего нового - в данном случае также "традиционно" позаимствовал идею, ...

Конечно ничего нового. Я сам первый раз в серийном изделии использовал импульсную подтяжку низкоомным резистором в году эдак 2002. Вот только использовать её не для концевиков, а для клавиатуры как по мне это уже оверкилл...
AlexandrY
Цитата(ArtemKAD @ Jun 26 2018, 01:31) *
Конечно ничего нового. Я сам первый раз в серийном изделии использовал импульсную подтяжку низкоомным резистором в году эдак 2002. Вот только использовать её не для концевиков, а для клавиатуры как по мне это уже оверкилл...

Что за блажь использовать низкоомную подтяжку для механических контактов.
Кто этот миф распускает, интересно?
Т.е. интересует первоисточник.
Forger
Цитата(AlexandrY @ Jun 26 2018, 08:17) *
Что за блажь использовать низкоомную подтяжку для механических контактов.

В чем проблема?

iliusmaster
Цитата(AlexandrY @ Jun 26 2018, 08:17) *
Что за блажь использовать низкоомную подтяжку для механических контактов.
Кто этот миф распускает, интересно?
Т.е. интересует первоисточник.



Например.http://omronfs.omron.com/en_US/ecb/products/pdf/en-b3sn.pdf. Советские ТУ на кнопочные переключатели.

Есть такое понятие как минимальный ток срабатывания. У нормальных(грамотных) производителей на любое контактное соединение оно приводится.
Контакты у реле, кнопок и контакторов не идеальные, образуется оксидная пленка, которая при малом токе не разрушается и контакта полноценного не образуется.
Вот для нормального функционирования кнопок с незолотыми и палладиевыми контактамии нужен увеличенный ток через контактную группу. Да и для золотых и палладиевых есть проблемы при токах меньше 1-10 мка.
=L.A.=
Цитата(iliusmaster @ Jun 26 2018, 08:30) *
Есть такое понятие как минимальный ток срабатывания. У нормальных(грамотных) производителей на любое контактное соединение оно приводится.
Контакты у реле, кнопок и контакторов не идеальные, образуется оксидная пленка, которая при малом токе не разрушается и контакта полноценного не образуется.
Вот для нормального функционирования кнопок с незолотыми и палладиевыми контактамии нужен увеличенный ток через контактную группу. Да и для золотых и палладиевых есть проблемы при токах меньше 1-10 мка.

*
Вообще-то оксидная пленка пробивается не током , а НАПРЯЖЕНИЕМ, минимальное значение которого и указывают для коммутационных устройств. Писанина про "минимальный ток" - бессмысленное словоблудие.
Единственный физический эффект, который может создать сверхмалый ток -это дробовой шум, вызванный неравномерностью потока электронов и дискретностью их заряда. Но этот шум никак не влияет на наличие контакта.
haker_fox
QUOTE (=L.A.= @ Jun 26 2018, 13:44) *
Писанина про "минимальный ток" - бессмысленное словоблудие.

И тем не менее в документе на кнопку есть
CODE
Minimum applicable load (reference value) 10 μA at 1 VDC (resistive load)

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

Разрушения этой пленки можно добиться лишь подняв до максимума напряжения на контакта нажатой кнопки с такими контактами.
По сути в таком виде кнопка в нажатом состоянии имеет некое сопротивление, скажем, несколько кОм.
Если резистор подтяжки будет сравним с сопротивлением нажатой кнопки с такими "окисленными" контактами, то схема попросту не "увидит" состояние кнопки.
Чтобы уменьшить сопротивление такой нажатой кнопки, нужно "пробить/сжечь" эту пленку.
Самый простой путь: значительно уменьшить сопротивление подтягивающего резистора - в разы меньше, чем сопротивление "окисленной" нажатой кнопки.
Тогда на ней будет напряжение, близкое к напряжению питания.
Вижу два варианта исхода:
1) кратковременный локальный разогрев этого паразитного сопротивления нажатой кнопки и оксидный слой выгорит от перегрева.
2) слой будет разрушен от пробоя более высоким напряжением.

Я считаю, что в реальных схемах с относительно невысоким напряжением питания 1й вариант более вероятен.

Цитата
В любом случае образование тонких высокоомных слоев на поверхности контактов мощных реле неизбежно и требует учета при разработке и эксплуатации реле.

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

Взято тут: https://www.atof.ru/pea/relay/rl_010.shtml
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.