Хорошо. Будем изучать прерывания
Может кто подкинет пример энкодера на прерываниях
Хорошо. Будем изучать прерывания
Может кто подкинет пример энкодера на прерываниях
Вбейте в гугол ""энкодер на AVR" и получите много примеров.
Первая ссылка. Готовая программа именно на прерываниях.
Спасибо от Integral
Владимир_К, а что, по размеру не приаттачивается?
Да нет, просто не хочется потом отвечать на критику, так как я не профессиональный программист, и желающих лягнуть будет достаточно.
Хотя, могу и выложить. Тем более, что многие их присутствующих здесь помогали, всем спасибо. Завидовский, Tadas, ur3lif и др.
Энкодер, вообще-то, не по прерыванию. Был вариант и по прерываниям и он где-то есть, но так получилось лучше.
Опрос энкодера происходит в основном цикле. Если было изменение положения, в буфер энкодера записывается единица с плюсом и наоборот с "минусом". Прерывание работает от счетчика, через 5 мс(если память не изменяет). При этом обрабатывается буфер энкодера, считается новая частота, выводится на экран, переключаются диапазоны и пр.
Последний раз редактировалось Владимир_К; 09.06.2019 в 17:14.
Спасибо от UN7RX
Radio_Ham, понятно. Это не мой код. Вы просили код демонстрирующий использование прерываний, а я просто поделился ссылкой из гугли.
#define F_CPU 8000000UL //Частота генерации
#include <avr/io.h>
#include <util/delay.h>
#include "LCD.h" //Библиотека дисплея
#include "LCD.c"
#include <avr/interrupt.h>
/* Дефайны */
#define F_CPU 8000000UL // тактовая частота 1MHz
#define PIND_MASK 0b00001100 // Маска для сравнения с PIND
/* Переменные */
volatile uint8_t next_state, prev_state, up_state, down_state;
int angle_antena =0, angle_ang =0; // Передача
char lcd_angle_antena[3],lcd_angle[3];
/* Прерывания */
ISR (TIMER1_COMPA_vect)
{
next_state = PIND & PIND_MASK; // Считываем текущее значение битов
if (next_state != prev_state)
{
switch (prev_state)
{
case 8:
{
if (next_state == 12) up_state++;
if (next_state == 0 ) down_state++;
break;
}
case 0:
{
if (next_state == 8) up_state++;
if (next_state == 4) down_state++;
break;
}
case 4:
{
if (next_state == 0) up_state++;
if (next_state == 12) down_state++;
break;
}
case 12:
{
if (next_state == 4) up_state++;
if (next_state == 8) down_state++;
break;
}
default:
{
break;
}
}
prev_state = next_state; // Текущее состояние становится предыдущим
}
TCNT1H=0x00;
TCNT1L=0x00; // Обнуляем счетчик
}
void timer1_init()
{
TCCR1A = 0x00;
TCCR1B |= (1<<CS11); // Тактировать с коэффициентом деления 8
TCNT1H = 0x00; // Обнуляем счетный регистр старший байт
TCNT1L = 0x00; // Обнуляем счетный регистр младший байт
OCR1AH=0x03; // Настраиваем регистр сравнения старший байт
OCR1AL=0xE8; // Настраиваем регистр сравнения младший байт
// Разрешаем прерывание таймера по совпадению с OCR1A
TIMSK |= (1<<OCIE1A);
}
void yct_antenna(int yct, int flagms){ // процедура поворота антенны
int i;
if (flagms == 1)
for (i = 0; i < yct; i = i +5){
PORTD = 0b00011100;
_delay_ms(100);
PORTD = 0b00001100;
_delay_ms(100);
angle_ang = angle_ang +5;
}
if(flagms == 0)
for (i = 2; i < yct; i = i +5){
PORTD = 0b00011100;
_delay_ms(100);
PORTD = 0b00001100;
_delay_ms(100);
angle_ang = angle_ang -5;
}
}
int main(void)
{
int sum_ant = 0;
DDRD = 0x11110011;
PORTD = 0b00001110;
timer1_init(); // Инициализация таймера1
LCDinit(); //Иницилизация дисплея
sei(); // Разрешить глобальные прерывания
while(1)
{
if (up_state >= 4 && angle_antena < 360) // 1 раз за 4 импульса изменяем состояние передачи
{
angle_antena = angle_antena + 5; // Передача +
up_state = 0;
}
if (down_state >= 4 && angle_antena > 0)
{
angle_antena = angle_antena - 5; // Передача -
down_state = 0;
}
if((PIND&(1<<PD1))== 0){//Если на PB1 логический ноль то будет вращатся антенна
if(angle_ang < angle_antena){
sum_ant = angle_antena - angle_ang;
yct_antenna(sum_ant, 1);
}
if (angle_ang > angle_antena){
sum_ant = angle_ang - angle_antena;
yct_antenna(sum_ant, 0);
}
}
itoa(angle_antena,lc d_angle_antena,10);
itoa(angle_ang,lcd_a ngle,10);
LCDstring("ANTENNA", 0,1);
LCDstring("YCT ANTENNA",0,0);
LCDstring("\xDFY",15 ,0);
LCDstring("\xDFY",15 ,1);
LCDstring(lcd_angle_ antena,12,0);
LCDstring(lcd_angle, 12,1);
}
}
Э....
Не вту сторону "копаем"
Надо использовать внешнее прерывание.
При повороте енкодера импульс по одному из проводов вызывает внешнее прерывание процессора
#include <avr/interrupt.h>//библиотека прерываний
int position=0;
ISR (INT0_vect)
{
if (((PIND&0x01)==0x00) &&(position<9999) ) position=position+1; //инкремент position
if (((PIND&0x01)==0x01) &&(position>-9999))position=posit ion-1; //декремент position
}
int main(void)
{
DDRD=0xfa; //PD0,PD2 как входа, остальные - выхода
PORTD=0x05;
MCUCR=(1<<ISC01)|(1< <ISC00); //Включаем прерывание INT0 по фронту на PD2
GICR=(1<<INT0);
write_position(); //Пишем position
sei(); //Разрешаем прерывания
while(1)
write_position();
return 1;
}
Не все входа avr могут быть использованы под внешнее прерывание !
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)