Перейти к содержанию

Помогите с инкрементом в операторе ветвления


Юстас

Рекомендуемые сообщения

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Всё не так. Так программы не пишутся.  Давайте без суеты. Для начала, создаёте на каком нибудь таймере прерывания каждые 40-60 мс. В обработчике пишите программу анализа состояния кнопок и складываете их в какие нибудь флаги. Там уже готовое всё должно лежать - такие то кнопки нажаты, такие то нет. Всё. Это самостоятельная программа, никаких rjmp, всё на прерываниях.

Никогда не спорьте с дураком - люди могут не заметить между вами разницы

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Особенности хранения литиевых аккумуляторов и батареек

Потеря емкости аккумулятора напрямую зависит от условий хранения и эксплуатации. При неправильном хранении даже самый лучший литиевый источник тока с превосходными характеристиками может не оправдать ожиданий. Технология, основанная на рекомендациях таких известных производителей литиевых источников тока, как компании FANSO и EVE Energy, поможет организовать правильный процесс хранения батареек и аккумуляторов. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Я бы немного подкорректировал совет Григория. В прерывании таймера поднимать флаг глобального разрешения, а все остальные функции вызывать в основном цикле (основываясь на поднятии флага). Таким образом проще распределять выполнение функций программы. 

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Цитата

ldi   temp, 0b00000000
out DDRC, temp           ; PORTC на вход
ser temp
out DDRD, temp

Забавно, что зануляете переменную через ldi (а не clr), а заполняете единицами через ser (а не ldi). Это не ошибка, просто смотрится странно

Цитата

;НАСТРОЙКА ТАМЕРА 0//
ldi   temp, 0b00000011   ; предделитель 64
out   TCCR0, temp
ldi temp, 0b00000001     ; прерывание по переполнению каждые 980 мкс
out   TIMSK, temp

С точки зрения форматирования кода лучше использовать сдвиги и логические операции, например ldi temp, (1<<CS01 | 1<<CS00)

Цитата

KNOPKI:
in temp, PINC        ; считываем PINC в переменную
cpi temp, 0b00000011 ; сравниваем с константой  

Зря вы подпустили Капитана Очевидность к исходному коду, он там комментарии оставил. Лучше сами написали чего хотите добиться этими командами, а не что они делают на самом деле. На первый взгляд константа 0b00000011 ни о чем не говорит

Цитата

 

cpi ANTDRBZG, 0x3c ; сравним переменую с 60 (примерно 60 мс)

ret ; если равно 60 мс, то...

rjmp SET_PORTD0 ; ... прыгаем установить 1 в PORTD.0

 

Вот тут серьезная ошибка или несоответствие кода комментарию: ret будет выполнен независимо от сравнения, поскольку команды условного перехода (хотя бы breq) нет

Цитата

;ОСНОВНЩЙ ЦИКЛ**********************************
tst flag           ; пповерим флаг
breq INKRIMENT     ; если поднят, прыгаем в INKRIMENT

Очевидно, просто опечатки.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Обработчик я написал так для начала.

код:

Скрытый текст

;***********************************************
;*******ПРЕРЫВАНИЕ ПО ВЕКТОРУ TIMER0_OVF********
;***********************************************
TIMER0_OVF:
cli
in PINC, REG_PINC        ; прочтём PINC
cpi REG_PINC, 0b00000011 ; сравним с константой PINC биты 0 и 1
ldi FLAG_PINC_1_2, 1     ; если равно, то поднимем флаг PINC
sei
reti
;***********************************************

Скрытый текст

;***********************************************
;*******ПРЕРЫВАНИЕ ПО ВЕКТОРУ TIMER0_OVF********
;***********************************************
TIMER0_OVF:
cli
in PINC, REG_PINC        ; прочтём PINC
cpi REG_PINC, 0b00000011 ; сравним с константой PINC биты 0 и 1
ldi FLAG_PINC_1_2, 1     ; если равно, то поднимем флаг PINC
sei
reti
;***********************************************

 

 

14 минуты назад, COKPOWEHEU сказал:

Забавно, что зануляете переменную через ldi (а не clr), а заполняете единицами через ser (а не ldi). Это не ошибка, просто смотрится странно

Знал что кто нибудь да заметит)))

14 минуты назад, COKPOWEHEU сказал:

С точки зрения форматирования кода лучше использовать сдвиги и логические операции, например ldi temp, (1<<CS01 | 1<<CS00)

Знаю... больше не буду))

Ладно, хватит придираться к опечаткам, я начал новую жизнь, как говорится с чистого листа))) 

Подправил)

;НАСТРОЙКА ТАМЕРА 0//
ldi   temp, (1<<CS02 | 1<<CS00)   ; предделитель 1024
out   TCCR0, temp        ; прерывание по переполнению каждые 61 мс
ldi temp, 0b00000001     
out   TIMSK, temp
sei
;***********************************************

Обработчик

Скрытый текст

;***********************************************
;*******ПРЕРЫВАНИЕ ПО ВЕКТОРУ TIMER0_OVF********
;***********************************************
TIMER0_OVF:
cli
in REG_PINC, PINC       ; прочтём PINC
cpi REG_PINC, 0b00000011 ; сравним с константой PINC биты 0 и 1
ldi FLAG_PINC_1_2, 1     ; если равно, то поднимем флаг PINC
sei
reti
;***********************************************

 

 

Изменено пользователем Юстас
Ссылка на комментарий
Поделиться на другие сайты

Уберите из кода cli и sei, они сами сработают, как только вы войдёте в прерывание. А использование sei, как это использовано у вас даже опасно, можете при определенных обстоятельствах не выйти из данного прерывания.

После того как считали данные из порта, наложите маску по and для тех бит, которые используются. Если у вас только две кнопки на 0 и 1 разрядах, то это будет так

andi Key, 0b00000011

а в основном теле программы проверяйте какой бит в переменной Key установлен, правда нужно ещё дребезг контактов устранить.

 

p.s.

если использовать прерывание таймера не по переполнению, а по сравнению (используя регистр OCR), то отпадёт необходимость каждый раз в прерывании инициализировать регистр TCCR0 (что у вас почему то отсутствует)

Изменено пользователем dm37
Ссылка на комментарий
Поделиться на другие сайты

наверно не лучше, дело в том, что вам нужно будет также делать устранение дребезга контактов. Т.е. считать милисекунды, от появления флага нажатой кнопки и лучше это делать в прерывании по таймеру (оно ведь у вас уже есть).

Я использую как основное прерывание на 1 млсек в нём обрабатываю кнопки (включая дребезг контактов), обработку звука при нажатии, вывожу на дисплей (у вас это семисегментный индикатор, если не ошибаюсь), ну и т.д., что сочту нужным. И всё это в одном прерывании на 1 млсек.

А в основном теле программы только анализирую флаги.

Ссылка на комментарий
Поделиться на другие сайты

вы принципиально хотите на ассемблере? На Си будет быстрее и понятнее и примеров больше, а написав на Си код, вы всегда можете посмотреть его ассемблерный вариант

В некоторых случаях код в прерывании лучше писать на ассемблере

Изменено пользователем dm37
Ссылка на комментарий
Поделиться на другие сайты

@Юстас в прерываниях для обработки кнопок нужно иметь по два флага на каждую кнопку. Если пин кнопки установлен, то проверяете первый флаг. Если он не установлен, поднимаете его. Если он установлен, то поднимаете второй. Этот второй и будет общедоступным состоянием кнопки. аналогично и с отпусканием кнопок.

Никогда не спорьте с дураком - люди могут не заметить между вами разницы

Ссылка на комментарий
Поделиться на другие сайты

с Си всё намного проще, чем вы думаете.

Вот например весь код для динамической индикации, а во вложении есть файл проект (IAR EW) + proteus (симулятор).

Цитата

#include <ina90.h>
#include <iom168.h>
#include <stdint.h>

volatile unsigned char Vibor_Razrada;
volatile unsigned char LEDBuf[4];

const __flash unsigned char TableLEDRazrad[] = {0x01,0x02,0x04,0x08}; // лог.1 включает индикатор
const __flash unsigned char TableLEDDecode[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; // лог.0 зажигает сегмент (инверсия)

//==============================================================================
//
//==============================================================================
void main(void)
{
  TCCR0A = (1<<WGM01) | (0<<WGM00);           // режим CTC - сброс при совпадении
  TCNT0 = 0x00;                               // начальное значение счётчика
  OCR0A = 0x7C;                               // значение для сравнения
  TIMSK0 |= (1<<OCIE0A);                      // разрешаем прерывания от таймера 0 по сравнению
  TCCR0B = (0<<CS02) | (1<<CS01) | (1<<CS00); // делитель на 64

  DDRD = 0xFF;      // Порт D на вывод
  PORTD = 0xFF;     // начальное значение
  DDRB = 0x0F;      // Порт B на вывод
  PORTB = 0x00;     // начальное значение
 
// заполняем буфер для отображения
 
  LEDBuf[0] = TableLEDDecode[6];
  LEDBuf[1] = TableLEDDecode[7];
  LEDBuf[2] = TableLEDDecode[8];
  LEDBuf[3] = TableLEDDecode[9];

 
  _SEI();
 
  while(1)
  {
  }
}

//==============================================================================
// Прерывание каждую миллисекунду
//==============================================================================
#pragma vector = TIMER0_COMPA_vect
__interrupt void RefreshLcdKbd(void)    // опрос клавиатуры и регенерация дисплея
{
    Vibor_Razrada++;
    PORTB = 0;  // гасим все индикаторы
    PORTD = LEDBuf[Vibor_Razrada & 0x03];    // выводим наш символ
    PORTB = TableLEDRazrad[Vibor_Razrada & 0x03];  // включаем индикатор
}

 

dyn_ind.zip

Ссылка на комментарий
Поделиться на другие сайты

Капец))) Как пыльным мешком по голове)) Что-то понятно, что-то не очень. Не прозрачно как-то. На асме я всё пальцами чувствую (в пределах моих знаний)

Ссылка на комментарий
Поделиться на другие сайты

26 минут назад, dm37 сказал:

...написав на Си код, вы всегда можете посмотреть его ассемблерный вариант...

Боюсь, что вариант дизассемблирования Юстасу будет еще менее понятным, чем советы тут собравшихся.

Пока что попытка написания программы в простейшем виде похожа на попытку ехать на маховике коленвала вместо колес (двигатель есть и он крутится, про трансмиссию забыли).

Как упоминал Григорий, алгоритм нужен.

Изменено пользователем Геннадий
Ссылка на комментарий
Поделиться на другие сайты

в этом коде из того, что вы не знаете, наверно, так это только массивы, всё остальное вы пишите на ассемблере практически как есть (оформление прерывания я не считаю)

поверьте, ассемблер сложнее, чем си

Ссылка на комментарий
Поделиться на другие сайты

Не поверю. Если хорошо знать МК, то не важно на чем писАть. Вот только на Си библы нужны и решение обычно "в лоб". На Ассме можно решить как угодно и библы не нужны.

Да и вопрос сейчас стоит не тот. Пишем на Ассме, учим Юстаса порядку в программе.

Изменено пользователем Геннадий
Ссылка на комментарий
Поделиться на другие сайты

Генадий, да я всё понимаю, а вот начинаю код писать и такой вот огород получается)

dm37, не сложились у меня пока-что взаимные отношения с си, может позже, когда с асмой разберусь.

Так где лучше считывать PINC в основной программе или в прерывании по таймеру?

 

Думаю надо TIMER2 заюзать, с интервалом 1 мс. для считывания кнопок.

Ссылка на комментарий
Поделиться на другие сайты

Юстас, заюзайте один таймер с интервалом 1мс. Дальше посмотрим.

Вам не только антидребезг нужен, потребуется еще и функция одновибратора (один раз нажал - одно приращение получил).

Изменено пользователем Геннадий
Ссылка на комментарий
Поделиться на другие сайты

4 минуты назад, Геннадий сказал:

Юстас, заюзайте один таймер с интервалом 1мс. Дальше посмотрим.

Вам не только антидребезг нужен, потребуется еще и функция одновибратора (один раз нажал - одно приращение получил).

Вот так. Вы же не в Си пишете. Тут немного подумать надо прежде чем принять решение. Не торопитесь. Все надо делать пошагово и обдуманно.

Начнем с начала. 

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...