Seeeduino XIAO считывает продолжительность (период) ШИМ, используя таймеры, которые меняют контакты с D2 на D1.
Я спроектировал печатную плату, и мне нужно проверить работоспособность. Поэтому мне нужно изменить код, чтобы он считывал данные с контактов D1, а не с D2. К сожалению, я не знаком с высокоуровневым программированием, поэтому я не уверен, что получил все изменения. В основном используются все PINS в цепи.
Базовый код можно найти здесь: Seeeduino XIAO записывает и читает длительность (период) ШИМ с помощью таймеров
Чтение коротких прямоугольных сигналов с выводом D2 Seeeduino XIAO
// Настройте TC4 для захвата ширины и периода импульса на цифровом выводе D2 на Seeeduino Xiao
volatile boolean periodComplete;
volatile uint32_t isrPeriod;
volatile uint32_t isrPulsewidth;
uint32_t period;
uint32_t pulsewidth;
void setup() {
SerialUSB.begin(115200); // Инициализируем родной последовательный порт
while(!SerialUSB); // ждем открытия консоли
PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Включаем периферийное устройство системы событий
GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) | // Делим системную частоту 48 МГц на 1 = 48 МГц
GCLK_GENDIV_ID(4); // Установка деления на Generic Clock Generator (GCLK) 4
GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC | // Установите рабочий цикл на 50/50 ВЫСОКИЙ/НИЗКИЙ
GCLK_GENCTRL_GENEN | // Включить GCLK 4
GCLK_GENCTRL_SRC_DFLL48M | // Установите источник синхронизации на 48 МГц
GCLK_GENCTRL_ID(4); // Установить источник синхронизации на GCLK 4
while (GCLK->STATUS.bit.SYNCBUSY); // Ждем синхронизации
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Маршрутизируем GCLK4 к TC4 и TC5
GCLK_CLKCTRL_GEN_GCLK4 |
GCLK_CLKCTRL_ID_TC4_TC5;
// Включить мультиплексор портов на выводе порта PA10
PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
// Настраиваем контакт как EIC (прерывание) на контакте порта PA10
PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10; // Разрешить вывод события по внешнему прерыванию 10
EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH; // Установить событие обнаружения ВЫСОКОГО уровня
EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10; // Отключить прерывания по внешнему прерыванию 10
EIC->CTRL.reg |= EIC_CTRL_ENABLE; // Включить периферийное устройство EIC
while (EIC->STATUS.bit.SYNCBUSY); // Ждем синхронизации
EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) | // Прикрепляем пользователя события (получателя) к каналу 0 (n + 1)
EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU); // Установить пользователя события (получателя) как таймер TC4
EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // Нет обнаружения фронта события
EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Установить путь события как асинхронный
EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) | // Установить генератор событий (отправитель) как внешнее прерывание 10
EVSYS_CHANNEL_CHANNEL(0); // Прикрепляем генератор (отправитель) к каналу 0
TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI | // Разрешить ввод события TC
//TC_EVCTRL_TCINV | // Инвертировать вход события
TC_EVCTRL_EVACT_PPW; // Настраиваем таймер для захвата: период CC0, ширина импульса CC1
TC4->COUNT32.CTRLC.reg = TC_CTRLC_CPTEN1 | // Включить захват на CC1
TC_CTRLC_CPTEN0; // Включить захват на CC0
while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Ждем синхронизации
NVIC_SetPriority(TC4_IRQn, 0); // Установите приоритет Nested Vector Interrupt Controller (NVIC) для TC4 на 0 (самый высокий)
NVIC_EnableIRQ(TC4_IRQn); // Подключаем таймер TC4 к контроллеру вложенных векторных прерываний (NVIC)
TC4->COUNT32.INTENSET.reg = TC_INTENSET_MC1 | // Разрешить прерывания канала сравнения 1 (CC1)
TC_INTENSET_MC0; // Разрешить прерывания канала сравнения 0 (CC0)
TC4->COUNT32.CTRLA.reg = //TC_CTRLA_PRESCSYNC_PRESC | // Переполнение на часах предкалера (а не на GCLK)
TC_CTRLA_PRESCALER_DIV1 | // Установите прескалер на 1, 48 МГц/1 = 48 МГц
TC_CTRLA_MODE_COUNT32; // Установить TC4/TC5 в режим 32-битного таймера
TC4->COUNT32.CTRLA.bit.ENABLE = 1; // Включить TC4
while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Ждем синхронизации
}
void loop() {
if (periodComplete) // Проверяем, завершен ли период
{
noInterrupts(); // Читаем новый период и длительность импульса
period = isrPeriod;
pulsewidth = isrPulsewidth;
interrupts();
SerialUSB.print("PW: ");
SerialUSB.print(pulsewidth);
SerialUSB.print(F(" "));
SerialUSB.print("P: ");
SerialUSB.println(period);
periodComplete = false; // Начать новый период
}
}
void TC4_Handler() // Процедура обслуживания прерывания (ISR) для таймера TC4
{
// Проверка совпадения счетчика 0 (MC0) прерывание
if (TC4->COUNT32.INTFLAG.bit.MC0)
{
TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ | // Разрешить запрос на чтение
TC_READREQ_ADDR(0x18); // Адрес смещения регистра CC0
while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Ожидание (чтение) синхронизации
isrPeriod = TC4->COUNT32.CC[0].reg; // Копируем период
periodComplete = true; // Указываем, что период завершен
}
// Прерывание проверки совпадения счетчика 1 (MC1)
if (TC4->COUNT32.INTFLAG.bit.MC1)
{
TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ | // Разрешить запрос на чтение
TC_READREQ_ADDR(0x1A); // Адрес смещения регистра CC1
while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Ожидание (чтение) синхронизации
isrPulsewidth = TC4->COUNT32.CC[1].reg; // Копируем ширину импульса
}
}
Мне нужно только изменить IO:
от:
ПОРТ->Группа[PORTA].PINCFG[10].bit.PMUXEN = 1;
ПОРТ->Группа[ПОРТ].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
кому:
ПОРТ->Группа[PORTA].PINCFG[4].bit.PMUXEN = 1;
ПОРТ->Группа[ПОРТ].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;
или мне нужно модифицировать больше кода?
Спасибо за помощь.
@Hannes, 👍0
1 ответ
Лучший ответ:
Помимо упомянутых вами изменений, ваши способы использования EIC_EVCTRL_EXTINTEO10
, EIC_INTENCLR_EXTINT10
и EVSYS_ID_GEN_EIC_EXTINT_10
должны быть изменены на EIC_EVCTRL_EXTINTE4.
, EIC_INTENCLR_EXTINT4
и на EVSYS_ID_GEN_EIC_EXTINT_4
, чтобы перенацелить источник системы событий, поскольку PORT_PMUX_PMUXE_A
на обоих эти контакты направляют сигнал на EIC, но не на точно такой же номер прерывания. Строка EIC->CONFIG
должна измениться на первую группу из 8 ([0]
) и четвертый SENSE в этой группе (EIC_CONFIG_SENSE4_HIGH
) к изменению на D1 (PA04) использует EXTINT4. Это то, что я упустил из первого редактирования, прежде чем смог протестировать. В конце концов я нашел XIAO для тестирования, и эти модификации, кажется, теперь позволяют ему нормально работать на цифровом контакте 1 вместо цифрового контакта 2.
EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTE4;
EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;
EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT4;
EIC->CTRL.reg |= EIC_CTRL_ENABLE;
while (EIC->STATUS.bit.SYNCBUSY);
...
EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |
EVSYS_CHANNEL_PATH_ASYNCHRONOUS |
EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) |
EVSYS_CHANNEL_CHANNEL(0);
Изменения, о которых вы упомянули, и те, которые я назвал выше как различия:
--- original.ino
+++ modified.ino
@@ -24,14 +24,14 @@
GCLK_CLKCTRL_GEN_GCLK4 |
GCLK_CLKCTRL_ID_TC4_TC5;
- // Включить мультиплексор портов на выводе порта PA10
- PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
- // Настраиваем вывод как EIC (прерывание) на выводе порта PA10
- PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
+ // Включить мультиплексор портов на выводе порта PA04
+ PORT->Group[PORTA].PINCFG[4].bit.PMUXEN = 1;
+ // Настройте контакт как EIC (прерывание) на контакте порта PA04
+ PORT->Group[PORTA].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;
- EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10; // Разрешить вывод события по внешнему прерыванию 10
- EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH; // Установить событие обнаружения ВЫСОКОГО уровня
- EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10; // Отключить прерывания по внешнему прерыванию 10
+ EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO4; // Разрешить вывод события по внешнему прерыванию 4
+ EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH; // Установить событие обнаружения ВЫСОКОГО уровня
+ EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT4; // Отключить прерывания по внешнему прерыванию 4
EIC->CTRL.reg |= EIC_CTRL_ENABLE; // Включить периферийное устройство EIC
while (EIC->STATUS.bit.SYNCBUSY); // Ждем синхронизации
@@ -40,7 +40,7 @@
EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // Нет обнаружения фронта события
EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Установить путь события как асинхронный
- EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) | // Установить генератор событий (отправитель) как внешнее прерывание 10
+ EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) | // Установить генератор событий (отправитель) как внешнее прерывание 4
EVSYS_CHANNEL_CHANNEL(0); // Прикрепляем генератор (отправитель) к каналу 0
TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI | // Разрешить ввод события TC
- Seeeduino СЯО запись и чтение ШИМ продолжительность (период) с помощью таймеров
- Как устранить сильную аномальную выходную мощность датчика?
- Проверка кода таймера с использованием часов реального времени и OLED-экрана
- Пассивный зуммер потребляет 500 мА
- Функции, задерживающие распознавание датчика жестов
- Плата Arduino с StandardFirmata не отвечает на запросы клиентов C# и Python
- Нужна помощь в отладке кода частоты сердечных сокращений/фильтра (вычисление частоты сердечных сокращений не работает)