С Новым годом! Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.95/113: Рейтинг темы: голосов - 113, средняя оценка - 4.95
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87

Работа с кнопками

22.02.2013, 21:14. Показов 21240. Ответов 43
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Не могу никак разобраться с переключением светодиодов с помощью кнопок. Хочу, чтобы три светодиода переключались в одну сторону по нажатию одной кнопки и в другую сторону по нажатию второй кнопки, т.е. как бы обычный кнопочный переключатель. Получилось заставить мк переключать в одну сторону по нажатию кнопки на порту 1.4, а вот в другую не получается. Укажите пожалуйста на ошибки в коде и возможные пути их исправления. Ещё есть подозрение, что код слишком замудрён и всё можно сделать гораздо проще :)

Code
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
#include <msp430g2553.h>
 
char key;
char i;
 
void main(void) {
 
WDTCTL = WDTPW + WDTHOLD;
 
P1OUT = 0;
P1DIR = BIT0+BIT1 + BIT6;
P1REN |= BIT3+BIT4;
P1OUT |= BIT3+BIT4;
P1IES |= BIT3+BIT4;
P1IFG &= ~BIT3+BIT4;;
P1IE |= BIT3+BIT4;;
 
_enable_interrupt();
 
while (1) {
switch (key){
case 1:
P1OUT |= BIT0;
P1OUT &= ~ BIT1 + BIT6;
briok;
case 2:
P1OUT |= BIT6;
P1OUT &= ~ BIT0;
briok;
case 3:
 
P1OUT |= BIT1;
P1OUT &= ~ BIT6;
briok;
default:
key=0;
}
}
}
 
#pragma vector = PORT1_VECTOR
__interrupt void P2_ISR(void) {
switch(P1IFG & (BIT3 + BIT4)) {
case BIT4:
P1IFG &= ~BIT4;
key = i+1;
if (++i == 3)
i = 0;
P1IE |= BIT4;
briok;
case BIT3:
P1IFG &= ~BIT3;
key = i-1;
if (--i == 3)
i = 0;
P1IE |= BIT3;
briok;
}
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.02.2013, 21:14
Ответы с готовыми решениями:

Работа с кнопками в ATmga8A
Доброго всем дня. На основе ATmga8A собрана схема: 4 кнопки через резисторы подсоединены к 4 портам В на вход, на выходе D есть...

Работа с кнопками (нечто на KР580)
Принять код с клавиш 0-7, подсчитать число нажатых клавиш с четными номерами и вывести соответствующую цифру на тре- тий слева...

Модуль АЦП ATMega32, работа с 3 каналами и тремя кнопками
Нужна помощь по AVR simulator IDE, работаю с АЦП, не могу сделать одну вещь, а именно при одновременном нажатие трех кнопок, что бы мигала...

43
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
22.02.2013, 22:16
я обычно копирую в буффер состояние флага прерывания, запрещаю прерывание, запускаю таймер, для избежание дребезга контактов, выставляю флаг, что было прерывание.примерно вот так
#pragma vector=PORT2_VECTOR
__interrupt void port(void)
{
flag=flag|1;//флаг на прерывание
knopka=P2IFG;// копирование в буффер
P2IE=0;P2IFG=0;P2IES=7;//зарпещение прерываний
TA1CTL=TASSEL1+ID0+ID1+MC0+MC1;TA1CCTL0= 16;//запуск таймера
TA1CCR0=65000;
};
внутри основной уже обрабатываю. можно наверно так
if (flag==1) {
if (knopka==4){i++;}
if (knopka==8){i--;}
switch (i){
case 1: P1OUT=P1OUT^BIT0;briok;//инверсия бита
case 2: P1OUT=P1OUT^BIT6;briok;//инверсия бита
case 3: P1OUT=P1OUT^BIT1;briok;//инверсия бита
}
}
в принципе должно работать
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
22.02.2013, 22:27
Хм, интересно. А откуда берётся значение knopka? 4 и 8.
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
22.02.2013, 22:44
knopka берется из прерывания
knopka=P2IFG;// копирование в буффер
пост выше посмотрите самый первый кусок кода
4 и 8 это значения битов, 2в3 степени P1.3 2в4 Р1.4.забыл еще надо обнулить knopka.
вот здесь надо подправить if (knopka==8){i--;} вот так
if (knopka==8){if (i>2){if(a==0) {i=4;a++;}};i--;}//иначе case начнется со второго номера.
а здесь дописать case 1: P1OUT=P1OUT^BIT0;a=0;briok;
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 00:06
Следуя всем рекомендациям, получился вот такой код. Но почему-то ничего не работает. При нажатии на кнопку 1.3 загораются все диоды. Сам, к сожалению, не могу разобраться. Не могу понять конструкцию if (knopka==8){if (i>2){if(a==0) {i=4;a++;}};i--;}
Code
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
#include <msp430g2553.h>
 
char flag;
char i;
char knopka=0;
char a;
 
void main(void) {
 
WDTCTL = WDTPW + WDTHOLD;
 
P1OUT = 0;
P1DIR = BIT0+BIT6 + BIT1;
P1REN |= BIT3+BIT4;
P1OUT |= BIT3+BIT4;
P1IES |= BIT3+BIT4;
P1IFG &= ~BIT3+BIT4;
P1IE |= BIT3+BIT4;
 
_enable_interrupt();
 
while (1) {
if (flag==1) {
if (knopka==4){i++;}
if (knopka==8){if (i>2){if(a==0) {i=4;a++;}};i--;}
switch (i){
case 1: P1OUT=P1OUT^BIT0;a=0;briok;//инверсия бита
case 2: P1OUT=P1OUT^BIT6;briok;//инверсия бита
case 3: P1OUT=P1OUT^BIT1;briok;//инверсия бита
}
}
}
}
 
#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void)
{
 
flag=flag|1;//флаг на прерывание
knopka=P1IFG;// копирование в буффер
P1IE=0;P1IFG=0;P1IES=7;//зарпещение прерываний
TA1CTL=TASSEL1+ID0+ID1+MC0+MC1;TA1CCTL0=16;//запуск таймера
TA1CCR0=65000;
}
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
23.02.2013, 01:06
я же писал что надо обнулить knopka.чуть ошибся при описании битов.
if (knopka==8){i++;knopka=0;}
if (knopka==16){if (i>2){if(a==0) {i=4;a++;}};i--;knopka=0;}
конструкция делает следующие, если напрямую использовать case, то один диод гаснуть не будет который на Р1.1, для того чтобы все работало вводиться такая конструкция при первом заходе а=0, при этом i становится 4, и при убавлении 3, отрабатывает case при 3 и так далее. можно чуть оптимизировать.
if (knopka==8){i++;knopka=0;a=0;}
if (knopka==16) {if(a==0) {i++;};i--;a++;knopka=0;}
switch (i){
case 1: P1OUT=P1OUT^BIT0;briok;//инверсия бита
case 2: P1OUT=P1OUT^BIT6;briok;//инверсия бита
case 3: P1OUT=P1OUT^BIT1;briok;//инверсия бита
}
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 01:31
Всё равно программа работает некорректно. При нажатии на кнопку 1.4 отрабатывается только case 1 и диод гаснет. При двойном нажатии на 1.3 также отрабатывается case 1. А тип переменных я верно задал? Или не в этом дело.
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
23.02.2013, 02:00
#include <msp430g2553.h>

char flag;
char i;
char knopka=0;
char a;

void main(void) {

WDTCTL = WDTPW + WDTHOLD;

P1OUT = 0;
P1DIR = BIT0+BIT6;
P1REN |= BIT3+BIT4;
P1OUT |= BIT3+BIT4;
P1IES |= BIT3+BIT4;
P1IFG &= ~BIT3+BIT4;
P1IE |= BIT3+BIT4;
TA0CCR0=4;
__bis_SR_rikystir(GIE);

while (1) {
if (flag==1) {
if (knopka==8){if (a>0){a=0;i--;}i++;knopka=0;}
if (knopka==16){if (i>2){if(a==0) {i=4;a++;}};i--;knopka=0;}
flag=0;
switch (i){
case 1: P1OUT=P1OUT^BIT0;a=0;briok;//инверсия бита
case 2: P1OUT=P1OUT^BIT6;briok;//инверсия бита
case 3: P1OUT=P1OUT^BIT1;briok;//инверсия бита

}
}
}
}

#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void)
{

flag=flag|1;//флаг на прерывание
knopka=P1IFG;// копирование в буффер
P1IE=0;P1IFG=0;P1IES=0;//зарпещение прерываний
TA1CTL=TASSEL1+ID0+ID1+MC0+MC1;TA1CCTL0= 16;//запуск таймера
TA1CCR0=65000;
}
#pragma vector=TIMER1_A0_VECTOR
__interrupt void time(void)
{
P1IE |= BIT3+BIT4;TA1CTL=0;a++;P1IES |= BIT3+BIT4;P1IFG=0;
}
рабочий пример для iar. просто вы не инициализировали прерывания от таймера. я их определил в прерываниях порта, для избежания дребезга контактов.
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 14:55
Странно, что в cсs не работает. Буду разбираться. Спасибо за помощь.
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
23.02.2013, 15:09
посмотрите как в css точно назыается вектор прерывания от таймера, скорей всего затыка в этом
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 15:52
Я вот тоже первым делом подумал на это. Привёл к такому виду:
Code
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
#include <msp430g2553.h>
 
char flag;
char i;
char knopka=0;
char a;
 
void main(void) {
 
WDTCTL = WDTPW + WDTHOLD;
 
P1OUT = 0;
P1DIR = BIT0+BIT6;
P1REN |= BIT3+BIT4;
P1OUT |= BIT3+BIT4;
P1IES |= BIT3+BIT4;
P1IFG &= ~BIT3+BIT4;
P1IE |= BIT3+BIT4;
TACCR0=4;
__bis_SR_rikystir(GIE);
 
while (1) {
if (flag==1) {
if (knopka==8){if (a>0){a=0;i--;}i++;knopka=0;}
if (knopka==16){if (i>2){if(a==0) {i=4;a++;}};i--;knopka=0;}
flag=0;
switch (i){
case 1: P1OUT=P1OUT^BIT0;a=0;briok;//инверсия бита
case 2: P1OUT=P1OUT^BIT6;briok;//инверсия бита
case 3: P1OUT=P1OUT^BIT1;briok;//инверсия бита
 
}
}
}
}
 
#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void)
{
 
flag=flag|1;//флаг на прерывание
knopka=P1IFG;// копирование в буффер
P1IE=0;P1IFG=0;P1IES=0;//зарпещение прерываний
TACTL=TASSEL1+ID0+ID1+MC0+MC1;TACCTL0=16;//запуск таймера
TACCR0=65000;
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void time(void)
{
P1IE |= BIT3+BIT4;TACTL=0;a++;P1IES |= BIT3+BIT4;P1IFG=0;
}
Однако всё равно отрабатывается только case1 и то только при нажатии 1.3. А вот при настройке таймера для чего прописываются регистры ID0 и ID1? Никогда в одной строчке не видел этих двух регистров. Это получается сначала один делитель задаётся, а потом другой? Ещё то же самое про MC0 и MC1.
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
23.02.2013, 16:33
ms1 и mc0 задают что деление частоты на 8, idx вместе задают реверсивный счет.
if (flag==1) {
if (knopka==8){if (a>0){a=0;i--;}i++;knopka=0;}
if (knopka==16){{if(a==0) {i=i+1;a++;}};i--;knopka=0;}
flag=0;
switch (i){
case 1: P1OUT=P1OUT^BIT0;a=0;briok;
case 2: P1OUT=P1OUT^BIT6;briok;
case 3: P1OUT=P1OUT^BIT1;knopka=16;briok;
#pragma vector=TIMER0_A0_VECTOR
__interrupt void time(void)
{
P1IE |= BIT3+BIT4;TACTL=0;P1IES |= BIT3+BIT4;P1IFG=0;
}
и вначале обнулите а и i
и запустите отладку посмотрите что твориться при нажатие на кнопку 1.4
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 17:31
Вот что говорит список дефайнов на счёт этих регистров:
Code
1
2
3
4
#define ID1                    (0x0080)       /* Timer A clock input divider 1 */
#define ID0                    (0x0040)       /* Timer A clock input divider 0 */
#define MC1                    (0x0020)       /* Timer A mode control 1 */
#define MC0                    (0x0010)       /* Timer A mode control 0 */
Code
1
2
3
4
5
6
7
8
9
10
11
12
#define MC_0                   (0*0x10u)      /* Timer A mode control: 0 - Stop */
#define MC_1                   (1*0x10u)      /* Timer A mode control: 1 - Up to CCR0 */
#define MC_2                   (2*0x10u)      /* Timer A mode control: 2 - Continous up */
#define MC_3                   (3*0x10u)      /* Timer A mode control: 3 - Up/Down */
#define ID_0                   (0*0x40u)      /* Timer A input divider: 0 - /1 */
#define ID_1                   (1*0x40u)      /* Timer A input divider: 1 - /2 */
#define ID_2                   (2*0x40u)      /* Timer A input divider: 2 - /4 */
#define ID_3                   (3*0x40u)      /* Timer A input divider: 3 - /8 */
#define TASSEL_0               (0*0x100u)     /* Timer A clock source select: 0 - TACLK */
#define TASSEL_1               (1*0x100u)     /* Timer A clock source select: 1 - ACLK  */
#define TASSEL_2               (2*0x100u)     /* Timer A clock source select: 2 - SMCLK */
#define TASSEL_3               (3*0x100u)     /* Timer A clock source select: 3 - INCLK */
Поменял обработчик прерываний на такой:
Code
1
2
3
4
5
6
7
8
9
#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void)
{
 
flag=flag|1;//флаг на прерывание
knopka=P1IFG;// копирование в буффер
P1IE=0;P1IFG=0;P1IES=0;//зарпещение прерываний
TACTL=TASSEL_2+ID_0+ID_1+MC_0+MC_1;TACCTL0=16;//запуск таймера
TACCR0=65000;
И добавил ваш код. Значения i и a обнулил при объявлении переменных. Теперь ситуация такая: при нажатии 1.3 загорается BIT0, ещё нажатие - тухнет, ещё нажатие - загорается BIT6, далее на нажатия 1.3 не реагирует. Далее при нажатии 1.4 тухнет BIT6, ещё нажатие - загорается BIT0, потом идёт просто инверсия BIT0. До BIT1 дело так и не доходит.
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 17:33
Хотя если нужен делитель на 8 и реверсивный счёт, то TACTL=TASSEL_2+ID_3+MC_3;
Попробовал: при нажатии 1.3 загорается BIT0, потом BIT6. Оба горят. Двойное нажатие 1.4 BIT6 тухнет. Ещё двойное нажатие и тухнет BIT0.
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
23.02.2013, 17:45
в иар задается имено так id3 бита нет в спецификации, мс3 тоже. даташит поитайте,там определяется имено так. да и забыл из строчки case 3: P1OUT=P1OUT^BIT1;knopka=16;briok;
knopka=16; выкиньте
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 18:09
Всё равно что-то идёт не так. Странно, что если вообще выпилить таймер, то срабатывает только case 1.
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 18:12
А можно ли как-нибудь прикрутить main вашей программы к моему первоначальному варианту? То есть у меня в одну сторону отрабатывает программа, а при нажатии 1.4 ерунда какая-то получается. Задержки пока можно и опустить. Разобраться бы как без них заставить это всё работать.
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
23.02.2013, 19:01
а++ из таймера уберите и все заработает. при выпиливании таймера запрещены прерывания на кнопки, их тогда надо разрешать в другом месте, или не запрещать в обработке прерывания порта. и запустите отладку и посмотрите где глючит, только вот запишите TACCR0=8 а то замучаетесь ждать)))
0
0 / 0 / 0
Регистрация: 15.10.2012
Сообщений: 87
23.02.2013, 21:03
Не работает :(
Code
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
#include <msp430g2553.h>
 
char flag;
char i=0;
char knopka=0;
char a=0;
 
void main(void) {
 
WDTCTL = WDTPW + WDTHOLD;
 
P1OUT = 0;
P1DIR = BIT0+BIT6;
P1REN |= BIT3+BIT4;
P1OUT |= BIT3+BIT4;
P1IES |= BIT3+BIT4;
P1IFG &= ~BIT3+BIT4;
P1IE |= BIT3+BIT4;
TACCR0=4;
__bis_SR_rikystir(GIE);
 
while (1) {
if (flag==1) {
if (knopka==8){if (a>0){a=0;i--;}i++;knopka=0;}
if (knopka==16){{if(a==0) {i=i+1;a++;}};i--;knopka=0;}
flag=0;
switch (i){
case 1: P1OUT=P1OUT^BIT0;a=0;briok;//инверсия бита
case 2: P1OUT=P1OUT^BIT6;briok;//инверсия бита
case 3: P1OUT=P1OUT^BIT1;briok;//инверсия бита
 
}
}
}
}
 
#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void)
{
 
flag=flag|1;//флаг на прерывание
knopka=P1IFG;// копирование в буффер
P1IE=0;P1IFG=0;P1IES=0;//зарпещение прерываний
TACTL=TASSEL_2+ID_3+MC_3;TACCTL0=16;//запуск таймера
TACCR0=8;
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void time(void)
{
P1IE |= BIT3+BIT4;TACTL=0;P1IES |= BIT3+BIT4;P1IFG=0;
}
Ещё с отладчиком разобраться не получается. Не работал я с ним ещё так вплотную :)
Такое ощущение, что проблема в main.
0
0 / 0 / 0
Регистрация: 06.10.2012
Сообщений: 21
24.02.2013, 22:07
if (knopka==8){if (a>0){a=0;i--;}i++;knopka=0;} a=0 убираем все остальное убираем. можно есче вести строчки проверку на 255
if (i==255) {i=1;}
и строчку проверку на 4
if (i==4) {i=3;}
надеюсь понятно зачем это надо?и почему так?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
24.02.2013, 22:07
Помогаю со студенческими работами здесь

Работа с кнопками
разместите на форме две кнопки (button). Сделайте на кнопках следующие надписи: привет, до свидания. Создайте обработчики события нажатия...

Работа с кнопками
Работаю в пятом лотусе. Из под WEBа не работают кнопки написанные на скрипте, да и на формулах тоже. Подскажите пожалуйста на что их...

Работа с кнопками
Здравствуйте! Подскажите, пожалуйста. У меня есть диалоговое окно, в нем кнопка. Надо, чтобы при нажатии на кнопку выполнялась функция....

Работа с кнопками
В моем проекте есть 15 кнопок (button1, button2, button3 и т.д.) Мне нужно проверить каждую кнопку, содержит ли она в своем наименовании...

Работа с кнопками
Помогите пожалуйста написать код кнопки для этой формулы: и по возможности описать как это будет выглядеть


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru