AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
17.07.2024, 11:43
|
#1
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Atmega128 вызов прерывания кнопкой
Добрый день! прошу помощи - написал код. По смысл такой - есть сервомашинка, работа машинки должна запускаться и останавливаться одной кнопкой. Когда нажимаю кнопку, серва запускается, а вот при повторном нажатии остановка не происходит(хотя должна после того как серва сделает полный цикл), срабатывает только после удержания кнопки некоторое время. и то не всегда, пробовал в протеусе
Нажмите, чтобы открыть спойлер
PHP код:
|
#define F_CPU 8000000UL #include ‹avr/io.h› #include ‹util/delay.h› #include ‹stdlib.h› #include ‹avr/interrupt.h› #include "n5110.h"
#define SERVO_MIN 1000 // Минимальная ширина импульса (1 мс) #define SERVO_MAX 2000 // Максимальная ширина импульса (2 мс)
volatile uint16_t rotation_count = 0; // Счетчик количества поворотов volatile char system_state = 0; // Состояние системы: 0 - выключено, 1 - включено
void button_init() { DDRD &= ~(1 ‹‹ PIND2); // Установка PD2 как вход PORTD |= (1 ‹‹ PIND2); // Включение подтягивающих резисторов для PD2 EICRA |= (1 ‹‹ ISC01) | (1 ‹‹ ISC11); // Срабатывание прерываний по спадающему фронту сигнала EIMSK |= (1 ‹‹ INT0) | (1 ‹‹ INT1); // Разрешение внешних прерываний INT0 и INT1 }
// Обработчик прерывания для INT0 (Запуск) ISR(INT0_vect) { _delay_ms(10); // Защита от дребезга system_state = 0; // Включение системы }
// Обработчик прерывания для INT1 (Остановка) ISR(INT1_vect) { _delay_ms(50); // Защита от дребезга system_state = 0; // Выключение системы }
void displey_start(void) { DDRB &= ~((1‹‹PINB0) | (1‹‹PINB1) | (1‹‹PINB2) | (1‹‹PINB3) | (1‹‹PINB4)); PORTB = 0x00; Lcd_init(); Lcd_clear(); Lcd_update(); LcdContrast(62); }
void servo_init() { TCCR1A |= (1 ‹‹ WGM11) | (1 ‹‹ COM1A1); // Fast PWM, 10-bit TCCR1B |= (1 ‹‹ WGM12) | (1 ‹‹ WGM13) | (1 ‹‹ CS11); // Предделитель 8 ICR1 = 20000; // TOP значение для 20 мс периода (50 Гц) DDRB |= (1 ‹‹ PINB5); // Установка PB5 (OC1A) как выход }
void servo_set_position(uint16_t position) { OCR1A = position; }
int main(void) { sei(); servo_init(); displey_start(); // Запуск дисплея button_init(); // Инициализация кнопки
uint8_t prev_button_state = 0; // Предыдущее состояние кнопки // Обновление дисплея Lcd_clear(); char buff[20]; itoa(rotation_count, buff, 10); Lcd_print(0, 0, FONT_1X, (unsigned char *)"серва"); Lcd_print(0, 1, FONT_1X, (unsigned char *)"запущена:"); Lcd_print(0, 2, FONT_1X,(unsigned char *)buff); Lcd_print(4, 2, FONT_1X, (unsigned char *)" раз"); Lcd_update();
while (1) { uint8_t current_button_state = PIND & (1 ‹‹ PIND2); // Текущее состояние кнопки
// Проверка на нажатие кнопки (переход с 1 на 0) if (!current_button_state && prev_button_state) { system_state = !system_state; // Переключение состояния системы _delay_ms(20); // Простая защита от дребезга } prev_button_state = current_button_state; // Обновление предыдущего состояния кнопки
if (system_state) // Если система включена { // Поворот сервомотора на полный угол servo_set_position(SERVO_MIN); _delay_ms(700); // Задержка 700 мс
// Поворот сервомотора обратно servo_set_position(SERVO_MAX); _delay_ms(700); // Задержка 700 мс
// Увеличение счетчика поворотов после завершения полного цикла rotation_count++;
itoa(rotation_count, buff, 10); Lcd_print(0, 2, FONT_1X,(unsigned char *)buff); Lcd_update(); }
}
return 0; }
|
Последний раз редактировалось Devil Byte; 17.07.2024 в 14:28.
|
|
|
|
17.07.2024, 12:08
|
#2
|
Почётный гражданин KAZUS.RU
Регистрация: 21.03.2007
Адрес: М.(осква)
Сообщений: 4,243
Сказал спасибо: 2,092
Сказали Спасибо 1,704 раз(а) в 965 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
Схема где?
" _delay_ms(700)" в основном теле программы - в это время Ваша программа тупо ни на что реагировать не будет.
По моему - программа делает именно то, что запрограммировано.
__________________
+ 7 903 641 87 25// 1. Иногда отвечаю "по памяти" 2. Часто заблуждаюсь >> Критикуйте, не обижусь.
|
|
|
|
17.07.2024, 12:21
|
#3
|
Почётный гражданин KAZUS.RU
Регистрация: 20.03.2007
Адрес: "Братское кольцо враждебности", т.е. ближайшее заМКАДье.
Сообщений: 6,926
Сказал спасибо: 2,986
Сказали Спасибо 3,163 раз(а) в 2,147 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
Сообщение от Devil Byte
|
.....
.....
volatile char system_state = 0; // Состояние системы: 0 - выключено, 1 - включено
.....
.....
// Обработчик прерывания для INT0 (Запуск)
ISR(INT0_vect)
{
_delay_ms(10); // Защита от дребезга
system_state = 0; // Включение системы
}
.....
.....
|
Проверяйте логику.
Хотя, конечно, этот говнокод с delay в прерывании надо переделывать полностью.
__________________
Экзорцист 40-го уровня.
|
|
|
|
17.07.2024, 14:19
|
#4
|
Почётный гражданин KAZUS.RU
Регистрация: 21.03.2007
Адрес: М.(осква)
Сообщений: 4,243
Сказал спасибо: 2,092
Сказали Спасибо 1,704 раз(а) в 965 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
ForcePoint, неееее.
Цитата:
|
if (!current_button_state && prev_button_state)
{
system_state = !system_state; // Переключение состояния системы
_delay_ms(20); // Простая защита от дребезга
}
|
__________________
+ 7 903 641 87 25// 1. Иногда отвечаю "по памяти" 2. Часто заблуждаюсь >> Критикуйте, не обижусь.
|
|
|
|
17.07.2024, 14:36
|
#5
|
Почётный гражданин KAZUS.RU
Регистрация: 20.03.2007
Адрес: "Братское кольцо враждебности", т.е. ближайшее заМКАДье.
Сообщений: 6,926
Сказал спасибо: 2,986
Сказали Спасибо 3,163 раз(а) в 2,147 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
Сообщение от mtit
|
неееее.
|
Я ничего не предлагал. Я просто подсветил, что Devil Byte вместо включения - выключает. Неисправленная копипаста, наверное.
Не говоря о том, что с т.з. пальцетыка и дребезга - 10 и 50 мс практически неотличимы.
__________________
Экзорцист 40-го уровня.
|
|
|
|
17.07.2024, 14:39
|
#6
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
Сообщение от ForcePoint
|
Проверяйте логику.
Хотя, конечно, этот говнокод с delay в прерывании надо переделывать полностью.
|
То что вы принимайте за ошибку не имеет ни какого основания, так как нажатие кнопки в любом случае изменит статус на нужный. о дилеях - контроллер не производит ни какой вычислительной деятельности кроме счета одной переменной, поэтому без разницы использовать неблокирующую задержки или использовать простой дилей, вообще побоку что он простоит там несколько тысяч тактов. И использование очередного таймера не решит вопрос с кнопкой. Касательно дребезга и 10 и 50мс достаточно более чем при нормальных кнопках и соответствующей обвязке. Так что в принципе ваше пояснение дерьмо.
Последний раз редактировалось Devil Byte; 17.07.2024 в 17:06.
|
|
|
|
17.07.2024, 18:15
|
#7
|
Почётный гражданин KAZUS.RU
Регистрация: 19.02.2008
Сообщений: 1,801
Сказал спасибо: 124
Сказали Спасибо 602 раз(а) в 419 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
Сообщение от Devil Byte
|
uint8_t current_button_state = PIND & (1 ‹‹ PIND2); // Текущее состояние кнопки
// Проверка на нажатие кнопки (переход с 1 на 0)
if (!current_button_state && prev_button_state)
{
system_state = !system_state; // Переключение состояния системы
_delay_ms(20); // Простая защита от дребезга
}
prev_button_state = current_button_state; // Обновление предыдущего состояния кнопки
[/PHP]
[/SPOILER]
|
То есть проверки состояния кнопки после delay нет. Я бы проверил состояние кнопки, _delay_ms(20);, а потом вновь проверка и утверждение о
system_state = !system_state; // Переключение состояния системы
|
|
|
|
17.07.2024, 18:50
|
#8
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
andries5, Типа вот так ?
Нажмите, чтобы открыть спойлер
PHP код:
|
uint8_t current_button_state = PIND & (1 ‹‹ PIND2); // Текущее состояние кнопки
// Проверка на нажатие кнопки (переход с 1 на 0) if (!current_button_state && prev_button_state && !button_pressed) { system_state = !system_state; // Переключение состояния системы button_pressed = 1; // Установка флага нажатия кнопки _delay_ms(50); // Простая защита от дребезга } else if (current_button_state && button_pressed) { // Если кнопка отпущена, сбросить флаг нажатия button_pressed = 0; _delay_ms(50); // Задержка для стабилизации состояния кнопки }
|
Попробовал, но смысл такой что все равно для того что бы серва остановилась Нужно выгадать момент когда начнется движение и нажать с удержанием кнопку до момента как она повернется в +90 градусов((. Хотя даже не преследую цели тормозить ее на любом угле, мне даже удобней если она завершает полный цикл, а потом останавливается
Последний раз редактировалось Devil Byte; 17.07.2024 в 19:02.
|
|
|
|
18.07.2024, 13:24
|
#9
|
Почётный гражданин KAZUS.RU
Регистрация: 19.02.2008
Сообщений: 1,801
Сказал спасибо: 124
Сказали Спасибо 602 раз(а) в 419 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
PHP код:
|
// Проверка на нажатие кнопки (переход с 1 на 0)
if (!current_button_state && prev_button_state)
{
system_state = !system_state; // Переключение состояния системы
_delay_ms(20); // Простая защита от дребезга
}
prev_button_state = current_button_state; // Обновление предыдущего состояния кнопки
|
Думаю так лучше
PHP код:
|
// // Проверка на нажатие кнопки (переход с 1 на 0)
if (!current_button_state && prev_button_state)
{
_delay_ms(50); // Простая защита от дребезга
{
if (!current_button_state && prev_button_state)
{
system_state = !system_state; // Переключение состояния системы
prev_button_state = current_button_state; // Обновление предыдущего состояния кнопки
}
}
}
|
Зачем в прерывании _delay_ms(10); // Защита от дребезга ?
Непонятно.
system_state = 0; // Включение системы
system_state = 0; // Выключение системы
Тоже непонятно.
PHP код:
|
//
// Обработчик прерывания для INT0 (Запуск)
ISR(INT0_vect)
{
_delay_ms(10); // Защита от дребезга
system_state = 0; // Включение системы
}
// Обработчик прерывания для INT1 (Остановка)
ISR(INT1_vect)
{
_delay_ms(50); // Защита от дребезга
system_state = 0; // Выключение системы
}
|
А также _delay_ms(700); // Задержка 700 мс ?
PHP код:
|
//
// Поворот сервомотора на полный угол
servo_set_position(SERVO_MIN);
_delay_ms(700); // Задержка 700 мс
|
Возможно по прерыванию от кнопки Вы хотите остановить мотор? Непонятно.
А прерывание точно обрабатывается?
|
|
|
|
18.07.2024, 13:32
|
#10
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Atmega128 вызов прерывания кнопкой
andries5, Спасибо за помощь. Решил проблему несколько иным путем. Просто создал функцию и сделал дополнительный флаг мотор раннинг, во втором таймере просто сделал счетчик одной миллисекунды, и использовал это для отслеживания работы. По сути это и есть контроль кнопки. У меня сейчас кроме протеуса под рукой ничего нет. Смогу проверить как домой прилечу, но в протеусе работает прекрасно
Нажмите, чтобы открыть спойлер
PHP код:
|
void check_button() { static uint32_t last_debounce_time = 0; if (!(PIND & (1 ‹‹ BUTTON_PIN))) { // Если кнопка нажата if (!button_state && (ms_counter - last_debounce_time › 50)) { // Простое антидребезговое условие button_state = 1; // Установка флага состояния кнопки last_debounce_time = ms_counter; motor_running = !motor_running; // Переключение состояния мотора } } else { if (button_state && (ms_counter - last_debounce_time › 50)) { // Простое антидребезговое условие button_state = 0; // Сброс флага состояния кнопки last_debounce_time = ms_counter; } } }
void motor_control() { static uint32_t last_action_time = 0; if (motor_running) { if (ms_counter - last_action_time › 200) { // Примерный период в нужные ХХХ мс static uint8_t position_flag = 0; if (position_flag) { servo_set_position(SERVO_MIN); position_flag = 0; } else { servo_set_position(SERVO_MAX); position_flag = 1; } last_action_time = ms_counter; rotation_count++; } } }
|
Последний раз редактировалось Devil Byte; 18.07.2024 в 13:37.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 17:22.
|
|