Управление матричной клавиатурой и светодиодами в разных временных и световых режимах, отслеживание количества цепей питания.
1 Настоящее руководство предназначено для изучения принципа действия и технических характеристик электронного пульта-имитатора (далее по тексту – пульта-имитатора).
2 Ток потребления от источника постоянного тока 12 В — не более 120 мА.
3 Пульт-имитатор обеспечивает имитацию 11 шлейфов, из них:
— 7 охранных с состояниями НОРМА, ОБРЫВ;
— 1 пожарный с состояниями НОРМА, КЗ, ОБРЫВ, ДЫМ, ТЕПЛО;
— 2 контролируемых шлейфа выходных ключей с состояниями НОРМА, КЗ, ОБРЫВ;
— 1 шлейф датчика прибытия патруля с состояниями ОБРЫВ и КЗ (или НОРМА, при снятой перемычке XS3).
4.1 Пульт-имитатор представляет собой электронное устройство с микропроцессорным управлением. В качестве выходных ключей используется микросхема ULN2003AD, а для контролируемых шлейфов оптрон 4N25.
4.2 На крышке пульта-имитатора находятся следующие органы управления и индикации:
— клавиатура с кнопками “1” — “8”, “КШ” для индивидуального выбора шлейфов, “НОРМА”, “КЗ”, “ОБРЫВ”, “ТЕПЛ”, “ДЫМ” для перевода шлейфов в соответствующее состояние, “ПАТР” для управления шлейфом датчика прибытия патруля;
— индикаторы “ВСВ (ВЫХ5)”, “СОП (ВЫХ1)”, “СИР (ВЫХ2)”, “ДОП (ВЫХ3)”, “ПОЖАР (ВЫХ4)”, “Пож. оповещ.”, “РПДУ” для индикации состояния выходных ключей приборов, “1” — “8”, “КШ” для индикации состояния шлейфов, “+12В” для индикации включения питания внешних нагрузок;
— тумблер “+12В” – “Вкл.” для включения питания внешних нагрузок;
4.3 Индикаторы “1” — “8”, “КШ” отображают состояние выбора следующим образом: зеленый мигает с частотой 4 раза в секунду.
4.4 Индикаторы “1” — “6”, “8” отображают состояние соответствующих шлейфов следующим образом:
— НОРМА: зеленый горит постоянно;
— КЗ, ОБРЫВ: красный мигает с частотой 1 раз в секунду (фактически, в обоих случаях шлейф в состоянии ОБРЫВ).
4.5 Индикатор “7” отображает состояние пожарного шлейфа следующим образом:
— НОРМА: зеленый горит постоянно;
— КЗ, ОБРЫВ: красный 0,2 секунды, не горит 0,2 секунды, красный 0,2 секунды, не горит 4,4 секунды;
— ДЫМ: красный 0,2 секунды, не горит 4,8 секунды;
— ТЕПЛО: красный мигает с частотой 1 раз в секунду.
4.6 Индикатор “КШ” отображает состояние контролируемых шлейфов выходных ключей следующим образом:
— НОРМА: зеленый горит постоянно;
— КЗ: красный горит постоянно;
— ОБРЫВ: не горит.
4.7 Индикатор “КШ” отображает состояние шлейфа датчика прибытия патруля следующим образом:
— ОБРЫВ: отображает состояние контролируемых шлейфов выходных ключей;
— КЗ (или НОРМА, при снятой перемычке XS3): оранжевый горит постоянно;
4.8 Индикатор “КШ” отображает ошибки залипания клавиатуры следующим образом:
— ошибка залипания в разных колонках одной строки: красный 0,125 секунды, не горит 0,125 секунды, красный 0,125 секунды, не горит 0,125 секунды, красный 0,125 секунды, не горит 0,5 секунды, т.е., пачками по 3 импульса;
— ошибка залипания одной или более кнопок в разных строках в течение 5 секунд: красный 0,125 секунды, не горит 0,25 секунды, красный 0,125 секунды, не горит 0,5 секунды, т.е., пачками по 2 импульса.
При обоих типах залипаний, в случае восстановления работоспособности клавиатуры, через 5 секунд индикатор “КШ” возвращается в предыдущее состояние и возобновляется возможность управления.
4.9 Однократное нажатие кнопок “1” — “8”, “КШ” приводит к выбору соответствующего шлейфа, при этом одноименный индикатор горит зеленым 0,125 секунды, не горит 0,125 секунды. Повторное нажатие приводит к отмене выбора, а индикатор отображает предшествующее состояние.
При наличии выбранных шлейфов нажатие кнопок “НОРМА”, “КЗ”, “ОБРЫВ”, “ТЕПЛ”, “ДЫМ” влияет только на эти шлейфы. При отсутствии выбранных шлейфов нажатие кнопок “НОРМА”, “КЗ”, “ОБРЫВ” влияет на все шлейфы. Кнопки “ТЕПЛ”, “ДЫМ” влияют только на 7 шлейф.
Кнопка “ПАТР” последовательно переводит шлейф датчика прибытия патруля в состояние КЗ (или НОРМА, при снятой перемычке XS3), ОБРЫВ.
4.11 После подачи питания на пульт-имитатор производится тестирование индикаторов “1” — “8”, “КШ” путем последовательного включения сначала зеленым, затем красным на время 0,2 секунды.
После тестирования индикаторов производится проверка количества подключенных цепей “GND” и “+12В” посредством измерения напряжения на делителе. Количество подключенных цепей “GND” соответствует количеству включенных постоянно красным индикаторов “1” — “5”. В случае понижения напряжения ниже расчетного предела индикатор “5” мигает красным с частотой 1 раз в секунду.
Количество подключенных цепей “+12В” соответствует количеству включенных постоянно красным индикаторов “7”, “8”. В случае повышения напряжения выше расчетного предела индикатор “8” мигает красным с частотой 1 раз в секунду.
Переход в рабочий режим осуществляется нажатием любой кнопки.
Скачать схему в разных форматах и исходник для P-CAD 2006 можно здесь:
Схемы пульта-имитатора (74 Загрузки)P-CAD 2006 можно скачать здесь:
PCAD_2006 (74 Загрузки)Проект для IAR EWAAVR 6.3.3.1990 (думается, что лишнюю A вколотил в листинги) можно скачать здесь:
STAND_PI_CONNECTOR.rar (13 Загрузок)Потерялся IAR EWAVR 6.3.3.1990, остался ewavr511b_full, но он не потянул проект, как и ожидалось. Можно было все переформатировать, исходники в наличии, но хотелось все упростить. День гуглил. Неработающие архивы. Не стоит пренебрегать Яндексом. Скачал ewavr-6121_full.
Скачать ewavr-6121_full
ewavr-6121_full.rar (22 Загрузки)Буду использовать этот код в части АЦП, индикации и управления для проекта автономной зарядки аккумуляторов для смартфона. Пишут, что некоторые аккумуляторы не имеют встроенного ограничителя уровня.
Исходники программ на C
main.c
/*! \file ********************************************************************
*
* \li File: main.c
* \li Compiler: IAR EWAAVR 6.3.3.1990
*
* \li Supported devices: ATmega32 16 MHz
*
*
* $Revision: 4
* $Date: Июнь 11, 2014 $
****************************************************************************/
#include <ioavr.h>
#include <inavr.h>
#include <stdio.h>
#include "pgmspace.h"
#include "stand_PI.h"
#include "timer0_comp.c"
#include "timer1_compa.c"
#include "init.c"
#include "ser_write.c"
#include "adc.c"
#include "uart.c"
int main( void )
{
init_ports();
init_timer0();
init_timer1();
init_UART();
currled = 0;
adc_init();
for (ii = 0; ii < 9; ii++) mode_hs[ii] = 0; //или изменить при объявлении
for (ii = 0; ii < 9; ii++) new_mode_hs[ii] = 1;
__enable_interrupt();
__delay_cycles(DELAY_TEST);
for (ii = 0; ii < 9; ii++)
{
mode_hs[ii] = 5;
new_mode_hs[ii] = 1;
__delay_cycles(DELAY_TEST);
mode_hs[ii] = 0;
new_mode_hs[ii] = 1;
__delay_cycles(ZERO);
}
for (ii = 0; ii < 9; ii++) mode_hs[ii] = 0;
for (ii = 0; ii < 9; ii++) new_mode_hs[ii] = 1;
__delay_cycles(DELAY_TEST);
for (ii = 0; ii < 9; ii++)
{
mode_hs[ii] = 0x0C;
new_mode_hs[ii] = 1;
__delay_cycles(DELAY_TEST);
mode_hs[ii] = 0;
new_mode_hs[ii] = 1;
__delay_cycles(ZERO);
}
ADMUX = (0 << REFS1)|(1 << REFS0)|(0 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(1 << MUX2)|(1 << MUX1)|(0 << MUX0);
//6 канал
adc1();
if (adc_gnd < 933) // < 4,5 V 1 с/д кр.
{
mode_hs[0] = 0x0C;
new_mode_hs[0] = 1;
if (adc_gnd < 800) // < 3,9 V 2 с/д кр.
{
mode_hs[1] = 0x0C;
new_mode_hs[1] = 1;
if (adc_gnd < 690) // < 3,35 V 3 с/д кр.
{
mode_hs[2] = 0x0C;
new_mode_hs[2] = 1;
if (adc_gnd < 611) // < 2,95 V 4 с/д кр.
{
mode_hs[3] = 0x0C;
new_mode_hs[3] = 1;
if (adc_gnd < 555) // < 2,65 V 5 с/д кр.
{
mode_hs[4] = 0x0C;
new_mode_hs[4] = 1;
if (adc_gnd < 400) // < 2 V 5 с/д кр. - не горит
{
mode_hs[4] = 6;
new_mode_hs[4] = 1;
}
}
}
}
}
}
ADMUX = (0 << REFS1)|(1 << REFS0)|(0 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(1 << MUX0);
//5 канал
adc1();
if (adc_gnd > 410) // > 2 V 7 с/д кр.
{
mode_hs[6] = 0x0C;
new_mode_hs[6] = 1;
if (adc_gnd > 720) // > 3,5 V 8 с/д кр.
{
mode_hs[7] = 0x0C;
new_mode_hs[7] = 1;
if (adc_gnd > 940) // > 4,5 V 8 с/д кр. - не горит
{
mode_hs[7] = 6;
new_mode_hs[7] = 1;
}
}
}
while (key_status != 2);
key_status = 0;
for (ii = 0; ii < 9; ii++) mode_hs[ii] = 5;
for (ii = 0; ii < 9; ii++) new_mode_hs[ii] = 1;
adc_init();
__enable_interrupt();
for (;;)
{
if ((adc_new_status == 1) && (curr_adc_buf == 0))
{
PORTD |= (1 << PD2);
UDR = 0xAA;
UCSRB |= (1 << UDRIE);
}
if ((key_err > 0) && (key_err_count == 0))
{
key_err_count = 1;
ks_temp = mode_hs[8];
if (key_err == 1) mode_hs[8] = 0x0D;
//залипание 1 - длительное нажатие одной или в разных колонках и строках
if (key_err == 2) mode_hs[8] = 0x0F;
//залипание 2 - в разных колонках и одинаковой строке
//if (key_err == 3) mode_hs[15] = 0x0F;
new_mode_hs[8] = 1;
}
if (key_err_count == 10)
{
//printf_P(f_col, col);
key_count = 0;//?????
mode_hs[8] = ks_temp;
new_mode_hs[8] = 1;//
key_err = 0;
key_err_count = 0;
}
if (ser_break == 1)
{
for (ii = 0; ii < 8; ii++)
{
mode_hs[ii] = 6;
shift_reg &= ~(1 << sh_reg_arr[ii]);
ser_write();
for (j = 0; j < 9; j++)
{
{
new_mode_hs[j] = 1;
}
}
__delay_cycles(SER_BR);
}
key_status = 0;
ser_break = 0;
}
if (key_status == 2) //считывание кода кнопки прошло успешно
{
if (key_curr < 9) // key_curr - код кнопки
{
if (mode_hs[key_curr] != 4)
{
mode_hs_temp[key_curr] = mode_hs[key_curr];
mode_hs[key_curr] = 4;
}
else
{
mode_hs[key_curr] = mode_hs_temp[key_curr];
}
}
else
{
all_key = 0; //нет выбранных шлейфов
for (ii = 0; ii < 9; ii++)
{
if (mode_hs[ii] == 4)
{
all_key = 1;
}
}
switch (key_curr)
{
case 9: //НОРМА
for (ii = 0; ii < 9; ii++)
{
if ((mode_hs[ii] == 4) || (all_key == 0))
{
mode_hs[ii] = 5; //в любом случае
if (ii == 6)
{
PORTA &= ~((1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA7));
// Отключение резисторов нарушений пож. шлейфа //была ошибка PORTB
shift_reg |= (1 << 7);// НОРМА пож. шлейфа
//ser_write();
}
else if (ii == 8) // КШ
{
PORTD |= (1 << PD4);
PORTD &= ~(1 << PD3);
}
else shift_reg |= (1 << sh_reg_arr[ii]);
}
}
break;
case 10: //КЗ
for (ii = 0; ii < 9; ii++)
{
if ((mode_hs[ii] == 4) || (all_key == 0))
{
if (ii == 6) // КЗ пож. шлейфа
{
mode_hs[ii] = 8;
shift_reg &= ~(1 << 7);
PORTA &= ~((1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA7)); //была ошибка PORTB
PORTA |= (1 << PA7);//была ошибка PORTB
}
else if (ii == 8) // КШ
{
mode_hs[ii] = 0x0C;
PORTD |= (1 << PD4);
PORTD |= (1 << PD3);
}
else
{
mode_hs[ii] = 6;
shift_reg &= ~(1 << sh_reg_arr[ii]);
}
}
}
break;
case 11: //ОБРЫВ
for (ii = 0; ii < 9; ii++)
{
if ((mode_hs[ii] == 4) || (all_key == 0))
{
if (ii == 6)
{
mode_hs[ii] = 8;
shift_reg &= ~(1 << 7);
//ser_write();
PORTA &= ~((1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA7)); //была ошибка PORTB
PORTA |= (1 << PA2); //была ошибка PORTB
}
else if (ii == 8)
{
mode_hs[ii] = 0;
PORTD &= ~(1 << PD3);
PORTD &= ~(1 << PD4);
}
else
{
mode_hs[ii] = 6;
shift_reg &= ~(1 << sh_reg_arr[ii]);
}
}
}
break;
case 12: //ТЕПЛО
if ((mode_hs[6] == 4) || (all_key == 0))
{
mode_hs[6] = 0x0B;
shift_reg &= ~(1 << 7);
//ser_write();
PORTA &= ~((1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA7)); //была ошибка PORTB
PORTA |= (1 << PA0); //была ошибка PORTB
}
break;
case 13: //ДЫМ
if ((mode_hs[6] == 4) || (all_key == 0))
{
mode_hs[6] = 0x07;
shift_reg &= ~(1 << 7);
//ser_write();
PORTA &= ~((1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA7)); //была ошибка PORTB
PORTA |= (1 << PA1);//была ошибка PORTB
}
break;
case 14: //ПАТРУЛЬ
if (patrol == 0)
{
patrol = 1;
mode_hs_temp[8] = mode_hs[8];
mode_hs[8] = 9;
PORTD |= (1 << PD7);
}
else
{
patrol = 0;
mode_hs[8] = mode_hs_temp[8];
PORTD &= ~(1 << PD7);
}
break;
}
}
key_status = 0;
all_key = 1;
for (ii = 0; ii < 9; ii++)
{
{
new_mode_hs[ii] = 1;
}
}
}
ser_write();
}
}
adc.c
/*! \file ********************************************************************
*
* \li File: adc.c
* \li Compiler: IAR EWAAVR 6.3.3.1990
*
* \li Supported devices: ATmega32 16 MHz
*
*
* \li Description: ADC input signal
*
*
* $Revision: 3
* $Date: Monday, November 11, 2013 8:25:08 $
****************************************************************************/
//ADC
void adc(unsigned char adc_ind)
{
ADCSRA |= (1 << ADSC); // запуск преобразования
while (!(ADCSRA&(1 << ADIF)));
adchr = (ADCH >> 5);
ADCSRA |= (1 << ADIF); // сброс флага преобразования
if (adchr != adc_old_arr[adc_ind])
{
adc_new_loc = 1;
adc_old_arr[adc_ind] = adchr;//adc_result;//adchr;
}
}
void adc1()
{
ADCSRA |= (1 << ADSC); // запуск преобразования
while (!(ADCSRA&(1 << ADIF)));
adc_gnd = ADC;
ADCSRA |= (1 << ADIF); // сброс флага преобразования
}
init.c
/*! \file ********************************************************************
*
* \li File: init.c
* \li Compiler: IAR EWAAVR 6.3.3.1990
*
* \li Supported devices: ATmega32 16 MHz
*
*
* \li Description: Initiation
*
*
* $Revision: 2
* $Date: Wednesday, March 13, 2013 15:27:08 $
****************************************************************************/
/*****************************************************************************
Timing parameters
*****************************************************************************/
void init_timer0()
{
TCCR0 |= (1 << CS00) | (1 << CS02) | (1 << WGM01); //prescaler = 1024; CTC mode
//TIMSK = (1 << TOIE0); // Overflow interrupt enable
TIMSK |= (1 << OCIE0);
OCR0 = 16; //1 mS
//OCR0 = 32; //2 mS
}
void init_timer1()
{
TCCR1B |= (1 << CS10) | (1 << CS12) | (1 << WGM12); //prescaler = 1024; CTC mode
//TIMSK = (1 << TOIE1); // Overflow interrupt enable
TIMSK |= (1 << OCIE1A);
OCR1A = 15625; //1 S
}
void init_UART()
{
UBRRL = 51;//8;//115200//51; // 25 Baud Rate = 19200
UCSRB |= (1 << RXEN)|(1 << TXEN);
UCSRC |= (1 << URSEL)|(1 << UCSZ0)|(1 << UCSZ1);
//while (UCSRA & (1 << RXC)) j = UDR;
UCSRB |= (1 << RXCIE);//|(1 << UDRIE);
}
int putchar(int c)
{
while (!(UCSRA & (1 << UDRE)));
UDR = c;
return c;
}
void init_ports()
{
DDRB |= (1 << PB4)|(1 << PB5)|(1 << PB7); //(1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3)|
//управление регистром РВ5 - данные, РВ7 - тактовые, РВ4 - перезапись
PORTB &= ~((1 << PB4)|(1 << PB5)|(1 << PB7));
//исходное значение 0
PORTB &= ~((1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3));
shift_reg = 0xFF;
//7 шлейф и прочие
ser_write();
DDRD |= (1 << PD2)|(1 << PD3)|(1 << PD4)|(1 << PD5)|(1 << PD6)|(1 << PD7);
PORTD &= ~((1 << PD2)|(1 << PD3)|(1 << PD7)|(1 << PD5)|(1 << PD6));
PORTD |= (1 << PD4);
//PD2 - управление 485, 0 - прием
// PD3 - PD4 - КШ, PD7 - ПАТРУЛЬ
patrol = 0;
DDRA |= (1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA7);
}
void adc_init(void)
{
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(1 << MUX0);
// AVCC with external capacitor at AREF pin, 3 канал
ADCSRA |= (1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0); // prescaler 128, 125 kHz
ADCSRA |= (1 << ADEN);
}
ser_write.c
/*! \file ********************************************************************
*
* \li File: ser_write.c
* \li Compiler: IAR EWAAVR 6.3.3.1990
*
* \li Supported devices: ATmega32 16 MHz
*
*
* \li Description: Recording register 74HC595D
*
*
* $Revision: 2
* $Date: Wednesday, March 13, 2013 15:27:08 $
****************************************************************************/
//Перезапись даныых из shift_reg в сдвиговый регистр 74HC595D
void ser_write(void)
{
unsigned char i;
for (i = 0x80; i > 0; i >>= 1)
{
if (shift_reg & i)
{
PORTB |= (1 << PB5);
}
else
{
PORTB &= ~(1 << PB5);
}
PORTB |= (1 << PB7);
__no_operation(); //проталкиваем
PORTB &= ~(1 << PB7);
}
PORTB |= (1 << PB4);
__no_operation(); //выводим
PORTB &= ~(1 << PB4);
}
stand_PI.h
/*! \file ********************************************************************
*
* \li File: stand_PI.h
* \li Compiler: IAR EWAAVR 6.3.3.1990
* \li Supported devices: ATmega32 16 MHz
*
* \li Description: Dinamic indication
*
*
* $Revision: 3
* $Date: Monday, November 11, 2013 8:25:08 $
****************************************************************************/
/*****************************************************************************
Timing parameters
*****************************************************************************/
#define CPU_FREQUENCY 16.000000
#define OWI_DELAY_OFFSET_CYCLES 13 //!< Timing delay when pulling bus low and releasing bus.
#define dd 1000
#define cc 254
// Bit timing delays in clock cycles (= us*clock freq in MHz).
#define DELAY_A ((dd * CPU_FREQUENCY) - OWI_DELAY_OFFSET_CYCLES)
#define DELAY_B ((2000000 * CPU_FREQUENCY) - OWI_DELAY_OFFSET_CYCLES)
#define DELAY_TEST ((200000 * CPU_FREQUENCY) - OWI_DELAY_OFFSET_CYCLES)
#define ZERO ((2000 * CPU_FREQUENCY) - OWI_DELAY_OFFSET_CYCLES)
#define SER_BR ((300000 * CPU_FREQUENCY) - OWI_DELAY_OFFSET_CYCLES)
#define t0_125 125000/9/dd
#define t0_2 200000/9/dd
#define t0_25 250000/9/dd
#define t0_5 500000/9/dd
#define t4_4 4400000/9/dd/3 //3 раза
#define t4_8 4800000/9/dd/3 //3 раза
//Время в мкс делим на период обращения к индикатору в мкс
//Период определяется периодом таймера dd, количеством индикаторов - 9 и,
//если требуется, числом байтовых фрагментов: dd*9*3
#define MAX_STR 3
//максимальное количество строк
#define sbv(port_letter, bit, val) do{\
if (val == 0) (PORT ## port_letter) &= ~(1<<(bit)); else (PORT ## port_letter) |= (1<<(bit));
(DDR ## port_letter) |= (1<<(bit));}while(0)
//SetBitVal
#define DDRC_MASK 0x07
void ser_write(void);
unsigned int patrol_count;
unsigned char patrol = 0;
unsigned char key_curr;
//значение нажатой клавиши
unsigned char key_status;
//0 - клавиша не активна, 1 - совпало 20 раз, 2 - отжата 20 раз
unsigned int key_count;
//счетчик следующих подряд считываний совпадающих кодов
unsigned char key_err;
//залипание 1 - длительное нажатие одной или в разных колонках и строках
//залипание 2 - в разных колонках и одинаковой строке
unsigned char blank_count;
//счетчик следующих подряд считываний пустых кодов
unsigned char col;
//значение колонок: col = PORTB | DDRB_MASK;
unsigned char key_err_count;
//счетчик индикации ошибки залипания
unsigned char ks_temp;
//временное хранение КШ на время индикации залипания
unsigned char all_key;
//если 0 - выполнять действия для всех шлейфов с учетом тактики
unsigned char str[3] = {0xFE, 0xFD, 0xFB}; //{(~(1 << PC0)), (~(1 << PC1)), (~(1 << PC2))};
//массив построчного обращения
unsigned char ddr[3] = {0x01, 0x02, 0x04}; //{(1 << PC0)), (1 << PC1)), (1 << PC2))};
//массив построчного обращения путем изменения направления
unsigned char sh_select[9] = {0,0,0,0,0,0,0,0,0};
//массив выбранных с/д (шлейфов)
unsigned char sh_status[9] = {5,5,5,5,5,5,5,5,5};
//массив состояний с/д (шлейфов) - исходно норма (зеленый)
unsigned char matrix[3][5] = {{0,1,2,9,10},{3,4,5,11,12},{6,7,8,13,14}};
//матрица 3 строки, 5 колонок, на перекрестии индекс sh_select, если меньше 9
//или цифровой код функциональной клавиши
unsigned char hs00[] = {1, cc, 0}; //1 цикл, макс. длина, не горит
unsigned char hs01[] = {1, cc, 0}; //1 цикл, макс. длина, не горит
//unsigned char hs00[] = {4, t0_125, t0_25, t0_125, t0_5, 2, 0, 2, 0};
//unsigned char hs01[] = {4, t0_125, t0_25, t0_125, t0_5, 2, 0, 2, 0};
unsigned char hs02[] = {2, t0_25, t0_25, 1, 0}; //2 цикла, 1/4 сек, зел. - не горит
unsigned char hs03[] = {2, t0_25, t0_25, 2, 1}; //2 цикла, 1/4 сек, кр. - зел.
unsigned char hs04[] = {2, t0_125, t0_125, 1, 0}; //2 цикла, 1/8 сек, зел. - не горит
//выбор
unsigned char hs05[] = {1, cc, 1}; //1 цикл, макс. длина, зел.
unsigned char hs06[] = {2, t0_5, t0_5, 2, 0}; //2 цикла, 1/2 сек, кр. - не горит
unsigned char hs07[] = {4, t0_2, t4_8, t4_8, t4_8, 2, 0, 0, 0};
//4 цикла, 1/5 сек кр., 4,8 sec - не горит
unsigned char hs08[] = {6, t0_2, t0_2, t0_2, t4_4, t4_4, t4_4, 2, 0, 2, 0, 0, 0};
//6 циклов, 1/5 сек кр., 1/5 сек - не горит, 1/5 сек кр., 4,4 sec - не горит
unsigned char hs09[] = {2, 1, 1, 2, 1}; //2 цикла, кр. - зел. через цикл
unsigned char hs0A[] = {2, t0_125, t0_125, 2, 1}; //2 цикла, 1/8 сек, кр. - зел.
unsigned char hs0B[] = {2, t0_5, t0_5, 2, 0}; //2 цикла, 1/2 сек, кр. - не горит
unsigned char hs0C[] = {1, cc, 2}; //1 цикл, макс. длина, кр.
unsigned char hs0D[] = {4, t0_125, t0_25, t0_125, t0_5, 2, 0, 2, 0};
//4 цикла, 1/8 сек кр., 1/4 - не горит, 1/8 сек кр., 1/2 - не горит
unsigned char hs0E[] = {4, t0_125, t0_25, t0_125, t0_5, 2, 0, 0, 0};
//4 цикла, 1/8 сек кр., 1/4 - не горит, 1/8 сек не горит, 1/2 - не горит
unsigned char hs0F[] = {6, t0_125, t0_125, t0_125, t0_125, t0_125, t0_5, 2, 0, 2, 0, 2, 0};
//6 циклов, 1/8 сек кр., 1/8 - не горит, 1/8 кр., 1/8 - не горит, 1/8 сек кр., 1/2 - не горит
unsigned char buf_hs00[16];
unsigned char buf_hs01[16];
unsigned char buf_hs02[16];
unsigned char buf_hs03[16];
unsigned char buf_hs04[16];
unsigned char buf_hs05[16];
unsigned char buf_hs06[16];
unsigned char buf_hs07[16];
unsigned char buf_hs08[16];
unsigned char * arr_led[] = {hs00, hs01, hs02, hs03, hs04, hs05, hs06, hs07,
hs08, hs09, hs0A, hs0B, hs0C, hs0D, hs0E, hs0F};
//массив исходных строк состояний с/д hs
unsigned char * temp_hs;
//указатель на массив hs
unsigned char * arr_buf[] = {buf_hs00, buf_hs01, buf_hs02, buf_hs03, buf_hs04, buf_hs05,
buf_hs06, buf_hs07, buf_hs08};
//массив буферов на 9 с/д hs
unsigned char color_hs[] = {0,0, 1,0, 2,0, 0,1, 1,1, 2,1, 0,2, 1,2, 2,2,};
//ножки порта B: PB0 - PB2;
//ножки порта С: PC0 - PC2; с/д 1-9: 0+ 0- зел.: 0- 0+ кр.: строка, столбец
unsigned char nled, currled, ledmod, num_sec, ii, jj, temp, i; //nled,
//циклический счетчик, текущий с/д, цвет 0-н.г. 1-зел 2-кр, счетчик секунд, просто счетчик
unsigned char mode_hs [9] = {5,5,5,5,5,5,5,5,5};
//массив индикаторов режима с/д hs ; 0-14
unsigned char mode_hs_temp [9] = {5,5,5,5,5,5,5,5,5};
//массив временного хранения индикаторов режима с/д hs ; 0-8
unsigned char new_mode_hs [9] = {0,0,0,0,0,0,0,0,0};
//массив форсирования перезаписи из-за больших счетчиков
unsigned char t, u, n, f, j;
//t - счетчик продвижения по buf_hs
unsigned char shift_reg;
unsigned char sh_reg_arr[] = {0,6,5,4,3,2,7,1};
//положение шлейфов относительно "железного" регистра
const __flash char f_key_curr[] = "key_curr=%o ;";
const __flash char f_str[] = "str=%o; ";
const __flash char f_col[] = "col=%o;\n";
const __flash char ph1[] = "+H1=%d; ";
const __flash char mh1[] = "-H1=%d;\n\r";
const __flash char ph2[] = "+H2=%d; ";
const __flash char mh2[] = "-H2=%d;\n\r";
const __flash char vsv[] = "VSV=%d; ";
const __flash char sir[] = "SIR=%d;\n\r";
const __flash char sop[] = "SOP=%d; ";
const __flash char dop[] = "DOP=%d;\n\r";
//unsigned int adc_result = 0;
unsigned char adchr = 0, adclr = 0, adc_ind = 0, adc_new_status = 0;
//adchr - значение ADCH, adclr - не используется,
//adc_ind - adc_old_arr[adc_ind], adc_new_status - 1 - пересылать, 0 - измерять
unsigned char curr_adc = 7, curr_adc_buf = 0, adc_new_loc = 0, adc_n_msec = 0;
//curr_adc - adc(curr_adc), curr_adc_buf - UDR = adc_old_arr[curr_adc_buf],
//adc_new_loc - 1 - произошло хотя бы 1 изменение за цикл (из 8),
//adc_n_msec - кол-во пропускаемых циклов для преобразовния 1 входа
unsigned char adc_old_arr[] = {0,0,0,0,0,0,0,0};
unsigned int adc_gnd;
unsigned char col_mag[3];
unsigned char ser_break = 0; //Условие для последовательного нарушения = 1
timer0_comp.c
/*! \file ********************************************************************
*
* \li File: timer0_comp.c
* \li Compiler: IAR EWAAVR 6.3.3.1990
* \li Support mail:
*
* \li Supported devices: ATmega32 16 MHz
*
* \li Description: Dinamic indication
*
*
* $Revision: 2
* $Date: Wednesday, March 13, 2013 15:27:08 $
****************************************************************************/
#pragma vector = TIMER0_COMP_vect
__interrupt void ind_set(void) //Подпрограмма обработки прерывания 1 mS таймера 0
{
//unsigned char counter_temp;
void adc(unsigned char adc_ind);
//СЧИТЫВАНИЕ ADC
if ((adc_new_status == 0) && (adc_n_msec >= 5))
//передача завершена и прошло не менее 50 мсек после последнего прохода
{
if (curr_adc == 7)
{
curr_adc = 0;
adc_n_msec = 0;
}
else
{
curr_adc++;
}
// Снимает показания и подготавливает новый канал
switch (curr_adc)
{
case 0: //+H1
adc(curr_adc);
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(0 << MUX0);
//4 канал
break;
case 1: //-H1
adc(curr_adc);
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD6);
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(1 << MUX0);
//3 канал
break;
case 2: //+H2
adc(curr_adc);
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(0 << MUX0);
//4 канал
break;
case 3: //-H2
adc(curr_adc);
PORTD &= ~(1 << PD5);
PORTD |= (1 << PD6);
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(1 << MUX0);
//3 канал
break;
case 4: //VSV
adc(curr_adc);
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(0 << MUX0);
//4 канал
break;
case 5: //SIR
adc(curr_adc);
PORTD |= (1 << PD5)|(1 << PD6);
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(1 << MUX0);
//3 канал
break;
case 6: //SOP
adc(curr_adc);
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(0 << MUX0);
//4 канал
break;
case 7: //DOP
adc(curr_adc);
PORTD &= ~((1 << PD5)|(1 << PD6));
ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << ADLAR)|(0 << MUX4)|(0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(1 << MUX0);
//3 канал
PORTD &= ~(1 << PD2);
break;
}
if ((adc_new_loc == 1) && (curr_adc == 7))
{
adc_new_loc = 0;
adc_new_status = 1;
curr_adc_buf = 0;
}
}
adc_n_msec++;
//СЧИТЫВАНИЕ КЛАВИАТУРЫ
if (key_status != 2)
{
//DDRA = 0; //0x18; // строки с/д РА0 - РА2 на вход (не мешать РС0 - РС2)
//и ридер PA7 и свободные PA5, PA6
//PORTA = 0; //0x18;
DDRB &= 0xB0;//~7; //строки с/д РB0 - РB2 на вход (не мешать РС0 - РС2)
PORTB = 0;//&= ~7; //!!!!!!!!!!!!!!!!!!! был PORTA
DDRC = 0; //DDRC_MASK; //0хЕ0 : (1 << PC7) | (1 << PC6) | (1 << PC5) по строкам
PORTC = 0;//0xFF; //!!! почему-то помогло с красным цветом
col = 255;
for (t = 0; (t < MAX_STR) && (col == 255); t++)
{
DDRC = ddr[t];
PORTC = str[t]; //массив перебора строк
__delay_cycles(5);
for (i = 0; i < 3; i++)
{
col_mag[i] = PINC | DDRC_MASK;
__delay_cycles(10);
if (col_mag[i] < 255) col = 0;
}
DDRC = 0;
PORTC = 0;
if (col == 0) //кнопка нажата 3
{
if (col_mag[1] == col_mag[2]) col = col_mag[2];
else
if (col_mag[0] == col_mag[2]) col = col_mag[2];
else
if (col_mag[0] == col_mag[1]) col = col_mag[1];
else col = 255;
}
if (col < 255) //кнопка совпала хотя бы 2 из 3
{
key_count++;
if (key_count > 5000)//А таймер 1 считает 5 сек. времени индикации на КШ
{
key_count = 0;
if (key_err == 0)
{
key_err = 1;
//залипание 1 - длительное нажатие одной или в разных колонках и строках
}
}
else
{
blank_count = 0;
switch (col) //учитывает колонки по схеме PINC для matrix[3][5]
{
case 0xF7://0xFE://0xF7:
col = 0;
break;
case 0xEF://0xFD://0xEF:
col = 1;
break;
case 0xDF://0xFB://0xDF:
col = 2;
break;
case 0xBF://0xF7://0xBF:
col = 3;
break;
case 0x7F://0xEF://0x7F:
col = 4;
break;
default:
key_err = 2; //залипание 2 - в разных колонках и одинаковой строке
key_count = 0;
}
if ((key_err == 0) && (key_status == 0)) // Фиксируем код
{
key_curr = matrix[t][col]; //запоминаем код кнопки
key_status = 1;
}
//Новенькое. Условие для последовательного нарушения.
if ((key_count > 700)&&(key_curr == 10))
{
ser_break = 1;
key_status = 2;
blank_count = 0;//???????
}
}
}
}
if (col == 255) //кнопка не нажата
{
key_count = 0;//
if (key_status == 1) //набрали 3 балла по нажатию?
{
blank_count++; //увеличиваем счетчик отжатия
if (blank_count == 20) //набрали 20 баллов по отжатию?
{
key_status = 2; //код кнопки считан корректно
blank_count = 0;//???????
}
}
}
}
//УПРАВЛЕНИЕ МАТРИЦЕЙ СВЕТОДИОДОВ
t = 1;
if (nled < 9) currled = nled;
else
{
currled = 0;
nled = 0;
}
while ((t <= arr_buf[currled][0]) && (arr_buf[currled][t] == 0)) t++;
//пока не вышли за пределы счетчиков и очередной счетчик = 0 продвигаемся по buf_hs
if ((t > arr_buf[currled][0]) || (new_mode_hs[currled] == 1))
//значит все счетчики = 0 и требуется восстановить buf_hs
{t = 1;
n = arr_led[mode_hs[currled]][0] * 2;
//mode_hs - текущее состояние обслуживаемого (currled) с/д
//arr_led - указатель на соотв. массив hs, где 0 элемент - кол-во циклов
//т.о. n - кол-во переписываемых байтов
for (u = 0; u <= n; u++)
{
arr_buf[currled][u] = arr_led[mode_hs[currled]][u];
//переписываем из hs в buf_hs
}
new_mode_hs[currled] = 0;
//сброс форсирования перезаписи из-за больших счетчиков
}
arr_buf[currled][t]--;
//counter_temp = arr_buf[currled][t]--;
//уменьшаем значение счетчика состояния, без сохранения для анализа в конце п/п
f = arr_buf[currled][0] + t;
//f - индекс массива buf_hs для определения режима (зел., кр., не горит)
ledmod = arr_buf[currled][f];
//ledmod - запоминаем значение режима, чтобы потом выставить ножки
currled <<= 1;
//сдвиг <<= 1 умножение на 2 для попадания на половину, определяющую ноги
//для color_hs
DDRC = 0; PORTC = 0xFF;
DDRB &= 0xB0; PORTB = 0;
if (ledmod == 2)//красный из-за разводки //(ledmod == 1) зеленый
{
//DDRC = 0; PORTC = 0xFF;
sbv(B, color_hs[currled], 1); //!!!!!!!!!!!!!!!!!!!
sbv(C, color_hs[currled + 1], 0);
}
else if (ledmod == 1)//зеленый из-за разводки //(ledmod == 2) красный
{
//DDRC = 0; PORTC = 0xFF;
sbv(B, color_hs[currled], 0); //!!!!!!!!!!!!!!!!!!!
sbv(C, color_hs[currled + 1], 1);
}
//if ((ledmod != 1) || ((counter_temp % 2) == 1))
//если не зеленые или нечетный (чтобы крутить по зеленым не более 2 раз)
//было причиной увеличения времени незеленых, если есть зеленые
nled++;
//к следующему с/д
}
timer1_compa.c
/*! \file ********************************************************************
*
* \li File: timer1_compa.c
* \li Compiler: IAR EWAAVR 6.3.3.1990
* \li Supported devices: ATmega32 16 MHz
*
*
* \li Description: Dinamic indication
*
*
* $Revision: 2
* $Date: Wednesday, March 13, 2013 15:27:08 $
****************************************************************************/
#pragma vector = TIMER1_COMPA_vect
__interrupt void ind_shift() //Подпрограмма обработки прерывания 1 S таймера 1
{
if ((key_err > 0) && (key_err_count < 11)) key_err_count++;
}
//Подсчет времени после обнаружения ошибки. Пришлось ? увеличить вдвое для 5 сек?
// 11 потому, что в main key_err_count = 1
uart.c
/*! \file ********************************************************************
*
* \li File: uart.c
* \li Compiler: IAR EWAAVR 6.3.3.1990
*
* \li Supported devices: ATmega32 16 MHz
*
*
* \li Description: COM port
*
*
* $Revision: 2
* $Date: Wednesday, March 13, 2013 15:27:08 $
****************************************************************************/
#pragma vector = USART_RXC_vect
__interrupt void usart_rx(void) //USART Rx Complete
{
if (UDR == 1)
{
adc_new_loc = 1;
}
}
#pragma vector = USART_UDRE_vect
__interrupt void usart_tx(void) //USART Data Register Empty
{
if (curr_adc_buf < 8)
{
UDR = adc_old_arr[curr_adc_buf];
curr_adc_buf++;
}
else
{
UCSRB &= ~(1 << UDRIE);
adc_new_status = 0;
}
}