Светодиодная матрица. Первые шаги

Здесь принимаются все самые невообразимые вопросы... Главное - не стесняйтесь. Поверьте, у нас поначалу вопросы были еще глупее :)
Ответить
Родился
Сообщения: 13
Зарегистрирован: Сб июл 09, 2022 09:41:49

Сообщение Николай1961. »

[uquote="B@R5uk",url="/forum/viewtopic.php?p=4257077#p4257077"].... В вашем случае надо было воспользоваться операциями "деление нацело" и "взятие остатка". Последняя операция в си обозначается значком "%" (процент).[/uquote]

Вроде немного разобрался с операциями "деление нацело" и "взятие остатка".
Спойлер

Код: Выделить всё

#include <stdio.h>

int main(int argc, char* argv[])
{
 int x = 19610502;

printf("%d\n", x/10000000); //1
printf("%d\n", x%10000000/1000000);//9
printf("%d\n", x%1000000/100000);//6
printf("%d\n", x%100000/10000);//1
printf("%d\n", x%10000/1000);//0
printf("%d\n", x%1000/100);//5
printf("%d\n", x%100/10);//0
printf("%d\n", x%10);//2

  return 0;
}
Спасибо.

Добавлено after 4 minutes 23 seconds:
[uquote="mickbell",url="/forum/viewtopic.php?p=4257483#p4257483"]... Я предложил I2C-расширитель портов, предложение, однако, было проигнорировано..[/uquote]

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

Добавлено after 5 minutes 12 seconds:
[uquote="mickbell",url="/forum/viewtopic.php?p=4257483#p4257483"]ТСу. По управлению могу предложить сделать по-другому: вводите с цифровой клавиатуры номер канала, затем * или # - чтобы соответственно включить или выключить нагрузку. Это позволит произвольно коммутировать любое число нагрузок. Клавиатур с таким набором кнопок - кругом и везде. Номер канала 0 - широковещательный, последовательность 0# выключит все нагрузки сразу.[/uquote]
Этот вопрос меня давно интересует, облазил кучу сайтов, даже нашёл готовые автоматы опроса матричной клавиатуры но негде не могу найти хотя бы пример как это реализовать. То есть во всех найденных примерах отправка символа происходит сразу после нажатия на кнопку, я же искал вариант что Вы описали выше.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 6821
Зарегистрирован: Сб янв 28, 2006 22:47:24

Сообщение Asmodey »

Крайне нерациональное использование линий портов микроконтроллера. Без учета того факта, что порты имеют 3 состояния.
Астролябия-сама меряет, было бы что мерять!!!
Реклама
Родился
Сообщения: 13
Зарегистрирован: Сб июл 09, 2022 09:41:49

Сообщение Николай1961. »

[uquote="Asmodey",url="/forum/viewtopic.php?p=4257553#p4257553"]Крайне нерациональное использование линий портов микроконтроллера. Без учета того факта, что порты имеют 3 состояния.[/uquote] Буду рад если покажите пример рационального использования. В начале поста я писал что только начал изучение Си AVR... Прядок включения меняется переменным "k".

Файл main.c
Спойлер

Код: Выделить всё

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include "matrix.h"

  
int main()
 { 
 DDRA=0xFF;
 DDRB=0xFF;
 
 PORTA=0x00;
 PORTB=0x00;
 
 int k=4;
    
   switch(k){
	 case 1:  call(); c100(); break;
	 case 2:  call(); c200(); break;
	 case 3:  call(); c300(); break;
	 case 4:  call(); c400(); break;
	 case 5:  call(); c500(); break;
	 case 6:  call(); c600(); break;
	 case 7:  call(); c700(); break;
	 case 8:  call(); c800(); break;
	 case 9:  call(); c900(); break;
	 case 0:  call(); c000(); break;
	    default: PORTA=0x00; PORTB=0x00;
	 }
     
   while (1){
  ;
  }
 }
файл matrix.h
Спойлер

Код: Выделить всё

#define ROW PORTA
#define COLUMN PORTB
#define DELAY _delay_ms(3000);

 int a[9]= {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00};
 int b[9]={0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x00};
 int i;
 
      int call(void){
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[0];COLUMN=b[0];
	       DELAY
	       ROW=a[1];COLUMN=b[0];
	       DELAY
      
		  for(i=0;i<4;i++){
			ROW=a[4];COLUMN=b[2];
			DELAY
			ROW=a[7];COLUMN=b[7];
			DELAY
		     }
	       ROW=a[4];COLUMN=b[3];
	       DELAY
	       ROW=a[1];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	     }
 
 
     int c100(){ //100
	       ROW=a[1];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }


    int c200(){ //200
	       ROW=a[1];COLUMN=b[2];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }


      int c300(){ //300
	       ROW=a[1];COLUMN=b[3];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c400(){ //400
	       ROW=a[2];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c500(){ //500
	       ROW=a[2];COLUMN=b[2];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c600(){ //600
	       ROW=a[2];COLUMN=b[3];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c700(){ //700
	       ROW=a[3];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c800(){ //800
	       ROW=a[3];COLUMN=b[2];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c900(){ //900
	       ROW=a[3];COLUMN=b[3];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c000(){ //000
      
		  for(i=0;i<2;i++){
			 ROW=a[4];COLUMN=b[2];
			 DELAY
			 ROW=a[7];COLUMN=b[7];
			 DELAY
		     }
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	  }
 
Друг Кота
Аватара пользователя
Сообщения: 6821
Зарегистрирован: Сб янв 28, 2006 22:47:24

Сообщение Asmodey »

Вот пример:

Изображение

Поясню порядок зажигания светодиодов справа налево.

Чтобы зажечь светодиоды HL11 или HL12, нужно одну из линий pin0 и pin3 перевести в высокое состояние, другую в низкое. Или наоборот. Все остальные линии в состоянии Z.
Чтобы зажечь HL9 или HL10 такие же манипуляции производим с линиями pin0 и pin2, две неиспользуемые линии в состоянии Z.
То же самое HL7 и HL8, только они управляются линиями pin1 и pin2. Остальные линии в состоянии Z.
Дальше в том же духе.

Пяти линий должно хватить для ваших двадцати светодиодов (реле).

[uquote="Николай1961.",url="/forum/viewtopic.php?p=4257534#p4257534"]Этот вопрос меня давно интересует, облазил кучу сайтов, даже нашёл готовые автоматы опроса матричной клавиатуры но негде не могу найти хотя бы пример как это реализовать. То есть во всех найденных примерах отправка символа происходит сразу после нажатия на кнопку, я же искал вариант что Вы описали выше.[/uquote]
Проще простого, после каждого нажатия проверяется - было ли нажато #? Если нет, число соответствующее нажатой клавише помещается в буфер, и программа ждет следующего нажатия. Если следующее нажатие опять же не было #, снова помещаем в буфер еще одно число соответственно нажатой клавише. Если же при очередном нажатии было определено, что нажата клавиша #, тогда берем сохраненные числа из буфера и производим с ними определенные действия получая набранное на клавиатуре число. Используя это число включаем нужную нагрузку.
LED.gif
(3.91 КБ) 455 скачиваний
Астролябия-сама меряет, было бы что мерять!!!
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 16980
Зарегистрирован: Пт мар 30, 2012 05:17:29
Откуда: Екатеринбург

Сообщение mickbell »

Напоминаю: светодиоды - это не светодиоды вовсе, а обмотки релюшек. Нормального героя (который всегда идёт в обход) это, конечно, не остановит. :)))

Добавлено after 10 minutes:
[uquote="Николай1961.",url="/forum/viewtopic.php?p=4257534#p4257534"]немного ознакомился I2C. В данное время практически ничего не понял. Но надеюсь в будущем изучить этот интерфейс. Така как он мне показался весьма интересным.[/uquote]Пока в детали не лезьте особо, всему своё время. Сейчас просто имейте в виду, что это - интерфейс с довольно ограниченными возможностями, предполагается его применение внутри одного изделия, без выноса за его габариты. Скорость у него так себе, число адресуемых девайсов одного типа на одной линии - чаще всего не более восьми... короче, штука специфическая. Разработал его, кажется, Филька для своих телевизоров как интерфейс для управления громкостью, яркостью и прочими параметрами. То есть там, где длина линий небольшая и скорости не критичны. Для управления релюшками - самое оно. Другой интерфейс, более быстрый - SPI, можете пока и про него почитать, чтобы иметь представление. Ознакомьтесь с UARTом.
И хрюкотали зелюки,
Как мюмзики в мове.

На каждый РКН
Найдётся VPN.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 6821
Зарегистрирован: Сб янв 28, 2006 22:47:24

Сообщение Asmodey »

[uquote="mickbell",url="/forum/viewtopic.php?p=4257647#p4257647"]Напоминаю: светодиоды - это не светодиоды вовсе, а обмотки релюшек. Нормального героя (который всегда идёт в обход) это, конечно, не остановит. :)))[/uquote]
Тут попахивает горстью оптопар, без которых я не вижу способа коммутировать из матрицы ключи управляющие релюшками. Или каких-то особых реле, низковольтных и с током срабатывания не более 10-15 мА. Такие наверное есть, но вряд ли они будут дешевыми.

SPI и три последовательно-параллельных регистра видятся мне куда как менее затратным решением для управления нагрузками.
Астролябия-сама меряет, было бы что мерять!!!
Реклама
Друг Кота
Аватара пользователя
Сообщения: 16980
Зарегистрирован: Пт мар 30, 2012 05:17:29
Откуда: Екатеринбург

Сообщение mickbell »

Могут быть варианты с разными интерфейсами, но матрица - явно тут не при делах. Релюшки есть маложрущие, IMxxyy. К примеру, у меня на работе применяются IM07GR. Цену я не знаю.
И хрюкотали зелюки,
Как мюмзики в мове.

На каждый РКН
Найдётся VPN.
Родился
Сообщения: 13
Зарегистрирован: Сб июл 09, 2022 09:41:49

Сообщение Николай1961. »

Всем кто откликнулся огромное спасибо. Дабы в будущем не вводить Вас в заблуждение опишу свою задачу.
И так: Схема № 1 с 64 светодиодами.
Изображение
Здесь я пробовал написать скрипт управления матрицей светодиодов для более детального понимания управления этой матрицей. А так же хотел понять как можно лучше оптимизировать код, отдельное спасибо B@R5uk за пример кода.

Дальше я сократил количество светодиодов в матрице для простоты понимания процесса до 20шт.
Схема № 2.
Изображение
Здесь уже задал определенный алгоритм включения. Пока их 10 с c100() по c000().

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

Для того что б была понятна поставленная задача нарисовал примерную схему конечного устройства.
Схема № 3.
Изображение

Матрица работает так как задумана, единственное, я не уверен в оптимальности кода и в этом деле надеюсь на Вашу помощь и советы.

В будущем планируется подключить через UART и MAX485 вторую микросхему + матричную клавиатуру для управления.

Вот пока коды что я смог нафантазировать ( :) прошу сильно не пинать)
main.c
Спойлер

Код: Выделить всё

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include "matrix.h"

 
 
int main()
 { 
 DDRA=0xFF;
 DDRB=0xFF;
 
 PORTA=0x00;
 PORTB=0x00;
 
 int k=4;
    
   switch(k){
	 case 1:  call(); c100(); break;
	 case 2:  call(); c200(); break;
	 case 3:  call(); c300(); break;
	 case 4:  call(); c400(); break;
	 case 5:  call(); c500(); break;
	 case 6:  call(); c600(); break;
	 case 7:  call(); c700(); break;
	 case 8:  call(); c800(); break;
	 case 9:  call(); c900(); break;
	 case 0:  call(); c000(); break;
	    default: PORTA=0x00; PORTB=0x00;
	 }
     
   while (1){
  ;
  }
 }
matrix.h
Спойлер

Код: Выделить всё

#define ROW PORTA
#define COLUMN PORTB
#define DELAY _delay_ms(3000);

 int a[9]= {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00};
 int b[9]={0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x00};
 int i;
 
      int call(void){
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[0];COLUMN=b[0];
	       DELAY
	       ROW=a[1];COLUMN=b[0];
	       DELAY
      
		  for(i=0;i<4;i++){
			ROW=a[4];COLUMN=b[2];
			DELAY
			ROW=a[7];COLUMN=b[7];
			DELAY
		     }
	       ROW=a[4];COLUMN=b[3];
	       DELAY
	       ROW=a[1];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	     }
 
 
     int c100(){ //100
	       ROW=a[1];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }


    int c200(){ //200
	       ROW=a[1];COLUMN=b[2];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }


      int c300(){ //300
	       ROW=a[1];COLUMN=b[3];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c400(){ //400
	       ROW=a[2];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c500(){ //500
	       ROW=a[2];COLUMN=b[2];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c600(){ //600
	       ROW=a[2];COLUMN=b[3];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c700(){ //700
	       ROW=a[3];COLUMN=b[1];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c800(){ //800
	       ROW=a[3];COLUMN=b[2];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c900(){ //900
	       ROW=a[3];COLUMN=b[3];
	       DELAY
	       ROW=a[4];COLUMN=b[2];
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	 }

	 
      int c000(){ //000
      
		  for(i=0;i<2;i++){
			 ROW=a[4];COLUMN=b[2];
			 DELAY
			 ROW=a[7];COLUMN=b[7];
			 DELAY
		     }
	       DELAY
	       ROW=a[3];COLUMN=b[0];
	       DELAY
	       ROW=a[4];COLUMN=b[0]; 
	       DELAY
	       ROW=a[7];COLUMN=b[7];
	    return 0; 
	  }
 
Друг Кота
Аватара пользователя
Сообщения: 16980
Зарегистрирован: Пт мар 30, 2012 05:17:29
Откуда: Екатеринбург

Сообщение mickbell »

0. Да что вы, тут не пинаются... ну если не заходить в мяву - там и вовсе башку оторвать могут.
1. Всё-таки имейте в виду и не забывайте: если вам понадобится управлять несколькими, а то и многими реле одновременно, то неизбежно импульсное свечение светодиодов и, соответственно, подача тока на обмотки реле импульсами. Для попробовать и набить себе шишек вы избрали верный путь, вы их набьёте (это хорошо и правильно на самом деле), но заклинаю вас закладывать этот принцип в готовое изделие. Кстати, у вас есть осциллограф? Желательно его иметь для таких дел. Некоторые берут в китайпосылторге за недорого игрушечные осциллографы вроде народного DSO-138, или как там его... Почему бы нет? Лучше, конечно, иметь серьёзный аппарат.
2. Про диоды параллельно обмоткам реле вам уже говорили, ещё раз напоминаю.
3. Как писать код, я вас учить не буду - просто потому, что не считаю себя достаточно компетентным, чтобы это делать. Хотя вижу, что вам бы поучиться действительно надо. Я всем советую смотреть, как пишут другие. Просмотрев достаточно много исходников, вы, скорее всего, сами научитесь понимать, какой код хорош, какой не очень, а от иного вас будет воротить.
И хрюкотали зелюки,
Как мюмзики в мове.

На каждый РКН
Найдётся VPN.
Родился
Сообщения: 13
Зарегистрирован: Сб июл 09, 2022 09:41:49

Сообщение Николай1961. »

[uquote="mickbell",url="/forum/viewtopic.php?p=4257483#p4257483"]ТСу. По управлению могу предложить сделать по-другому: вводите с цифровой клавиатуры номер канала, затем * или # - чтобы соответственно включить или выключить нагрузку. Это позволит произвольно коммутировать любое число нагрузок. Клавиатур с таким набором кнопок - кругом и везде. Номер канала 0 - широковещательный, последовательность 0# выключит все нагрузки сразу.[/uquote]

Здравствуйте. Пытался воспользоваться Вашим советом. В интернете нашёл два скрипта и соединил их. До моих изменений в коде всё работает, то есть отправка от 1 до 0 нет проблем. А вот уже десятки и более не получается. Если честно я просто не соображу как это сделать. Если я правильно понял логику то это должно работать так:
Нажимаю на кнопку -> значение этой кнопки записывается в некую переменную temp -> скрипт проверяет нажата ли после этого кнопка '*' -> ели да то цифра передаётся на матрицу -> если нет то переменная temp умножаем на 10 и к нему плюсуем значение второй кнопки и тд до нажатия кнопки '*'. Но как это написать в коде никак не соображу.
Вот код:
Спойлер

Код: Выделить всё

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>


#define  CHISLO PORTD
#define  RAZRIAD PORTC


// Массив значений для порта вывода
unsigned char key_tab[4] = {0b11111110,
                            0b11111101,
                            0b11111011,
                            0b11110111
                           };


// Функция опроса клавиатуры
unsigned char scan_key(void)
{
    unsigned char key_value = 0;
    unsigned char i;

    for(i = 0; i < 4; i++)
    {
        PORTB = key_tab[i]; // выводим лог. 0 в порт вывода
        _delay_us(10);

        switch (PINB & 0xF0)
        {
        case 0b11100000:
            key_value = 1 + i * 3;
            return (key_value);
        case 0b11010000:
            key_value = 2 + i * 3;
            return (key_value);
        case 0b10110000:
            key_value = 3 + i * 3;
            return (key_value);
        default:
            break;
        }
    }
    return (key_value);
}







unsigned int razr1 = 0, razr2 = 0, razr3 = 0, razr4 = 0;
unsigned char bc547 = 1;
unsigned int z=0;


unsigned int chisla [10] = {0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, 0x6f};


void vse_chislo (unsigned int razbivka_chisla)
{
    razr1 = razbivka_chisla/1000; // тысячи
    razr2 = razbivka_chisla%1000/100; // сотни
    razr3 = razbivka_chisla%100/10; // десятки
    razr4 = razbivka_chisla%10; // единицы

}

ISR (TIMER0_OVF_vect)
{
    if (bc547 == 1)
    {
        RAZRIAD = 0b00000001;    //включаем 1-й разряд, остальные выключаем
        CHISLO = chisla[razr1];
    }
    if (bc547 == 2)
    {
        RAZRIAD = 0b00000010;    //включаем 2-й разряд, остальные выключаем
        CHISLO = chisla[razr2];
    }
    if (bc547 == 3)
    {
        RAZRIAD = 0b00000100;    //включаем 3-й разряд, остальные выключаем
        CHISLO = chisla[razr3];
    }
    if (bc547 == 4)
    {
        RAZRIAD = 0b00001000;    //включаем 4-й разряд, остальные выключаем
        CHISLO = chisla[razr4];
    }
    bc547++; // добавляем к переменной BC547 единицу
    if (bc547 > 4) bc547 = 1; // отслеживаем переменную BC547, чтобы она не превысила значение 4

}



int main(void)
{


    unsigned char key;

    // Настройка портов ввода-вывода
    DDRB |= (1 << PB3)|(1 << PB2)|(1 << PB1)|(1 << PB0); // Порт вывода
    DDRB &= ~(1 << PB7)|(1 << PB6)|(1 << PB5)|(1 << PB4); // Порт ввода
    PORTB = 0xF0; // Устанавливаем лог. 1 в порт ввода

    DDRD = 0b11111111;

    DDRC = 0b00001111;

    RAZRIAD = 0b00000001;
    CHISLO = 0x3f;

    // Настройка 0-го таймер счетчика на прерывание по переполнению

    TCCR0 |= (1<<1);
    TCCR0 &= ~((1<<0) | (1<<2)); // f/8
    TIMSK |= (1<<0);
    TCNT0 = 0;
    sei ();


    _delay_ms(10);

    while(1)
    {
        // Выводим значение нажатой кнопки на индикатор
        if(scan_key()==1)
        {
            key = 1;
        }
        if(scan_key()==2)
        {
            key = 2;
        }
        if(scan_key()==3)
        {
            key = 3;
        }
        if(scan_key()==4)
        {
            key = 4;
        }
        if(scan_key()==5)
        {
            key = 5;
        }
        if(scan_key()==6)
        {
            key = 6;
        }
        if(scan_key()==7)
        {
            key = 7;
        }
        if(scan_key()==8)
        {
            key = 8;
        }
        if(scan_key()==9)
        {
            key = 9;
        }
        if(scan_key()==10)
        {
            key = '*';
        }
        if(scan_key()==11)
        {
            key = 0;
        }
        if(scan_key()==12)
        {
            key = '#';
        }

unsigned int temp = key;

       if((temp)&(scan_key()==10))
        {
	vse_chislo(key);
	}else{ temp = (temp*10)+key;}



    }
}



Вот схема:
Изображение
Друг Кота
Аватара пользователя
Сообщения: 6821
Зарегистрирован: Сб янв 28, 2006 22:47:24

Сообщение Asmodey »

[uquote="Николай1961.",url="/forum/viewtopic.php?p=4258911#p4258911"]Если я правильно понял логику то это должно работать так:
Нажимаю на кнопку -> значение этой кнопки записывается в некую переменную temp -> скрипт проверяет нажата ли после этого кнопка '*' -> ели да то цифра передаётся на матрицу -> если нет то переменная temp умножаем на 10 и к нему плюсуем значение второй кнопки и тд до нажатия кнопки '*'. Но как это написать в коде никак не соображу.[/uquote]
Используйте if и else. При каждом нажатии в условии if проверяете, равно ли значение в temp коду кнопки *. Если да, тогда из тела if вызывается функция вывода числа в порты, на СД матрицу. Если нет, тогда if пропускается, а в теле else проделываются необходимые операции с числом - умножение и сложение значения нажатой кнопки с предыдущим значением и сохранение его в буферную переменную, плюс увеличение "счетчика декадности", который будет показывать, на сколько нужно умножать полученное число при очередном нажатии (на 1 при первом нажатии, на 10 при втором и т.д.). После чего снова ждем нажатия кнопок на клавиатуре. Не забывайте сбрасывать счетчик декадности при нажатии *.

И забудьте про "скрипты", надо собрать волю в кулак и избавляться от тяжкого наследия ардуины.

P.S. В принципе, можно сделать ввод с клавиатуры с временной задержкой без нажатия *. Скажем, нажали вы клавишу 1. Программа определила нажатие и секунду (или две, или больше) ждет, не будет ли нажата следующая клавиша. Если за определенный промежуток времени нажатие не произошло, программа зажигает светодиод 1. Если же в течении секунды после нажатия 1 было нажато еще и 2, тогда зажжется светодиод 12.
Астролябия-сама меряет, было бы что мерять!!!
Родился
Сообщения: 13
Зарегистрирован: Сб июл 09, 2022 09:41:49

Сообщение Николай1961. »

[uquote="Asmodey",url="/forum/viewtopic.php?p=4258931#p4258931"]Используйте if и else. При каждом нажатии в условии if проверяете, равно ли значение в temp коду кнопки *. Если да, тогда из тела if вызывается функция вывода числа в порты, на СД матрицу. Если нет, тогда if пропускается, а в теле else проделываются необходимые операции с числом - умножение и сложение значения нажатой кнопки с предыдущим значением и сохранение его в буферную переменную, плюс увеличение "счетчика декадности", который будет показывать, на сколько нужно умножать полученное число при очередном нажатии (на 1 при первом нажатии, на 10 при втором и т.д.). После чего снова ждем нажатия кнопок на клавиатуре. Не забывайте сбрасывать счетчик декадности при нажатии *.

И забудьте про "скрипты", надо собрать волю в кулак и избавляться от тяжкого наследия ардуины.

P.S. В принципе, можно сделать ввод с клавиатуры с временной задержкой без нажатия *. Скажем, нажали вы клавишу 1. Программа определила нажатие и секунду (или две, или больше) ждет, не будет ли нажата следующая клавиша. Если за определенный промежуток времени нажатие не произошло, программа зажигает светодиод 1. Если же в течении секунды после нажатия 1 было нажато еще и 2, тогда зажжется светодиод 12.[/uquote]
:( В том то и проблема что у меня не хватает то ли знания, то ли мозгов реализовать эти действия в программе. Уже весь мозг сломал. :(

Пока мозгов хватило только на это:

Код: Выделить всё

   if((key)&&(key!='*')&&(key!='#'))
    {
        temp = key;
    }
    if((temp)&&(key)&&(key!='*')&&(key!='#'))
    {
        temp=temp*10+key;
    }
    if(key=='*')
    {
        vse_chislo(temp);
    }

Но перестал включаться сегмент 0. При этом нажимая 1 получаю 11 :(
Друг Кота
Аватара пользователя
Сообщения: 16980
Зарегистрирован: Пт мар 30, 2012 05:17:29
Откуда: Екатеринбург

Сообщение mickbell »

Всё-таки я расскажу о том, как я пишу программы для МК, вдруг пригодится. Есть два варианта: с использованием FreeRTOS и без использования оной. Первое не рассказываю, это не для АВРок. А вот второе делаю так.
Как вы наверняка знаете, микроконтроллерный софт включает три компонента:
1. настройку железа МК (GPIO, таймеров, других интерфейсов, прерываний),
2. главный (и единственный!!!) бесконечный цикл,
3. обработку прерываний, которые иногда случаются.
Задача такая: поскольку могут существовать времязависимые процессы, первым делом надо позаботиться об обслуживании времени. Я выделяю под "системные" нужды один таймер и настраиваю его параметры так, чтобы он срабатывал каждую миллисекунду. Или каждые десять миллисекунд. Настраиваю прерывание, в котором при срабатывании этого таймера что-то произойдёт. В его обработчике прописываю условный инкремент (чтобы не вылазить за разрядную сетку) некоей глобальной переменной, за которой буду следить в главном цикле. Выглядеть объявление этой переменной может так:

Код: Выделить всё

volatile uint8_t tcf=0; // Флаг-счётчик тиков системного таймера
код в обработчике прерывания по таймеру может быть таким:

Код: Выделить всё

  if(tcf<255) tcf++;
а сам главный цикл выглядит так:

Код: Выделить всё

int main(void)
{
  // Объявление локальных переменных
  uint16_t t1=0, t2=0, t3=0;  // Какие-то счётчики времени
  uint8_t tcf_local=0; // Локальная копия tcf
  // Процедуры инициализации железа МК
  // ...
  while(1)
  // Главный цикл
  {
    //  Действия, требующие немедленного выполнения, например, поллинг лап МК
    // ...
    if(tcf)
    // Действия, выполняемые по тикам системного таймера
    {
      // Тут неплохо бы запретить прерывание по системному таймеру
      tcf_local=tcf;
      tcf=0;
      // А тут прерывание по системному таймеру надо разрешить
      // Полезные действия
      // ...
      // Счёт времени
      if(t1<65536-tcf_local) t1+=tcf_local;
      if(t2<65536-tcf_local) t2+=tcf_local;
      if(t3<65536-tcf_local) t3+=tcf_local;
      // Считаем всякие времена, задержки и прочее
      // ...
    }
  }
}
На такой шкилет программы, как на шампур мясо - последовательно, можно уже нанизывать какие-то действия. Сами действия должны выстраиваться друг за другом в главном цикле, при этом каждое действие (оформить его полезно инлайн-функцией, к примеру) НЕ ДОЛЖНО задерживать весь процесс, то есть, если надо реализовать задержку по времени, то нехрен, как это делают непосвящённые, писать тупые циклы задержек, из которых нет выхода, пока они не закончатся. А вот сбросить какой-то из счётчиков времени, а затем проконтролировать, а не равно ли его содержимое, скажем, 200 мс, а вдруг даже больше - это можно и нужно. Главное - всякая такая функция должна работать "на проход", никогда не задерживая процесс в себе сверх минимально необходимого. Большинство таких функций желательно помещать в секцию, работающую по тикам.
Надо бы много ещё рассказать, но мне тут надо в город ехать, пока прерываюсь. Ещё раз: это только моё мнение, причём мнение скорее железячника, так что мотайте на ус всё, что расскажут другие. Ну а если появятся конкретные вопросы - по возвращении, часа через два-три, буду готов ответить.

PS. Вернулся, почитал, скорректировал код. :))
И хрюкотали зелюки,
Как мюмзики в мове.

На каждый РКН
Найдётся VPN.
Родился
Сообщения: 13
Зарегистрирован: Сб июл 09, 2022 09:41:49

Сообщение Николай1961. »

Мозги совсем не работают.

Код: Выделить всё

if(key)// Если нажали на кнопку
{
    buttons[k] = key; //ЗАПИСЫВАЕМ ЗНАЧЕНИЕ КНОПКИ В МАССИВ
    k = k + 1; // увеличиваем счётчик нажатий на 1
  
  for(s=0; s<4; s++) //обходим массив и
    {
        vse_chislo(buttons[s]); //выводим на семисегментный индикатор значение счётчика.
    }
}
Что я опять сделал не так

И этот вариант не работает

Код: Выделить всё

if((key)&&(key!='*')&&(key!='#'))
{
    buttons[k] = key; //ЗАПИСЫВАЕМ ЗНАЧЕНИЕ КНОПКИ В МАССИВ
    k = k + 1; // увеличиваем счётчик нажатий на 1
}


if((key)&&(key=='*'))
{
    for(s=0; s<5; s++)
    {
        _delay_ms(200);
        vse_chislo(buttons[s]); //выводим на семисигментный индикатор значение счётчика.
    }
}
Друг Кота
Аватара пользователя
Сообщения: 16980
Зарегистрирован: Пт мар 30, 2012 05:17:29
Откуда: Екатеринбург

Сообщение mickbell »

Конечно, начальное значение k (k=0) где-то прописано, а при инкременте проверяется, что оно не укажет на элемент массива, выходящий за массив. :)) Но где всё это, мы не видим. :dont_know: Да и присвоение переменной key значения, соответствующего нажатой кнопке, тоже не видно. Оно есть вообще?
И хрюкотали зелюки,
Как мюмзики в мове.

На каждый РКН
Найдётся VPN.
Родился
Сообщения: 13
Зарегистрирован: Сб июл 09, 2022 09:41:49

Сообщение Николай1961. »

[uquote="mickbell",url="/forum/viewtopic.php?p=4260123#p4260123"]Конечно, начальное значение k (k=0) где-то прописано, а при инкременте проверяется, что оно не укажет на элемент массива, выходящий за массив. :)) Но где всё это, мы не видим. :dont_know: Да и присвоение переменной key значения, соответствующего нажатой кнопке, тоже не видно. Оно есть вообще?[/uquote]
Здравствуйте.
Прошу прощения Вот весь код:
Спойлер

Код: Выделить всё


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>


#define  CHISLO PORTA
#define  CHISLO2 PORTA
#define  RAZRIAD PORTC

unsigned char key;
unsigned char temp;
char buttons[5]; // массив нажатых кнопок
int k = 0; // счетчик нажатий
int s = 0;

// Массив значений для порта вывода
unsigned char key_tab[4] = {0b11111110,
                            0b11111101,
                            0b11111011,
                            0b11110111
                           };


// Функция опроса клавиатуры
unsigned char scan_key(void)
{
    unsigned char key_value = 0;
    unsigned char i;

    for(i = 0; i < 4; i++)
    {
        PORTB = key_tab[i]; // выводим лог. 0 в порт вывода
        _delay_us(10);

        switch (PINB & 0xF0)
        {
        case 0b11100000:
            key_value = 1 + i * 3;
            return (key_value);
        case 0b11010000:
            key_value = 2 + i * 3;
            return (key_value);
        case 0b10110000:
            key_value = 3 + i * 3;
            return (key_value);
        default:
            break;
        }
    }
    return (key_value);
}


unsigned int razr1 = 0, razr2 = 0, razr3 = 0, razr4 = 0;
unsigned char bc547 = 1;
unsigned int z=0;


unsigned int chisla [] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77,0x39};


void vse_chislo (unsigned int razbivka_chisla)
{
    razr1 = razbivka_chisla/1000; // тысячи
    razr2 = razbivka_chisla%1000/100; // сотни
    razr3 = razbivka_chisla%100/10; // десятки
    razr4 = razbivka_chisla%10; // единицы

}

ISR (TIMER0_OVF_vect)
{
    if (bc547 == 1)
    {
        RAZRIAD = 0b00000001;    //включаем 1-й разряд, остальные выключаем
        CHISLO = chisla[razr1];
    }
    if (bc547 == 2)
    {
        RAZRIAD = 0b00000010;    //включаем 2-й разряд, остальные выключаем
        CHISLO = chisla[razr2];
    }
    if (bc547 == 3)
    {
        RAZRIAD = 0b00000100;    //включаем 3-й разряд, остальные выключаем
        CHISLO = chisla[razr3];
    }
    if (bc547 == 4)
    {
        RAZRIAD = 0b00001000;    //включаем 4-й разряд, остальные выключаем
        CHISLO = chisla[razr4];
    }
    bc547++; // добавляем к переменной BC547 единицу
    if (bc547 > 4) bc547 = 1; // отслеживаем переменную BC547, чтобы она не превысила значение 4

}


int main(void)
{

    // Настройка портов ввода-вывода
    DDRB |= (1 << PB3)|(1 << PB2)|(1 << PB1)|(1 << PB0); // Порт вывода
    DDRB &= ~(1 << PB7)|(1 << PB6)|(1 << PB5)|(1 << PB4); // Порт ввода
    PORTB = 0xF0; // Устанавливаем лог. 1 в порт ввода

    DDRA = 0b11111111;

    DDRC = 0b00001111;
    DDRD |= 1 << PIND1;//контакт 1 portD устанавливаем на вывод данных
    DDRD &= ~(1 << PIND0);//контакт 0 portD устанавливаем на ввод данных
    PORTD |= 1 << PIND0;
    RAZRIAD = 0b00000001;
    CHISLO = 0x3f;


    int UBBRValue = 25;// установка бодовой скорости

    //записываем это значение в верхнюю часть регистра  (8 бит из 11)
    UBRRH = (unsigned char) (UBBRValue >> 8);

    // записываем оставшуюся часть регистра
    UBRRL = (unsigned char) UBBRValue;

    // задействуем передатчик и приемник
    UCSRB = (1 << RXEN) | (1 << TXEN);

    //устанавливаем 2 стоповых бита и 8-битную длину передаваемого символа
    UCSRC = (1 << USBS) | (3 << UCSZ0);

    TCCR0 |= (1<<1);
    TCCR0 &= ~((1<<0) | (1<<2)); // f/8
    TIMSK |= (1<<0);
    TCNT0 = 0;
    sei ();


    _delay_ms(10);

    while(1)
    {
        // Выводим значение нажатой кнопки на индикатор
        if(scan_key()==1)
        {
            key = 1;
        }
        if(scan_key()==2)
        {
            key = 2;
        }
        if(scan_key()==3)
        {
            key = 3;
        }
        if(scan_key()==4)
        {
            key = 4;
        }
        if(scan_key()==5)
        {
            key = 5;
        }
        if(scan_key()==6)
        {
            key = 6;
        }
        if(scan_key()==7)
        {
            key = 7;
        }
        if(scan_key()==8)
        {
            key = 8;
        }
        if(scan_key()==9)
        {
            key = 9;
        }
        if(scan_key()==10)
        {
            key = '*';
        }
        if(scan_key()==11)
        {
            key = 0;
        }
        if(scan_key()==12)
        {
            key = '#';
        }


        if((key)&&(key!='*')&&(key!='#'))
        {

            buttons[k] = key; //ЗАПИСЫВАЕМ ЗНАЧЕНИЕ КНОПКИ В МАССИВ
            _delay_ms(5);
            k = k + 1; // увеличиваем счётчик нажатий на 1

        }


        if(key=='*')
        {
            for(s=0; s<5; s++)
            {
                _delay_ms(500);
                vse_chislo(buttons[s]); //выводим на семисигментный индикатор значение счётчика.
                _delay_ms(500);
            }
        }



    }
}

Друг Кота
Аватара пользователя
Сообщения: 16980
Зарегистрирован: Пт мар 30, 2012 05:17:29
Откуда: Екатеринбург

Сообщение mickbell »

На первый взгляд явных ляпов нет. Значит, придётся отлаживать. Вопрос номер один: что именно тут не работает и как именно не работает, каковы клинические признаки? Вопрос номер два: а что работает, на что можно опереться? Хотя бы вывод в ноги GPIO работает? Скажем, чтобы узнать, что функция вызывается, можно в её тело подставить вывод в какую-нибудь ногу: единицы в начале тела функции и нуля в конце, а потом осциллографом смотреть, что и как происходит. Особенно это помогает налаживать взаимодействие задач во ФриРТОСе, сразу видно, какой задаче какое время выделено, и четырёхканальный осциллограф тут очень кстати. Для разных задач - разные ноги. Вы можете поступить точно так же, чтобы убедиться, что неработающий код хотя бы вызывается.
И хрюкотали зелюки,
Как мюмзики в мове.

На каждый РКН
Найдётся VPN.
Друг Кота
Аватара пользователя
Сообщения: 6821
Зарегистрирован: Сб янв 28, 2006 22:47:24

Сообщение Asmodey »

В код особо не вникал, но меня смущает оператор if с несколькими выражениями в условии. В MPLAB с компилятором XC8 напоролся на такое, что они мой if с четырьмя выражениями согласились понимать только после того, как я их по два сгруппировал в отдельные скобки, хотя они уже все в скобках были. Без чего логические операции летели к черту. Возможно, это был какой-то мой косяк, а может некое особое требование конкретного компилятора. Как там со средой под AVR не знаю, дел с ними почти не имел

Как правильно заметил mickbell нужно отлаживать. Ставить точки останова выполнения программы и смотреть, что там в переменных да в регистрах получается по нажатию той или иной кнопки. Но, тут программатор-отладчик желателен. Если отладчика нет, выводить отладочную информацию хотя бы на светодиоды, загоняя программу в бесконечные циклы с зажиганием "отладочных светодиодов" на портах при нажатии на кнопки, в зависимости от состояния тех или иных переменных.
Астролябия-сама меряет, было бы что мерять!!!
Друг Кота
Аватара пользователя
Сообщения: 16980
Зарегистрирован: Пт мар 30, 2012 05:17:29
Откуда: Екатеринбург

Сообщение mickbell »

Я не пользуюсь отладчиками. Обхожусь тем, что на плате расставляю несколько светодиодов и джамперов на свободные лапы МК, ими пользуюсь для отладки, а потом придумываю что-нибудь полезное на них выводить, а с джамперов вводить. В софт в нужном месте вставляю выдачу на СД и while(1). Другие варианты: вывожу отладочный лог на УАРТ (если задействован) или вообще пишу его в ЕЕПРОМ, потом читаю программатором. Короче, и без отладчиков можно отлаживать, если знать, как. Надеюсь, ТСу какие-то из этих советов окажутся небесполезными.
И хрюкотали зелюки,
Как мюмзики в мове.

На каждый РКН
Найдётся VPN.
Ответить

Вернуться в «Теория»