Trisector

Коротенький "бип"

43 сообщения в этой теме

Trisector    139

Привет всем.

Помогите с кодом, нужно озвучить нажатие кнопки, подключенной к порту PB0, то есть просто издать короткий "бип" одной частоты (примерно 1000 Гц) и длительностью примерно 0.2 секунды.

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

Выполняться оно должно в теле цикла:

while (1) 
    {
        while(PINB&0b00000001); // ждем нажатия на кнопку на порте PB0

<вот здесь должен быть бип>

 

п.с. забыл добавить - выполняться код будет на Attiny13a

Изменено пользователем Trisector

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291

if((PINB&0x01)==0){bip();}

 

//Func bip:

void bip()

{

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

delay_us(500);

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

delay_us(500);

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

delay_us(500);

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

}

Прошу прощения за такой корявый формат , с телефона пишу..

Такой пример в цикле будет выполнять ваши требования.

Можно добавить флаг и сбрасывать его когда нажатие уже произошло , чтобы бип был короткий и нужной длительностью.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139
12 минуты назад, artos5 сказал:

добавить флаг и сбрасывать его когда нажатие уже произошло , чтобы бип был короткий и нужной длительностью

Кстати да, это было бы удобно.

А можно весь бип заключить в цикл? чтобы не писать кучу одинаковых строк, то есть типа

int i;

for (i=0; i<200; i++)

{

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

delay_us(500);

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291

Естественно можно :)

С телефона неудобно писать много текста , накопировал бипов )))

Можно сделать и так:

void bip(int bip_time)

{

int i;

for (i=0; i<bip_time; i++)

{

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

delay_us(500);

}}

И будет бип нужной длительности , которую можно предварительно задать .

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139

Окей, так правильно будет?

 

int main(void)

{

// тут определяем входы-выходы, настраиваем порты

void bip(int bip_time) // определяем новую функцию "бип"

{

int i;

for (i=0; i<bip_time; i++)

{

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

delay_us(500);

}

}

     while (1)

     {

     while(PINB&0b0000001); // ждем нажатия на кнопку на порте PB0

     bip(200); // 200 циклов по 1 миллисекунде

     }

Изменено пользователем Trisector

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291

Нет , неправильно . Функция бип не должна быть в функции main()

Она должна быть до нее , или после нее с указанием прототипа (или как правильно называется, спецы поправят).

 

 

void bip(int bip_time) // определяем новую функцию "бип"

{

int i;

for (i=0; i<bip_time; i++)

{

PORTB|=0x02;

delay_us(500);

PORTB&=~0x02;

delay_us(500);

}

}

int main(void)

{

char flg=1;

// тут определяем входы-выходы, настраиваем порты

     while (1)

     {

     if((PINB&0x01)==0 && flg) {

     bip(200); // 200 циклов по 1 миллисекунде

 flg=0;}

if(PINB&0x01)flg=1;

     }}

Вот так заработает!

Можно сделать при помощи аппаратного таймера и дергать ногой при помощи прерывания по переполнению или при помощи аппаратного ШИМ , такое решение не будет сильно задействовать процессорное время и программа сможет выполнять другие задачи с высокой производительностью.

  • Одобряю 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139
19 минут назад, artos5 сказал:

при помощи аппаратного таймера и дергать ногой при помощи прерывания по переполнению или при помощи аппаратного ШИМ , такое решение не будет сильно задействовать процессорное время и программа сможет выполнять другие задачи с высокой производительностью

Нет, тут требуется простое решение, все операции выполняются последовательно.

Пошел проверять в Протеусе.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291

А что проверять? Проверять-то нечего)) будет работать !. Настрой только pb1 на выход. А pb0 на вход с подтяжкой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Aleksei80    0

Протеус всякие моргалки и бипы не очень хорошо делает. Уж лучше тогда на макетке. А так да - там все будет работать, если только не косячить с частотой, кварцем и фьюзами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139

Никак не могу разобраться, почему побитовое управление

PORTB|=(0<<3);

не работает

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291
4 минуты назад, Trisector сказал:

PORTB|=(0<<3);

Так надо так:

PORTB|=(1<<3);

Ещё можно так :

PORTB|=0x08;

Это тоже самое что предыдущее )

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139

да какая разница, 0 там или 1

просто управление всем портом работает, а побитовое нет.

вот это работает

PORTB=0b00011001;

_delay_ms(1000);

PORTB=0b00000001;

а вот это - нет

PORTB=0b00011001;
    _delay_ms(1000);
    PORTB|=(0<<3);
    PORTB|=(0<<4);

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291
3 минуты назад, Trisector сказал:

 PORTB|=(0<<3);
    PORTB|=(0<<4);

 

Оно и не будет работать как тебе надо))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139

а как тогда отдельными битами управлять и читать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
snn_krs    48

Для того чтобы установить бит надо применить операцию ИЛИ

PORTB |= ( 1 << N ); // N - номер бита который надо установить ( PORTB = PORTB | 0b00001000 для N = 3 )

Для того чтобы сбросить бит надо применить операцию И с нулем в нужной позиции

PORTB &= ~( 1 << N ); // ( PORTB = PORTB & 0b11110111 для N = 3 )

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291
3 минуты назад, Геннадий сказал:

ассемблерные вставки sbi и cbi ?

А зачем? Давай ещё сразу хекс поправим в ручную ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Геннадий    1 032

Религия не позволяет?:)

Неужели хуже выполнить одну команду, вместо трех?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291
2 минуты назад, Геннадий сказал:

Религия не позволяет?:)

Да нет))

Просто ему быстро не надо , поэтому и так сойдёт . Смысл от этого если он потом будет крутиться 0.5мс ничего не делая ? 

Тогда ему нужно уже ШИМ настроить , и уже шимом формировать меандр 1мс ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139

@snn_krs

Спасибо, почти разобрался.

Оказывается, нельзя просто так взять

SeanBeanBoromir.thumb.jpg.4b684018f7253a47007ce059fad4a83b.jpg

и установить ноль в каком-то бите, а нужно применять PORTB &= ~( 1 << N );

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    291

Ну так ясное дело . Это я и пытался тогда объяснить :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Геннадий    1 032
7 минут назад, Trisector сказал:

Оказывается, ...льзя просто так взять

и написАть

asm(sbi PORTB,x) - установить 1 на выводе порта или

asm(cbi PORTB,x) - установить 0 на выводе порта.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139
5 минут назад, Геннадий сказал:

и написАть

вот это уже гораздо понятнее.

только надо добавить __asm { } ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
солар    186
16 минут назад, Trisector сказал:

нужно применять PORTB &= ~( 1 << N );

Если вы пишете в CVAVR, то

PORTB.N= 0;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Trisector    139
2 минуты назад, солар сказал:

PORTB.N= 0;

в Atmel Studio выдает ошибку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Похожие публикации

    • Автор: parovoZZ
      Поставил LUFA, следом абсолютно не нужный мне ASF. Но в упор не понимаю - как создать проект на базе этой библиотеки из студии? Приходится вручную копировать папку с заголовочниками LUFA, прописывать пути в makefile, лишние телодвижения по добавлению папки в свойства проекта. Если я это делаю всё вручную, то тогда для чего это расширение? Примеры я могу и так покрутить. ЗЫ - не слишком высокий скилл в юзании Atmel Studio/
    • Автор: Zver2011
      Всем привет! 
      Дано: Контроллер подсветки рабочей зоны кухни, реализованный на Tiny 13A.  Светодиодная лента длиной 2,3 метра, led 5050, 120 светодиодов/метр. Принципиальная схема устройства ниже:

      Код прошивки:
      #include <tiny13.h> #include <delay.h> int triggered = 0; int ontimer = 0; void main(void) { // Input/Output Ports initialization // Port B initialization // Function: Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=Out DDRB=(0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (1<<DDB0); // State: Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=0 PORTB=(0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0); // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 37,500 kHz // Mode: Fast PWM top=0xFF // OC0A output: Non-Inverted PWM // OC0B output: Disconnected // Timer Period: 6,8267 ms // Output Pulse(s): // OC0A Period: 6,8267 ms Width: 0 us TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00); TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (0<<CS00); TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; while (1) { if (PINB.1==1) { triggered = 1; ontimer = 60; }; if (ontimer > 0) { ontimer--; } else { triggered = 0; }; if (triggered) { if (OCR0A<255) { OCR0A++; }; } else { if (OCR0A>0) { OCR0A--; }; }; delay_ms(10); } } Возникшая проблема:
      Греется полевой транзистор при работе. 
      Изначально поискав информацию на данную проблему, начал прикидывать. 
      Смотрим график зависимости пропускаемого тока стока (ID )от приложенного напряжения  затвор-сток (VGS),  при температуре окруж. среды 25 градусов: ID = 14 А (2,3 метра светодиодной ленты не могут столько кушать, по крайней мере я такую не видел).

      Было предположение что частота переключения ШИМ высокая - отсюда транзистор в не определенном состоянии = нагрев. Рассчитал макс. частоту так:
      Rg = 100 Ом, Vgs = 5V
      Заряд затвора:
      Qiss = Ciss * Vgs = 1800pF * 5v = 9nC
      Скрость нарастания:
      S = Rgate * Qiss = 100Ohm * 9nC = 0.009mV*sec
      Время на открытие или закрытие транзистора:
      t=S / Vgs = 0.002mV*sec * 3.2v = 4.5uSec
      Период  - это открытие + закрытие:
      T = t + t = 4.5uSec + 4.5uSec = 9uSec
      Максимальная частота переключения:
      F < 1 / T = 1 / 9uSec = 111KHz
      Ток через затвор (G) и цифровой выход Tiny 13A:
      I = Qiss / t = 2mA
      Максимальный выходной ток GPIO у Tiny 13A 40.0mA
      2mA < 40.0mA
      Выставил частоту ШИМ на 37,5 кHz. Вуаля - при подключении 1м светодиодной ленты (тестировал на обрезке), нагрева нет. Но как только подключил все 2,3 метра - транзистор стал снова спустя время греться, аж дотронуться не возможно.  Захотел померить ток, который потребляет 1 метр ленты, проверить продавца. Потребление 1 метра ленты оказалось вместо заявленных 600 мА, все 1,85 А, причем заметил странную вещь - ток начал возрастать спустя время на сотые доли  и дошел до 1,9 А. Дальше ждать не стал. Режим амперметра в мультиметре сломался?
      Далее подумал что слишком большая мощность рассеивается на транзисторе. Если учесть то, что при открытом транзисторе, его переход можно представить в виде линейного резистора с маленькой величиной сопротивления,  можно рассчитать рассеиваемую мощность на транзисторе:
      Смотрим сопротивление транзистора в открытом состоянии при VGS = 5В : RDS(on) = 0.18 Ом
      P1 = 1,9*1,9*0,18 = 0,65 Вт. (1 метр св.ленты).
      Раз мы взяли потребление 1 метра ленты  1, 9 А, тогда 2,3 метра потребляют  = 4,4 А. (Теперь не уверен в своем мультиметре).
      P2=4.4*4.4*0.18 = 3.5 Ватт - довольно таки многовато я думаю.
      В общем: Правильно ли я делаю расчеты? Что упустил?  Как снизить нагрев транзистора, без применения вентиляторов и здоровенных радиаторов? Есть вариант замены светодиодной ленты на что нибудь поменьше жрущее (60 светодиодов/ метр например), но в будущем еще много раз придется сталкиваться с полевиками, хотелось бы разобраться .
    • Автор: Денис Оробей
       Помогите написать простую задачку (для вас - простую, а я не шарю), на плате контроллера-конструнтора KIT-8515 нужно  сделать вот это: "Пусть движковыми переключателями задаются два четырехзначных операнда.  Напишите и протестируйте программу, при работе которой после нажатия кнопки 1 операнды складывались, а при нажатии кнопки 2 операнды вычитались, а результат операции выводился на светодиоды"
      Прикреплённый файл - начало задачки.
      Заранее благодарствую:)
      123.rar
    • Автор: Николай Зубий
      Как сделать  устройство, выводящие на индикатор время, прошедшее с момента последней перезагрузки контроллера?
    • Автор: forestdozor
      Здравствуйте!

      Мне нужно измерить длительность импульса. Для этого сначала применял внешнее прерывание, а теперь перешел на режим захвата таймера в Atmega 328.
      Однако сейчас происходит странное: Через определенное таймер просто останавливается. Гугл результатов не дает, ни у кого захват таймера 1 не останавливается.
      Подскажите пожалуйста, что делать?
      Среда разработки CodeVisionAVR v3.12. Сейчас попробовал версию 3.3, толку нет. Не работает. Код максимально упростил, но по прежнему толку ноль.
      Переполнение таймера 0 так же работает отлично, до тех пор, пока что-то не произойдет с прерыванием по захвату. Как только что-то произошло - мк останавливается...
      Может немножко подождать, и увеличить значение счетчика current_timp еще на пару значений... Совсем не знаю что делать.
       
       
      interrupt [TIM1_OVF] void timer1_ovf_isr(void)
      {
      TCNT1H = 0x00;
      TCNT1L = 0x00;
      }
      // Timer1 input capture interrupt service routine
      interrupt [TIM1_CAPT] void timer1_capt_isr(void)
      {
       
             TCNT1H = 0x00;
             TCNT1L = 0x00;           // Это уже уровень танцев с бубном "авось поможет" - не помогает.
         
              current_timp++;          // Все упрощено до максимума. Мне бы он хоть количество периодов для начала...
              
        //  }
      }
      // Прерывание по переполнению первого таймера
      interrupt [TIM0_OVF] void timer0_ovf_isr(void)
      {
      // Обнуление счетного регистра.
      TCNT0=0x00;

          
          counter ++;
          if (counter > 10)
          {
                  lcd_clear();
                  sprintf(buffer,"%d us", current_timp);
                  lcd_gotoxy(0,0);
                  lcd_puts(buffer);
                  counter = 0;
          }
          
          
      }

      // Главный цикл программы
      void main(void)
      {

      #pragma optsize-
      CLKPR=(1<<CLKPCE);
      CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
      #ifdef _OPTIMIZE_SIZE_
      #pragma optsize+
      #endif

      // Port B initialization
      // Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
      DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
      // State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
      PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
      // Port C initialization
      // Function: Bit6=In Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
      DDRC=(0<<DDC6) | (1<<DDC5) | (1<<DDC4) | (1<<DDC3) | (1<<DDC2) | (1<<DDC1) | (1<<DDC0);
      // State: Bit6=T Bit5=1 Bit4=1 Bit3=1 Bit2=1 Bit1=1 Bit0=1
      PORTC=(0<<PORTC6) | (1<<PORTC5) | (1<<PORTC4) | (1<<PORTC3) | (1<<PORTC2) | (1<<PORTC1) | (1<<PORTC0);
      // Port D initialization
      // Function: Bit7=Out Bit6=Out Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
      DDRD=(1<<DDD7) | (1<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
      // State: Bit7=1 Bit6=1 Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
      PORTD=(1<<PORTD7) | (1<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);
      // Делители таймера 0 рассчитаны таким образом , что его тактовая частота = 15,625 КГц. Расчет был на применение в схеме семисегментников, но с LCD индикатором будет информативнее.
      TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
      TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (1<<CS00);
      TCNT0=0x00;
      OCR0A=0x00;
      OCR0B=0x00;
       
      // Настройка таймера 1
      TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
      TCCR1B=(1<<ICNC1) | (1<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);
      TCNT1H=0x00;
      TCNT1L=0x00;
      ICR1H=0x00;
      ICR1L=0x00;
      OCR1AH=0x00;
      OCR1AL=0x00;
      OCR1BH=0x00;
      OCR1BL=0x00;
      // Разрешение прерывания по переполнению таймера 0
      TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0);
      // Timer/Counter 1 Interrupt(s) initialization
      TIMSK1=(1<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (1<<TOIE1);