Наверное, вы в своей жизни на различных выборах видели специальные машины для голосования. В этой статье мы постараемся собрать упрощенную модель подобной машины на микроконтроллере ATmega32A (семейство AVR). На данном микроконтроллере можно собрать машину для голосования 32 людей, однако в целях упрощения мы в данной статье ограничимся схемой для голосования 4 людей. У нас будет 4 кнопки для 4 людей и всегда, когда кнопка будет нажата, голос от соответствующего человека будет засчитан и количество голосов от каждого человека будет показываться на жидкокристаллическом (ЖК) дисплее.

Необходимые компоненты
Аппаратное обеспечение
- Микроконтроллер ATmega32 (купить на AliExpress).
- Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
- JHD_162ALCD (ЖК дисплей 16x2) (купить на AliExpress).
- Конденсатор 100 нФ (5 шт.) (купить на AliExpress).
- Конденсатор 100 мкФ (соединенный по питанию) (купить на AliExpress).
- Кнопки (5 шт.) (купить на AliExpress).
- Резистор 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 (Си) с пояснениями
Программа для рассматриваемой схемы представлена следующим фрагментом кода. Комментарии к коду программу поясняют принцип работы отдельных команд.
/*
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 сейчас тоже добавлю в код программы, почему то здесь она была пропущена