Вот, гляньте на этот код. Как минимум, в Proteus всё работает. Правда, нет защиты от дребезга при отпускании кнопки, но, возможно, она и не нужна при отпускании.
Для WiseLord Спасибо огромное за код, из hex заработал на макете. буду изучать код, смотреть где накосячил
Для ks0 По моей логике да. Изначально была команда, но подумав я её исключил, т.к. команда на установку этого бита была подана в пред идущем условии, и других команд на отмену не поступало, так что просто сбрасываем флаг и счетчик. Или я чего не правильно понимаю? Я ж тока тока познакомился с C++
Контроллер упорно не желает выходить из прерывания - преверяю условие внутри функции прерывания, при его выполнении хочу выйти из функции - условие выполняется, контроллер выполняет действия по условию, но из прерывания не выходит, продолжает выполнять функцию обработки до конца.
Вот код функции обработки прерывания:
Код:
ISR(INT0_vect) // Внешнее прерывания по появлению сигнала { CTR=0; ERR=0; TW=0; HS=0; k=0; uint8_t n=0; while (n<50) //цикл ожидания сигнала { /*измеряем длительность импульса*/ CTR=0; while (!(PINB&(1<<PB1))) //пока сигнал 0 меряем длительность сигнала { _delay_ms(100); //делаем задержку CTR++; if (CTR>=30) //если сигнал длинный { n=49; break; //переходи на включение автомата } } if ((CTR>=1) && (CTR<30)) //если сигнал короткий { k++; //увеличиваем период счетчик количества сигналов на 1 n=0; // обнуляем период ожидания нажатия сигнала if (k>=LOS) // если уже получено 3 сигнала { /* ручное включение */ PORTB|=(1<<3); //вкл индикатора PORTB&=~(1<<4); //0 на порт РВ4 delay_s(MLt); PORTB|=(1<<4); PORTB &= ~_BV(PB3); return; //reti(); //выходим из прерывания } } _delay_ms(100); n++; } for(n=0; n<100; n++){ PORTB^=(1<<PB3); _delay_ms(150); } }
Прошу совета, есть такой код, обработки индикатора и ультразвукового датчика HC-SR04, все работает, но в конце кода, в цикле присутствует "_delay_ms(60);", из-за чего происходит мерцание индикатора, без задержки не вариант! Как это обойти? Сильно не пинайте, только учусь)
volatile long avg = 0; volatile unsigned char up = 0; volatile uint32_t running = 0; volatile uint32_t timercounter =0;
// Прерывание INT1, для определения изменений высокого/низкого уровня напряжения, to detect high/low voltage changes ISR(TIMER0_OVF_vect) { if (up) { timercounter++; } }
void dig_out(int num); // Объявление функции вывода на индикатор
SIGNAL(INT1_vect){ if(running){ //прерывания разрешаются, только когда датчик запущен if (up == 0) { // voltage rise, start time measurement up = 1; timercounter = 0; TCCR0 |= (0 << CS02)|(0 << CS01)|(1 << CS00); // Start/initialize timer with prescalar 0 TCNT0 = 0; // Initialize Counter } else { // voltage drop, stop time measurement up = 0; avg = (timercounter*32+TCNT0)/58;// divide by 58 to get distance in cm running = 0;
} } }
void dig_out(int num) // Функция для вывода на индикатор 4-х разрядов { unsigned char i = 0; // Переменная счетчика unsigned char raz = 1; // Номер разряда unsigned char dig_num[] = { 0x3f, //0 0x06, //1 0x5b, //2 0x4f, //3 0x66, //4 0x6d, //5 0x7d, //6 0x07, //7 0x7f, //8 0x6f}; // Коды цифр для индикатора с общим катодом unsigned char dig[] = {0, 0, 0, 0}; // Массив для значения разряда
while(num > 999) // Получение количества тысяч { dig[0]++; num -= 1000; }
while(num > 99) // Получение количества сотен { dig[1]++; num -= 100; }
while(num > 9) // Получение числа десятков { dig[2]++; num -= 10; }
dig[3] = num; // Получения количества единиц
while(raz <= 0x10) // Крутимся пока не заполним все 4 разряда { PORTA = raz; // Выбираем разряд PORTC = dig_num[dig[i]]; // Выводим цифру raz = raz<<1; // Сдвигаемся на следующий разряд i++; // Увеличиваем индекс следующей цифры _delay_ms(1); // Задержка 1 мс } }
int main(void) {
DDRA = 0x0F; // Настройка портов DDRC = 0xFF; // для работы с индикатором Порт A для разрядов, Порт C для цифр DDRD = 0xf0; //PD4 вход ECHO, PD5 выход на триггер PORTD = 0x00;
itak: это где вы такому научились - циклы, стомиллисекундные задержки - и всё это внутри прерывания? Прерывание должно выполняться максимально возможно быстро.
-=eagle=-: Вызывайте dig_out() по аппаратному таймеру, а не в цикле main(). Дополнительно, для оптимизации кода не создавайте массив цифр каждый раз в этой функции, объявите его один раз как static. Или даже const static, так как содержимое его не изменяется.
WiseLord: - спасибо, направление, подумаю как сделать по другому.
РS в проекте контроллер ничего не делает (спит) до наступления события. Задержки минутные. Интервалы между событиями часы. В Proteus программа работает....
-=eagle=-: Вызывайте dig_out() по аппаратному таймеру, а не в цикле main(). Дополнительно, для оптимизации кода не создавайте массив цифр каждый раз в этой функции, объявите его один раз как static. Или даже const static, так как содержимое его не изменяется.
Сделал по таймеру сравнения, все заработало, но не совсем корректно, показания с датчика чудят при определенный настройках, а когда не чудит. индикатор мерцает, никак не совместить эти моменты, не пойму как грамотно его настроить
volatile long avg = 0; volatile long result = 1234; volatile unsigned char up = 0; volatile uint32_t running = 0; volatile uint32_t timercounter =0;
// Прерывание INT1, для определения изменений высокого/низкого уровня напряжения, to detect high/low voltage changes ISR(TIMER0_OVF_vect) { if (up) { timercounter++; } }
void dig_out(int num); // Объявление функции вывода на индикатор
SIGNAL(INT1_vect){ if(running){ //прерывания разрешаются, только когда датчик запущен if (up == 0) { // voltage rise, start time measurement up = 1; timercounter = 0; TCCR0 |= (0 << CS02)|(0 << CS01)|(1 << CS00); // Start/initialize timer with prescalar 0 TCNT0 = 0; // Initialize Counter } else { // voltage drop, stop time measurement up = 0; avg = (timercounter*32+TCNT0)/58;// divide by 58 to get distance in cm running = 0;
while(num > 999) // Получение количества тысяч { dig[0]++; num -= 1000; }
while(num > 99) // Получение количества сотен { dig[1]++; num -= 100; }
while(num > 9) // Получение числа десятков { dig[2]++; num -= 10; }
dig[3] = num; // Получения количества единиц
while(raz <= 0x10) // Крутимся пока не заполним все 4 разряда { PORTA = raz; // Выбираем разряд PORTC = dig_num[dig[i]]; // Выводим цифру raz = raz<<1; // Сдвигаемся на следующий разряд i++; // Увеличиваем индекс следующей цифры _delay_ms(1); // Задержка 1 мс } }
int main(void) {
DDRA = 0x0F; // Настройка портов DDRC = 0xFF; // для работы с индикатором Порт A для разрядов, Порт C для цифр DDRD = 0xF0; //PD4 вход ECHO, PD5 выход на триггер PORTD = 0x00;
//вектор прерывания по окончанию приема байта ISR(USART_RXC_vect) { while (UCSRA & (1 << RXC)) input_bits = UDR; }
Это я пытаюсь считать 8-бит данных через аппаратный USART контроллера Atmega8 и выдать их на порт Б. Вроде как логика простая: включаю прерывание по окончанию приема, считываю данные из регистра UDR, пока флаг окончания приема не сбросится, передаю данные в другую переменную и вывожу ее на порт. Но не работает. На выводах порта какая-то чушь. Проверяю в Протеусе, тот при этом выдает сообщение RX Frame Error. Кажется, я туплю в понимании методики приема. Подскажите. куда копать?
_________________ We do what we must because we can (c) GLaDOS
С прерыванием оно как-то красивше. Получили пакет, тут же засунули его в переменную, которую можно потом обработать как душе угодно. Всегда свежие данные есть. В вашем случае данные получаем только один раз за рабочий цикл программы, независимо от того, сколько раз они обновились. Если просто индицировать, оно вроде как и рационально, но я потом планирую еще с этими данными работать.
Вопрос не в этом. Должно же работать и с прерыванием. А оно почему то никак.
_________________ We do what we must because we can (c) GLaDOS
В прерывании ожидание сброса флага RXC. В интернетах пишут, что он может не сбросится после первого чтения из UDR, потому читаем до победного, пока не сбросится. Сегодня ковыряться некогда было, завтра попробую без прерываний самый простой вариант, но, кажется, дело не в том.
_________________ We do what we must because we can (c) GLaDOS
Такой появился вопрос. Если у меня постоянно на вход UART приходят пакеты, то как определяется, где начало, где конец? На картинке пример. Когда приходят нули, все понятно. А когда не ноль, то за стоп/старт-биты может быть принято любое последовательное сочетание 1 и 0. Как этот вопрос разрешается при использовании аппаратного асинхронного UART для пары котнроллеров (передатчик-приемник)?
_________________ We do what we must because we can (c) GLaDOS
Стоп-бит фиксируется не по любому переходу из низкого в высокий. Получив стартовый бит, автомат USARTа отмеривает время, необходимое для передачи заданного количества бит, включая стартовый, на заданной скорости, после чего проверяет состояние RxD . Если высокий, байт считается принятым, аппарат готов к приему следующего. Если низкий - FRAME ERROR . Поэтому важно, чтобы приемник UART был настроен в соответствии с передаваемыми данными : число бит ( инф. и стоповых ), скорость передачи. Иначе - FRAME ERROR, если его игнорировать, читаем абракадабру.
Со стопом понятно. Но старт-битом ведь считается любой переход от 1 к 0. Контроллеры не синхронизированны по частоте, и в какой момент (имеется в виду начальный, при включении питания контроллеров) начнется передача на передатчике и прием на приемнике (жуть какая) не ясно. Т.е. приемник может включиться на прием чуть позже и считать переход от второго бита на третий как переход стоп-старт (см. рисунок выше). Или это как-то не так работает?
_________________ We do what we must because we can (c) GLaDOS
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения