Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 16:42:54

Путано как-то все. Пришлось в 10 местах про массивы прочитать, чтобы дошло... и все равно неоднозначно так. Размер от 1 до n, а элементы от 0 до n-1. Не логично.

Добавлено after 22 minutes 11 seconds:
Еще вопросик. Я сдвинул число нужное мне вправо на 12 позиций. Типа

temp = (temp >> 12);

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

Как узнать на какой позиции в первых четырех битах стоит единица? Она может быть только одна. Т.е. 0001, либо 0010, либо 0100, либо 1000. Мне надо знать позицию единицы 0, 1, 2 или 3.

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 16:43:18

СКАЗОЧНИК писал(а):Размер от 1 до n, а элементы от 0 до n-1. Не логично
Неправильно мыслите. Размер не "от 1 до n", а просто "n"
СКАЗОЧНИК писал(а):Как узнать на какой позиции в первых четырех битах стоит единица?
Как вариант - сдвигать дальше на 1 и считать сдвиги.
Последний раз редактировалось WiseLord Ср фев 20, 2019 16:45:39, всего редактировалось 1 раз.

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 16:46:33

Да, неправильно. Я имею ввиду, что начало размера не от нуля. )

Добавлено after 1 minute 53 seconds:
Я примерно решил задачу выше через цикл и условие. В цикле переменная i автоматом бы заполнялась до нужной позиции, где стоит единица.
Но может есть проще варианты?

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 16:47:53

СКАЗОЧНИК писал(а):Я имею ввиду, что начало размера не от нуля. )
У размера нет начала или конца, он просто есть сам по себе - одно число, по сути - количество элементов.

P.S. А зачем знать именно _позицию_ единицы? Сразу, готовые маски 0x08, 0x04, 0x02, 0x01 вместо позиции никак бы не подошли?

P.P.S.
Код:
int orig_num = 0x4000;
// Вместо сдвига >> 12 и вычисления позиции единицы (2):

if (orig_num & 0x8000) {
  // Сразу делаем то, что собирались с вычисленной позицией 3
} else if (orig_num & 0x4000) {
  // Сразу делаем то, что собирались с вычисленной позицией 2
} else if (orig_num & 0x2000) {
  // Сразу делаем то, что собирались с вычисленной позицией 1
} else if (orig_num & 0x1000) {
  // Сразу делаем то, что собирались с вычисленной позицией 0
}

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 17:45:30

Если вот так сделаю, примерно правильно будет?

Код:
unsigned long int stroka = 0;

temp = (((~(GPIOB->IDR)) & 0xF000) >> 12); // считать первую строку и двинуть ее в начало слова

   while ((temp & 1) != 0)
   {
      temp >>= 1;
      stroka++;
   }
      stolbetz = 0;


А где-то дальше уже обращение к элементу массива типа

indikator = button [stroka][stolbetz];

Добавлено after 10 minutes 27 seconds:
Я просто пока мало еще понимаю, что в памяти займет больше места и что по быстродействию будет лучше.... Цикл с условием или просто условия.

Добавлено after 36 seconds:
З.Ы. Еще через case можно сделать.
Ищу красивый оптимальный вариант.

Добавлено after 7 minutes 9 seconds:
З.З.Ы. А вообще это я просто изучаю работу с матричной клавиатурой на СТМ32 с языком Си. Изначально забил массив с кнопками. А потом считываю строки клавиатуры и то значение, которое вернулось должно совпадать с элементом массива. А из массива уже присваиваю на вывод (пусть на индикатор).
Может не оптимальный вариант, но такой взбрел в голову и где-то подсмотрел.
А т.к. опрос клавиатуры происходит по системному таймеру, то надо бы все равно в прерывании побыстрее все делать. Чтобы только готовый результат был с кодом кнопки.

Добавлено after 10 minutes 26 seconds:
P/S И еще, вроде как прерывание по тому же системному 24 битному таймеру - это обычная функция. Но по умолчанию она описана как

void SysTick_Handler (void)

А если у меня в ней вычисляются глобальные переменные, то надо менять тип возвращаемого значения? Или у меня эта функция все равно ничего не возвращает?
Последний раз редактировалось СКАЗОЧНИК Ср фев 20, 2019 18:08:49, всего редактировалось 1 раз.

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 18:08:00

Я просто пока мало еще понимаю, что в памяти займет больше места и что по быстродействию будет лучше.... Цикл с условием или просто условия.


Пусть меня закидают тапками. Да пофиг, не парься. Главное, чтобы 1) не было ошибок 2) код был максимально понятным

Код:
unsigned long int stroka = 0;

Почему не просто
Код:
int stroka = 0;


Ситуации, когда не установлен ни один из четырех битов регистра, не может быть? Если может, то цикл будет бесконечным.
Ситуации, когда установлены несколько из четырех бит регистра, не может быть? Если может, то чему должна быть равна переменная stroka в этом случае?

Когда я просматриваю код, приведенный WiseLord, у меня таких вопросов не возникает. :))
Последний раз редактировалось viiv Ср фев 20, 2019 18:17:09, всего редактировалось 1 раз.

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 18:16:51

viiv писал(а):Ситуации, когда не установлен ни один из четырех битов регистра, не может быть?

Блин, точно. Может... :facepalm:

viiv писал(а):Ситуации, когда установлены несколько из четырех бит регистра, не может быть?

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

У меня просто опрос матричной клавиатуры 4х4. Включаю первую строку (открытый коллектор) и считываю всю строку разом (на строках подтяжка к плюсу). То, что нажато, будет нулем, остальные единицами.
Включаю следующую строку. Опять считываю все разом, но уже номер строки равен двум (ну или единице, если я использую массив).
И т.д.
В итоге, после обработки получаем значение i,j элемента массива, который сохранен в памяти со значением кнопки клавиатуры.

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 20:35:38

я матрицу 4х4 опрашиваю проще, за 6 обращений к регистрам порта
сначала делаю биты порта строк входами с подтяжкой, а биты столбцов - выходами с нулем. считываю пины строк - если где-то была нажата кнопка, то в одной или более строк будет считан 0. запоминаю считанное с инверсией, т.е. нажатые строки равны 1.
теперь делаю стобцы входами с подтяжкой, а строки - выходами и вывожу с инверсией то, что только что запомнил. в итоге получаю нули в тех столбцах, что соответствуют нажатым кнопкам. запоминаю это с инверсией тоже.
теперь оба запомненных значения соединяю в байт и получаю код, однозначно соответствующий нажатым кнопкам.
вот код для AVR для случая, когда матрица подключена к линиям одного и того же порта PORT_KBD (младшие 4 бита строки, старшие 4 бита столбцы):
Код:
   // подаем на все столбцы нули, а строки делаем входами с подтяжкой
   DDR(PORT_KBD) = ALL_COL;
   PORT(PORT_KBD) = ALL_ROW;
   // запоминаем инверсное значение состояния строк
   rows = (~PIN(PORT_KBD)) & ALL_ROW;
   // делаем столбцы входами с подтяжкой, а на строки подаем запомненное значение с инверсией
   DDR(PORT_KBD) = ALL_ROW;
   PORT(PORT_KBD) = ~rows;
   // запоминаем инверсное значение состояния столбцов
   cols = ~PIN(PORT_KBD) & ALL_COL;
   // отключаем порт
   DDR(PORT_KBD) = 0;
   // если строки и столбцы ненулевые
   if(cols && rows) cols |= rows;
   else           cols = 0;
// теперь в cols имеем код, однозначно соответствующий нажатым кнопкам, можно делать с ним, что угодно
ALL_ROW это 0x0F, а ALL_COL это 0xF0 - маски всех битов строк и столбцов соответственно

Re: Вопросы по С/С++ (СИ)

Ср фев 20, 2019 22:35:25

СКАЗОЧНИК писал(а):Я просто пока мало еще понимаю, что в памяти займет больше места и что по быстродействию будет лучше

Таблицей быстрее. Но будет 12 лишних из 16 значений.
СКАЗОЧНИК писал(а):Ищу красивый оптимальный вариант.

Краcивый, но не оптимальный ))

indikator = button [log2(temp>>12)][stolbetz];

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 03:02:12

ARV писал(а): за 6 обращений к регистрам порта

Елки, уже три раза прочитал, вдумываяь и в код тоже. Ниче понять не могу... :facepalm: :oops:

Есть, где такая логика еще расписана другим языком? :)

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 05:28:26

ARV писал(а):за 6 обращений к регистрам порта
при таком опросе нельзя сразу несколько кнопок нажимать - программа их не сможет различить...

Добавлено after 7 minutes 43 seconds:
Станислав клавиатура - матрица, при обычном построчном опросе мы просматриваем каждую строку отдельно (подаем питание на каждую строку по очереди и смотрим откликнувшиеся столбцы), а тут - сначала окинули взглядом всю матрицу в фас (получили координату х нажатой кнопки), потом в профиль (получили координату у нажатой кнопки)
т.е подали питание на все строки - увидели откликнувшийся столбец, "перевернули" матрицу, подали питание на все столбцы - увидели откликнувшуюся строку.
(не знаю, какой вариант понятней будет)

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 05:38:07

Вот я и делаю, как первый вариант, когда каждую строку по отдельности опрашивать.

Однако, вариант, предложенный Романом, мне тоже нравится. Он как-то проще выглядит. :)
Ну и я пытаюсь придумать, зачем мне нажимать сразу несколько кнопок на клавиатуре? :dont_know:

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 06:45:34

СКАЗОЧНИК писал(а):Есть, где такая логика еще расписана другим языком?
насколько я вкурсе, такую логику никто ранее не применял :) а она проста.
1. сначала мы определяем, на каких столбцах есть нажатые кнопки. для этого сразу на все строки мы подаем активные уровни.
2. активные уровни - это такие, которые система "замечает" при нажатии кнопки. в нашем случае, система заметит, если на вход с подтяжкой (лог.1) придет твердый ноль. поэтому мы выдаем нули на все строки и смотрим, куда эти нули дошли на столбцах.
3. затем меняем местами роли строк и столбцов, но теперь подаем не на все линии подряд, а только на те, которые обнаружили на первом этапе. и тогда мы узнаем, с каких строк дошли эти уровни.

так понятнее?

попробую битами.

1. настроили столбцы на входы с подтяжкой, строки - выходы с нулем. на порту получилось 00001111
2. если мы нажали кнопку на пересечении третьей строки и третьего столбца, на порту получилось 00001101
3. запомнили это значение с инверсией. нас интересуют только столбцы, т.е. 4 бита. получили 00000010
4. теперь меняем строки и слолбцы ролями, делая столбцы выходами, а строки входами с подтяжкой. то есть мы бы получили в этом случае 11110000, но так как на столбцы мы подаем ранее считанные биты (0010) с инверсией (1101), то получаем, что 0 с третьего столбца через нажатую кнопку попадает только на столбец 3, т.е. имеем на порту 11011101.
5. запоминаем состояние столбцов с инверсией 0010.
6. итак, получили строки 0010 и столбцы 0010 - кнопка нажата на пересечении третьего столбца и третьей строки.
7. сделали один общий байт 00100010 и радуемся коду нажатой кнопки.
8. для борьбы с дребезгом и отсечению вариантов, когда кнопку отпустили между опросами половинок, следует убедиться, что каждая тетрада ненулевая, т.е. что там есть хоть 1 бит. если это не так - результат надо игнорировать.
9. ну и делать это надо периодически, в каком-то прерывании. я делаю 1 раз в 20 мс, и никаих дополнительных мер по дребезгу не требуется.

Ivanoff-iv писал(а):при таком опросе нельзя сразу несколько кнопок нажимать
теперь вы видите, что сможет? во всяком случае до тех пор, пока это позволяет схема матрицы кнопок без развязывающих диодов.

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 07:03:25

такой алгоритм правильней, если клавиатура без разделительных диодов, то на ней не сделать замыкания лог 1 и лог 0, в отличии от варианта с построчным опросом...
кстати, такой вариант опроса очень похож на опрос резистивного тачскрина... (сначала опрашивается координата Х, потом У) и к таковому её можно вывести, понадобится 4 лапы контроллера из них 2 с входом АЦП и одинаковых резисторов (размерностьХ+размерностьУ-2)шт.

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 07:04:57

Ivanoff-iv писал(а):такой алгоритм правильней, если клавиатура без разделительных диодов, то на ней не сделать замыкания лог 1 и лог 0, в отличии от варианта с построчным опросом...
поясните - я как-то с утра не понял вашу мысль... видимо, кофе еще не подействовал.

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 07:14:00

У меня СТМ 32, там не замкнешь так 0 и 1, если клавиатура без диодов. Там на одном порту тупо можно же настроить открытый коллектор (открытый сток точнее). Он может быть либо в высокоимпедансном, либо замкнуть на землю. А другие, которые, например на строках, настроены на вход с подтяжкой. Я считаю, что это плюс довольно большой у СТМ в отличии от АВР, где по невнимательности можно попалить порты.

А вот код кнопки же, который получен подобным образом не соответствует точно значению на клавиатуре. Его же потом надо еще через case определять?! Я пытался сразу в прерывании получить точное значение цифры на клавиатуре. )))

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 07:15:45

СКАЗОЧНИК писал(а):я пытаюсь придумать, зачем мне нажимать сразу несколько кнопок на клавиатуре?
при ограниченном количестве кнопок, что вполне себе норма для встраиваемых устройств, это требуется не так уж и редко. вы вспомните клавиатуру компьютера - не смотря на изобилие кнопок все равно постоянно требуется нажатие по 2 и даже 3 кнопки одновременно! реально больше 2 кнопок - уже очень неудобно в эксплуатации

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 07:16:38

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

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 07:19:48

СКАЗОЧНИК писал(а):А вот код кнопки же, который получен подобным образом не соответствует точно значению на клавиатуре.
и что? этот способ выдет "скан-коды", а смысловое значение каждого скан-кода - это задча более верхнего уровня ПО. и делать это можно уже не в прерывании, а где нужно, и где можно не жалеть тактов на обработку.

в частности, в программе абсолютно не важно, соответствует ли код кнопки 1 значению символа '1' или числа 0x01. вы определяете дефайном соответствие скан-кода символу, и затем используете этот символ в программе.
Код:
#define KEY_1  0b00100010
Последний раз редактировалось ARV Чт фев 21, 2019 07:27:42, всего редактировалось 2 раз(а).

Re: Вопросы по С/С++ (СИ)

Чт фев 21, 2019 07:23:15

ARV писал(а):дефайном соответствие скан-кода символу,

Точно. Чет я не догадался.!
Ответить