[uquote="lin17",url="/forum/viewtopic.php?p=3867637#p3867637"]ARV - я думаю...[/uquote]
NStorm писал(а):...обычно мало пригодные для правки человеком. С тем же успехом можно пытаться.....
Даладна!!!
Коллеги, это только мне кажется, что ARV ерничает? Вообще то это был сарказм. И тут можно только поржать, но никак не обсуждать на полном серьезе перспективы.
А как в MPLAB X посмотреть дизасм? Компилятор XC8. Версии MPLAB X и компилятора последние.
Вот только с Ассемблера перешел на СИ, написал работающую программу. Хотелось бы узнать мнение гуру о коде программы. Пойдет такое написание на СИ? Или что-то можно по другому скомпоновать в программе?
Спойлер
[uquote="4uvak",url="/forum/viewtopic.php?p=3909568#p3909568"]А как в MPLAB X посмотреть дизасм? Компилятор XC8. Версии MPLAB X и компилятора последние.[/uquote]
Включить отладку (можно через симулятор), потом Window->Debugging->Disassembly
Добавлено after 25 minutes 22 seconds: 4uvak, напишите модель МК для кода, так проверить удобнее будет собрав исходник.
Добавлено after 2 minutes 56 seconds:
Вообще конечно видно, что переход был с асма ) Стилистика осталась в асм стиле. Вместо меток лучше в виде функций оформить. Да и вообще в Си метки почти никогда не нужны.
Добавлено after 23 minutes 7 seconds:
Чисто в плане избавления от ненужных меток:
Спойлер
void init() {
PWM1CON = 0b00000000; // отключаем ШИМ1
FVRCON = 0b00000000; // отключаем ИОН, отключаем температурный индикатор
ADCON = 0b00000000; // отключаем модуль АЦП
PORTA = 0; // все выходы порта переводим в низкое состояние
__delay_ms(500);
IOCIE = 1; // разрешаем прерывание по изменению уровня PORTA
IOCAF = 0; // сбрасываем флаг IOCAF (свидетельствующий о прерывании RA3)
SWDTEN = 0; // отключаем сторожевой таймер на период сна
SLEEP(); // здоровый крепкий сон до пробуждения нажатием кнопки)
IOCIE = 0; // запрет прерывания по изменению уровня PORTA
SWDTEN = 1; // включаем сторожевой таймер
}
void power_on() {
LED = 1; // включаем питание
PWM1CON = 0b11000000; // вкл ШИМ для двухтонального сигнала включения
TMR2 = 0; // сброс TMR2 для исключения пауз между тонами
PR2 = 10; // первый тон сигнала включения ~ 700 Гц
PWM1DCH = 5; // -//-
__delay_ms(111);
TMR2 = 0; // сброс TMR2 для исключения пауз между тонами
PR2 = 6; // второй тон сигнала включения ~ 1,1 кГц
PWM1DCH = 3; // -//-
__delay_ms(111);
PWM1CON = 0b01000000; // выкл ШИМ
FVRCON = 0b10000001; // включаем ИОН 1,024V, отключаем температурный индикатор
ADCON = 0b00011101; // включаем модуль АЦП, FVR вход (фиксированное опорное напряжение), FOSC/2
}
void power_off() {
PWM1EN = 1; // вкл ШИМ для двухтонального сигнала выключения
TMR2 = 0; // сброс TMR2 для исключения пауз между тонами
PR2 = 6; // первый тон ~ 1,1 кГц
PWM1DCH = 3; // -//-
__delay_ms(111);
TMR2 = 0; // сброс TMR2 для исключения пауз между тонами
PR2 = 10; // второй тон ~ 700 Гц
PWM1DCH = 5; // -//-
__delay_ms(111);
PWM1EN = 0; // выкл ШИМ
LED = 0; // отключаем питание
}
void main(void) {
init();
power_on();
CLRWDT();
while (1) {
for (n = 0; n <= 15000; n++) // время работы основного цикла программы, где 1000n соответствует ~ 1 минуте работы (максимальный n=65535, ТЕ 65мин)
{
if (!TK1) // если перемычка на 0, то бесконечный режим работы (без таймера))
{
n = 0;
}
CLRWDT();
__delay_ms(52);
if (!TK) // если кнопка нажата - подаем короткий звуковой сигнал
{
PWM1EN = 1; // вкл ШИМ звукового сигнала нажатия кнопки
__delay_ms(55);
PWM1EN = 0;
__delay_ms(999);
if (!TK) // если кнопка нажата более 1 сек - отключаем питание
{
power_off();
return;
} else // если кнопка нажата менее 1 сек - обнуляем таймер ожидания
{
break;
}
}
GO_nDONE = 1; //начать преобразование АЦП
while (GO_nDONE); //ожидание окончания преобразования АЦП
if (ADRES > 86) //если U ниже 3.0В выключаем питание
{
power_off();
return;
} else {
if (ADRES > 80) //если U ниже 3.3В включим двойной предупредительный звуковой сигнал о низком заряде АКБ, который повторяется каждые 15с
{
if (i < 2) {
PWM1EN = 1; // вкл ШИМ для предупредительного звукового сигнала
__delay_ms(55);
PWM1EN = 0; // выкл ШИМ
__delay_ms(33);
}
i++;
}
}
if (n == 14000) // вкл предупредительный 4-хкратный звуковой сигнал, предупреждающий о отключении питания, где 1000n соответствует ~ 1 минуте работы (максимальный n=65535, ТЕ 65мин)
{
for (m = 0; m <= 3; m++) {
PWM1EN = 1; // вкл ШИМ для предупредительного звукового сигнала
__delay_ms(155);
PWM1EN = 0; // выкл ШИМ
__delay_ms(77);
}
}
}
return;
}
}
Что еще я бы улучшил, но уже безотносительно перехода с асма:
1. Мне не нравится сброс n каждый раз в случае перемычки. Обычно перемычку на работающем ус-ве не меняют. Поэтому обычно значение перемычки считается только один раз. А дальше я бы просто сделал бы бесконечный цикл, где n приращивалось бы или нет.
2. Нажатие кнопки проверяется разово. При этом ожидание и замеры АЦП останавливаются. Дребезгом или дрочением кнопки можно тормознуть выполнение другого участка кода.
3. Вместо перехода на конец программы, где просто будет бесконечный цикл ничего не делания крутится, я бы в конце power_off() в спящий режим бы уходил бы постоянный.
Последний раз редактировалось NStorm Вт окт 20, 2020 13:47:05, всего редактировалось 1 раз.
NStorm, спасибо. Дизасму включил. Камень pic10f322, это я реализовал контроллер управления питанием от Li-ion, который включает/выключает нагрузку от нажатия кнопки на 15 минут (с автоотключением), или без автоотключения в зависимости от положения перемычки. Так же идет предупреждение звуковым сигналом, если напряжение на АКБ меньше 3,2В, или отключение при напряжении на АКБ менее 3В.
По поводу:
1. Так как это контроллер управления питанием, то он всегда подключен к банке АКБ, поэтому единоразовая проверка(во время инициализации регистров) не подходит поэтому проверка в коде программы, и режимы работы легко меняются в активном состоянии. Хотя раньше я делал в ассемблере, как Вы советуете.
2. А как кнопка может тормознуть программу? Опрос кнопки идет на определенном участке программы, а прерывания отключены в основном цикле программы, и вкл только на период сна
3. Так с конца программы после звукового сигнала отключения итак идет переход на начало (после Power_Off) на while (1) и контроллер уходит в спячку.
Насчет безGOTOвых переходов еще потренируюсь писать программы, чтобы обойтись без них.
2. Ну вас в коде одна проверка: "if (!TK) // если кнопка нажата - подаем короткий звуковой сигнал" внутри сразу уже в любом случае происходит сигнал, после которого ожидание 999мс. Вот тут и тормозится.
3. return в c - выход из функции. Из main() значит завершение программы. Не уверен, как код генерит xc8, но в avr-gcc насколько я помню в этом случае проиходит переход ко встроенной функции exit(), где просто крутится бесконечный цикл. Надо будет глянуть что xc8 выдает при return'e из main().
2. Точно, 2 проверки состояния кнопки. Короткое нажатие просто сбрасывает таймер ожидания и подает звуковой сигнал (чтобы устройство не отключилось). Длинное нажатие более 1 сек подает сначала короткий звуковой сигнал, а потом двухтональный сигнал отключения и спячка
Глянул выхлоп xc8 - понятно, он инициализацию пихает в конец, а return из main() реально возвращается в конец инициализации этой, на последней адрес во флэш памяти. Тем самым прокручивая PC обратно до 0. Но как-то это неправильно с точки зрения Си. Это не на while(1) прыжок обратно, а всей программы сначала. Все переменные будут переинициализированы.
Кстати полный дизасм еще генерится в каталоге с проектом в подкаталоге dist/default/TARGET/PROJECT.lst
3. В общем всё-равно на МК в общем принципе для портабельности лучше избегать return из main().
2. Ну если вам тут не важно, что нажатие кнопки даже короткое по сути откладывает измерение АЦП на секунду, то можно и так конечно оставить.
Да нет, именно на while(1) прыгает.
Это видимо оптимизатор постарался. Вообще в целом return из main() в embedded зависит от компилятора.
Вообщем СИ и МПЛАБ Х вещь, раньше сидел на Асме, и не знаю сколько бы у меня ушло времени на написание аналогичной программы, где куча программных таймеров связанных между собой. А вышеуказанную программу написал менее чем за день с учетом того, что раньше не имел опыта написания программ на СИ (мигание светодиода не в счет).
Еще конфигурируемые логические ячейки довольно забавная вещь. https://habr.com/ru/post/372509/ Я проверил - работает, но правда ног у 10f322 очень мало. Закажу МК, где ног побольше для экспериментов. Можно будет например аппаратные подавители дребезга контактов кнопки/энкодера делать...
4uvak, всё-таки это не программные таймеры, а просто задержки. Но в остальном вы правы, на Си куда проще многие штуки делаются. Но надо учиться абстрагироваться от асма, тут так в лоб не надо. Я даже не о сложных абстракциях, которые можно делать в Си, а просто хотя бы к базовым вещами привакать - не надо "переходить", надо вызывать функции. А потом еще привыкаем к тому, что у функций бывают аргументы и возвращаемое значение.
[uquote="NStorm",url="/forum/viewtopic.php?p=3909698#p3909698"]у функций бывают аргументы и возвращаемое значение.[/uquote]
Прямого отношения к Си это не имеет. На АСМе совершенно так же делаются вызовы, в подпрограмму передаются значения и подпрограмма возвращает значение.
Тут дело не в языке, а в мышлении. В способности генерировать абстракции вообще, а не потому, что так требует язык.
Кстати, код написанный на АСМе в стиле языка высокого уровня не намного более объёмен нежели в ЯВУ.
[uquote="КРАМ",url="/forum/viewtopic.php?p=3909720#p3909720"]Прямого отношения к Си это не имеет. На АСМе совершенно так же делаются вызовы, в подпрограмму передаются значения и подпрограмма возвращает значение.
Тут дело не в языке, а в мышлении. В способности генерировать абстракции вообще, а не потому, что так требует язык.[/uquote]
Без сомнения. Но обычно на асме более прямолинейно всегда пишут. ЯВУ всё-таки более располагает к большему уровню абстракции
[uquote="КРАМ",url="/forum/viewtopic.php?p=3909720#p3909720"]Кстати, код написанный на АСМе в стиле языка высокого уровня не намного более объёмен нежели в ЯВУ.[/uquote]
Смотря какой уровень сложности программы и владения ЯВУ. Структуры в Си, например, очень сильно могу сократить объем и наглядность кода. Да и портабельность с ЯВУ проще - перейти с одной архитектуры на другую с ЯВУ попроще - не надо набор инструкций на низком уровне изучать и "привыкать" к ним. Но я не хочу разводить холивар на этом месте. Везде свои преимущества. Оптимизация под архитектуру на асме ес-но возможна такая, которой ни один оптимизатор ЯВУ не сможет.
[uquote="4uvak",url="/forum/viewtopic.php?p=3910220#p3910220"]Подскажите как[/uquote]
Вы лучше сформулируйте задачу.
Вместо goto нужно оформить цикл while с условием или без него - бесконечный цикл:
Это начало основного цикла while (1), по условиям ложного срабатывания (контроллер чувствителен к помехам по цепям питания) и он ложно может выйти из сна через прерывание. Поэтому я добавил строку с проверкой срабатывания кнопки после сна. Если кнопка не нажата нужно повторно отправиться спать. Я организовал команду перехода через goto qwe. Есть другой способ начать цикл заново?
while(1){
// тут какой то код перед началом ожидания кнопки
while(условие не нажатой кнопки){
// тут код пока кнопка не нажата
}
// тут код после нажатой кнопки
}
4uvak, я вам дал на прошлой странице пример с функциями. Просто вынесите выключение и сон в отдельную функцию и вызывайте её в данном случае. А после неё можно как у вас сделать return (уже из main()), чтобы "перезапуститься".
Еще лучше - начинать переходить к конечному автомату. Если писать сразу так, то все эти переходы между состояниями легче расширяются и обрабатываются.
Вот простенький относительно пример: https://github.com/N-Storm/flashlight/b ... ashlight.c
Это я делал для фонарика прошивку на замен штатному китайскому МК на базе PIC10F200 - самый простой и примитивный МК пожалуй в мире из ныне выпускающихся. У него нет прерываний. Поэтому с некоторыми вещами пришлось "извращаться" и очень мало памяти, чтобы сделать красивее. Но оно работает. ) Вот выключение сделано в функции enter_sleep(), которая всё выключает и отправляет МК в сон, как вам нужно.
С нажатием кнопки тоже посмотрите как сделано. Точно также лучше просто в основном цикле если нажата кнопка - увеличиваем некую переменную счетчик. А если отжата - проверяем значение счетчика и тут понятно что у нас было - короткое нажатие, длинное или просто дребезг.
Но если хотите "простыней", то что мешает вместо if (TK) goto qwe; написать:
оператор continue немедленно осуществляет переход к проверке условия продолжения цикла (внутри которого находится этот оператор) - это 100% то самое, что вам нужно для замены goto
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...