Перейти к содержанию

Игра "лампочки" На Atmega 328P


maxbelyx

Рекомендуемые сообщения

Здравствуйте ув. форумчане!

Обращаюсь к Вам за помощью в разъяснении некоторого вопроса.

Существует такая игра, как "лампочки", я хотел реализовать ее в "железе".

Имеется панель с 16 кнопками без фиксации и лампочкой внутри каждой кнопки. Кнопки расположены как матрица 4х4. Изначально кнопки светятся в заранее заданной последовательности (не имеет значения какой) и нажимая правильную комбинацию этих кнопок надо заставить их все потухнуть. После того, как это условие выполнено (потухли все) - они все разом зажигаются, и на свободную ножку МК подается импульс, и программа останавливается до Reset`а.

Вот простое условие, которое описывает всю суть этой, достаточно простой программы:

-При нажатии на горящую клавишу потухают все, что вокруг нее, в том числе и сама нажатая клавиша, а если они были потухшие — загораются.

-При нажатии на потухшую клавишу загораются все вокруг нее и сама клавиша. Если до этого горели — потухают.

-Необходимо нажимая правильную последовательность кнопок "потушить" все.

Написал код. Так как кнопок 16, а выводов не так много, чтобы их все задействовать, я решил использовать АЦП, и, подключив все 16 кнопок через разные резисторы к АЦП "снимаю" показания и вычисляю какая кнопка нажата.

Так же написал Инициализацию для всех светодиодов, функции включения и выключения, но код, почему-то не работает.

А если я непонятно объяснил суть программы, это, по сути игра. Я ее нашел вот здесь, очень простая и понятная игра "Лампочки". Как вариант она есть на этом сайте: http://flash-yes.ru/lampochki/ (перечитал правила форума, надеюсь можно оставить ссылку здесь).

В оригинале игра 5*5, мне необходима именно 4*4, реализованная в коде. Заранее извиняюсь за кривой код, пока только учусь. Уверен его можно написать куда более кратко и прозрачно, но, для начала необходимо добиться, чтобы он хотя бы выполнялся. И заранее извиняюсь за огромный прикрепленный код. Не совсем понял, как его можно было бы свернуть для читаемости.

Файл main:

#define F_CPU 16000000UL // Atmega 328P with 16MHz crystal
#include <avr/io.h>
#include <avr/interrupt.h> //подгружаем прерывание
#include "keyboard.h"
#include "leds.h"
#include <util/delay.h>
void InitADC(void);
void ButtonState(void);
void StartGame(void);
void GameWin(void);
// Прерывание по АЦП
ISR (ADC_vect)
{
Keyboard();
}
int main(void)
{
InitADC();
LedsOutput();
StartGame();
while(1)
{
	 if(num_ &(1<<7)) //если 7 бит в 1 то цифра записана
	 {
		 num_ &=~ (1<<7); //cброс 7 бита в регистре num_, остается код кнопки
	 }
	 ButtonState();
	 GameWin();
}
}
void StartGame(void)
{
// Рандомно заданные начальные условия игры
LED1_ON();
LED2_ON();
LED3_ON();
LED4_ON();
LED5_ON();
LED6_OFF();
LED7_OFF();
LED8_ON();
LED9_ON();
LED10_OFF();
LED11_OFF();
LED12_ON();
LED13_ON();
LED14_ON();
LED15_ON();
LED16_ON();
}
void ButtonState(void)
{
// Тушить саму кнопку при нажатии или зажигать, если не горела.
// Тушить все кнопки вокруг нажатой, если горели, зажигать, если нет.
/****BUTTON_1*****/
if (num_ == 1)
{
if (LED1_PIN & (1<<LED1_BIT)) LED1_OFF();
else LED1_ON();
if (LED2_PIN & (1<<LED2_BIT)) LED2_OFF();
else LED2_ON();
if (LED5_PIN & (1<<LED5_BIT)) LED5_OFF();
else LED5_ON();
}
/****BUTTON_2*****/
if (num_== 2)
{
if (LED2_PIN & (1<<LED2_BIT)) LED2_OFF();
else LED2_ON();
if (LED1_PIN & (1<<LED1_BIT)) LED1_OFF();
else LED1_ON();
if (LED3_PIN & (1<<LED3_BIT)) LED3_OFF();
else LED3_ON();
if (LED6_PIN & (1<<LED6_BIT)) LED6_OFF();
else LED6_ON();
}
/****BUTTON_3****/
if (num_ == 3)
{
if (LED3_PIN & (1<<LED3_BIT)) LED3_OFF();
else LED3_ON();
if (LED2_PIN & (1<<LED2_BIT)) LED2_OFF();
else LED2_ON();
if (LED4_PIN & (1<<LED4_BIT)) LED4_OFF();
else LED4_ON();
if (LED7_PIN & (1<<LED7_BIT)) LED7_OFF();
else LED7_ON();
}
/****BUTTON_4****/
if (num_ == 4)
{
if (LED4_PIN & (1<<LED4_BIT)) LED4_OFF();
else LED4_ON();
if (LED3_PIN & (1<<LED3_BIT)) LED3_OFF();
else LED3_ON();
if (LED8_PIN & (1<<LED8_BIT)) LED8_OFF();
else LED8_ON();
}
/****BUTTON_5****/
if (num_ == 5)
{
if (LED5_PIN & (1<<LED5_BIT)) LED5_OFF();
else LED5_ON();
if (LED1_PIN & (1<<LED1_BIT)) LED1_OFF();
else LED1_ON();
if (LED6_PIN & (1<<LED6_BIT)) LED6_OFF();
else LED6_ON();
if (LED9_PIN & (1<<LED9_BIT)) LED9_OFF();
else LED9_ON();
}
/****BUTTON_6****/
if (num_ == 6)
{
if (LED6_PIN & (1<<LED6_BIT)) LED6_OFF();
else LED6_ON();
if (LED2_PIN & (1<<LED2_BIT)) LED2_OFF();
else LED2_ON();
if (LED5_PIN & (1<<LED5_BIT)) LED5_OFF();
else LED5_ON();
if (LED7_PIN & (1<<LED7_BIT)) LED7_OFF();
else LED7_ON();
if (LED10_PIN & (1<<LED10_BIT)) LED10_OFF();
else LED10_ON();
}
/****BUTTON_7****/
if (num_== 7)
{
if (LED7_PIN & (1<<LED7_BIT)) LED7_OFF();
else LED7_ON();
if (LED3_PIN & (1<<LED3_BIT)) LED3_OFF();
else LED3_ON();
if (LED6_PIN & (1<<LED6_BIT)) LED6_OFF();
else LED6_ON();
if (LED8_PIN & (1<<LED8_BIT)) LED8_OFF();
else LED8_ON();
if (LED11_PIN & (1<<LED11_BIT)) LED11_OFF();
else LED11_ON();
}
/****BUTTON_8****/
if (num_== 8)
{
if (LED8_PIN & (1<<LED8_BIT)) LED8_OFF();
else LED8_ON();
if (LED4_PIN & (1<<LED4_BIT)) LED4_OFF();
else LED4_ON();
if (LED7_PIN & (1<<LED7_BIT)) LED7_OFF();
else LED7_ON();
if (LED12_PIN & (1<<LED12_BIT)) LED12_OFF();
else LED12_ON();
}
/****BUTTON_9****/
if (num_== 9)
{
if (LED9_PIN & (1<<LED9_BIT)) LED9_OFF();
else LED9_ON();
if (LED5_PIN & (1<<LED5_BIT)) LED5_OFF();
else LED5_ON();
if (LED10_PIN & (1<<LED10_BIT)) LED10_OFF();
else LED10_ON();
if (LED13_PIN & (1<<LED13_BIT)) LED13_OFF();
else LED13_ON();
}
/****BUTTON_10****/
if (num_ == 10)
{
if (LED10_PIN & (1<<LED10_BIT)) LED10_OFF();
else LED10_ON();
if (LED6_PIN & (1<<LED6_BIT)) LED6_OFF();
else LED6_ON();
if (LED9_PIN & (1<<LED9_BIT)) LED9_OFF();
else LED9_ON();
if (LED11_PIN & (1<<LED11_BIT)) LED11_OFF();
else LED11_ON();
if (LED14_PIN & (1<<LED14_BIT)) LED14_OFF();
else LED14_ON();
}
/****BUTTON_11****/
if (num_ == 11)
{
if (LED11_PIN & (1<<LED11_BIT)) LED11_OFF();
else LED11_ON();
if (LED7_PIN & (1<<LED7_BIT)) LED7_OFF();
else LED7_ON();
if (LED10_PIN & (1<<LED10_BIT)) LED10_OFF();
else LED10_ON();
if (LED12_PIN & (1<<LED12_BIT)) LED12_OFF();
else LED12_ON();
if (LED15_PIN & (1<<LED15_BIT)) LED15_OFF();
else LED15_ON();
}
/****BUTTON_12****/
if (num_ == 12)
{
if (LED12_PIN & (1<<LED12_BIT)) LED12_OFF();
else LED12_ON();
if (LED8_PIN & (1<<LED8_BIT)) LED8_OFF();
else LED8_ON();
if (LED11_PIN & (1<<LED11_BIT)) LED11_OFF();
else LED11_ON();
if (LED16_PIN & (1<<LED16_BIT)) LED16_OFF();
else LED16_ON();
}
/****BUTTON_13****/
if (num_ == 13)
{
if (LED13_PIN & (1<<LED13_BIT)) LED13_OFF();
else LED13_ON();
if (LED9_PIN & (1<<LED9_BIT)) LED9_OFF();
else LED9_ON();
if (LED14_PIN & (1<<LED14_BIT)) LED14_OFF();
else LED14_ON();
}
/****BUTTON_14****/
if (num_ == 14)
{
if (LED14_PIN & (1<<LED14_BIT)) LED14_OFF();
else LED14_ON();
if (LED10_PIN & (1<<LED10_BIT)) LED10_OFF();
else LED10_ON();
if (LED13_PIN & (1<<LED13_BIT)) LED13_OFF();
else LED13_ON();
if (LED15_PIN & (1<<LED15_BIT)) LED15_OFF();
else LED15_ON();
}
/****BUTTON_15****/
if (num_ == 15)
{
if (LED15_PIN & (1<<LED15_BIT)) LED15_OFF();
else LED15_ON();
if (LED11_PIN & (1<<LED11_BIT)) LED11_OFF();
else LED11_ON();
if (LED14_PIN & (1<<LED14_BIT)) LED14_OFF();
else LED14_ON();
if (LED16_PIN & (1<<LED16_BIT)) LED16_OFF();
else LED16_ON();
}
/****BUTTON_16****/
if (num_ == 16)
{
if (LED16_PIN & (1<<LED16_BIT)) LED16_OFF();
else LED16_ON();
if (LED12_PIN & (1<<LED12_BIT)) LED12_OFF();
else LED12_ON();
if (LED15_PIN & (1<<LED15_BIT)) LED15_OFF();
else LED15_ON();
}
}
void GameWin()
{
// Условие выйгрыша - все светодиоды потухли
if ()
{
}
WIN_PORT |= (1<<WIN_BIT);
}
void InitADC(void)
{
// Инициализация АЦП
PORTC &=~(1<<PC0);
DDRC &=~ (1<<PC0);
ADCSRA|=(1<<ADEN)|(1<<ADIE)|(1<<ADPS2)|(1<<ADSC)|(1<<ADATE);
ADMUX |=(1<<REFS0);
asm("sei");
}

Функция LED1_ON имеет такой вид:

void LED1_ON(void)
{
LED1_PORT |=(1<<LED1_BIT);
}

Функцию чтения данных с АЦП стащил с одного видеоурока

 volatile unsigned char num_;
 Keyboard()
 {
	 static unsigned char Deistvie, Kol_Proverok, Temp;
	 unsigned char num;
	 //-----------------//
	 num = NumADC();
	 if(Deistvie & (1<<0))
	 {
		 if(num == 100)
		 {
		 if((Kol_Proverok++) < 250)
			 {
				 if(num != Temp)
				 {
					 Temp = num;
					 Kol_Proverok=0;
				 }
			 }
			 else
			 {
				 Kol_Proverok=0;
				 Deistvie &=~(1<<0);
			 }
			 return;
		 }
		 else
		 {
		 Temp =0;
		 Kol_Proverok=0;
		 }
	 }
	 //====================//
	 else
	 {
		 if(num_ != (1<<7))
		 {
		 if(num != 100)
			 {
			 Deistvie &=~(1<<1);
			 if((Kol_Proverok++) < 150)
			 {
				 if(num!= Temp)
				 {
					 Temp = num;
					 Kol_Proverok=0;
				 }
			 }
			 else
			 {
				 num_ = Temp|(1<<7);
				 Kol_Proverok=0;
				 Deistvie|=(1<<0);
			 }
			 return;
			 }
		 }
		 if(Deistvie != (1<<1))
		 {
		 Kol_Proverok=0;
		 Temp=100;
		 Deistvie|=(1<<1);
		 }
	 }
 }
 NumADC()
 {
	 unsigned int ACP;
	 ACP = ADCW;
	 if(ACP < 45)
	 return 1;
	 if(ACP < 74)
	 return 2;
	 if(ACP < 94)
	 return 3;
	 if(ACP < 220)
	 return 4;
	 if(ACP < 280)
	 return 5;
	 if(ACP < 340)
	 return 6;
	 if(ACP < 400)
	 return 7;
	 if(ACP < 505)
	 return 8;
	 if(ACP < 580)
	 return 9;
	 if(ACP < 630)
	 return 10;
	 if(ACP < 710)
	 return 11;
	 if(ACP < 790)
	 return 12;
	 if(ACP < 870)
	 return 13;
	 if(ACP < 950)
	 return 14;
	 if(ACP < 1000)
	 return 15;
	 if(ACP <1024)
	 return 16;
	 return 100;
 }

Заранее благодарю за ответ,

С уважением,

Максим.

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

По теме - сначала проверьте работу функции чтения кнопок и управления светодиодами. Логику игры оставьте на потом.

Я не раздаю удочки. Я продаю рыбу.

Ссылка на комментарий
Поделиться на другие сайты

Организация питания на основе надежных литиевых аккумуляторов EVE и микросхем азиатского производства

Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

"...решил использовать АЦП, и, подключив все 16 кнопок через разные резисторы к АЦП "снимаю" показания и вычисляю какая кнопка нажата..."

Не правильное решение. Сложно в программировании и некрасиво.

Смотрите пример http://radioparty.ru/prog-avr/program-c/455-lesson-matrix-keyboard.

И не совсем понятно, когда написали "через разные резисторы". Приводите схему. Вход Ацп понимает напряжение, поэтому нужен делитель напряжения на резисторах , а не просто резисторы.

И для зажигания светодиодов (лампочек) посмотрите примеры -динамическая индикация.

Ниже вариант схемы

post-201981-0-33900400-1467185550_thumb.jpg

Ссылка на комментарий
Поделиться на другие сайты

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Не по теме - резисторы в примере нужно поставить в цепь каждого светодиода. Иначе яркость будет страдать при включении разного количества светодиодов.

Я не раздаю удочки. Я продаю рыбу.

Ссылка на комментарий
Поделиться на другие сайты

Литиевые аккумуляторы EVE Energy и решения для управления перезаряжаемыми источниками тока (материалы вебинара)

Опубликованы материалы вебинара Компэл, посвященного литиевым аккумуляторам EVE Energy и решениям для управления перезаряжаемыми источниками тока.

На вебинаре мы представили информацию не только по линейкам аккумуляторной продукции EVE, но и по решениям для управления ею, что поможет рассмотреть эти ХИТ в качестве дополнительной альтернативы для уже выпускающихся изделий. Также рассмотрели нюансы работы с производителем и сервисы, предоставляемые Компэл по данной продукции. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Они так и стоят. Это же динамическая индикация, в каждый момент открыт только один транзистор. Впрочем, если диоды маломощные, можно и без транзисторов обойтись, повесить их не порт контроллера.

Можно подтянуть выводы кнопок (PD0-PD3 либо PD4-PD7, зависит от алгоритма) к питанию через резисторы, это увеличит помехозащищенность.

Раз аналоговая часть не используется, конденсатор на AREF не нужен.

maxbelyx, напишите отдельные модули для опроса кнопок и индикации на светодиоды, чтобы они вызывались по таймеру, например. Главное - отдельно от основной программы. Для проверки можете подсвечивать нажатую кнопку, причем код этой подсветки должен быть максимально простым и абстрагированным от железа, что-то вроде

for(i=0;i<4;i++)
 for(j=0;j<4;j++)
   if(button[i][j])led[i][j]=1; else led[i][j]=0;

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

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

void ButtonState(void)
{
// Тушить саму кнопку при нажатии или зажигать, если не горела.
// Тушить все кнопки вокруг нажатой, если горели, зажигать, если нет.
/****BUTTON_1*****/
if (num_ == 1)
{
if (LED1_PIN & (1<<LED1_BIT)) LED1_OFF();
else LED1_ON();
if (LED2_PIN & (1<<LED2_BIT)) LED2_OFF();
else LED2_ON();
if (LED5_PIN & (1<<LED5_BIT)) LED5_OFF();
else LED5_ON();
}
/****BUTTON_2*****/
if (num_== 2)
{
if (LED2_PIN & (1<<LED2_BIT)) LED2_OFF();
else LED2_ON();
if (LED1_PIN & (1<<LED1_BIT)) LED1_OFF();
else LED1_ON();
if (LED3_PIN & (1<<LED3_BIT)) LED3_OFF();
else LED3_ON();
if (LED6_PIN & (1<<LED6_BIT)) LED6_OFF();
else LED6_ON();
}

жесть жестокая...

достаточно завести 16битную переменную типа int биты которой будут соответствовать номеру кнопки и номеру светодиода

для инверсии нужных битов достаточно выполнить операцию "исключающие ИЛИ"

тогда автомат состояний сведется к обычному case с проверкой 17-ти условий

switch (выражение) {
case 0: // все кнопки отжаты
flag_batton=0;
break;
case 1: // нажата кнопка 1
if(!flag_batton)
 {
 flag_batton=1;
 metrix ^= (1<<0)|(1<<1)|(1<<4)|(1<<5);
 }
break;
case 2: // нажата кнопка 2
if(!flag_batton)
 {
 flag_batton=1;
 metrix ^= (1<<0)|(1<<1)|(1<<2)|(1<<4)|(1<<5)|(1<<6);
 }
break;
case 2: // нажата кнопка 2
if(!flag_batton)
 {
 flag_batton=1;
 metrix ^= (1<<1)|(1<<2)|(1<<3)|(1<<5)|(1<<6)|(1<<7);
 }
break;
.......
.......
......
case 10: // нажата кнопка 10
if(!flag_batton)
 {
 flag_batton=1;
 metrix ^= (1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<9)|(1<<10)|(1<<12)|(1<<13)|(1<<14);
 }
break;
.......
.......
default:
последовательность операторов;
}

Ссылка на комментарий
Поделиться на другие сайты

И для зажигания светодиодов (лампочек) посмотрите примеры -динамическая индикация.

Ниже вариант схемы

ТСу для его задачи динамка нах не нужна! у него 16 кнопок и 16 СД для работы нужно 16 выводов , настраиваем порт на выход - светим СД, переключаем на вход читаем состояние батонов.

post-124881-0-97735200-1467296734_thumb.png

итого динамики нет, алгоритм проще, кол-во выводов одинаковое.

Ссылка на комментарий
Поделиться на другие сайты

Зато надо ставить 64 резистора и 16 транзисторов вместо 8 резисторов (для более мощных диодов - 12 резисторов и 4 транзистора). Если и делать предельно простую схему, то на ATmega8515 хотя бы, там как раз выводов хватает, понадобится всего 32 резистора (48 резисторов + 16 транзисторов).

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

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

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

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

ничего она не выиграет, у ТСа кнопки со встроенными лампами

Ссылка на комментарий
Поделиться на другие сайты

Надо с некоторым интервалом опрашивать клавиатуру, а все остальное время осуществлять индикацию, причем переключать с частотой не менее 200 Гц. Та же самая динамическая индикация, только состояний 2 а не 4 - 8 как в другом варианте.

А что не так с кнопками со встроенными лампочками?

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

COKPOWEHEU , ну вы меня удивляете , что бы опросить порты с учетом переключения направления максимум потребуется 10-15маш.циклов , все остальное время светики будут бодро светить пока выполняется код до следующего опроса портов , о какой ДИ вы ведете речь?

Ссылка на комментарий
Поделиться на другие сайты

Для защиты от дребезга опрос контактов стоит делать с равными интервалами и с низкой частотой. Конечно, можно подгонять скорость выполнения основного кода, добавлять делеи и так далее. Но я бы все равно вынес в таймер обработку динамической индикации и кнопок. Либо уж развести на пару портов кнопки а на другую - диоды. Не знаю мощность этих кнопок, но в крайнем случае можно и разобрать чтобы поменять родную лампочку на маломощный диод чтобы обойтись без транзисторов. Ставить 16 транзисторов на такую схему как-то неохота, не говоря о полусотне резисторов.

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

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Спасибо большое за советы. Интересные способы подключения, а главное более рациональные и правильные. В будущем обязательно буду пользоваться :)

Но, проблема в том, что схема уже была разведена и запаяны компоненты, кроме резисторов АЦП. Насчет АЦП - да, действительно, используется резистивный делитель. Вход АЦП притянут через 47кОм к +5В, и все кнопки подключены так, что замыкаются на землю через разные резисторы (от 1кОм до 47кОм с шагом 3кОм). Все резисторы прецизионные. В программе задал диапазоны для кнопок, и протестировал значения АЦП после нагрева резистора паяльником (знаю, не очень разумно, но, какой никакой результат получил). АЦП считывал по UART. Все в принципе работает, не работает только функция GameWin. В чем может быть проблема?

#define F_CPU 16000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "keyboard.h"
#include "leds.h"

void InitADC(void);
void ButtonState(void);
void StartGame(void);
void GameWin(void);
unsigned int ACP;

ISR (ADC_vect)
{
Klava();
}

int main (void)
{
InitADC();

LedsOutput();
Sifra_ = 0;
StartGame();
while(1)
{
if(Sifra_ &(1<<7)) //если 7 бит в 1 то цифра записана
{
Sifra_ &=~ (1<<7); //cброс 7 битав регистре Sifra_, остается код кнопки
}

ButtonState();
//GameWin();
}
}
void StartGame(void)
{
/****Рандомно заданные начальные условия игры****/
}
void ButtonState(void)
{
// Тушить саму кнопку при нажатии или зажигать, если не горела.
// Тушить все кнопки вокруг нажатой, если горели, зажигать, если нет.
/****BUTTON_1*****/
if (Sifra_ == 1)
{
if (LED1_PIN & (1<<LED1_BIT)) LED1_OFF();
else LED1_ON();
if (LED2_PIN & (1<<LED2_BIT)) LED2_OFF();
else LED2_ON();
if (LED5_PIN & (1<<LED5_BIT)) LED5_OFF();
else LED5_ON();
Sifra_=0;
}
*****************************************
}
}
void GameWin()
{
/***Условие выйгрыша - все светодиоды горят****/
if (LED1_PIN & (1<<LED1_BIT), LED2_PIN & (1<<LED2_BIT),
LED3_PIN & (1<<LED3_BIT), LED4_PIN & (1<<LED4_BIT), LED5_PIN & (1<<LED5_BIT),
LED6_PIN & (1<<LED6_BIT), LED7_PIN & (1<<LED7_BIT), LED8_PIN & (1<<LED8_BIT),
LED9_PIN & (1<<LED9_BIT), LED10_PIN & (1<<LED10_BIT), LED11_PIN & (1<<LED11_BIT),
LED12_PIN & (1<<LED12_BIT), LED13_PIN & (1<<LED13_BIT), LED14_PIN & (1<<LED14_BIT),
LED15_PIN & (1<<LED15_BIT), LED16_PIN & (1<<LED16_BIT))
{
WIN_PORT |= (1<<WIN_BIT);
/****Задержка 30 секунд после выйгрыша****/
_delay_ms(30000);
/****Начать игру заново****/
WIN_PORT &= ~(1<<WIN_BIT);
StartGame();
}
}

С уважением,

Максим.

Изменено пользователем maxbelyx
Ссылка на комментарий
Поделиться на другие сайты

Что говорит симуляция и пошаговая отладка?

Выложите весь проект чтобы можно было скомпилировать и проверить. Исправьте орфографические ошибки (один "выЙгрыш" чего стоит!) и отформатируйте код (чтобы не пришлось постоянно следить за скобками для определения какая строчка к какому блоку относится).

Ну и в условии определения "выЙгрыша" логическая операция больно длинная. Наверняка можно сократить до логической операции на нескольких портах, вроде (PORTB & (1<<0 | 1<<1 | 1<<5)) | (PORTC & (1<<4) ); Надеюсь, вызов этой функции закомментирован только в выложенном куске, а не в том, который вы проверяли.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

К сожалению ни симуляцию, ни отладку включить не могу (пользую Eclipse под Linux).

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

Архив прикрепляю, спасибо!

С уважением,

Максим.

Game_Lights.zip

Ссылка на комментарий
Поделиться на другие сайты

Протеус прекрасно работает под wine'ом. Хотя некоторые кнопки и съезжают.

Форматирование ужасно. Особенно отступы и названия переменных и функций. Неужели нельзя было подобрать подходящие английские названия? Так нет ведь, даже оттранслитировано неправильно.

Объявлять глобальные переменные в заголовке - плохая идея.

Sifra_ASP()

{

unsigned int ACP;

ACP = ADCW;

//===========//

if(ACP > 15 && ACP < 23)

return 1;

if(ACP > 75 && ACP < 85)

return 2;

if(ACP > 128 && ACP < 135)

return 3;

Сложновато. Кстати, а где объявлено возвращаемое функцией значение? Проще сделать примерно так

unsigned char ADC2num(unsigned int adc){
if( adc < 50 )return 1; //возможно, стоит определить эти числа как константы, но они используются только здесь, так что это было бы бесполезным усложнением
if( adc < 100 )return 2;
...//отлов неправильных значений АЦП вряд ли нужен. Они и так будут видны.
}

#define LED1_DDR DDRC

#define LED1_BIT PC1

#define LED1_PORT PORTC

#define LED1_PIN PINC

С точки зрения модифицируемости сделано правильно, но можно упростить. Посмотрите мою реализацию pinmacro.h по ссылке в подписи. Тогда достаточно задать LED1 C,1 а остальное сделают макросы. ...и ведь не лень было столько одинаковых определений и процедур писать...
void StartGame(void)

{

/****Рандомно заданные начальные условия игры****/

LED1_ON();

LED2_ON();

LED3_ON();

LED6_OFF();

LED7_OFF();

Лол! Рандом во все поля!

void GameWin(void)

{

if ((LED1_PIN & (0<<LED1_BIT))

Что хотел сказать автор фразой if( PINC & 0 )? Кроме того, установленное изнутри программы состояние выводов лучше проверять через PORT а не через PIN, вам же нужно записанное вами значение, а не то которое оказалось на ножке из-за перегрузки или чего-то еще. Собственно, вот наиболее вероятное место ошибки.
ADCSRA|=(1<<ADEN)|(1<<ADIE)|(1<<ADPS2)|(1<<ADSC)|(1<<ADATE);

ADMUX |=(1<<REFS0);

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

void USART0Init(void)

void USART0SendByte(unsigned char data)

void send_int_Uart(unsigned int c)

А что, у вас используется UART?
if (LED1_PIN & (1<<LED1_BIT)) LED1_OFF();

else LED1_ON();

Удобнее добавить макрос

#define LED_toggle(port, num) port ^= (1<<num)
...
LED_toggle(LED1_PORT, LED1_BIT);

Само собой, еще лучше это сочетается с другими макросами.

Изменено пользователем COKPOWEHEU

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Про функцию считывания АЦП, комментарии и стиль названия переменных писал выше - стащил готовый код с урока на YouTube ничего не меняя.

Проверка по PIN реализована в каждой из Button State и все в порядке работает. ( На всякий случай, конечно же я проверил с помощью PORT - не работает все равно)

UART используется для того, чтобы узнать значения АЦП, возникающие при нажатии на кнопки. Хотя, по коду это итак видно, что и зачем и куда.

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

Столько критики по поводу кода, отступов, комментариев. Спасибо, конечно, но, в чем все таки может быть проблема?

Менять уже 100% рабочую часть кода не вижу смысла. Может быть так правильнее и красивее, я не спорю, но оно работает, и работает хорошо, не работает только одна функция - GameWin, причем, по непонятным мне причинам. Или она не работает из за этого?

Максим.

Изменено пользователем maxbelyx
Ссылка на комментарий
Поделиться на другие сайты

Я же написал, дело в условии.

if ((LED1_PIN & (0<<LED1_BIT))

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

(0<<LED1_BIT) --> (0<<PC1) --> (0<<1) --> 0

LED1_PIN & (0<<LED1_BIT) --> PINC & 0 --> 0

if(LED1_PIN & (0<<LED1_BIT)) --> if(0)

Поэтому повторяю вопрос: что хотел сказать автор этим условием?

.

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

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Понятно. Потыркал программу, видимо я что то снова делаю не так. Каким образом правильно проверить состояние ножки через PORT а не PIN?

Максим.

Изменено пользователем maxbelyx
Ссылка на комментарий
Поделиться на другие сайты

Еще раз: в регистре PORT хранится именно то что туда записали независимо от того что на выводе физически. В PIN, наоборот, что-то записывать бесполезно а считывается физический уровень. Для проверки кнопок надо использовать только PIN, а в вашем случае (когда надо проверять именно записанное значение независимо от схемы) лучше PORT, хотя и PIN не будет ошибкой.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

К сожалению идея с АЦП почти отпала. Несмотря на то, что схема собрана, видимо, ее прийдется переделывать. Из за плохих кнопок и плавающих (сильно!) значений ацп на резисторах стабильно настроить не удается, буквально вечером настроив утром можно все заново перенастраивать. Очевидно, прийдется переделывать на один из предложенных вариантов ниже.

Есть еще вариант такой, но будет ли он лучше? https://www.terraele...ushki.php?ID=42

Или лучше сразу делать что то подобное, что на картинке ниже?

post-197389-0-70370800-1468576046_thumb.jpg

Ссылка на комментарий
Поделиться на другие сайты

В 2008 писал подобную игрушку для ПК на Delphi: Puzzle.rar

Создается массив состояний "лампочек" (получается некое виртуальное игровое поле, которое с помощью процедуры отрисовки переносится на сами "лампочки") (у меня в программе от 2х2 до 100х100)

В процедуре опроса кнопок считывается КООРДИНАТА нажатой кнопки

Для мк:

sg1.Cells — массив состояний "лампочек"

sg1.RowCount — кол-во строк в массиве

sg1.ColCount — кол-во столбцов в массиве

Col, Row — КООРДИНАТА нажатой кнопки (колонка, столбец соответственно)

:='X' :=''; — заполнение массива (1, 0 — "лампочка" горит, не горит соответственно)

Заполнение виртуального игрового поля:

procedure TMForm.SG1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Col,Row:integer; //Это и будет КООРДИНАТА нажатой кнопки
begin
Col:=sg1.MouseCoord(X,Y).X;
Row:=sg1.MouseCoord(X,Y).Y;
if Button=mbLeft then
begin
 if (col=0) and (row=0) then //проверка углов игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col+1,row]='' then
	 sg1.Cells[col+1,row]:='X'
	 else
	 sg1.Cells[col+1,row]:='';
	 if sg1.Cells[col,row+1]='' then
	 sg1.Cells[col,row+1]:='X'
	 else
	 sg1.Cells[col,row+1]:='';
 end;

 if (col=0) and (row>0) and (row<sg1.RowCount-1) then //проверка сторон игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col+1,row]='' then
	 sg1.Cells[col+1,row]:='X'
	 else
	 sg1.Cells[col+1,row]:='';
	 if sg1.Cells[col,row+1]='' then
	 sg1.Cells[col,row+1]:='X'
	 else
	 sg1.Cells[col,row+1]:='';
	 if sg1.Cells[col,row-1]='' then
	 sg1.Cells[col,row-1]:='X'
	 else
	 sg1.Cells[col,row-1]:='';
 end;

 if (col=0) and (row=sg1.RowCount-1) then //проверка углов игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col+1,row]='' then
	 sg1.Cells[col+1,row]:='X'
	 else
	 sg1.Cells[col+1,row]:='';
	 if sg1.Cells[col,row-1]='' then
	 sg1.Cells[col,row-1]:='X'
	 else
	 sg1.Cells[col,row-1]:='';
 end;

 if (col>0) and (col<sg1.ColCount-1) and (row=0) then //проверка сторон игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col+1,row]='' then
	 sg1.Cells[col+1,row]:='X'
	 else
	 sg1.Cells[col+1,row]:='';
	 if sg1.Cells[col,row+1]='' then
	 sg1.Cells[col,row+1]:='X'
	 else
	 sg1.Cells[col,row+1]:='';
	 if sg1.Cells[col-1,row]='' then
	 sg1.Cells[col-1,row]:='X'
	 else
	 sg1.Cells[col-1,row]:='';
 end;

 if (col>0) and (col<sg1.ColCount-1) and (row>0) and (row<sg1.RowCount-1) then //проверка середины игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col+1,row]='' then
	 sg1.Cells[col+1,row]:='X'
	 else
	 sg1.Cells[col+1,row]:='';
	 if sg1.Cells[col,row+1]='' then
	 sg1.Cells[col,row+1]:='X'
	 else
	 sg1.Cells[col,row+1]:='';
	 if sg1.Cells[col-1,row]='' then
	 sg1.Cells[col-1,row]:='X'
	 else
	 sg1.Cells[col-1,row]:='';
	 if sg1.Cells[col,row-1]='' then
	 sg1.Cells[col,row-1]:='X'
	 else
	 sg1.Cells[col,row-1]:='';
 end;

 if (col>0) and (col<sg1.ColCount-1) and (row=sg1.RowCount-1) then //проверка сторон игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col+1,row]='' then
	 sg1.Cells[col+1,row]:='X'
	 else
	 sg1.Cells[col+1,row]:='';
	 if sg1.Cells[col,row-1]='' then
	 sg1.Cells[col,row-1]:='X'
	 else
	 sg1.Cells[col,row-1]:='';
	 if sg1.Cells[col-1,row]='' then
	 sg1.Cells[col-1,row]:='X'
	 else
	 sg1.Cells[col-1,row]:='';
 end;

 if (col=sg1.ColCount-1) and (row=0) then //проверка углов игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col-1,row]='' then
	 sg1.Cells[col-1,row]:='X'
	 else
	 sg1.Cells[col-1,row]:='';
	 if sg1.Cells[col,row+1]='' then
	 sg1.Cells[col,row+1]:='X'
	 else
	 sg1.Cells[col,row+1]:='';
 end;

 if (col=sg1.ColCount-1) and (row>0) and (row<sg1.RowCount-1) then //проверка сторон игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col-1,row]='' then
	 sg1.Cells[col-1,row]:='X'
	 else
	 sg1.Cells[col-1,row]:='';
	 if sg1.Cells[col,row+1]='' then
	 sg1.Cells[col,row+1]:='X'
	 else
	 sg1.Cells[col,row+1]:='';
	 if sg1.Cells[col,row-1]='' then
	 sg1.Cells[col,row-1]:='X'
	 else
	 sg1.Cells[col,row-1]:='';
 end;

 if (col=sg1.ColCount-1) and (row=sg1.RowCount-1) then //проверка углов игрового поля
 begin
	 if sg1.Cells[col,row]='' then
	 sg1.Cells[col,row]:='X'
	 else
	 sg1.Cells[col,row]:='';
	 if sg1.Cells[col-1,row]='' then
	 sg1.Cells[col-1,row]:='X'
	 else
	 sg1.Cells[col-1,row]:='';
	 if sg1.Cells[col,row-1]='' then
	 sg1.Cells[col,row-1]:='X'
	 else
	 sg1.Cells[col,row-1]:='';
 end;
end;
end;

Проверка выигрыша (заполненность игрового поля) :

procedure TMForm.SG1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
LFlg:boolean;
i,j:integer;
begin
LFlg:=true;
for i:=0 to sg1.ColCount-1 do
for j:=0 to sg1.RowCount-1 do
 if sg1.Cells[i,j]='' then
 LFlg:=false;
if LFlg then
begin
 ShowMessage('Congratulation!'+#13#10+'You WIN!!!');
//Очистка игрового поля
 for i:=0 to sg1.ColCount-1 do
 for j:=0 to sg1.RowCount-1 do
	 sg1.Cells[i,j]:='';
end;
end;

Ссылка на комментарий
Поделиться на другие сайты

Именно приведенная схема не заработает, базы VT3, VT4 висят на аналоговых входах. Если я правильно помню, переключить их на выход невозможно. Лучше пожертвуйте точностью тактовой частоты (вместо кварца встроенный RC-генератор) и повесьте на PORTB.

Какова мощность лампочек? Может там и транзисторы не нужны. По даташиту максимальный ток вывода 40 мА, это по 10 мА на диод, это довольно много, учитывая что индикаторному диоду хватает 1 мА.

При желании можно объединить выбор строки (столбца) кнопок с динамической индикацией строки (столбца) диодов, но там надо поаккуратнее со схемой.

Самое простое - использовать микросхему с достаточным количеством выводов, хотя бы ATmega8515, тогда динамическая индикация не понадобится.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...