Опрос матричной клавиатуры.

Обсуждаем контроллеры компании Atmel.
Ответить
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

Доброе время суток. Есть код опроса матричной клавиатуры и вывода данных на LCD дисплей. У автора он работал. Я внёс не большое изменения, переключил строки на другой порт и теперь как бы я не старался, код не работает. С автором связаться не смог так как статья 24.08.2013 года. Может кто поможет понять ошибку? Сам код и схема :
Спойлер

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

#include <mega8.h>
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>

int i=0,j=0;
char portStateC[4]= {0xEF,0xDF,0xBF,0x7F};
char inputStateD[4]={0x01,0x02,0x04,0x08};
char mass2[4][4]={{'1','2','3','4'},
                  {'5','6','7','8'},
                  {'9','A','B','C'},
                  {'D','E','F','D'}};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{ 
    for(i=0; i<4; i++)
    { 
       PORTD=portStateC[i];
       for(j=0; j<4; j++)
       { 
          if(((PIND&inputStateD[j])==0) && (PINC&inputStateD[j]))
          {
             while((PIND&inputStateD[j])!=inputStateD[j]){};
             lcd_putchar(mass2[i][j]);                                     
          }  
       }                          
    }  
}

void main(void)
{


PORTC=0xFF;
DDRC=0x0F;


PORTD=0xFF;
DDRD=0xF0;


ASSR=0x00;
TCCR2=0x0F;
TCNT2=0x00;
OCR2=0xC3;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x80;


lcd_init(8);

// Global enable interrupts
#asm("sei")
while (1)
      {
      
      };
}
Изображение

Добавил файлы проекта.
Вложения
key4x4.zip
(18.74 КБ) 94 скачивания
Последний раз редактировалось azerhud Пт июл 22, 2022 09:30:37, всего редактировалось 2 раза.
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Проект вместе с протеусом сюда, в архив zip, иначе ни кто вам этот код разбирать не будет.
Реклама
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32

Сообщение Martian »

char portStateC[4]= {0xEF,0xDF,0xBF,0x7F}; здесь смещение нуля в старших разрядах, но в схеме подключено к младшим.
char inputStateD[4]={0x01,0x02,0x04,0x08}; здесь смещение единицы в младших разрядах, но в схеме подключено к старшим.
PORTD=portStateC здесь к D происходит подключение того, что для C, и 1это вроде бы делает логичным нелогичное выше, но нелогично в целом.
if(((PIND&inputStateD[j])==0) && (PINC&inputStateD[j])) - inputStateD как бы намекает, что это для сравнения с D как со входом... но: выше уже всё было перепутано, а тут внезапно сравнивается и PIND и PINC...

И всё это вообще неважно: по схеме порт D является входом для сигнала с порта C. В порту C в младших четырёх разрядах должна бегать единичка, притом, цикл из 4 итераций не нужен, лучше поднять частоту срабатывания таймера. И массив для перемещения единичким тоже не нужен, есть прекрасные короткие сдвиги. А в программе всё наоборот и в кашу
Контактная информация:
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

Здесь подправил.

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

char portStateC[4]= {0xFE,0xFD,0xFB,0xF7};
char inputStateD[4]={0x01,0x20,0x40,0x80};

//...

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    for(i=0; i<4; i++)
    {
       PORTC=portStateC[i];
       for(j=0; j<4; j++)
       {
          if(((PIND&inputStateD[j])==0) && (PINC&inputStateD[j]))
          {
             while((PIND&inputStateD[j])!=inputStateD[j]){};
             lcd_putchar(mass2[i][j]);                                     
          } 
       }                         
    } 
}
//...
Но похоже опять я сделал что то не так
Последний раз редактировалось azerhud Пт июл 22, 2022 13:59:44, всего редактировалось 1 раз.
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32

Сообщение Martian »

А я тоже ошибся, в логике. Прошу прощения.
Сканирующим портом всё-таки является порт D и там должен бегать лог. 0 - тогда при нажатии двух и более кнопок исключается закорачивание выходов, если бы сканирование было на порту С

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

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

char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
//...
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    for(i=0; i<4; i++)
    {
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       {
          //...
       }                         
    }
}
то есть, осталось всего лишь правильно определить во втором цикле, где на порту С образовался 0.
Кстати, порт С должен обязательно быть сконфигурирован с внутренней подтяжкой к питанию.
например, так:

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

char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
//...
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    for(i=0; i<4; i++)
    {
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       {
          if(!(PORTС & (1 << j))
          {
                   //здесь получили координаты i и j кнопки
           }
       }                         
    }
}
Контактная информация:
Реклама
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

Не совсем понял этот момент.
[uquote="Martian",url="/forum/viewtopic.php?p=4263505#p4263505"]...
то есть, скан должен быть так (как и было в самом начале, за исключением несовпадающих по логике наименований):

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

char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
//...
    
[/uquote]

мне нужно дважды задать этот массив?

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

har portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
Весь код.
Спойлер

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

#include <mega8.h>
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

int i = 0, j = 0;
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08};
char mass2[4][4] = {{'1', '2', '3', '4'},
	{'5', '6', '7', '8'},
	{'9', 'A', 'B', 'C'},
	{'D', 'E', 'F', 'D'}
};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
	for(i = 0; i < 4; i++)
		{
		PORTD = portStateD[i];
		for(j = 0; j < 4; j++)
			{
			if((!(PORTC) & (1 << j)))
				{
				if(((PIND & inputStateC[j]) == 0) && (PINC & inputStateC[j]))
					{
					while((PIND & inputStateC[j]) != inputStateC[j]) {};
					lcd_putchar(mass2[i][j]);
					}
				}
			}
		}
}

void main(void)
{


	PORTC = 0xFF;
	DDRC = 0x0F;


	PORTD = 0xFF;
	DDRD = 0xF0;


	ASSR = 0x00;
	TCCR2 = 0x0F;
	TCNT2 = 0x00;
	OCR2 = 0xC3;

	// Timer(s)/Counter(s) Interrupt(s) initialization
	TIMSK = 0x80;


	lcd_init(8);

	// Global enable interrupts
#asm("sei")
	while (1)
		;
}
Реклама
Вымогатель припоя
Сообщения: 599
Зарегистрирован: Ср янв 06, 2010 10:01:46

Сообщение metan »

Вам же дали готовую процедуру
Вот так попробуйте

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

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
  for(i = 0; i < 4; i++) {
    PORTD = portStateD[i];
    for(j = 0; j < 4; j++) {
     if((!(PINC) & (1 << j)))
       lcd_putchar(mass2[i][j]);
    }
  }
}
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F}; //только один раз, конечно нужно объявлять
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08}; // в предлагаемом варианте вообще не нужен

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

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

// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P 
PORTB=0xFF;
DDRB=0x00;
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

Уже не знаю что делать, вроде перепробовал все Ваши варианты.
Спойлер

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

#include <mega8.h>
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

int i = 0, j = 0;
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};

char mass2[4][4] = {{'1', '2', '3', '4'},
   {'5', '6', '7', '8'},
   {'9', 'A', 'B', 'C'},
   {'D', 'E', 'F', 'D'}
};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
  for(i = 0; i < 4; i++) {
    PORTD = portStateD[i];
    for(j = 0; j < 4; j++) {
     if((!(PINC) & (1 << j)))
       lcd_putchar(mass2[i][j]);
    }
  }
}

void main(void)
{      
   DDRC = 0x0F; // Единица младших разрядах, порт настроен как выход, 
   PORTC = 0xFF; // Включаем подтягивающие резисторы

   DDRD = 0xF0; // Ноль младших разрядах, порт настроен как вход,
   PORTD = 0xFF; // Включаем подтягивающие резисторы

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;


   lcd_init(8);

   // Global enable interrupts
#asm("sei")
   while (1)
      ;
}
Опишу проблему. Исходная статья по адресу http://avr-start.ru/?p=1244&cpage=1#comments
Всё работает отлично, но мне нужно подключить клавиатуру 4х5 и передавать символы нажатой кнопки по UART. Для этого я и решил разделить строки и столбцы. Но как бы я не пытался не удаётся мне запустить программу. Может найдётся человек который напишет мне рабочую программу с подробным описанием. Готов заплатить. Бюджет не большой :(

У самого уже мозги кипят. :(
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Спойлер

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

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08};
char mass2[4][4] = {{'1', '2', '3', '4'},
   {'5', '6', '7', '8'},
   {'9', 'A', 'B', 'C'},
   {'D', 'E', 'F', 'D'}
};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{   char i,j;
    for(i=0; i<4; i++)
    { 
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       { 
          if(((PINC&inputStateC[j])==0))
          {
             while((PINC&inputStateC[j])!=inputStateC[j]){};
             lcd_putchar(mass2[i][j]);                                     
          }  
       }                          
    }  
}

void main(void)
{     
   DDRC = 0x00; 
   PORTC = 0xFF; 

   DDRD = 0xF0; 
   PORTD = 0xFF; 

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;

   lcd_init(8);

#asm("sei")
   while (1)
      ;
}
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

Dimon456, Огромное СПАСИБО за помощь
Вымогатель припоя
Сообщения: 599
Зарегистрирован: Ср янв 06, 2010 10:01:46

Сообщение metan »

azerhud писал(а): DDRC = 0x0F; // Единица младших разрядах, порт настроен как выход,
   PORTC = 0xFF; // Включаем подтягивающие резисторы
metan писал(а):И да, вам еще сказали, что младшие линии порта опроса (PORTC) должны быть настроены на вход с подтяжкой. И посмотрите, как у вас.
Dimon456 писал(а): DDRC = 0x00;
   PORTC = 0xFF;
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

metan, Dimon456, Спасибо. Пытаюсь поставить плюс но мне сообщают что менять карму ещё рано.

Добавлено after 1 hour 9 minutes 44 seconds:
Вроде всё получилось благодаря Вам.
Схема проекта.
Изображение

Код проекта:
Спойлер

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

#include <mega8.h>
#include <delay.h>
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[5] = {0x01, 0x02, 0x04, 0x08, 0x10};
char key;
int temp = 0;
char mass2[4][5] =
{
	{'1', '2', '3', '4', '5'},
	{'6', '7', '8', '9', '0'},
	{'A', 'B', 'C', 'D', 'E'},
	{'F', 'G', 'I', 'K', 'L'}

};
//отправка символа по usart`у
void USART_SendChar(unsigned char sym)
{
	while(!(UCSRA & (1 << UDRE)));
	UDR = sym;
}



interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
	char i, j;
	for(i = 0; i < 4; i++)
		{
		PORTD = portStateD[i];
		for(j = 0; j < 5; j++)
			{
			if(((PINC & inputStateC[j]) == 0))
				{
				while((PINC & inputStateC[j]) != inputStateC[j]) {};
				lcd_putchar(mass2[i][j]);
				key = (mass2[i][j]);
				temp = 1;
				}
			}
		}
}

void main(void)
{
	DDRC = 0x00;
	PORTC = 0xFF;

	DDRD = 0xF0;
	PORTD = 0xFF;

	//инициализация USART`a
	UBRRH = 0;
	UBRRL = 51; //скорость обмена 9600 бод при Fcpu = 8MГц
	UCSRB = (1 << TXEN); // разр передачи.
	UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); //размер слова 8 разрядов

	ASSR = 0x00;
	TCCR2 = 0x0F;
	TCNT2 = 0x00;
	OCR2 = 0xC3;

	TIMSK = 0x80;

	lcd_init(16);
    PORTB.3=0;

#asm("sei")
	while(1)
		{
		//если зафиксировано нажатие,
		//отправить код кнопки в терминал
		if ((key) && (temp == 1))
			{
             DDRD |= 1<<2;
			USART_SendChar(key);

			temp = 0;
            delay_ms(200);
            DDRD &= ~(1<<2);
			}
		}
}
Если не трудно, проверьте пожалуйста, нет ли ошибок и недочётов.

;)
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

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

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

   PORTC = 0x0F;
   DDRC = 0x00;

   PORTD = 0xF0 | (1<<2) ;
   DDRD = 0xF0;
Переменная temp должна быть объявлена как volatile, так как изменяется в прерывании, да и не зачем ее int делать, то есть volatile char , если переменная будет принимать значение 0 и 1, то достаточно ее объявить как volatile bit

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

volatile bit temp = 0;
Какой смысл проверять key?

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

if ((key) && (temp == 1))
Вы с key дальше ни чего не делаете.
Достаточно проверить

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

if (temp == 1)
У вас массив mass2 объявлен как тип char, соответственно функция USART_SendChar() должна так же принимать тип char

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

void USART_SendChar(char sym)
С MAX487 я не работал, не знаю как правильно, подскажут другие.
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

Всё что смог на данный момент:
Изображение
Спойлер

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

#include <mega8.h>
#include <delay.h>

// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[5] = {0x01, 0x02, 0x04, 0x08, 0x10};
char key;
volatile bit temp = 0;

char mass2[4][5] = {
	{'1', '2', '3', '4', '5'},
	{'6', '7', '8', '9', '0'},
	{'A', 'B', 'C', 'D', 'E'},
	{'F', 'G', 'I', 'K', 'L'}

};
//отправка символа по usart`у
void USART_SendChar(char sym)
{
	while(!(UCSRA & (1 << UDRE)));
	UDR = sym;
}



interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
	char i, j;
	for(i = 0; i < 4; i++) {
		PORTD = portStateD[i];
		for(j = 0; j < 5; j++) {
			if(((PINC & inputStateC[j]) == 0)) {
				while((PINC & inputStateC[j]) != inputStateC[j]) {};

				key = (mass2[i][j]);

				switch(key) {
					case '1':  lcd_puts("TOT"); delay_ms(500); lcd_clear(); break;
					case '2':  lcd_puts("TIM"); delay_ms(500); lcd_clear(); break;
					case '3':  lcd_puts("DAY"); delay_ms(500); lcd_clear(); break;
					case '4':  lcd_puts("MTH"); delay_ms(500); lcd_clear(); break;
					case '5':  lcd_puts("RES"); delay_ms(500); lcd_clear(); break;
					case '6':  lcd_puts("COU"); delay_ms(500); lcd_clear(); break;
					case '7':  lcd_puts("1"); break;
					case '8':  lcd_puts("4"); break;
					case '9':  lcd_puts("7"); break;
					case '0':  lcd_puts("*"); delay_ms(500); lcd_clear(); break;
					case 'A':  lcd_puts("<"); delay_ms(500); lcd_clear(); break;
					case 'B':  lcd_puts("2"); break;
					case 'C':  lcd_puts("5"); break;
					case 'D':  lcd_puts("8"); break;
					case 'E':  lcd_puts("0"); break;
					case 'F':  lcd_puts(">"); delay_ms(500); lcd_clear(); break;
					case 'G':  lcd_puts("3"); break;
					case 'I':  lcd_puts("6"); break;
					case 'K':  lcd_puts("9"); break;
					case 'L':  lcd_puts(" OK"); break;
				}
				temp = 1;
			}
		}
	}
}

void main(void)
{
	PORTC = 0x0F;
	DDRC = 0x00;

	PORTD = 0xF0 | (1 << 2) ;
	DDRD = 0xF0;

	//инициализация USART`a
	UBRRH = 0;
	UBRRL = 51; //скорость обмена 9600 бод при Fcpu = 8MГц
	UCSRB = (1<<RXEN) | (1<<TXEN); // разр приём и передачи.
	UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); //размер слова 8 разрядов

	ASSR = 0x00;
	TCCR2 = 0x0F;
	TCNT2 = 0x00;
	OCR2 = 0xC3;

	TIMSK = 0x80;

	lcd_init(16);
	PORTB.3 = 0;

#asm("sei")
	while(1) {
		//если зафиксировано нажатие,
		//отправить код кнопки в терминал
		if(temp == 1) {
			DDRD |= 1 << 2;
			USART_SendChar(key);
			temp = 0;
			delay_ms(200);
			DDRD &= ~(1 << 2);
			if((key == '5') || (key == 'L')) {
				delay_ms(500);
				lcd_clear();
			}
		}
	}
}
Вложения
key201_main.zip
(32.59 КБ) 86 скачиваний
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32

Сообщение Martian »

for(j = 0; j < 5; j++) можно переписать так, что inputStateC станет лишним, а значит, и тройное обращение к нему в условиях - тоже.
Контактная информация:
Вымогатель припоя
Сообщения: 599
Зарегистрирован: Ср янв 06, 2010 10:01:46

Сообщение metan »

Martian писал(а):for(j = 0; j < 5; j++) можно переписать
Это конечно, так, но это пустяки по сравнению с конскими задержками внутри прерывания, как мне кажется :)
Я бы перенес проверку значения key внутрь главного цикла.
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

Пока только так смог:
Спойлер

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

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
	char i, j;
	for(i = 0; i < 4; i++) {
		PORTD = portStateD[i];
		for(j = 0; j < 5; j++) {
			if(((PINC & inputStateC[j]) == 0)) {
				while((PINC & inputStateC[j]) != inputStateC[j]) {};

				key = (mass2[i][j]);

				switch(key) {
					case '1': lcd_clear(); lcd_puts("TOT");   break;
					case '2': lcd_clear(); lcd_puts("TIM");   break;
					case '3': lcd_clear(); lcd_puts("DAY");   break;
					case '4': lcd_clear(); lcd_puts("MTH");   break;
					case '5': lcd_clear(); lcd_puts("RES");  break;
					case '6': lcd_clear(); lcd_puts("COU");   break;
					case '7':  lcd_puts("1"); break;
					case '8':  lcd_puts("4"); break;
					case '9':  lcd_puts("7"); break;
					case '0':  lcd_puts("*");   break;
					case 'A':  lcd_puts("<");   break;
					case 'B':  lcd_puts("2"); break;
					case 'C':  lcd_puts("5"); break;
					case 'D':  lcd_puts("8"); break;
					case 'E':  lcd_puts("0"); break;
					case 'F':  lcd_puts(">");   break;
					case 'G':  lcd_puts("3"); break;
					case 'I':  lcd_puts("6"); break;
					case 'K':  lcd_puts("9"); break;
					case 'L': lcd_clear(); lcd_puts(" OK"); break;
				}
				temp = 1;
			}
		}
	}
}
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

azerhud, вот такой код, поиграйся
Спойлер

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

#include <mega8.h>
#include <delay.h>

// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08};

char mass2[4][4] = {{'1', '2', '3', '4'},
   {'5', '6', '7', '8'},
   {'9', 'A', 'B', 'C'},
   {'D', 'E', 'F', 'D'}
};

//отправка символа по usart`у
void USART_SendChar(char sym)
{
   while(!(UCSRA & (1 << UDRE)));
   UDR = sym;
}

#include <string.h>

#define MAX_DMA_BUFFERS_COUNT 16     // 4 8 16 32 64 128
#define BUFFER_MASK (MAX_DMA_BUFFERS_COUNT-1)
volatile unsigned char BUFF_RX_BUF[MAX_DMA_BUFFERS_COUNT]={0};
volatile unsigned char DMA_WR_BUF = 0;
volatile unsigned char DMA_RD_BUF = 0;

// Timer 2 output compare interrupt service routine
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{   char key;
    
    char i,j;
    for(i=0; i<4; i++)
    { 
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       { 
          if(((PINC&inputStateC[j])==0))
          {
             while((PINC&inputStateC[j])!=inputStateC[j]){};
             key = (mass2[i][j]);
             
		    DMA_WR_BUF++;
		    DMA_WR_BUF &= BUFFER_MASK; 
            
            BUFF_RX_BUF[DMA_WR_BUF] = key;  
       }                          
    }  
  }
}

void main(void)
{  char key_x;

   PORTC = 0x0F;
   DDRC = 0x00;

   PORTD = 0xF0 | (1 << 2) ;
   DDRD = 0xF0;

   //инициализация USART`a
   UBRRH = 0;
   UBRRL = 51; //скорость обмена 9600 бод при Fcpu = 8MГц
   UCSRB = (1<<RXEN) | (1<<TXEN); // разр приём и передачи.
   UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); //размер слова 8 разрядов

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;

   lcd_init(16);
   PORTB.3 = 0;
   
#asm("sei")

   while(1)
   {
      //если зафиксировано нажатие      
      while (DMA_RD_BUF != DMA_WR_BUF) {

            DMA_RD_BUF++;
	    DMA_RD_BUF &= BUFFER_MASK;
	    
            key_x = BUFF_RX_BUF[DMA_RD_BUF];

            switch(key_x) {
               case '1':  lcd_puts("TOT"); delay_ms(500); lcd_clear(); break;
               case '2':  lcd_puts("TIM"); delay_ms(500); lcd_clear(); break;
               case '3':  lcd_puts("DAY"); delay_ms(500); lcd_clear(); break;
               case '4':  lcd_puts("MTH"); delay_ms(500); lcd_clear(); break;
               case '5':  lcd_puts("RES"); delay_ms(500); lcd_clear(); break;
               case '6':  lcd_puts("COU"); delay_ms(500); lcd_clear(); break;
               case '7':  lcd_puts("1"); break;
               case '8':  lcd_puts("4"); break;
               case '9':  lcd_puts("7"); break;
               case '0':  lcd_puts("*"); delay_ms(500); lcd_clear(); break;
               case 'A':  lcd_puts("<"); delay_ms(500); lcd_clear(); break;
               case 'B':  lcd_puts("2"); break;
               case 'C':  lcd_puts("5"); break;
               case 'D':  lcd_puts("8"); break;
               case 'E':  lcd_puts("0"); break;
               case 'F':  lcd_puts(">"); delay_ms(500); lcd_clear(); break;
               case 'G':  lcd_puts("3"); break;
               case 'I':  lcd_puts("6"); break;
               case 'K':  lcd_puts("9"); break;
               case 'L':  lcd_puts(" OK"); break;
            }          

           DDRD |= 1 << 2;
           USART_SendChar(key_x);
           delay_ms(200);
           DDRD &= ~(1 << 2);
           if((key_x == '5') || (key_x == 'L')) {
            delay_ms(500);
            lcd_clear();
           }        
        } 
        
   };        
         
}



Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Чт июл 21, 2022 15:37:28

Сообщение azerhud »

[uquote="Dimon456",url="/forum/viewtopic.php?p=4268575#p4268575"]вот такой код, поиграйся[/uquote]
Спасибо. Применил Ваш код.
Но боюсь вновь намудрил.
Спойлер

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

//*** Пример работы с USART интерфейсом микроконтроллеров AVR ***

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

#define BAUDRATE 9600 // Скорость обмена данными
#define F_CPU 8000000UL // Рабочая частота контроллера
#define PAUSE PAUSE_ms(100);
#include <string.h>

#define MAX_DMA_BUFFERS_COUNT 16     // 4 8 16 32 64 128
#define BUFFER_MASK (MAX_DMA_BUFFERS_COUNT-1)
volatile unsigned char BUFF_RX_BUF[MAX_DMA_BUFFERS_COUNT] = {0};
volatile unsigned char DMA_WR_BUF = 0;
volatile unsigned char DMA_RD_BUF = 0;

unsigned char NUM = 0;
unsigned char count = 0;
unsigned char byte_receive = 0;
unsigned char i = 1;
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[5] = {0x01, 0x02, 0x04, 0x08, 0x10};
char key;
volatile int temp = 0;

char mass2[4][5] =
{
	{'1', '2', '3', '4', '5'},
	{'6', '7', '8', '9', '0'},
	{'A', 'B', 'C', 'D', 'E'},
	{'F', 'G', 'I', 'K', 'L'}

};

// Функция задержки в мкс
void PAUSE_us(unsigned char time_us)
{
	register unsigned char i;

	for(i = 0; i < time_us; i++)
		{
		asm volatile(" PUSH  R0 ");
		asm volatile(" POP   R0 ");
		}
}

// Функция задержки в мс
void PAUSE_ms(unsigned int time_ms)
{
	register unsigned int i;

	for(i = 0; i < time_ms; i++)
		{
		PAUSE_us(250);
		PAUSE_us(250);
		PAUSE_us(250);
		PAUSE_us(250);
		}
}

#define RS PB2
#define EN PB3

// Функция передачи команды
void lcd_com(unsigned char p)
{
	PORTB &= ~(1 << RS); // RS = 0 (запись команд)
	PORTB |= (1 << EN); // EN = 1 (начало записи команды в LCD)
	PORTB &= 0x0F; PORTB |= (p & 0xF0); // старший нибл
	PAUSE_us(100);
	PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
	PAUSE_us(100);
	PORTB |= (1 << EN); // EN = 1 (начало записи команды в LCD)
	PORTB &= 0x0F; PORTB |= (p << 4); // младший нибл
	PAUSE_us(100);
	PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
	PAUSE_us(100);
}

// Функция передачи данных
void lcd_data(unsigned char p)
{
	PORTB |= (1 << RS) | (1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
	PORTB &= 0x0F; PORTB |= (p & 0xF0); // старший нибл
	PAUSE_us(100);
	PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
	PAUSE_us(100);
	PORTB |= (1 << EN); // EN = 1 (начало записи команды в LCD)
	PORTB &= 0x0F; PORTB |= (p << 4); // младший нибл
	PAUSE_us(100);
	PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
	PAUSE_us(100);
}

// Функция инициализации LCD
void lcd_init(void)
{
	PAUSE_ms(50); // Ожидание готовности ЖК-модуля

	// Конфигурирование четырехразрядного режима
	PORTB |= (1 << PB5);
	PORTB &= ~(1 << PB4);

	// Активизация четырехразрядного режима
	PORTB |= (1 << EN);
	PORTB &= ~(1 << EN);
	PAUSE_ms(5);

	lcd_com(0x28); // шина 4 бит, LCD - 2 строки
	lcd_com(0x08); // полное выключение дисплея
	lcd_com(0x01); // очистка дисплея
	PAUSE_us(100);
	lcd_com(0x06); // сдвиг курсора вправо
	lcd_com(0x0C); // включение дисплея, курсор не видим
}

// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
	lcd_com(0x0C);
	lcd_com(command);
	while(*string != '\0')
		{
		lcd_data(*string);
		string++;
		}
}

// Функция передачи данных по USART
void uart_send(char data)
{
	while(!( UCSRA & (1 << UDRE)));   // Ожидаем когда очистится буфер передачи
	UDR = data; // Помещаем данные в буфер, начинаем передачу
}

// Функция передачи строки по USART
void str_uart_send(char *string)
{
	while(*string != '\0')
		{
		uart_send(*string);
		string++;
		}
}

// Функция приема данных по USART
int uart_receive(void)
{
	while(!(UCSRA & (1 << RXC))); // Ожидаем, когда данные будут получены
	return UDR; // Читаем данные из буфера и возвращаем их при выходе из подпрограммы
}

// Функция инициализации USART
void uart_init(void)
{
	// Параметры соединения: 8 бит данные, 1 стоповый бит, нет контроля четности
	// USART Приемник: Включен
	// USART Передатчик: Включен
	// USART Режим: Асинхронный
	// USART Скорость обмена: 9600

	UBRRL = (F_CPU / BAUDRATE / 16 - 1); // Вычисляем скорость обмена данными
	UBRRH = (F_CPU / BAUDRATE / 16 - 1) >> 8;

	UCSRB |= (1 << RXCIE) | // Разрешаем прерывание по завершению приема данных
			 (1 << RXEN) | (1 << TXEN); // Включаем приемник и передатчик

	UCSRC |= (1 << URSEL) | // Для доступа к регистру UCSRC выставляем бит URSEL
			 (1 << UCSZ1) | (1 << UCSZ0); // Размер посылки в кадре 8 бит
}

// Прерывание по окончанию приема данных по USART
ISR(USART_RXC_vect)
{
	NUM = UDR; // Принимаем символ по USART
	byte_receive = 1;
	uart_send(NUM); // Посылаем символ по USART


}

ISR(TIMER2_COMP_vect)
{
	char key;

	int i, j;
	for(i = 0; i < 4; i++)
		{
		PORTD = portStateD[i];
		for(j = 0; j < 5; j++)
			{
			if(((PINC & inputStateC[j]) == 0))
				{
				while((PINC & inputStateC[j]) != inputStateC[j]) {};
				key = (mass2[i][j]);

				DMA_WR_BUF++;
				DMA_WR_BUF &= BUFFER_MASK;

				BUFF_RX_BUF[DMA_WR_BUF] = key;
				}
			}
		}


	temp = 1;
}

// Главная функция
int main(void)
{
	char key_x;

	PORTC = 0x1F;
	DDRC = 0x00;

	PORTD = 0xF0 | (1 << 2) ;
	DDRD = 0xF0;
        
	DDRB  = 0b11111110;
	PORTB = 0x00;


	ASSR = 0x00;
	TCCR2 = 0x0F;
	TCNT2 = 0x00;
	OCR2 = 0xC3;

	TIMSK = 0x80;

	lcd_init(); // Инициализация LCD
	uart_init(); // Инициализация USART

	sei(); // Глобально разрешаем прерывания

	str_uart_send("Initialization system\r\n"); // Передаем строку по USART
	lcd_string(0x80, " AVR USART TEST "); // Выводим строку на LCD
	PAUSE_ms(2500);
	lcd_com(0x01); // Очищаем LCD

	while(1)
		{

		while (DMA_RD_BUF != DMA_WR_BUF)
			{

			DMA_RD_BUF++;
			DMA_RD_BUF &= BUFFER_MASK;

			key_x = BUFF_RX_BUF[DMA_RD_BUF];

			switch(key_x)
				{
				case '1':  str_uart_send( "1"); lcd_string(0x80, "TOT"); PAUSE_ms(500); lcd_com(0x01);  break;
				case '2':  str_uart_send( "2");  lcd_string(0x80, "TIM"); PAUSE_ms(500); lcd_com(0x01);  break;
				case '3':  str_uart_send( "3"); lcd_string(0x80, "DAY"); PAUSE_ms(500); lcd_com(0x01);  break;
				case '4':  str_uart_send( "4");  lcd_string(0x80, "MTH"); PAUSE_ms(500); lcd_com(0x01);  break;
				case '5':  str_uart_send( "5");  lcd_string(0x80, "RES"); PAUSE_ms(500); lcd_com(0x01);  break;
				case '6':  str_uart_send( "6");  lcd_string(0x80, "COU"); PAUSE_ms(500); lcd_com(0x01);  break;
				case '7':  str_uart_send( "7"); lcd_string(0x80, "1"); PAUSE_ms(500); break;
				case '8':  str_uart_send( "8"); lcd_string(0x80, "4"); PAUSE_ms(500); break;
				case '9':  str_uart_send( "9"); lcd_string(0x80, "7"); PAUSE_ms(500); break;
				case '0':  str_uart_send( "0"); lcd_string(0x80, "*"); PAUSE_ms(500);  PAUSE_ms(500); lcd_com(0x01);  break;
				case 'A':  str_uart_send( "A");  lcd_string(0x80, "<"); PAUSE_ms(500); PAUSE_ms(500); lcd_com(0x01);  break;
				case 'B':  str_uart_send( "B"); lcd_string(0x80, "2"); PAUSE_ms(500); break;
				case 'C':  str_uart_send( "C"); lcd_string(0x80, "5"); PAUSE_ms(500); break;
				case 'D':  str_uart_send( "D"); lcd_string(0x80, "8"); PAUSE_ms(500); break;
				case 'E':  str_uart_send( "E"); lcd_string(0x80, "0"); PAUSE_ms(500); break;
				case 'F':  str_uart_send( "F");  lcd_string(0x80, ">"); PAUSE_ms(500);  PAUSE_ms(500); lcd_com(0x01);  break;
				case 'G':  str_uart_send( "G"); lcd_string(0x80, "3"); PAUSE_ms(500); break;
				case 'I':  str_uart_send( "I"); lcd_string(0x80, "6"); PAUSE_ms(500); break;
				case 'K':  str_uart_send( "K"); lcd_string(0x80, "9"); PAUSE_ms(500); break;
				case 'L':  str_uart_send( "L"); lcd_string(0x80, " OK"); PAUSE_ms(500); PAUSE_ms(500); lcd_com(0x01);  break;

				}


			if(byte_receive)
				{
				byte_receive = 0;
				count++;
				//USART_SendChar(key_x);
				lcd_data(NUM); // Выводим символ на LCD
				if(count > 16) // Если строка заполнена
					{
					count = 0;
					lcd_com(0x01); // Очищаем LCD
					}
				}
			}
		}
}
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

azerhud писал(а):Но боюсь вновь намудрил.
Да уж, намудрили так намудрили.
Особенно Функцию задержки, откуда вы это только берете?
У avr-gcc и так нормальный delay.
Ответить

Вернуться в «AVR»