Кодовый замок

Anonymous write:
"Думаю актуальным будет направление про охранные устройства:
- кодовый замок с клавиатурой 4х4, с lcd(и без), с возможностью смены кода с клавиатуры.
в качестве исполнительного устройства использовать соленоид или движок от центрального замка автомобиля"

vakula по этой теме когда-то писал здесь: https://avrlab.com/node/85
Повторюсь:
"Давай условимся, что код у нас только цифровой, т.е. состоит из цифр от 0 до 9. В примере сделана клавиатура с кнопками "Backspace" и "Сброс", что облегчает задачу. Теперь нужно добавить функционал: "при нажатии клавиши "С" кодовый замок сверяет введенный код с кодом, разрешающим доступ, и если они совпадают - отпирает какое-то там реле и т.д.". Отобразим наши рассуждения в коде:

  1. #include <avr/io.h>
  2. #include <avr/interrupt.h>
  3.  
  4. #define NUMBER_SIZE 6 //Максимальная разрядность числа
  5.  
  6. #define RS 2 //RS=PD2
  7. #define E 3 //E=PD3
  8.  
  9. #define TIME 10 //временная константа для ЖКИ
  10. //Тактовая частота 4Mhz
  11.  
  12. #define CODE 123456 //Код нашего кодового замка
  13.  
  14. unsigned char key_code[4][4]={{'C','D','E','F'},
  15. {'B','3','6','9'},
  16. {'A','2','5','8'},
  17. {'0','1','4','7'}}; //Коды клавиш
  18.  
  19. unsigned char row[NUMBER_SIZE]={}; //массив, который содержит нажатые клавиши
  20. unsigned char row_counter=0; //количество нажатых клавиш
  21.  
  22. unsigned long int number=0; //Число морганий курсора
  23.  
  24. void pause (unsigned int a)
  25. { unsigned int i;
  26.  
  27. for (i=a;i>0;i--)
  28. ;
  29. }
  30.  
  31. //Передача команды ЖКИ
  32. void lcd_com (unsigned char lcd)
  33. { unsigned char temp;
  34.  
  35. temp=(lcd&~(1<<RS))|(1<<E); //RS=0 – это команда
  36. PORTD=temp; //Выводим на portD старшую тетраду команды, сигналы RS, E
  37. asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
  38. PORTD=temp&~(1<<E); //Сигнал записи команды
  39.  
  40. temp=((lcd*16)&~(1<<RS))|(1<<E); //RS=0 – это команда
  41. PORTD=temp; //Выводим на portD младшую тетраду команды, сигналы RS, Е
  42. asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
  43. PORTD=temp&~(1<<E); //Сигнал записи команды
  44.  
  45. pause (10*TIME); //Пауза для выполнения команды
  46. }
  47.  
  48. //Запись данных в ЖКИ
  49. void lcd_dat (unsigned char lcd)
  50. { unsigned char temp;
  51.  
  52. temp=(lcd|(1<<RS))|(1<<E); //RS=1 – это данные
  53. PORTD=temp; //Выводим на portD старшую тетраду данных, сигналы RS, E
  54. asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
  55. PORTD=temp&~(1<<E); //Сигнал записи данных
  56.  
  57. temp=((lcd*16)|(1<<RS))|(1<<E); //RS=1 – это данные
  58. PORTD=temp; //Выводим на portD младшую тетраду данных, сигналы RS, E
  59. asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
  60. PORTD=temp&~(1<<E); //Сигнал записи данных
  61.  
  62. pause(TIME); //Пауза для вывода данных
  63. }
  64.  
  65. //Иниализация ЖКИ
  66. void lcd_init (void)
  67. {
  68. lcd_com(0x2c); //4-проводный интерфейс, 5x8 размер символа
  69. pause(100*TIME);
  70. lcd_com(0x0c); //Показать изображение, курсор не показывать
  71. pause(100*TIME);
  72. lcd_com(0x01); //Очистить DDRAM и установить курсор на 0x00
  73. pause (100*TIME);
  74. }
  75.  
  76.  
  77. void init_timer (void)
  78. {
  79. TIMSK=(1<<TOIE0); //Разрешить прерывания по переполнению таймера0
  80. TCCR0=(1<<CS00)|(1<<CS01)|(0<<CS02); //Делитель =/64
  81. }
  82.  
  83. //Проверка, является ли х цифрой, если да результат =1, иначе результат =0
  84. unsigned char is_digit (unsigned char x)
  85. {
  86. if ((x>='0')&&(x<='9')) return 1;
  87. else return 0;
  88. }
  89.  
  90. //Конвертирует "row" в int значение number
  91. void get_number(void)
  92. { unsigned char i;
  93. number=0;
  94. for (i=0;i<row_counter;i++)
  95. {
  96. number=number*10;
  97. number=number+row[i]-0x30;
  98. }
  99. }
  100.  
  101. //Пишем row на ЖКИ
  102. void write_row (void)
  103. { unsigned char i;
  104.  
  105. lcd_com(0x86); //Перейдем в начало
  106. for (i=0;i<row_counter;i++) //Пишем row
  107. lcd_dat(row[i]);
  108. for(i=row_counter;i<NUMBER_SIZE;i++) //Очистим незаполненные ячейки
  109. lcd_dat(' ');
  110. }
  111.  
  112. ISR (TIMER0_OVF_vect)
  113. { unsigned char i,j;
  114.  
  115. DDRC=0x00; //PortC как вход
  116. PORTC=0x0f;
  117. DDRB=0x0f; //PortB как выход
  118. PORTB=0x00;
  119.  
  120. pause(10); //Задержка для устренения всяких переходных процессов, важно ее не забыть!
  121. i=4;
  122. if ((PINC&0x01)==0x00) i=0; //Если нажата клавиша в 0й колонке, i=0
  123. if ((PINC&0x02)==0x00) i=1; //...
  124. if ((PINC&0x04)==0x00) i=2;
  125. if ((PINC&0x08)==0x00) i=3;
  126.  
  127. DDRC=0x0f; //PortC как выход
  128. PORTC=0x00;
  129. DDRB=0x00; //PortB как вход
  130. PORTB=0x0f;
  131.  
  132. pause(10); //Задержка для устренения всяких переходных процессов, важно ее не забыть!
  133. j=4;
  134. if ((PINB&0x01)==0x00) j=0; //Если нажата клавиша в 0й строке, j=0
  135. if ((PINB&0x02)==0x00) j=1; //...
  136. if ((PINB&0x04)==0x00) j=2;
  137. if ((PINB&0x08)==0x00) j=3;
  138.  
  139. if ((i!=4)&&(j!=4))
  140. { //Если была нажата клавиша
  141. while ((PINB&_BV(j))==0x00) //Ждем отжатия
  142. ;
  143.  
  144. if ((is_digit(key_code[i][j])==1)&& //Нажата цифра и не достигнут лимит в NUMBER_SIZE
  145. (row_counter<NUMBER_SIZE)) { //Добавить в row и увеличить row_counter
  146. row[row_counter]=key_code[i][j];
  147. row_counter++;
  148. }
  149. if (key_code[i][j]=='F') row_counter=0x00; //Если нажата 'F' очищаем row
  150. if ((key_code[i][j]=='E')&&
  151. (row_counter>0x00)) row_counter--; //Если нажата 'E'
  152. //и есть введенные цифры – удалить последнюю
  153. if (key_code[i][j]=='C') { //Если нажата 'C' тогда сверяем number и код доступа замка
  154. get_number();
  155. if (number==CODE) {
  156. //отпираем замок
  157. }
  158. }
  159. }
  160. write_row(); //Пишем row на ЖКИ
  161. }
  162. TCNT0=0x00; //Очищаем таймер и флаг переполнения
  163. TIFR=0x00;
  164.  
  165. return;
  166. }
  167.  
  168. int main(void)
  169. {
  170. DDRD=0xfc; //Инициализация PortD
  171. PORTD=0x00;
  172.  
  173. pause(1000); //Задержка для включения ЖКИ
  174. lcd_init(); //Инициализация ЖКИ
  175. init_timer(); //Инициализация нулевого таймера
  176. lcd_dat('D'); //Напишем на ЖКИ "Data= "
  177. lcd_dat('a');
  178. lcd_dat('t');
  179. lcd_dat('a');
  180. lcd_dat('=');
  181. lcd_dat(' ');
  182.  
  183. sei(); //Разрешения прерываний
  184.  
  185. while(1) //Вечный цикл
  186. ;
  187.  
  188. return 1;
  189. }

Как видно, от последнего макета прошивка отличается строками 152-168. Также был добавлен #define в строку 12.

ИМХО: изменения кода доступа с клавиатуры как-то неправильно. Код доступа должен зашиваться, или выставляться какими-то джамперами, минипереключателями, чтобы у злоумышленника не было возможности открыть замок, кроме как ввести правильный код."

hex

Афтор добавь пожалуйсто файл прошивки.

Афтар пишет, что какбэ в

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

Почитай как сделать hex

Почитай как сделать hex прошивку, автор вряд ли найдет время. Верней если все-таки автор не отпишется, попробуй сам сделай файл прошивки.

спасибо собрал все как

спасибо собрал все как написано в статье, работает