Не удается изменить указатель на порт в главном цикле
Я тестирую на Arduino UNO. Я хочу использовать timer1 и прерывания для создания различных светодиодных шаблонов. Светодиоды могут охватывать несколько портов, т. е. PORTB и PORTD. Я хочу использовать указатель "volatile uint8_t*" для сохранения того, следует ли переключать вывод на PORTB или PORTD, т. е. хранить указатель &PORTB или &POINTD. А затем используйте его по мере необходимости. Однако после установки я, похоже, не смогу изменить указатель в цикле.
Еще несколько деталей: Я использую timer1 в режиме CTC (очистить при сопоставлении) и использую прерывания OCR1A и OCR1B. Когда выходное сравнение прерывания совпадает, индикатор включается, и для основного контура устанавливается флаг для изменения светодиодов. Когда выходные данные сравнивают совпадения прерываний B, светодиод выключается. Оператор switch работает, и контакты светодиода могут быть изменены, т. е. next_led и current_led, однако операторы next_port и current_port игнорируются в основном цикле. Изменение вывода светодиода работает при переходе с варианта 3 на вариант 1 (когда они оба являются PORTB), но при изменении переменной next_port на PORTD это полностью игнорируется.
В самом начале кода, если я инициализирую current_port и next_port с помощью &PORTD, то загорится только индикатор PORTD, и основной цикл не изменит переменные current_port и next_port на &PORTB.
Я пробовал использовать volatile uint16_t* для следующего порта и текущего порта, и это тоже не работает.
Что я делаю не так?
int red_led = 9; //PORTB 1
int green_led = 10; //PORTB 2
int led3 = 5; //PORTD 5
volatile uint8_t current_led = 1; //port number of led
volatile uint8_t next_led = 1;
volatile uint8_t *current_port = &PORTB;
volatile uint8_t *next_port = &PORTB;
int counter = 0;
volatile int change_led_flag = 0;
volatile uint8_t led_state = 1;
uint16_t ocr1a_val = 10000-1; //determines period. 16MHz clock, Prescaler=8, 10000-1 ticks = 5ms period (200Hz)
uint16_t ocr1b_val = 9900-1; //determines duty cycle (99% for 10000 ticks)
void setup() {
pinMode(red_led, OUTPUT);
pinMode(green_led, OUTPUT);
pinMode(led3, OUTPUT);
TCCR1A = 0;
TCCR1B = 0;
//set CTC mode
TCCR1B |= (1<<WGM12);
//set OCR1A value
OCR1A = ocr1a_val;
//set OCR1B value
OCR1B = ocr1b_val;
//set pre-scaler to 8
TCCR1B |= (1 << CS11);
//enable output compare interrupts
TIMSK1 |= (1 << OCIE1A);
TIMSK1 |= (1 << OCIE1B);
sei();
}
void loop() {
if(change_led_flag == 1){
change_led_flag = 0;
current_led = next_led; //set the current led to what was just turned on
current_port = next_port; //this statement doesn't do anything.
switch (led_state) {
case 1:
led_state = 2;
next_led = 2;
next_port = &PORTB; //this statement doesn't do anything
break;
case 2:
led_state = 3;
next_led = 5;
next_port = &PORTD; //this statement doesn't do anything
break;
case 3:
led_state = 1;
next_led = 1;
next_port = &PORTB; //this statement doesn't do anything
break;
} //end switch statement
} //end if
} //end loop()
//turn on next_led and set change_led_flag
ISR(TIMER1_COMPA_vect){
*next_port |= (1 << next_led); //turn on led
change_led_flag = 1; //set flag to update next led
}
//turn off current_led
ISR(TIMER1_COMPB_vect){
*current_port &= ~(1 << current_led); //turn off led
}
@Tommy Ray, 👍-1
Обсуждение1 ответ
Лучший ответ:
Я не знаю, в чем ваша проблема, но в любом случае это проблема. Сам указатель, а не только то, на что он указывает, также должен быть квалифицирован как изменчивый. То есть:
volatile uint8_t *volatile current_port = &PORTB;
volatile uint8_t *volatile next_port = &PORTB;
Изменчивость
после декларатора указателя ( *
) определяет изменчивое
качество самого указателя. Изменчивость
, которая у вас уже была до декларатора, просто определяет то, на что указано, в данном случае порт, который необходим по аналогичным причинам.
Без того, чтобы сам указатель был изменчивым
, вы не можете ожидать, что изменения в нем будут правильно отражены между контекстами ISR и обычной основной линией выполнения, которая запускает настройку
, цикл
и почти все остальное. Компилятор/оптимизатор может предположить, что, поскольку он не видит никакого способа добраться до кода, который может изменить значение, значение, следовательно, не меняется. Сообщения ISR находятся вне его поля зрения.
Также в случае, когда вы обновляете next_port
за пределами ISR, вам, вероятно, следует убедиться, что прерывания отключены во время его обновления:
noInterrupts();
next_port = &PORTB;
interrupts();
Поскольку значение указателя является двухбайтовым адресом, если вы не отключите прерывания при его назначении, ваш ISR может быть отправлен в середине назначения, когда объект указателя еще не действителен. Я говорю "должен" выше, потому что в вашей ситуации адреса, которые используются для портов, могут иметь одинаковое значение верхнего байта. Это хорошая привычка, несмотря ни на что.
Большое вам спасибо! Добавление дополнительной " изменчивости` исправило код. (Это первый раз, когда я использовал изменчивый указатель, который сам по себе является изменчивым!) Вы делаете некоторые хорошие замечания по неатомным заданиям. Вероятно, было бы хорошей идеей поместить назначение "next_led" также в этот блок без прерываний, чтобы ISR не отправлялся с несоответствующим светодиодом и портом. Еще раз спасибо!, @Tommy Ray
- 4-битный счетчик вверх и вниз
- Проблема с использованием Arduino Mega Timer2 с прерыванием PinChange
- Обнаружение входящего импульса 7,875 кГц для использования в качестве триггера
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Включить и отключить отдельные прерывания
- Измерить количество циклов и время цифрового входа
- Программирование Arduino Uno R3 для срабатывания реле каждые 24 часа
- Проблема прерывания библиотеки MPU6050 Arduino Jeff Rowberg
Я получаю ошибку: не удается преобразовать "volatile uint8_t* {aka volatile без знака*}" в "volatile uint16_t* {aka volatile без знака int*}" при инициализации volatile uint16_t *next_port = &PORTB;, @Tommy Ray
Добро пожаловать в SE/Arduino! Пожалуйста, пройдите [экскурсию], чтобы узнать, как работает этот сайт. Если у вас есть какая-либо дополнительная информация, пожалуйста, [отредактируйте] свой вопрос, не оставляйте комментариев. Это не будет прочитано, это не форум. -- Однако, пожалуйста, сведите свою программу к самому простому примеру, где вы меняете только указатель порта и используете его для доступа к портам. -- Если это в целом не работает, вы можете вернуться к использованию функций Arduino, таких как "digitalWrite ()" или, например, использовать "перечисление" и "переключатель"., @the busybee