Обсуждаем контроллеры компании Atmel.
Ответить

Re: WinAvr в вопросах и ответах

Чт окт 03, 2024 12:11:45

... но заняться этим уже силов нет, и стимула. Добить бы как-то оставшиеся Тиньки, и то было бы хорошо.
"Любил я книги, выпивку и женщин.
И большего у бога не просил.
Теперь азарт мой возрастом уменьшен.
Теперь уже на книги нету сил."
И. Губерман.

Re: WinAvr в вопросах и ответах

Пт окт 04, 2024 09:50:03

Хотя WinAvr сильно устарел и вряд ли эта ветка имеет большую актуальность, последние сообщения ну совсем оффтоп...

Re: WinAvr в вопросах и ответах

Пт окт 04, 2024 11:27:24

Точно. Удалить на фиг. И этот пост - тоже.
Mea culpa. Это я направил тему в офф. топку. Больше постараюсь не буду.
Последний раз редактировалось Jack_A Пт окт 04, 2024 22:46:52, всего редактировалось 1 раз.

Re: WinAvr в вопросах и ответах

Пт окт 04, 2024 16:08:53

Хотя WinAvr сильно устарел и вряд ли эта ветка имеет большую актуальность, последние сообщения ну совсем оффтоп...

Последнее время на форуме ТАКАЯ активность! Хорошо хоть кто то что то пишет...

Re: WinAvr в вопросах и ответах

Пт окт 04, 2024 16:27:56

А это общая тенденция к умиранию форумов - Казус, Изиэлектроникс, Электроникс. Это вообще нынче такая тенденция, что молодняк не желает учиться и делать что-то материальное, они желают развозить еду и выдавать товары на пунктах выдачи Озона.
Раньше в юности я еще увлекался 3D-моделированием. Сейчас эта тема вообще полностью умерла. Раньше я думал, что новое поколение будет намного умнее меня. А оказалось, что я в то время знал больше, чем молодняк сейчас при наличии этих ваших интернетов.

Re: WinAvr в вопросах и ответах

Пн окт 21, 2024 20:13:25

Доброго времени суток!
Большое спасибо всем ответившим.
Извиняюсь за долгое отсутствие. Дело в том, что это любительская конструкция "выходного дня". И все это время я пытался найти баги в программе опираясь на прочитанное в этой теме.
Кое что получилось. Всемогущий volatile - частично помог. Я пересмотрел всю программу и сделал все глобальные переменные используемые в прерываниях volatile. В результате стал нормально работать энкодер (раньше "заедал"). Заработала функция определения мощности. Но, при компиляции Optimize debugging experience (-Og) - глючит. Постоянно определяет мощность ТЭН2. При компиляции Optimize for size (-Os), Optimize most (-O3), Optimize more (-O2) - нормально. При Optimize (-O1) - глюки с выводом float (ну, и бог с ним, это ерунда).
Далее я решил перенести функцию определения мощности в библиотеку. И.... все! Не работает...
header file:
Спойлер#ifndef INCFILE_H_
#define INCFILE_H_

#define F_CPU 25000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <avr/eeprom.h>
#include "lcd2004x4.h"
#include "periphericals.h"
#include "Uart.h"
#include "pzem004t.h"
#include "wire.h"
#include "ds18b20.h"
#include "EEprom.h"

volatile uint8_t lcd_data[20][4]; //массив для вывода на дисплей. Используется в lcd2004
volatile uint8_t uart_data[26]; //массив для входящих данных UART. Используется в UART
volatile float power_percent[3]; //проценты от мощности

volatile uint8_t address_pzem004t; //адрес PZEM-004t
volatile uint8_t request_pzem; //переменная запроса PZEM-004

volatile uint8_t data_count; //счетчик для массива uart_data[26]. Используется в UART
volatile uint8_t response_time; //счетчик времени ожидания ответа от PZEM-004t. Используется в PZEM-004t

#endif /* INCFILE_H_ */

Текст функции:
Спойлерfloat Power_Measurement (void)
{
float min_power = 1000000000; //минимальная мощность
uint8_t cycle_timer = 0;
uint8_t cycle_timer0 = 0;
request_pzem = 0;
enable_sync;
do
{
if (request_pzem)
{
if (PZEM_response())
{
request_pzem = 0;
power_percent[0] = (float)PZEM_Voltage()/10; //измеренное напряжение
power_percent[1] = (float)PZEM_Current()/1000; //измеренный ток
power_percent[2] = (float)PZEM_Power()/10; //измеренная мощность
if (PZEM_Current() != 0)
{
temperatura = power_percent[0]*power_percent[1]; //вычисленная мощность
power_percent[1] = temperatura/100; //ошибка
power_percent[0] = temperatura-power_percent[1]; //min (вычисленная мощность - ошибка)
power_percent[1] += temperatura; //max (вычисленная мощность + ошибка)
if ((power_percent[2]<power_percent[1]) && (power_percent[2]>power_percent[0]))
{
if (min_power > power_percent[2]) min_power = power_percent[2];
cycle_timer++;
}
}
else cycle_timer0++;
}
}
if (cycle_timer0 == 10)
{
cycle_timer = 10;
min_power = 0;
}
} while (cycle_timer < 10);
disable_sync;
return min_power;
}

Для того, что бы не плодить лишние переменные, я использую массив power_percent[3], кторый использульзуется у меня при работе основной программы. А пременную - volatile float temperatura (температура радиатора определенную в main.c и так, же используемую основной программой), я заменяю на float calc_power, которую определяю в функции Power_Measurement.

BDDW, еще обратите внимание, сколько ОЗУ у вас занято. Иногда бывает, что стек наползает на область данных и начинаются интересные глюки )

Я то же на это грешу. Как видно добавление нового float - дает глюки.
А как можно на пальцах прикинуть этот стек?
Используется ATmega168. Вот данные компилятора:
Спойлер// Optimize (-O1)
// Program Memory Usage : 8468 bytes 51,7 % Full
// Data Memory Usage : 163 bytes 15,9 % Full
// Warning: Memory Usage estimation may not be accurate if there are sections other than .text sections in ELF file
// EEPROM Memory Usage : 310 bytes 60,5 % Full

// Optimize more (-O2)
// Program Memory Usage : 8766 bytes 53,5 % Full
// Data Memory Usage : 163 bytes 15,9 % Full
// Warning: Memory Usage estimation may not be accurate if there are sections other than .text sections in ELF file
// EEPROM Memory Usage : 310 bytes 60,5 % Full

// Optimize most (-O3)
// Program Memory Usage : 10758 bytes 65,7 % Full
// Data Memory Usage : 163 bytes 15,9 % Full
// Warning: Memory Usage estimation may not be accurate if there are sections other than .text sections in ELF file
// EEPROM Memory Usage : 310 bytes 60,5 % Full

// Optimize for size (-Os) - мелкие глюки с выходом из режима функции
// Program Memory Usage : 8428 bytes 51,4 % Full
// Data Memory Usage : 163 bytes 15,9 % Full
// Warning: Memory Usage estimation may not be accurate if there are sections other than .text sections in ELF file
// EEPROM Memory Usage : 310 bytes 60,5 % Full

// Optimize debugging experience (-Og) - глючит. Постоянно определяет мощность ТЭН2
// Program Memory Usage : 8592 bytes 52,4 % Full
// Data Memory Usage : 163 bytes 15,9 % Full
// Warning: Memory Usage estimation may not be accurate if there are sections other than .text sections in ELF file
// EEPROM Memory Usage : 310 bytes 60,5 % Full

Как видно, не сильно занята память.
P.S. Программа довольно таки большая, по этому я ее тут не выкладываю. Если кто то захочет с ней разобраться - то выложу

Re: WinAvr в вопросах и ответах

Пн окт 21, 2024 21:52:42

1. Выкладывать не надо: если вы пытаетесь исправить проблемы бездумной расстановкой volatile, то в вашем коде никто ковыряться не захочет.
2. Ваше упоминание volatile для всех переменных, используемых в прерываниях, вы сопроводили кусочком кода, где таковыми помечены массивы вывода на ЖКИ... Это не то, чтобы плохо, это категорически неприемлемо - из прерываний выводить на ЖКИ! Если, конечно, я прав (код ваш смотрел 3 секунды)
3. Расход стека проще всего определить при помощи протеуса. Если там запустить свою программу на некоторое время, а потом поставить на паузу и открыть окно просмотра RAM, можно элементарно понять, сколько жрет стек. Стек будет в виде мусора в конце памяти, а от начала будут рабочие переменные. Если между ними будет достаточно много нулевых ячеек, стек не переполняется и не налезает на переменные. А вот если этого промежутка не будет, сливай воду...

Re: WinAvr в вопросах и ответах

Пн окт 21, 2024 22:10:47

1. Выкладывать не надо: если вы пытаетесь исправить проблемы бездумной расстановкой volatile, то в вашем коде никто ковыряться не захочет.

Нет. Я именно проверил все глобальные переменные, которые изменяются в прерываниях и их сделал volatile.
2. Ваше упоминание volatile для всех переменных, используемых в прерываниях, вы сопроводили кусочком кода, где таковыми помечены массивы вывода на ЖКИ... Это не то, чтобы плохо, это категорически неприемлемо - из прерываний выводить на ЖКИ! Если, конечно, я прав (код ваш смотрел 3 секунды)

Нет. Я этого не делаю. Я из прерывания могу изменять содержание того или иного поля массива вывода на ЖКИ. А вывожу в основном цикле.
3. Расход стека проще всего определить при помощи протеуса. Если там запустить свою программу на некоторое время, а потом поставить на паузу и открыть окно просмотра RAM, можно элементарно понять, сколько жрет стек. Стек будет в виде мусора в конце памяти, а от начала будут рабочие переменные. Если между ними будет достаточно много нулевых ячеек, стек не переполняется и не налезает на переменные. А вот если этого промежутка не будет, сливай воду...

Я, к сожалению, не пользуюсь протеусом. А как нибудь по другому можно?

Re: WinAvr в вопросах и ответах

Вт окт 22, 2024 14:33:17

BDDW писал(а):Я, к сожалению, не пользуюсь протеусом.

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

"AVRStudio" пробовали?

Если подозрения на стек, возьмите похожий проц помощнее и проверьте на нем.

Re: WinAvr в вопросах и ответах

Чт окт 24, 2024 12:27:24

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

Я знаю про протеус. И как то пытался его ставить. Но у меня ничего не получилось.

"AVRStudio" пробовали?

Для отладки каких ни будь кусков программы - пользуюсь. А вот как всю программу отладить??? Как имитировать внешние прерывания и другие входящие сигналы?
В протеусе - понятно. А тут как?
Если подозрения на стек, возьмите похожий проц помощнее и проверьте на нем.

Да. Можно поставить ATmega328. Но, хотелось бы разобраться с тем, что так разносит стек аж на 75% памяти. У меня переменными занято всего 163 байта из 1024.

Re: WinAvr в вопросах и ответах

Пт окт 25, 2024 12:43:39

BDDW писал(а):Но, хотелось бы разобраться с тем, что так разносит стек аж на 75% памяти.

Откуда узнали?
BDDW писал(а):Я знаю про протеус. И как то пытался его ставить. Но у меня ничего не получилось.

С процессором тоже не получилось, но пробуете, а протеус бросили.

BDDW писал(а):Можно поставить ATmega328. Но, хотелось бы разобраться с тем,

Так это только для того, чтобы проверить, а не просто заменить на более мощный.

BDDW писал(а):А вот как всю программу отладить??? Как имитировать внешние прерывания и другие входящие сигналы?


Все просто или вручную установив нужный бит в нужном регистре или подключить модуль протеуса, а отладку делать в студио(но работает в старой версии студии).
BDDW писал(а):аж на 75% памяти

Библиотеку для работы с float подключили?

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 12:28:24

Если кто то захочет с ней разобраться - то выложу

давайте архивом весь проект, полюбопытствую, что там такое вы наделали.
только дополнительно описание задачи какое-то, что ли. если есть, конечно.

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 15:54:23

BDDW писал(а):Но, хотелось бы разобраться с тем, что так разносит стек аж на 75% памяти.

Откуда узнали?

Это просто мои предположения. Компилятор пишет: Data Memory Usage : 163 bytes 15,9 % Full.
Значит остальное может занимать стек. Про то, что стек может наползать на данные, у меня закрадывалась мысль, а ответ Just_Fluffy полностью утвердил меня в моих предположениях.
P.S. Я кажется нашел грабли!!! Стек тут не причем. Но, об этом немного позже. Будет несколько вопросов.
BDDW писал(а):Я знаю про протеус. И как то пытался его ставить. Но у меня ничего не получилось.

С процессором тоже не получилось, но пробуете, а протеус бросили.

Там проблема, по моему, была в дистрибутиве. Просто не нашел рабочую версию. А желания "хочу, аж кушать не могу" - не было. Все получалось и без него, методами отладки в AVR Studio.
BDDW писал(а):Можно поставить ATmega328. Но, хотелось бы разобраться с тем,

Так это только для того, чтобы проверить, а не просто заменить на более мощный.

Именно так я и хотел сделать. Просто надо пол гаража перерыть в поисках уже спаянных макеток и собрать все в кучу.
Библиотеку для работы с float подключили?

Пожалуйста, не пинайте меня сильно, но я не знаю как это сделать. Много искал, читал. В этой теме говорилось неоднократно (по моему). Где то писали, что в Microchip Studio 7.0 и последних AVR Studio она подключается автоматически.
Вы говорите про подключение про libm.a?
СпойлерИзображение

Это оно?

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 16:08:41

Предложение: удалить float. Напряжение: в миллиВольтах, ток: в миллиамперах, мощность: в миллиВаттах, переменные: в uint32_t/unsigned long int/, а при печати просто поставьте точку там, где хотите. Таким образом, используемой памяти будет мало, будет быстро и т.д. Просто в будущем используйте float там, где необходимо.

Но с использованием float я почти уверен, что проблема не в его. Дайте либо весь код программы, либо более крупный фрагмент вашей программы /если что-то из нее "скрываете" для публичного обсуждения/. А так непонятно, в чем причина.

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 17:21:18

давайте архивом весь проект, полюбопытствую, что там такое вы наделали.
только дополнительно описание задачи какое-то, что ли. если есть, конечно.

Большое спасибо за желание помочь, но мне кажется, что я нашел причину.
Дело в том, что несколько лет назад я написал такую функцию для вывода float на LCD:
Спойлерchar lcd_data[4][20]; //массив для вывода на дисплей LCD 2004
void LcdFloat(float ch, uint8_t _len, uint8_t accur, uint8_t PosCur_X, uint8_t PosCur_Y)
{
char bufer[_len];
dtostrf(ch, _len, accur, bufer);
for(uint8_t x=0; x<_len; x++) lcd_data[PosCur_Y][PosCur_X+x]=bufer[x];
}
где: ch - выводимое число
_len - кол-во выводимых знаков
accur - кол-во знаков после запятой
PosCur_X - позиция в строке
PosCur_Y - номер строки

И все, работало без замечаний.
Недавно пересмотрел эту функцию и не понял, нафига я организую массив, а потом его еще и переписываю? И решил переделать напрямую так:
dtostrf(temperatura, 5, 1, lcd_data[2]+1);
Но, дело в том, что я отвожу 5 символов для вывода температуры - 3 под целые (в том числе и для отрицательных значений), одно под запятую и одно для десятых.
А на самом деле dtostrf заполняет 6 символов. Последний символ - 0 (0x0).
И тут видно, что при использовании выше приведенной функции под массив bufer я отвожу (в данном случае) 5 байт, а заполняется 6 байт.
Можно ли, и как можно избавится от последнего нуля?

Добавлено after 38 minutes:
Предложение: удалить float. Напряжение: в миллиВольтах, ток: в миллиамперах, мощность: в миллиВаттах, переменные: в uint32_t/unsigned long int/, а при печати просто поставьте точку там, где хотите. Таким образом, используемой памяти будет мало, будет быстро и т.д. Просто в будущем используйте float там, где необходимо.

Я делаю регулятор мощности. Имея 3 ТЭНа по 1 кВт с помощью ШИМ модулятора я могу добиться что бы отдаваемая мощность была, скажем 1200 Вт. И поддерживалась автоматически при изменении напряжения в сети.
Информацию о напряжении в сети, потребляемом токе и мощности я беру с модуля PZEM-004t. Все измеряемые им величины я получаю в uint32_t по шине UART. Так, что теоретически это возможно. А вот практически? Ведь мне туда надо будет прикрутить еще ПИД регулятор.

Но с использованием float я почти уверен, что проблема не в его. Дайте либо весь код программы, либо более крупный фрагмент вашей программы /если что-то из нее "скрываете" для публичного обсуждения/. А так непонятно, в чем причина.

Тут мне скрывать нечего. Единственное, пинайте за "быдлокодерство".
Вложения
13.10.2024.zip
Для ATmega168
(30.22 KiB) Скачиваний: 30

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 17:32:01

(Мне нравится "рисунки" выводов МК ATmega8 в "текстовом виде" :) ).

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 17:38:26

А как еще писать? Всегда нужна схема перед глазами. А так, когда думаешь, руки сами чем ни будь занимаются....

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 21:58:42

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


буду писать по мере нахождения "нюансиков".

1. Вот у вас есть функция PZEM_request, которая в свою очередь использует в цикле Uart_Transmit, которая, даже судя по названию работает с "медленным" USART (и по факту, это так)... и что, спросите вы? а то, что PZEM_request у вас вызывается из обработчика прерывания INT0!!!
вот и скажите мне, чем это отличается от ранее предвиденного мною?
это категорически неприемлемо - из прерываний выводить на ЖКИ!
да, вместо медленного ЖКИ вы выводите в еще более медленный USART...

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 22:07:56

BDDW писал(а):Значит остальное может занимать стек.
Про то, что стек может наползать на данные, у меня закрадывалась мысль, а ответ Just_Fluffy полностью утвердил меня в моих предположениях.

У вас обоих неправильное предположение.

BDDW писал(а):Пожалуйста, не пинайте меня сильно, но я не знаю как это сделать.

То был вопрос, а не совет подключить.
Последний раз редактировалось codenamehawk Сб окт 26, 2024 22:10:58, всего редактировалось 1 раз.

Re: WinAvr в вопросах и ответах

Сб окт 26, 2024 22:29:48

чем отличаются функции в следующем коде:
Код:
//Вычисление Тока
uint32_t PZEM_Current (void)
{
   uint32_t pzem_data32 = 0;
   pzem_data32 = (uart_data[7]<<8|uart_data[8])&0xFFFF;
    pzem_data32 = (pzem_data32<<8|uart_data[5])&0xFFFFFF;
    pzem_data32 = pzem_data32<<8|uart_data[6];
   return pzem_data32;
}

//Вычисление мощности
uint32_t PZEM_Power (void)
{
      uint32_t pzem_data32 = 0;
      pzem_data32 = (uart_data[11]<<8|uart_data[12])&0xFFFF;
      pzem_data32 = (pzem_data32<<8|uart_data[9])&0xFFFFFF;
      pzem_data32 = pzem_data32<<8|uart_data[10];
      return pzem_data32;
}

//Вычисление потребленной энергии
uint32_t PZEM_Energy (void)
{
   uint32_t pzem_data32 = 0;
   pzem_data32 = (uart_data[15]<<8|uart_data[16])&0xFFFF;
   pzem_data32 = (pzem_data32<<8|uart_data[13])&0xFFFFFF;
   pzem_data32 = pzem_data32<<8|uart_data[14];
   return pzem_data32;
}
три функции, которые делают абсолютно одинаковые действия! разница лишь в том, с какими ячейками массивов они работают! но ведь тут очевидно напрашивается ОДНА функция, которая получает в параметре номер первой рабочей ячейки, а уж остальное делает относительно этого адреса... поправьте меня, если это не так:
Код:
uint32_t calculate(uint8_t index){
   uint32_t data = (uart_data[index+2]<<8 | uart_data[index + 3]) & 0xFFFF;
   data = ((data << 8) | uart_data[index]) & 0xFFFFFF;
   return data << 8 | uart_data[index+1];
}
и что-то сильно-сильно мне подсказывает, что в этой функции вы решили провести низкоуровневую оптимизацию вычислений... как-то странно выглядят эти сдвиги и маски. почему-то мне кажется, что все можно было сделать гораздо проще

Добавлено after 52 seconds:
3. там дальше по коду еще много похожих "одинаковых" функций.

Добавлено after 11 minutes 49 seconds:
в общем, моё мнение однозначно: нужен глубокий рефакторинг кода. чтобы и собственное понимание задачи и пути её решения выкристаллизовалось лучше.

у вас в коде намешаны низкоуровневые операции типа обращения к портам с высокоуровневыми действиями типа расчетов полученных извне значений.
то же самое касается и "деления" кода на функции: складывается впечатление, что это делалось не путем разработки алгоритма, а путем вычленения кусков "гладкого кода" в отдельные кусочки, чтобы просто хоть как-то можно было уследить за ходом процессов... но так писать не стоит.

почитайте мою статью (правда, там движок сайта попорчен и код не красивый) о нисходящем программировании: https://simple-devices.ru/articles/7-so ... 0-16-40-05
может быть, на какие-то мысли вас натолкнет.

не знаю, что именно делает ваша программа, но, имхо, функция main должна выглядеть примерно так (кода нет, одни комменты к несуществующим функциям

Код:
int main(void){
  // инициализация всей периферии
  // обращение к внешней аппаратуре и инициализация её
  // подготовка данных (считывание из EEPROM? поиск там каких-то адресов и т.п.)
  // вывод на ЖКИ приветствия (или меню, заставки и т.п.)
  // запуск прерываний (это не обязательно, может, только некоторых из них)
  while(1){
    // измерения
    // обработка измерений
    // вывод результатов
    // опрос событий EVENT (пришли данные по UART? нажаты кнопки? повернут энкодер? и т.п.)
    switch(EVENT){
      case EV_USART: // обработка данных из USART
        break;
      case EV_KBD: // обработка нажатий кнопок
        break;
      // и так далее, все события
    }
  }
}


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

Добавлено after 8 minutes 13 seconds:
и последнее.

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

https://simple-devices.ru/articles/7-so ... -interface вот так можно красиво работать "стандартными средствами" с ЖКИ
https://simple-devices.ru/articles/7-so ... console-io а вот так с USART

последним способом я пользуюсь уже много лет, и ни разу не пожалел. согласитесь, гораздо проще написать
printf("U=%d\nI=%d\n", U, I);
и тем самым отправить в USART две строки с значениями напряжения и тока, чем городить то же самое с помощью кучи массивов, циклов и т.п. неочевидных преобразований... 2 килобайта FLASH ради такого - не великая цена. ну и еще 2К, если никак без float в этом случае не обойтись... нервы дороже.
Ответить