Сенсорные кнопки

02/02/2011 - 20:32 Pashgan, Petrov
     Управление с помощью компьютера  исполнительным механизмом или иным устройством не всегда удобно. Первые два дня это, конечно, интересно, но потом начинает напрягать, потому что приходится совершать много лишних действий – включать компьютер, запускать программу и т.д. Возникает вопрос, а  не изготовить ли для этих целей автономный управляющий модуль с клавиатурой и дисплеем?
   Так как делается это для себя, то требуется дешевое, но в то же время красивое решение. С выбором дисплея особо не помудришь, дешевле и удобнее символьных LCD с контроллером еще не придумали, а вот при выборе клавиатуры можно хорошенько сэкономить.
 Рассмотрим варианты. За готовую матричную клавиатуру придется выложить 100-200 рублей. Клавиатура из кнопок обойдется рублей в 36 (3р * 12 кнопок), не считая колпачков.   Сенсорную клавиатуру можно изготовить почти задаром из куска фольгированного текстолита, при этом в корпусе устройства не придется сверлить отверстия под кнопки. 
   По-моему выбор очевиден, осталось только понять, как с такой клавиатурой  работать. Но для начала нужно хотя бы разобраться с одиночной сенсорной кнопкой. 
   
  Одиночная сенсорная кнопка представляет собой металлическую площадку,  подключенную к выводу  микроконтроллера. Поскольку любое проводящее тело обладает емкостью, величина которой зависит от геометрии тела и окружающего его диэлектрика, такое подключение равносильно подключению к выводу конденсатора.    
   Человеческое тело тоже обладает емкостью (~100..300 pF), поэтому при поднесении пальца к сенсору суммарная емкость на входе микроконтроллера увеличится (ведь при параллельном соединении конденсаторов их емкости складываются). По именениям этой емкости и можно делать вывод о прикосновении к сенсору. 

Сенсорная кнопка, подключенная к микроконтроллеру

С1 — паразитная емкость вывода мк, С2 — емкость сенсора, С3 и С4 – емкости, вносимые прикосновением.  
  
   Поскольку все КМОП микросхемы болезненно переносят воздействие статического электричества, а человеческое тело ,обладая вышеуказанной емкостью, может заряжаться до нескольких тысяч вольт, схему следует дополнить небольшой защитной цепью. 
    Защита микроконтроллера от статического электричества
  
  При прикосновении к сенсору, накопленный телом заряд благополучно разрядится через один из диодов. В принципе такая защитная схема (не считая резистора) спрятана внутри микроконтроллера, но полагаться на нее не стоит, так как встроенные диоды выдерживают ток лишь в 1 ма.
   Кстати, внешние диоды добавят к входной емкости еще пару тройку пикофарад.

  Ну ладно, принцип понятен, а каким образом измерить емкость? Величину емкости можно оценить по времени ее заряда. Подключим к выводу микроконтроллера высокоомный подтягивающий резистор (смотри схему) и получим RC цепь. Манипулируя выводом микроконтроллера можно вызвать заряд и разряд нашего виртуального конденсатора, а контролирую потенциал вывода в процессе заряда емкости - оценивать ее величину. Чем больше емкость, тем медленнее она будет заряжаться.   

Вырисовывется следующий алгоритм работы:
 
1. Переключаем вывод микроконтроллера в режим выхода и сбрасываем в ноль. Паразитная емкость разрядится на внутренние цепи микроконтроллера.

2. Переключаем вывод микроконтроллера в режим входа в состоянии Hi-Z. Емкость начнет заряжаться через внешний подтягивающий резистор.

3. Контролируем состояние вывода и отсчитываем время. Как только емкость зарядится до напряжения логической единицы, снимаем показания счетчика.

4. Сравниваем полученное значение счетчика с заданной эталонной величиной и определяем, увеличилась ли емкость или нет. 
 
  Ничего сложного и можно перейти к делу.  Представляю сделанную на скорую руку, но, тем не менее, рабочую схему и исходники устройства.

Микроконтроллер и две сенсорные кнопки
 
Исходник не большой и, я думаю, main.c можно выложить полностью, он у меня хорошо прокомментирован.

//***************************************************************************
//
//  Author(s)...: Pashgan    http://ChipEnable.Ru, Petrov http://svyaz.blogspot.com/
//
//  Target(s)...: ATtiny2313
//
//  Compiler....: IAR EWA 5.11
//
//  Description.: ATtiny sensor
//
//  Data........: 19.01.11
//
//***************************************************************************
#include <ioavr.h>
#include <intrinsics.h>
#include "usart.h"
 
//макросы для работы с битами
#define InvBit(reg, bit)  reg ^= (1<<(bit))
#define ClearBit(reg, bit)       reg &= (~(1<<(bit)))
#define SetBit(reg, bit)          reg |= (1<<(bit))
#define BitIsSet(reg, bit)       ((reg & (1<<bit)) != 0)
 
//сколько циклов опроса кнопка должна удерживаться
#define THRESHOLD 20
// величина которую, возможно придется подстраивать
#define TOUCH_COUNT 1 
//переменные для подсчета количества переполнений Т0
volatile unsigned char sub_time_pin0 = 0;
volatile unsigned char sub_time_pin1 = 0;
//переменная для защиты от дребезга
unsigned char comp = 0;
 
int main( void )
  USART_Init();
 
  // Инициализация таймера T0 для Tiny2313
  TIMSK = (1<<OCIE0A);    //разрешаем прерывание таймера T0 при событии совпадение
  TCCR0A = (1<<WGM01)|(0<<WGM00);
  TCCR0B = (0<<CS02)|(1<<CS01)|(0<<CS00);  //режим СТС, прескалер - 8
  TCNT0 = 0;              //обнуляем счетный регистр
  OCR0A = 0x32;            //прерывания каждые ~ 50мкс
 
  // Инициализация таймера T1 для Tiny2313
  TIMSK |= (1<<OCIE1A);                 //разрешаем прерывание таймера т1 при событии совпадение
  TCCR1A = (0<<WGM11)|(0<<WGM10);
  TCCR1B = (0<<WGM13)|(1<<WGM12)|(0<<CS12)|(1<<CS11)|(0<<CS10);  //режим работы СТС, прескалер - 8
  TCNT1 = 0; //обнуляем счетный регистр
  OCR1A = 0x2710; //прерывания  каждые 10мс
 
  //разрешаем прерывания  
  __enable_interrupt();
  USART_SendStr("Button: "); 
  DDRD |=(1<<PD2)|(1<<PD3)|(1<<PD4); //устанавливаем  PD2, PD3 и PD4 на выход
  PORTD = 0;
 
//++++++++++++++++++++++++++++++++++++++++++++++++++
  while(1){
  /*если на выводе PB0 единица и таймер переполнился 
  несколько раз -> увеличить антидребезговую переменную
  затем, если значение переменной comp превысило порог ->
  инвертировать пин PD2, послать по УАРТУ номер кнопки,
  обнулить антидребезговую переменную  */
  if (BitIsSet(PINB, PB0)) { 
     if (sub_time_pin0 > TOUCH_COUNT) { 
        comp++;   
        if (comp >= THRESHOLD){ 
           InvBit(PORTD,PD2); 
           USART_SendStr("1 "); 
           comp = 0;
        }
     }
     sub_time_pin0 = 0;
   }
  /* то же самое */
  if (BitIsSet(PINB, PB1)) {
     if (sub_time_pin1 > TOUCH_COUNT) {
       comp++;
       if (comp >= THRESHOLD){
          InvBit(PORTD, PD3);
          USART_SendStr("2 "); 
          comp=0;
       }
     }
     sub_time_pin1 = 0;
  }
//++++++++++++++++++++++++++++++++++++++++++++++++++    
  }
  return 0;
}
 
// Прерывание Таймера 0 используемого для сканирования пина
#pragma vector = TIMER0_COMPA_vect
__interrupt void Timer0Comp(void)
{
// Увеличиваем на 1 счетчики переполнений таймера  
  sub_time_pin0++;
  sub_time_pin1++;
  
//это для мониторинга в Протеусе
  InvBit(PORTD,PD4);
}
 
// Прерывание Т1
//Инициализация порта, к которому подключены сенсорные кнопки согласно алгоритму
#pragma vector = TIMER1_COMPA_vect
__interrupt void Timer1CompA(void)
{
  //переключаем порт в режим выхода и устанавливаем 0
  //разряжая паразитную емкость на внутренние цепи AVR
  DDRB = 0xFF;
  PORTB = 0x00;
  
  //переключаем порт в режим входа в состоянии Hi-Z
  DDRB = 0x00;
 
  //обнуляем количество срабатываний для нулевого и первого выводов PORTB
  sub_time_pin0 = 0; 
  sub_time_pin1 = 0; 
  
  TCNT0 = 0; // Обнуляем счетный регистр T0

Comments   

# TERMIN 2011-02-02 22:41
Отличный проектик, как макетная плата придет, сразу попробую на ней
# Petrov 2011-02-03 03:03
Страрамся :-) Скоро будет про ИК управление и, в перспективе, обмен данными между МК по инфракрасному каналу.
# ANN 2011-02-03 03:31
Интересно всё изложено....хот елось бы увидеть фото данной модели. Наверняка будет красивенько :)
# Pashgan 2011-02-03 11:49
Petrov!! Где фотографии?
# CrazySynergetic 2011-02-03 10:02
Не хилая такая кнопочка, которая таймер у тебя отжирает... Зато модно...
# Pashgan 2011-02-03 12:07
Да ладно, при грамотном программировани и эти таймеры можно задействовать и для остальных нужд.
# CatMurr 2011-02-03 11:45
На Хабре недавно была подобная статья, немного схемотехника другая, а принцип тот же. Хорошо б такую клавиатуру делать на кмоп логике, чтоб ресурсы не отжирала!
# Petrov 2011-02-03 13:29
:-) Та какие там фотографии, не делал еще само устройство. Вообще задумывалось как выключатель света в ванной и туалете. Малышка не дотягивается, а жена запретила стену сверлить и выключатель ниже ставить. Был вариант висюльку повесить, ну знаете дернешь включилось, еще раз выключилось, также было зарезано на корню. Вот и пришла идея наклеить прозрачным скотчем тонкие проводники, опустив до нужного уровня(где детка достанет) Идея реализована на макетке, а до "внедрения на производстве" пока руки не дошли :lol: Обещаю как сделаю - выложу.
# Leo 2012-11-20 10:40
Может лучше датчик движения поставить? Я тут для туалета делаю схему. Два датчика движения, управление яркостью и задержкой освещения, управление вытяжкой.
# Витек. 2011-02-03 14:49
Обалдеть. Вы про статику не слыхали что ли? Может оказаться что вход проживет до первого нажатия, потом ноге AVRки каюк. Про электрошокер молчу.
# Pashgan 2011-02-03 15:28
1. Между сенсором и пальцем находится изолятор.
2. Входы защищены двумя диодами.
3. Можно добавить между выводом и подтягивающим резистором низкоомный резистор для ограничения входного тока.
4. И наконец кто мешает поставить стабилитроны или супрессоры (TVS-диоды).
# Витек. 2011-02-03 15:59
Входы защищены диодами - супер! Без резисторов, но диоды стоят. И много они простоят при 500 вольтовых скачках "через изолятор"? :) Ну так что мешало нарисовать защиту-то, чтобы начинающие не набивали себе шишек?
# Pashgan 2011-02-03 19:36
Quote:
Ну так что мешало нарисовать защиту-то, чтобы начинающие не набивали себе шишек?
Ничего страшного, от шишек еще никто не умирал. Наоборот, они как правило идут на пользу.
# Petrov 2011-02-04 02:51
Quoting Витек.:
...Ну так что мешало нарисовать защиту-то, чтобы начинающие не набивали себе шишек?

Дык кто вам мешает, окажите услугу покажите как надо! Мы вам спасибо скажем. А критиковать то проще всего, не иначе. 8)
Предрекая все дальнейшие размышления и вопросы предлагаю ознакомится с AppNote от Atmel
(http://www.atmel.com/dyn/resources/prod_documents/doc10620.pdf)
Документ многим будет интересен, как в части защиты от статики, так и в части юзабилити.
# GurovIlya 2011-02-04 05:05
Опасения правильные. Посмотрите по ссылке, там есть Описание эффективности типовых методик защиты от статического электричества при разработке сенсорных клавиатур (Effects of ESD Protection Devices on Capacitive Sensing Performance) an376. http://www.efo.ru/doc/Silabs/Silabs.pl?2050
# CatMurr 2011-02-04 06:12
А при разработке платы для сенсора, когда площадки расположены на одном слое, что делать со вторым? Оставить металлизацию, оставить и присоединить к земле или удалить? Atmel, насколько я понял при беглом просмотре, рекомендует к земле...
# Владимир 2011-02-16 08:30
Полагаю, теория изложена не верно,
наводки окружающих электрических полей,которые вокруг нас наведённые на тело человека 50 гц,передаёт при прикосновении к сенсору.а никакое не изменение ёмкости.
Представьте,что ваше устройство надо будет эксплуатировать в чистом поле, где нет ЛЭП и прочих коммуникаций и электрических полей,
Ваше устройство там работать не будет,
нечему там наводиться на тело человека.
# Pashgan 2011-02-16 21:59
Теория подробно изложена на страницах интернета. Проект не мой. Повторю конструкцию и сообщу о результатах.
# Владимир 2011-02-23 11:35
Quote:
Повторю конструкцию и сообщу о результатах
Уважаемый Pashgan,
Ну чего нам ссылаться на чужие источники,мало ли кто какой бред пишет?..)))и проверки этих сомнительных теорий,
Хотя,любая теория проверяется практикой,
поэтому,
давайте рассуждать логически и здраво,
возьмите в руку щуп осциллографа,и Вы сразу увидите эти наводки на экране в виде синусоиды 50 гц,
коснитесь пальцем НЧ усилителя,и в колонках Вы услышите этот самый фон 50 Гц,
наводимый на ваше тело, Ваш палец и передаёт на вход УНЧ этот самый сигнал, точно так же,как и в случае с сенсорами,
если только речь не идёт об действительно измерении ёмкости вашего тела в пикофарадах и сравнением этой ёмкости после измерения её с заданной величиной,
но в этой статье,как я понял ,речь идёт вовсе не о таком варианте работы схемы.
# Владимир 2011-02-23 11:43
Quote:
поэтому при поднесении пальца к сенсору суммарная емкость на входе микроконтроллера увеличится (ведь при параллельном соединении конденсаторов их емкости складываются). По именениям этой емкости и можно делать вывод о прикосновении к сенсору.

Я собственно об этом куске текста в Вашей статье.
# Petrov 2011-02-23 14:10
"Я вам удивляюсь" Владимир :lol: .
Еще раз цитирую вами же процитированный кусок Quote:
поэтому при поднесении пальца к сенсору
. Нет прямого контакта! по ТЗ, его нет :D По нахватались вершков. В коментах даже на апноуты от атмела ссылки есть, потрудитесь почитать. Quote:
если только речь не идёт об действительно измерении ёмкости вашего тела в пикофарадах и сравнением этой ёмкости после измерения её с заданной величиной, но в этой статье,как я понял ,речь идёт вовсе не о таком варианте работы схемы.
Именно об этом идет речь. :P
# Владимир 2011-02-24 08:53
Petrov
Я оказался не прав,вынужден признать,
невнимательно читал,сейчас перечитал заново статью.
получается нечто похожее на QT102 от Атмел.
# ankar 2011-03-13 21:15
На гетчипе getchip.net эта система полностью отработана. И работает без помех. Так, что прежде чем критиковать автора повторите схему. А потом лезте в дебри.
# кулибин 2011-05-04 08:29
данная кнопка врятли может применяться в реальных схемах так как много ресурсов и без того слабого avr потребляет -я предлагаю Вам использовать мой вариант сенсорной кнопки которая надежно работает=радо вход порта контроллера поставить на ноль (без подтяжки)и в обратном направлении подключить диод на плюс а кнопка будет состоять из этого входа и минусовой площадки рядом и при прикосновении этих двух контактов вход вполне надежно работает как сенсор сопротивление пальца вполне достаточно для работы входа
# Alca 2011-06-28 08:58
Подскажите, а что можно сделать чтоб поднять чувствительност ь?
# AVRson 2011-11-17 13:37
Спасибо большое автору за материалы на сайте! Много полезного нашел тут. Сижу перечитываю все статьи, хочу объединить многие вещи в один проект :).
# Иван 2011-12-25 20:03
Сделал печатную плату, проверял несколько раз:

http://s002.radikal.ru/i197/1112/82/60e7235f654c.jpg

Впаял все компоненты, прошил, но не работатет.
При подаче питани постоянно горит красная один из светодиодов, второй не горит вообще. нет никакой реакции на прикосновение к сенсору.

Помогите разобраться.
# ROM 2012-01-02 10:31
По схеме в протеусе...
Я пока не разобрался для чего у МК на ноге PD4 прямоугольные импульсы подаються на вход осцилографа, но если ее отключить - то реакция на нажатия кнопки довольно быстрая. Т.е. с осцилографом нужно подождать больше времни на то чтобы сработало нажатие.
# ROM 2012-01-02 21:35
Может кто-то конвертировать исходик с Тини2312 на Атмегу8? Очень нужно, весь десь сам проседел - так и не получилось разобраться (не все понятно с таймерами). Помогите пожалуйста начинающему!!!
# vikfreeman 2012-01-29 15:40
Добрый вечер! Я планирую использовать данную схема для своего проекта. Скажите мне пожалуйста, он через диэлектрик будет работать??? На сенсор (металл) хочу нанести один слой маслянной краски.
# Сергей123 2012-02-26 11:56
Будет
# DmitryyDAS 2012-09-29 23:26
Отличная статья - большое спасибо!!!))
# oxidizer 2013-02-08 11:51
Полезная статья. Большое спасибо.
Но вроде напутано в коде с PD2 PD3 PD4.
# mash 2015-02-14 16:09
Портировал проект на STM8L101. Кнопки работают отлично! Спасибо большое!!!
Попытался добавить звук, но включение еще одного таймера вызвало периодическое мигание светодиодов. Пока не разобрался где влияние. Прошу помочь, кто знает.
Code:
#include "stm8l10x_tim2.h"
#include "stm8l10x_tim3.h"
#include "stm8l10x_tim4.h"
#define Threshold 20
#define TouchCount 6 // подбор нужен
volatile unsigned char stpin0 = 0;
volatile unsigned char stpin1 = 0;
unsigned char comp = 0;

int main( void )
{
GPIO_Init(GPIOC,GPIO_Pin_0,GPIO_Mode_Out_PP_High_Fast);
GPIO_Init(GPIOC,GPIO_Pin_1,GPIO_Mode_Out_PP_High_Fast);
GPIO_Init(GPIOD,GPIO_Pin_0,GPIO_Mode_Out_PP_High_Fast);
CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv1);

// TIM2 прерывания каждые 50 мкс
CLK_PeripheralClockConfig(CLK_Peripheral_TIM2,ENABLE);
TIM2_TimeBaseInit(TIM2_Prescaler_1,TIM2_CounterMode_Up,200);
TIM2_ITConfig(TIM2_IT_Update,ENABLE); TIM2_Cmd(ENABLE);

// TIM3 прерывания каждые 10 мс
CLK_PeripheralClockConfig(CLK_Peripheral_TIM3, ENABLE);
TIM3_TimeBaseInit(TIM3_Prescaler_2, TIM3_CounterMode_Up, 40000);
TIM3_ITConfig(TIM3_IT_Update,ENABLE); TIM3_Cmd(ENABLE);

// TIM4 Звук
CLK_PeripheralClockConfig(CLK_Peripheral_TIM4,ENABLE);
TIM4_TimeBaseInit(TIM4_Prescaler_256, 200);
TIM4_ITConfig(TIM4_IT_Update,ENABLE);
TIM4_Cmd(ENABLE);

__enable_interrupt();

# mash 2015-02-14 16:32
Code:
while(1)
{
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)){if(stpin0>TouchCount){comp++;if(comp>=Threshold){GPIO_ToggleBits(GPIOC,GPIO_Pin_0);comp=0;}}stpin0=0;}
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)){if(stpin1>TouchCount){comp++;if(comp>=Threshold){GPIO_ToggleBits(GPIOC,GPIO_Pin_1);comp=0;}}stpin1=0;}
}
return 0;
}

INTERRUPT_HANDLER(TIM2_OVF, 19)
{
if (TIM2_GetFlagStatus(TIM2_FLAG_Update))
{
stpin0++; stpin1++;
TIM2_ClearFlag(TIM2_FLAG_Update);
}
}

INTERRUPT_HANDLER(TIM3_OVF, 21)
{
if (TIM3_GetFlagStatus(TIM3_FLAG_Update))
{
GPIO_Init(GPIOB, GPIO_Pin_0, GPIO_Mode_Out_OD_Low_Fast);
GPIO_Init(GPIOB, GPIO_Pin_1, GPIO_Mode_Out_OD_Low_Fast);
GPIO_Init(GPIOB, GPIO_Pin_0, GPIO_Mode_In_FL_No_IT);
GPIO_Init(GPIOB, GPIO_Pin_1, GPIO_Mode_In_FL_No_IT);
stpin0 = 0; stpin1 = 0;
// ? Обнуляем счетный регистр
TIM3_ClearFlag(TIM3_FLAG_Update);
}
}

INTERRUPT_HANDLER(TIM4_OVF, 25)
{
if (TIM4_GetFlagStatus(TIM4_FLAG_Update))
{
GPIO_ToggleBits(GPIOD,GPIO_Pin_0); // Вывод звука
TIM4_ClearFlag(TIM4_FLAG_Update);
}
}
# mash 2015-02-16 05:51
Кнопки работают отлично, пока не разрешишь еще один таймер. Если частота его низкая (раз в секунду), то кнопки работают (но это же не звук!). Если частота звуковая, то либо диоды моргают, либо кнопки не реагируют (если TouchCount увеличить до 8, чтоб диоды не моргали). В общем почему то доп.таймер вызывает как бы сработку кнопок. Может быть быстродействия не хватает? Тактовая 16 МГц.
# mash 2015-02-18 09:45
Вот, первая версия кнопок со звуком (многотон. звонок или пианино).
Code:
#define TouchCount 6
int time=6500;

void Sound(int Freq);
char ovf0,ovf1,ovf2,ovf3,ovf4,ovf5,ovf6,ovf7;

int main( void )
{
GPIO_Init(GPIOA,GPIO_Pin_2,GPIO_Mode_Out_OD_HiZ_Slow);

CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv1);

// TIM4 прер. 40 мкс
CLK_PeripheralClockConfig(CLK_Peripheral_TIM4,ENABLE);
TIM4_TimeBaseInit(TIM4_Prescaler_4, 155);
TIM4_ITConfig(TIM4_IT_Update,ENABLE); TIM4_Cmd(ENABLE);

// TIM2 прер. 2.5 мс
CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);
TIM2_TimeBaseInit(TIM2_Prescaler_1, TIM2_CounterMode_Up, 40000);
TIM2_ITConfig(TIM2_IT_Update,ENABLE); TIM2_Cmd(ENABLE);

//----- Инициализация TIM3 -- Звук
CLK_PeripheralClockConfig(CLK_Peripheral_TIM3, ENABLE);
TIM3_TimeBaseInit(TIM3_Prescaler_2, TIM3_CounterMode_Up, 20000);
TIM3_ITConfig(TIM3_IT_Update,ENABLE); TIM3_Cmd(DISABLE);

__enable_interrupt();

while(1)
{
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)) {if(ovf0 > TouchCount) Sound(4000); ovf0=0;}
. . .

// пока проверил на 11 кнопках

if (time==0)
{
TIM3_Cmd(DISABLE); time=6500;
GPIO_Init(GPIOA,GPIO_Pin_2,GPIO_Mode_Out_OD_HiZ_Slow);
} else time--;
}
return 0;
}

INTERRUPT_HANDLER(TIM4_UPD, 25)
{
ovf0++; ovf1++; ovf2++; ovf3++; ovf4++; ovf5++; ovf6++; ovf7++;
TIM4_ClearFlag(TIM4_FLAG_Update);
}

INTERRUPT_HANDLER(TIM2_UPD, 19)
{
GPIO_Init(GPIOB, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Fast);
GPIO_Init(GPIOB, GPIO_Pin_All, GPIO_Mode_In_FL_No_IT);
TIM2_ClearFlag(TIM2_FLAG_Update);
}

INTERRUPT_HANDLER(TIM3_UPD, 21) // Звук
{
GPIO_ToggleBits(GPIOA,GPIO_Pin_2);
TIM3_ClearFlag(TIM3_FLAG_Update);
}

void Sound(int Freq)
{
TIM3_TimeBaseInit(TIM3_Prescaler_2, TIM3_CounterMode_Up, Freq); TIM3_Cmd(ENABLE);
}

У вас недостаточно прав для комментирования.