Создание тонов в определенный промежуток времени с использованием программирования на C
Я использую язык C для PIC18F для создания тонов, которые воспроизводятся каждым из них в определенный промежуток времени. Я использовал ШИМ для создания тона. Но я не знаю, как создать интервалы. Вот моя попытка.
#pragma code //
void main (void)
{
int i=0;
// set internal oscillator to 1MHz
//OSCCON = 0b10110110; // IRCFx = 101
//OSCTUNEbits.PLLEN = 0; //PLL disabled
TRISDbits.TRISD7 = 0;
T2CON = 0b00000101; //timer2 on
PR2 = 240;
CCPR1L = 0x78;
CCP1CON= 0b01001100;
LATDbits.LATD7=0;
Delay1KTCYx(1000);
while(1);
}
3 ответа
Когда я занимаюсь встроенным программированием, я нахожу чрезвычайно полезным добавлять комментарии, поясняющие, что именно я имею в виду, когда я устанавливаю регистры конфигурации. Таким образом, мне не нужно возвращаться к таблицам данных, чтобы выяснить, что 0x01001010
делает, когда я пытаюсь получить код в следующий раз, когда я должен изменить его. (Просто убедитесь, что комментарии синхронизированы с изменениями).
Из того, что я могу декодировать, похоже, что у вас настроены ШИМ-регистры, но нет способа изменить частоту с заданными интервалами. Есть несколько способов сделать это, вот две идеи:
- Вы можете прочитать таймер при запуске, добавить желаемый интервал, чтобы получить целевое время, и опрашивать таймер в цикле while. Когда таймер достигнет цели, установите новый рабочий цикл ШИМ и добавьте следующий интервал к целевому времени. Это будет работать нормально, пока вы не начнете делать другие вещи в фоновом цикле.
- Вы можете установить счетчик timer0 в
0xFFFF-interval
и установите его для прерывания при опрокидывании. В ISR установите новый рабочий цикл ШИМ и сбросьте счетчик таймера 0 до следующего интервала.
Один из распространенных способов управления синхронизацией во встроенных процессах выглядит следующим образом:
int flag=0;
void main()
{
setup_interrupt(); //schedule interrupt for desired time.
while (1)
{
if (flag)
{
update_something();
flag = 0;
}
}
Где же flag
приготовься? В обработчике прерываний:
void InterruptHandler()
{
flag = 1;
acknowledge_interupt_reg = 0;
}
У вас есть все части в вашем примере, вам просто нужно собрать их в нужных местах. В твоем случае, update_something()
обновил бы ШИМ. Логика будет выглядеть так: "Если он включен, выключите его; в противном случае включите его. Обновите тон (коэффициент заполнения), если это необходимо"
Не должно быть необходимости в дополнительных задержках или паузах в основном цикле while. Цель в том, чтобы он просто бегал снова и снова, ожидая, что что-то сделать. Если программе нужно делать что-то еще с другой скоростью, вы можете добавить еще один флаг, который срабатывает совершенно независимо, и синхронизация этих двух задач не будет мешать друг другу.
РЕДАКТИРОВАТЬ:
Теперь я смущен тем, что вы пытаетесь достичь. Вы хотите серию импульсов одного и того же тона (вкл-выкл-выкл)? Или вы хотите серию разных нот без пауз (do-re-me-fa -...)? Я предполагал последнее, но теперь я не уверен.
После просмотра вашего обновленного кода я не уверен, как именно настроена ваша система, поэтому я просто задам несколько вопросов, которые, я надеюсь, будут полезны.
-
Работает ли ШИМ?Вы получаете начальный тон?Я предполагаю, что да. -
Есть ли на вашем оборудовании какой-то тактовый импульс, подключенный к выводу RA4/T0CKI?Если нет, то вам нужен режим T0, а не режим счетчика. -
Вызывается ли прерывание?Вы устанавливаете INT0IE, который включает внешнее прерывание, а не прерывание по таймеру -
Какой интервал вы хотите между обновлениями тонов?Прямо сейчас вы получаете0xFFFF / (clock_freq/8)
Вам нужно установить регистры TMR0H/L, если вы хотите что-то другое. - Что на LATD7? и почему вы это очищаете? Вы говорите, что это позволяет выход ШИМ?
- Почему вызов Delay()? Сам таймер должен обеспечивать необходимую задержку. Кажется, есть разногласия по поводу того, как сделать выбор времени. Я расширю свой другой ответ
- Где вы пытаетесь изменить частоту ШИМ? Вам не нужно писать в PR2? Вам нужно будет дать ему другое значение для каждого другого тона.
Msgstr "Остановка сборки при первом сбое в соответствии с запросом."
Это просто говорит о том, что у вас есть какая-то синтаксическая ошибка, не показывая нам отчет об ошибке, мы не можем помочь.
В Windows вы можете использовать функцию Beep в kernel32:
[DllImport("kernel32.dll")]
private static extern bool Beep(int frequency, int duration);