Наверное, вы в своей жизни на различных выборах видели специальные машины для голосования. В этой статье мы постараемся собрать упрощенную модель подобной машины на микроконтроллере ATmega32A (семейство AVR). На данном микроконтроллере можно собрать машину для голосования 32 людей, однако в целях упрощения мы в данной статье ограничимся схемой для голосования 4 людей. У нас будет 4 кнопки для 4 людей и всегда, когда кнопка будет нажата, голос от соответствующего человека будет засчитан и количество голосов от каждого человека будет показываться на жидкокристаллическом (ЖК) дисплее.
Необходимые компоненты
Аппаратное обеспечение
- Микроконтроллер ATmega32 (купить на AliExpress).
- Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
- JHD_162ALCD (ЖК дисплей 16x2) (купить на AliExpress).
- Конденсатор 100 нФ (5 шт.) (купить на AliExpress).
- Конденсатор 100 мкФ (соединенный по питанию) (купить на AliExpress).
- Кнопки (5 шт.).
- Резистор 10 кОм (5 шт.) (купить на AliExpress).
- Источник питания с напряжением 5 Вольт.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Программное обеспечение
- Atmel Studio версии 6.1 (или выше).
- Progisp или flash magic (необязательно).
Работа схемы
Схема устройства представлена на следующем рисунке.
Как видно из представленной схемы, PORTA микроконтроллера ATmega32 соединен с портом данных ЖК дисплея 16x2 (более подробно о подключении ЖК дисплея к микроконтроллеру ATmega32 можно прочитать в этой статье. Но следует помнить о том, что необходимо деактивировать интерфейс JTAG (отладки микроконтроллера) при помощи изменения фьюзов (fuse bytes) если вы хотите использовать PORTC в качестве обычного коммуникационного порта. В ЖК дисплее (если мы не хотим использовать черный цвет) можно задействовать только 14 его контактов: 8 контактов для передачи данных (7-14 или D0-D7), 2 контакта для подачи питания (1&2 или VSS&VDD или gnd&+5v), 3-й контакт для управления контарстностью, 3 контакта для управления (RS&RW&E).
В представленной схеме мы использовали только 2 контакта управления для лучшего понимания работы схемы. Бит контраста и READ/WRITE используются нечасто, поэтому они могут быть замкнуты на землю. Это обеспечивает ЖК дисплею максимальную контрастность и переводит его в режим чтения. Теперь нам всего лишь нужно контролировать контакты ENABLE и RS чтобы передать на ЖК дисплей символы и данные.
В схеме необходимо сделать следующие соединения с ЖК дисплеем:
PIN1 или VSS - земля
PIN2 или VDD или VCC - +5v питание
PIN3 или VEE - земля (обеспечивает максимальный контраст ЖК дисплею)
PIN4 или RS (Register Selection) – контакт PD6 микроконтроллера
PIN5 или RW (Read/Write) - земля (переводит ЖК дисплей в режим чтения что упрощает взаимодействие с ним для начинающих)
PIN6 или E (Enable) - контакт PD5 микроконтроллера
PIN7 или D0 - контакт PA0 микроконтроллера
PIN8 или D1 - контакт PA1 микроконтроллера
PIN9 или D2 - контакт PA2 микроконтроллера
PIN10 или D3 - контакт PA3 микроконтроллера
PIN11 или D4 - контакт PA4 микроконтроллера
PIN12 или D5 - контакт PA5 микроконтроллера
PIN13 или D6 - контакт PA6 микроконтроллера
PIN14 или D7 - контакт PA7 микроконтроллера
В схеме мы использовали 8-битную связь (D0-D7) ЖК дисплея с микроконтроллером, хотя можно было ограничиться и 4-битной – но в этом случае код программы стал бы немного сложнее.
Таким образом, мы использовали 10 контактов ЖК дисплея, 8 из которых будут использоваться для передачи данных и 2 для управления. 4 кнопки на схеме используются для подсчета (увеличения) числа голосов кандидатов и пятая кнопка – для сброса числа голосов.
Конденсаторы на схеме предназначены для устранения эффектов биений, возникающих при нажатии кнопок. Если их убрать, то микроконтроллер в некоторых случаях будет фиксировать более одного нажатия кнопки, хотя кнопка была нажата всего один раз. Резисторы, подсоединенные к контактам микроконтроллера, служат для ограничения тока во время нажатий на кнопки.
Во время нажатия кнопки на соответствующий контакт микроконтроллера подается "земля" и таким образом микроконтроллер распознает что кнопка была нажата и выполняет в связи с этим определенное действие: увеличивает число голосов кандидата или сбрасывает все голоса (в зависимости от того какая кнопка была нажата).
При нажатии кнопки, соответствующей какому-нибудь человеку, микроконтроллер распознает это и увеличивает соответствующую переменную в своей памяти, затем передает значение этой переменной на ЖК дисплей 16x2.
Исходный код программы на языке C (Си) с пояснениями
Программа для рассматриваемой схемы представлена следующим фрагментом кода. Комментарии к коду программу поясняют принцип работы отдельных команд.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
/* C Program for AVR Microcontroller Based Electronic Voting Machine */ #include <avr/io.h> //заголовок чтобы разрешить контроль данных на контактах #define F_CPU 1000000 //задание тактовой частоты #include <util/delay.h> //заголовок чтобы задействовать функции задержки в программе #define E 5 //задействуем 5-й контакт PORTD (“enable”), поскольку он соединен с контактом “enable” ЖК дисплея #define RS 6 //задействуем выбор регистра (“registerselection”) на 6-м контакте PORTD, поскольку он соединен с контактом RS ЖК дисплея void send_a_command(unsigned char command); void send_a_character(unsigned char character); int main(void) { DDRA = 0xFF; //установка porta и port d в качестве выходных контактов DDRD = 0xFF; _delay_ms(50); //задержка в 50ms DDRB = 0; //установка portB на ввод. int16_t COUNTA = 0; // число голосов от персоны 1 char SHOWA [16]; // отображаемый символ голосования персоны 1 на ЖК дисплее int16_t COUNTB = 0; // число голосов от персоны 2 char SHOWB [16]; // отображаемый символ голосования персоны 2 на ЖК дисплее int16_t COUNTC = 0; // число голосов от персоны 3 char SHOWC [16]; // отображаемый символ голосования персоны 3 на ЖК дисплее int16_t COUNTD = 0; // число голосов от персоны 4 char SHOWD [16]; // отображаемый символ голосования персоны 4 на ЖК дисплее send_a_command(0x01); //очистить экран ЖК дисплея 0x01 = 00000001 _delay_ms(50); send_a_command(0x38); // говорим ЖК дисплею что мы будем использовать 8-битный режим команд/данных _delay_ms(50); send_a_command(0b00001111); //включаем экран и мигание курсора на ЖК дисплее while(1) { send_a_string ("A="); // отображение имени персоны 1 send_a_command(0x80 + 2); // сдвигаем курсор на 3-ю позицию itoa(COUNTA,SHOWA,10); // устанавливаем номер переменной на ЖК дисплее, используем базу 10 send_a_string(SHOWA); // говорим дисплею чтобы он отобразил символ send_a_command(0x80 + 8); // сдвигаем курсор на 9-ю позицию send_a_string ("B="); // отображение имени персоны 2 send_a_command(0x80 + 10); // сдвигаем курсор на 11-ю позицию itoa(COUNTB,SHOWB,10); //command for putting variable number in LCD(variable number, in which character to replace, which base is variable(ten here as we are counting number in base10)) send_a_string(SHOWB); // говорим дисплею чтобы он отобразил символ. send_a_command(0x80 + 0x40 + 0); // сдвигаем курсор на 1-ю позицию второй строки send_a_string ("C="); // отображение имени персоны 3 send_a_command(0x80 + 0x40 + 2); // сдвигаем курсор на 3-ю позицию второй строки itoa(COUNTC,SHOWC,10); send_a_string(SHOWC); send_a_command(0x80 + 0x40 + 8); // сдвигаем курсор на 9-ю позицию второй строки send_a_string ("D="); // отображение имени персоны 4 send_a_command(0x80 + 0x40 + 10); // сдвигаем курсор на 11-ю позицию второй строки itoa(COUNTD,SHOWD,10); send_a_string(SHOWD); send_a_command(0x80 + 0); // сдвигаем курсор на 0-ю позицию if (bit_is_clear(PINB,0))// когда нажата кнопка 1 { COUNTA++; // увеличение числа голосов первой персоны на единицу } if (bit_is_clear(PINB,1)) // когда нажата кнопка 2 { COUNTB++; // увеличение числа голосов второй персоны на единицу } if (bit_is_clear(PINB,2)) // когда нажата кнопка 3 { COUNTC++; // увеличение числа голосов третьей персоны на единицу } if (bit_is_clear(PINB,3)) // когда нажата кнопка 4 { COUNTD++; // увеличение числа голосов четвертой персоны на единицу } if (bit_is_clear(PINB,4)) // когда нажата кнопка 5 { COUNTA=COUNTB=COUNTC=COUNTD=0; // очистка голосов всех персон } } } void send_a_command(unsigned char command) { PORTA = command; PORTD &= ~ (1<<RS); // установка 0 на контакте RS чтобы сообщить ЖК дисплею что мы будем передавать команду PORTD |= 1<<E; // говорим ЖК дисплею принять команду _delay_ms(50); PORTD &= ~1<<E; // сообщаем ЖК дисплею что мы закончили передачу команды PORTA= 0; } void send_a_character(unsigned char character) { PORTA= character; PORTD |= 1<<RS; // сообщаем ЖК дисплею что мы будем передавать данные PORTD |= 1<<E; // говорим ЖК дисплею что мы начали передачу данных _delay_ms(50); PORTD &= ~1<<E; // сообщаем ЖК дисплею что мы закончили передачу данных PORTA = 0; } void send_a_string(char *string_of_characters) { while(*string_of_characters > 0) { send_a_character(*string_of_characters++); } } |
Здравствуйте. При попытке компиляции выдало несколько ошибок. Первый в строке 44, лишняя скобка с точкой запятой, вторая в конце кода лишняя закрывающая скобка и главное, ругается на строку send_a_string. Не явное объявление функции. Скрипт так и не смог запустить 🙁
Добрый вечер, да, к сожалению в строке 44 имелась лишняя скобка с запятой, сейчас исправлю. Код функции send_a_string сейчас тоже добавлю в код программы, почему то здесь она была пропущена