Специальные цены   новые товары
Закрытая тема
Страница 31 из 33 ПерваяПервая ... 21 29 30 31 32 33 ПоследняяПоследняя
Показано с 1,201 по 1,240 из 1300

Открытый проект универсального зарядника

Тема раздела Самодельная электроника, компьютерные программы в категории Общие вопросы; +1...

  1. #1201

    Регистрация
    01.01.2008
    Адрес
    краснодар
    Возраст
    45
    Сообщений
    138
    Записей в дневнике
    2
    +1

  2.  
  3. #1202

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Согласен перегнул, исправлюсь, тем более, что я занимаюсь тем же и машина тоже есть. Прошу все наезды на ценности считать парадоксальной, частной точкой зрения из непроверенного источника.

    Урок №6 (Структура программы на Си)
    Когда-то давно, когда компьютеры еще не были столь сильны, компиляторы (преобразователи) программы Си в язык машинных кодов работали очень медленно, а также с целью легкости обнаружения ошибок, на текст программы Си было наложено ограничение. Все программы на Си должны иметь приблизительно такой вид:

    ------------------------------------------------------
    Команды препроцессора - команды для автоматического редактирования текста программы

    Описание переменных, видных во всех подпрограммах
    Подпрограмма1
    {
    Описание переменных, видных только внутри подпрограммы
    Тело подпрограммы
    }
    ...
    ПодпрограммаN
    {
    Описание переменных, видных только внутри подпрограммы
    Тело подпрограммы
    }

    Главная программа (запускается при включении или перезапуске ЗУ)
    {
    Описание переменных, видных только внутри подпрограммы
    Тело подпрограммы
    }
    ---------------------------------------------------------------

    Придерживаться такого вида программы - это стильно, это удобно, это стандартно, это понятно. Можно нарушать все, но когда-нибудь это выплывет боком. Уж лучше все делать хорошо и красиво это удобно для всех и все вас поймут и тоже будут делать хорошо и вы их поймете. Выпендреж сильно ухудшает взаимопонимание и тут обсуждение программы сводится к нахождению взаимопонимания. Выпендреж это растрата времени и сил. Ни кто вас наказывать не будет. Вы сами себя наказываете. С другой стороны, заботясь друг о друге, мы стараемся делать все наилучшим образом - это получается автоматически. Никто никого не заставляет. Вот вам закон любви в действии. Блин опять понесло.

    Итак теперь мы можем написать программу зарядника Вот она (содержимое файла main.cpp):

    #include <avr/io.h>_______// Подключаем файл с подпрограммами и переменными от avr
    #include "util.h"_________// Подключаем файл со всеми описаниями переменных
    #include "util.cpp"_______// Подключаем файл со всеми подпрограммами
    int main(void)____________// Главная программа
    {
    #include "init.cpp"_______// Инициализация всех ног процессора
    #include "zagruzka.cpp"___// Загрузка начальных переменных из ПЗУ
    while(true)_______________// Бесконечно повторяем {содержимое скобок}
    __{
    __wdt_reset();____________// Сброс собаки (авторесета) на случай зависания
    __#include "sh.cpp"_______// Прорисовка шаблонов - всех изображений ЖКИ
    __#include "test.cpp"_____// Рассчитываем все переменные по каналам
    __if(iK1!=iK0)____________// Если есть необработанные кнопки рисуем меню
    ____{
    ____#include "menu.cpp"___// Обработка кнопок
    ____}
    __TestMainParam();________// Если какой нибудь канал работает или тестирование проверяем не горит ли чего
    __if(Ch1.C)Go(Ch1);_______// Если запущен канал 1 обрабатываем этот канал
    __if(Ch2.C)Go(Ch2);_______// Если запущен канал 2 обрабатываем этот канал
    __#include "uart_in.cpp"__// Если надо чтонибудь получить с COM-порта
    __#include "uart_out.cpp"_// Если надо чтонибудь послать на COM-порт
    __}
    }

    Теперь я постараюсь объяснить почти каждую закорючку в этом тексте. Если я чтото пропустил обязательно спросите, иначе дальше будет не понятно!!!

    #include <avr/io.h> - подключает к моему файлу необходимые мне описания и функции из комплекта поставки winavr. Это очень удобно, т.к. мне не надо писать свои соответствующие подпрограммы. Угловые скобки говорят о том что файл надо искать в том месте куда установился winavr в папке avr файл io.h

    Фактически "#include" и все что начинается на "#" это команды препроцессора, т.е. перед (пре) компиляцией моей программы текст моей программы изменяется, в нее добавляются содержимое других файлов. Это удобно. Еслибы я тупо сам добавил в свой файл все эти тексты, то файл разросся бы и было бы неудобно все это листать и понимать, а так это всего лишь одна строка и мне все ясно. Эта команда является реализацией принципа - "Разбей сложное на много простых частей".

    #include "util.h"
    #include "util.cpp" - это другие файлы с описателями и функциями. Кавычки указывают компилятору, что файлы надо искать в тойже папке где главный файл main.cpp

    Расширение "cpp" говорит о том, что внутри файла лежат подпрограммы на языке Си. Расширение "h" говорит, что там лежат описания переменных и функций. В принципе компилятору все равно и он это не отслеживает, но это нужно людям.

    Есть еще одна широко используемая команда препроцессора:
    #define aaa bbb
    Эта команда перед компиляцией обыскивает весь мой файл и меняет aaa на bbb.

    Все команды препроцессора включая #include и #define на прямую никак не отражаются в конечной программе на машинных кодах, они просто меняют текст программы перед компиляцией, а после все возвращают не место.

    Сами слова #include и #define это жестко зафиксированные слова в Си и никак иначе их использовать нельзя.
    Есть и много других слов которые жестко зафиксированы.

    продолжение следует...
    Последний раз редактировалось R2D2; 17.03.2010 в 15:26.

  4. #1203

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Продолжение.

    После компиляции нашей Си программы получается файл main.hex это файл с машинными кодами. Как там все устроено нас пока не волнует. Важно только то, что у нас есть главная программа main(), котороя запустится сразу после включения ЗУ или после нажатия на кнопку RESET, если у вас такая есть.

    До сего момента я все время путался с названиями: программа, подпрограмма, функция. По большому счету это одно и тоже. Попробуем сформулировать определение на простом языке. Функция это подпрограмма. Внутрь функции можно передавать параметры. После окончания функция может возвращать один параметр. Приведем несколько примеров:

    Пример1:
    wdt_reset(); - это вызов функции сброса сторожевой собаки. Внутри процессора АТМЕГА32 есть специальный счетчик - собака. В зависимости от настроек приблизительно раз в 2 секунды он перезапускает процессор. Если этот счетчик не сбрасывать, то процессор будет каждые 2 секунды перезапускаться и вы так и не сможете заряжать аккумы. Этот механизм предусмотрен разработчиками АТМЕЛА для предотвращения зависания машинных программ. Всякое бывает, может компилятор глючит, может сама программа с ошибками, может железо процессора глючит например от перегрева или радиации, но программы иногда зависают. В этот момент могут происходить непредвиденные события, ЗУ может само себя спалить. Если программа зависла, то она не проходит основной цикл и не сбрасывает собаку, и процессор перезапускается и все процессы в ЗУ останавливаются. Конечно при таких делах надо искать ошибку и исправлять. И все же сторожевая собака должна быть.

    Возвращаемся к функциям. Данная конкретная функция не получает ни каких параметров (поэтому внутри скобок ничего нет) и не возвращает ничего, поэтому результат работы функции не присваивается никакой переменной.

    Чтобы иметь право вызвать на выполнение эту функцию надо чтобы ее текст был где-то выше вызова описан. Эта функция была написана внутри библиотек функций компилятора winavr, т.е. досталась нам готовенькой, и, чтобы мы могли ее вызвать мы должны описать компилятору что это за функция. Для этого надо в начале нашего файла подключить файл описателей включающий в себя описание функций собаки #include <avr/wdt.h>.

    Пример 2:
    x=sin(5);
    sin - это функция, которая получает параметр 5 и возвращает результат в переменную x.

    Пример 3:
    int main(void)
    {
    }

    main - это функция которая не имеет параметров об этом говорит слово void или пусто внутри скобок. Main возвращает как результат целое число об этом говорит слово int. Функция main вызывается один раз прямо там где написано ее тело, поэтому больше нигде ее не вызывают.
    Каждая функция, использованная в нашей программе, либо написана нами лично и помещена где-то выше или ниже вызова или заимствована из библиотеки стандартных функций. Если тело функции ниже вызова или в библиотеке, то выше вызова надо описать функцию.

    Если вы в тексте программы увидели слово из английских букв и цифр (первая обязательно буква или "_") и сразу после него круглые скобки, знайте это функция.

  5. #1204

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Продолжение:

    Процессор - исполнитель программ работает как простоватый рабочий действующий по своим записям. Выполняет все по порядку слева направо и сверху вниз. Читает одну команду и выполняет, читает и выполняет. Это относится к нашему процессору АТМЕГА32. Этот процессор не имеет никаких параллельных потоков выполнения. Существует одна точка текущего выполнения - один поток выполнения.

    Только кой какие счетчики, COM-порт и АЦП работают сами по себе - аппаратно.

    Вспоминаем, что АТМЕГА32 это маленький компьютер в одной микросхеме (в одном чипе). Внутри него есть сам процессор-исполнитель, ОЗУ, ПЗУ, порты ввода вывода и все это перевязано шинами данных, адреса и управления.

    Вот как работает процессор (на этот механизм мы повлиять не можем он строго зашит и является личностью и характером процессора):
    1. Юзер включил питание.
    2. Процессор ожил, все засчитало, но он спит и видит сон: беспорядочно метаются биты.
    3. Процессор увидел, что питание достигло уровня 95% от стандартного.
    4. Процессор пропустил тактовый генератор на схему исполнения команд, заодно инициализировал несколько системных регистров.
    5. Процессор начал выполнять команды, вытаскивая их по одной по порядку начиная с ячейки памяти с адресом ноль (или как у него там принято)
    6. Одна команда один такт. Один такт - 1/16 000 000 секунды.
    7. Один такт:
    __а) Проц выставляет адрес на шину адреса (для адресации 64кБ необходимо 16 проводов в шине, т.е. 16ти битная)
    __б) Проц выставляет управляющую команду на шину управления (шина управления 3-6 проводов: чтение/запись, запрос ОЗУ, запрос ПЗУ, запрос FLASH, запрос портов ввода вывода, прерывания). Команда например: Память дай данные с адреса который выставлен на шине адреса.
    __в) Память дала данные на шину данных (8 проводов, т.е. 8ми битная) и дернула за шину управления "данные готовы".
    __г) Проц взял данные. В данных лежала команда для исполнения. К этой команде возможно нужны еще несколько байтов (по 8бит считок из памяти). Если так то проц их дочитал.
    __д) Проц выполнил команду (это могла быть команда сложения или записи или перехода это тоже целая серия работ с шинами данных, управления и адреса)
    __е) Проц рассчитал адрес следующей команды и попросил ее из памяти потом выполнил.

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

    Например чтоб нарисовать точку на экране, проц в видеопамять записывает значения красного, синего, зеленого и яркости по байту на каждый параметр и все это для зажигания одной точки, а надо зажечь 1280х1024 точек и менять их 50 кадров в секунду.

    Чтобы сыграть мелодию на динамике, надо на катушку оттягивающую мембрану подавать величину оттяга от 0-256 (1 байт) с частотой 44 000 раз в секунду.

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

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

    Конечно мы тоже животные и обеспечивать себя должны и все животное нам не чуждо, но надо знать рамки и надо думать о высоком.
    Последний раз редактировалось R2D2; 18.03.2010 в 14:02.

  6.  
  7. #1205

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Вышеуказанные рассуждения характерны для людей работающих со схемами компьютеров и пишущих на ассемблере.

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

    Хотя создатели Си очень хорошо постарались для нас, полностью полагаться на них мы не будем. Вот если бы мы программировали на intel i7 920, то конечно, все изыски Си в нашем распоряжении, но т.к. мы программируем для АТМЕГА32 нам приходится искать золотую середину, что взять от Си, а что сделать самим. Мы слишком скованы ограниченной памятью и быстродействием. Мы возьмем от Си только самое необходимое, потому что это все нести нам в своем рюкзаке на самую высокую гору.

    Думая на языке Си мы можем быть более свободны чем в ассемблере. Мы более произвольно можем располагать куски программы. Компилятор наведет порядок и самым оптимальным способом трансформирует наши мысли на Си в язык машинных кодов. Создатели компилятора борются за каждый сэкономленный байт при трансляции стандартных функций. Мы не смогли бы добиться такого же качества машинного кода, потому что его придумывали многие светлые умы.

    Компилятор оптимизирует код по быстродействию или по размеру. Не все версии компиляторов работают одинаково. Придется выбирать нужный проводя сравнения производительности.

    Итак мы знаем, что программа - это последовательность действий для процессора. Программа должна предусмотреть все возможные ситуации в которые попадает наше ЗУ и должна содержать инструкции что делать процессору и как выпутаться с честью.

    А если юзер отцепит аккум во время зарядки?!
    А если юзер коротнет зарядку?!
    А если юзер забудет зарядку включенной и уедет в отпуск?!
    А если аккум перегреется и сожгет квартиру?!

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

    Программа это своеобразное живое существо которое живет внутри ЗУ и управляет им. Программа это сложное переплетение маленьких простых кусочков. Переходы между ними могут быть сильно запутаны. Язык Си помогает нам найти удобную форму для записи наших оригинальных мыслей так, чтобы потом мы могли понять себя и чтобы нас поняли другие, поэтому надо быть консерватором в стиле программирования и Моцартом в идеях реализации.

    Для освоения языка Си необходимо узнать мнемонику языка (характерные слова и символы для записи программы).

    Все языки высокого уровня суть одно и тоже и отличаются только мнемоникой. Также как все языки мира одно и тоже. Все языки программирования (до нынешних времен многоядерности) подразумевали один поток исполнения команд, как человек, работа, дом, работа, дом, магазин, если есть деньги - ресторан, отпуск, больница, работа, дом. Поток выполнения команд перескакивает то туда то сюда в зависимости от условий жизни, попадает в циклы работа дом и в конце концов смерть - окончание действия программы. Программа металась туда сюда чтото делала, но смысла в своих действиях не видела. Смысл виден, если вырваться за пределы программы. Аккум зарядился, был вставлен в самолет, который оторвался от земли. Человек который писал программу преодолел себя вышел на новый уровень понимания! Тогда смерти программы не существует!

    Материалист не найдет смысла в этом бреде. Смысл специально спрятан от понимания материалистами. Следующий уровень подразумевает отсутствие материи и выгоды. И всеже каждый может понять.

    Итак переходы и циклы, а между ними функции вот и все программирование.

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

    Итак переходы и циклы:
    ----------------------------------------------------------------------------------
    if(условие)
    __{
    __внутренность этих скобок выполняется однократно если условие выполнилось
    __}
    else
    __{
    __внутренность этих скобок выполняется однократно если условие НЕ выполнилось
    __}
    далее программа выполняет программу здесь
    ----------------------------------------------------------------------------------
    while(условие)
    __{
    __внутренность этих скобок выполняется до тех пор пока справедливо условие
    __}
    далее программа выполняет программу здесь
    ----------------------------------------------------------------------------------
    do{
    __внутренность этих скобок выполняется 1 раз и до тех пор пока справедливо условие
    __}while(условие);
    далее программа выполняет программу здесь
    ----------------------------------------------------------------------------------
    for(i=0; i<100; i=i+1)
    __{
    __внутренность этих скобок выполнится 100 раз
    __первый раз i=0
    __второй раз i=1
    __последний раз i=99
    __}
    далее программа выполняет программу здесь
    ----------------------------------------------------------------------------------

    ЭТО ВСЕ!!!
    Я считаю, что я Вам Си и смысл всех языков программирования объяснил. Далее просто детали. Далее мы просто будем расширять список функций и углубляться в детали написания.

    P.S. Т.к движок сайта жрет пробелы мне пришлось натыкать везде подчерков "_". Не обращайте на них внимание. Подчерки нужны мне чтобы сохранить рисунок программы, так легче отслеживать начало и конец цикла и условия.
    Последний раз редактировалось R2D2; 18.03.2010 в 21:33.

  8. #1206

    Регистрация
    26.12.2005
    Адрес
    Москва,Севастополь
    Возраст
    42
    Сообщений
    212
    Цитата Сообщение от R2D2 Посмотреть сообщение
    P.S. Т.к движок сайта жрет пробелы мне пришлось натыкать везде подчерков "_".
    а вы используйте тэг CODE, он вроде как для этого создан, и ничего не жрет

  9. #1207
    msv
    msv вне форума

    Регистрация
    05.03.2008
    Адрес
    Новокузнецк
    Возраст
    58
    Сообщений
    2,376
    Выражение i=i+1 для сишника выглядит непривычно..

  10.  
  11. #1208

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Спасибо за подсказки.
    i++ решил пока не пугать.

  12. #1209

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Урок №7 (Переменные)

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

    Где-то выше мы отмечали, что всему в мире можно присвоить код и этот код можно хранить в памяти компьютера в виде напряжений в ячейках памяти, которые устроены как конденсатор (заряжен/незаряжен) или как триггер из 6ти транзисторов (который соединяет выход либо с землей либо с +5в питания) или это домен (маленький магнит) в магнитном слое на винчестере/дискетке/ленте или это дырка в перфокарте как это было на заре цивилизации.

    Итак все вышеперечисленное это 1 бит информации - да/нет, инь/янь, земля/+5в, дырка/недырка, север/юг магнита, мужчина/женщина, нолик/единичка, день/ночь, порядок/хаос.

    Всего 2 состояния, поэтому и двоичная система исчисления. В двоичной системе всего две цифры 0 и 1. В двоичной системе нет цифры 2, но есть число 2 и оно записывается так: 10.

    Просмакуем ситуацию с десятичной системой исчисления.
    В десятичной системе исчисления 10 цифр: 0,1,2,3,4,5,6,7,8,9 и тоже нету цифры 10, но есть число 10 и записывается оно: 10.

    В шестнадцатиричной системе исчисления 16 цифр: 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f и тоже нет цифры 16, но есть число 16 и записывается оно: 10

    Теперь сделаем важное замечание: при попытке записать число в разных системах исчисления количество предметов не меняется, меняется способ записи, меняется вид, но смысл остается тот же.

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

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

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

    Исторически сложилось что первые нормальные процессоры были 8-битными. Это значит что в одной ячейке информации параллельно хранились 8 битов информации и это значит, что шина данных между процессором и памятью состояла из 8ми проводов. Запрашивая данные из ячейки памяти процессор получал одновременно 8 битов.

    8 битов информации могут хранить в себе число от 00000000 до 11111111 или в десятичной от 0 до 255 или в шестнадцатиричной от 00 до ff.

    Процессор АТМЕГА32 это 8 битный процессор, значит все вышесказанное относится к нам.

    С данными разобрались, теперь адрес. Если данные это содержимое ящичка, то адрес это номер ящичка по порядку. И то и другое есть число. И то и другое записывается в 2,10,16 тиричном исчислении. Необходимо четко понимать в компьютере есть только два вида чисел: данные и адрес. Все остальные слова, придуманные международным сообществом (ссылка, метка, идентификатор, дата ...) - это все либо данные либо адрес.

    Когда я себе представляю мысленно память компьютера, я вижу следующее:

    Адрес Данные
    0000 15
    0001 2f
    0002 ff
    0003 67
    .....
    fff9 12
    fffa 32
    fffb 00
    fffc ff
    fffd ff
    fffe aa
    ffff 45

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

    Хотите писать программу с датами, числами с плавающей точкой, с большими целыми числами - выкручивайтесь как хотите. Это ваши проблемы. Компьютер устроен так и не иначе.

    Вот мы и будем выкручиваться как хотим, но в соответствии с международными стандартами.

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

    Некоторые компиляторы неСи не требуют описания переменных, тогда они сами догадываются о типе из текста программы или во время работы программы меняют тип, но это излишние затраты памяти и быстродействия, а это произвол и нам это не подходит. Наш компилятор предсказуем, отсебятину не несет, делает строго то что мы просим и требует от нас исчерпывающей однозначно понимаемой информации. В противном случае компилятор сигнализирует о неполноте программы.

    ТИПЫ ДАННЫХ:

    -------------------------------------------------------------------------------------------
    "BYTE" - тип данных один байт - маленькое целое беззнаковое число от 0 до 255.
    "unsigned char" - это тоже самое по смыслу выражение и также будет понято компилятором.

    ВНИМАНИЕ! Язык Си, если не указано в настройках, различает большие и маленькие буквы. Т.е. написание букв большии или маленькими важно и отслеживается.

    Пример использования в Си:
    BYTE x=7, y=0x45, z=b00010010;

    В этой строке мы сказали компилятору выделить гденибудь где удобно в памяти 3 ячейки. В одной ячейке будет храниться переменная "x" в другой "y" в третей "z". Компилятору абсолютно все равно как вы назовете переменные, для него важно, что везде где встретится x в программе он будет вспоминать о том месте где он выделил память и будет оттуда брать саму переменную или записывать ее туда. Название переменной не попадет в текст машинного кода, значит длинна названия переменной никак не повлияет на экономию памяти машинного кода.
    Последний раз редактировалось R2D2; 19.03.2010 в 13:00.

  13. #1210

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Переменные могут называться только латинскими буквами и цифрами из 32 знаков причем первая обязательно должна быть буква.

    Когда компилятор выделяет память - это значит что у себя он где-то просто запомнил адрес который он выделил, а с памятью непосредственно он ничего делать не будет. Слово "выделил" ничего такого волшебного не подразумевает.

    При описании переменной мы поставили знак "=", этим мы сказали компилятору вписать в программу на машинных кодах небольшой код по инициализации переменных. Это значит, что после того как ЗУ включится, первым делом программа на машинных кодах впишет в ячейку с адресом переменной (которую мы называли x) число 7.

    В переменную "y" мы попросили записать 0x45 (таким образом мы сказали компилятору, что 45 это 16тиричное число).
    В переменную "z" мы попросили записать b00010010 - двоичное число. Мне именно необходимо двоичное число, чтобы видеть на какой ноге будет +5в. Каждый знак в двоичной записи соответствует ноге АТМЕГА32 - это очень удобно (это только если реч идет о порте ввода вывода A,B,C,D).

    Разные компиляторы по разному требуют запись двоичного числа. Тот компилятор который я использовал глючил в этом вопросе, поэтому для своего удобства я поправил ситуацию самодельщиной - добавил в программу команду препроцессора "#define b00010010 0x12", т.е. перед компиляцией заменить все b00010010 на 0x12.

    BYTE будем использовать для маленьких целых для организации циклов, для работы непосредственно с памятью, для хранения всяческих маленьких настроек ЗУ.
    -------------------------------------------------------------------------------------------------
    "int" - это 2 байта. В памяти хранится сначала младший байт потом старший байт. Когда мы говорим об адресе в памяти для переменной int, то говорим об адресе младшего байта, т.е. первого из двух.

    Два байта может вместить в себя беззнаковое число от b0000000000000000 до b1111111111111111 или от 0 до 65535 или от 0x0000 до 0xffff. Думаю уже понятно что есть что.
    А если число знаковое, то вот что придумали программеры.
    Последний раз редактировалось R2D2; 19.03.2010 в 14:00.

  14. #1211

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    они как бы перекинули половину диапазона в отрицательную часть числа. Получилось, что знаковый int может принимать значения от -32768 до 32767 это ровно такое же количество чисел как и было. Никто не пользуется отрицательными двоичными и шестнадцатиричными числами это может привести к путанице. 2ичные и 16тиричные используются в контексте реальных адресов и данных и непонятно что такое отрицательный адрес. Но заметим одну важную особенность: у отрицательного числа самый старший бит 1. Больше на эту тему распространяться пока не буду. Хотите поточнее узнать - играйтесь с калькулятором.

    int - это знаковое целое (-32768 до 32767)
    unsigned int - это беззнаковое целое (0-65535)

    unsigned int писать очень долго поэтому сделаем #define WORD unsigned int и будем везде писать WORD

    Этот тип переменных мы будем использовать для счетчиков циклов, для средних целых, для ШИМ счетчиков, для контрольных сумм, для АЦП суммирования.
    --------------------------------------------------------------------------------------------------------

    Заметьте уже второй тип переменных строго ограничен в своих значениях. С одной стороны мы точно знаем что потратили только 2 байта при использовании переменной, а мы по жмотски будем экономить каждый байт, но с другой стороны мы получили головную боль по переполнению переменных и жесткому отслеживанию рамок. Например если к WORD(65535) добавить 1 то получится 0. А если от WORD(0) отнять 5, то получится 65531 и компилятор вам не поможет в этом вопросе, т.к. вычисления производятся уже после того как прога с машинными кодами уже во всю заряжает и разряжает.

    По личному опыту, будьте внимательны, очень часто совершаются ошибки с переполнением или со сравнением разных типов. Эти ошибки очень трудно найти, только с отладчиком, но какой отладчик в ЗУ при зарядке? В принципе можно и отладчик, но это такие сложности с дополнительным железом. Легче писать правильно и иметь опыт.

    Тоже самое эмуляторы и симуляторы - очень неудобны, отнимают много времени. Мне кажется, что наиболее эффективны 2 способа: внимательно проверить программу и спросить специалиста о камнях или исправить программу с целью поставить опыт прямо на ЗУ с выводом необходимой инфы на экран ЗУ. К сожалению, это поможет, если вы уже переправились и захватили плацдарм в виде хотябы одной отзывчивой прошивки и от нее можете танцевать.
    Последний раз редактировалось R2D2; 19.03.2010 в 15:17.

  15. #1212

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Все что сказано про int (integer - целое число без дробной части) справедливо и для других двух типов: short (короткий 1 байт) и long (длинный 4 байта).

    unsigned short это тоже самое что и BYTE, за одним маленьким исключением: некоторые стандартные функции требуют именно short, а не BYTE.

    long - это ооочень много - это можно считать сотые доли секунды в течение всего дня и long не переполнится.
    ------------------------------------------------------------------------------------
    Ну и наконец float это число с плавающей точкой занимает 4 байта. Как хранится в памяти мне не известно да и не надо знать.
    Все точные вычисления до 4 знака после запятой будем делать в переменных типа float (токи, напряжения, сопротивления, балансировочные коэффициенты, интегралы-суммы, диференциалы-наклоны). Это самые медленные операции. Одна графическая карта ATI или nVIDEA может пережевать милионы операций с плавающей точкой, а АТМЕГА32 не более 100 операций в секунду и это сильно тормозит все остальные операции ЗУ.

    Поэтому перед тем как программировать надо ооочень хорошо подумать как сократить количество вычислений как упростить все формулы, а что можно вычислить заранее и ввести в формулу в качестве коэффициента.
    ------------------------------------------------------------------------------------
    Последний тип который нам понадобится - bool от слова boolean тип логической переменной, которая может принимать два значения true (правда) и false (лож), т.е. это и есть один бит информации. Хранить один бит информации в памяти где все хранится по 8 бит это у компилятора вызывает трудности: либо наплевать на экономию и хранить бит как байт (0-лож, >0-правда) либо заморачиваться с запоминанием в каком байте какой бит соответствует нашей переменной.
    Мы то точно будем заморачиваться на эту тему, т.к. мы жадные, а bool переменных (флагов) у нас много. Но об этом потом.
    ------------------------------------------------------------------------------------

    В заключение скажем, что меньшая банка помещается в большую легко. Например long=int компилятор спокойно преобразовывает. А вот в обратную сторону могут происходить чудеса. Нужно быть внимательными.


    ------------------------------------------------------------------------------------
    ------------------------------------------------------------------------------------
    В общем сказка стала суховатой и скучной. На следующем этапе будем ставить эксперименты с ЗУ, будем писать маленькие очень понятные программки и гонять их на ЗУ. Конечно примем меры чтобы не спалить транзисторы. Заодно будем наращивать мышцы.
    Последний раз редактировалось R2D2; 19.03.2010 в 19:57.

  16. #1213

    Регистрация
    18.03.2010
    Адрес
    Москва
    Возраст
    45
    Сообщений
    4
    Скажите пожалуйста, подойдет ли для этого проекта ATmega32A-AU?

  17. #1214

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    28.07.2008
    Выпущены новые микросхемы ATmega16A и ATmega32A - на замену микросхемам ATmega16 и ATmega32. В новых ATmega16A и ATmega32A переработана топология металлизированных слоев кристалла таким образом, чтобы уменьшить энергопотребление микросхемы, но при этом сохранить полную совместимость с популярными ATmega16 и ATmega32. Новые микросхемы имеют меньший ток потребления как в активном режиме работы микросхем, так и в режимах энергосбережения.
    В отличии от ATmega16 и ATmega32 новые микросхемы не будут иметь модификаций с суффиксом "L" - новые ATmega16A и ATmega32A будут работать в диапазоне напряжений питания от 2.7В до 5.5В, обеспечивая максимальную производительность 16МГц при напряжении питания 4,5..5,5В и 8МГц - при напряжении питания 2.7В.
    Ниже для сравнения приведены значения энергопотребления микросхем ATmega32 и ATmega32A

    Ниже для сравнения приведены значения энергопотребления микросхем ATmega16 и ATmega16A


    Да подходит.

  18. #1215

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Забыл сказать важную вещь про вычисления с плавающей точкой: необходимо таким образом составлять формулу, чтобы компилятор на каждом этапе вычислений находился в среднем диапазоне чисел это повысит точность вычислений. На каждом этапе вычислений точность падает до велечины округления. Т.к. мы используем float (4 байта на хранение и вычисление переменной), а не double (8 байт на хранение и вычисление переменной), точность с каждым вычислением будет уплывать и уплывать, особенно если мы будем выскакивать в +бесконечность или будем приближаться к нулю.

    Поэтому правило: стараться чтобы каждое вычисление внутри формулы приводило к результату от 0.001 до 1000 (по модулю) и хранилось в этом же диапазоне и только в самом конце (перед отображением) приводилось к истинному порядку величины. Такие простые правила позволят не потерять точность на стадии вычислений, хотя бы точность уже была потеряна на стадии помех в схеме ЗУ.

    Урок №8 (операторы)
    До сих пор я много говорил про команды процессора (управляющие ноги процессора, мостов, памяти, устройств ввода/вывода), говорил про команды машинных кодов, говорил про функции (подпрограммы и программы).

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

    Как видите мы утопаем в количестве информации про которую надо говорить и употребление слова команда приводит в замешательство: в каком смысле оно используется, поэтому при описании языка Си, имея ввиду команды, мы будем использовать слово ОПЕРАТОР.

    Оператор - это то, что должен исполнить процессор при выполнении программы.
    Оператор это как бы логическая единица выполнения.
    Оператор это одно выражение, заканчивающееся ";".
    Оператор может быть сложным, состоящим из множества функций.
    Оператор может состоять из одной функции. Функция и оператор это почти одно и тоже.
    Программа Си - это последовательность операторов.

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

    Операторы - это тело программы.
    Оператор - это кусок программы.
    При написании программы операторы могут располагаться в одной строчке или каждый оператор на новой строчке.
    Оператором может называться как все выражение от ";" до ";" так и самое главное слово или знак, отражающий смысл оператора.

    Например:

    x=47*y; // Здесь оператор "="
    goto qqq; // Оператор перехода goto
    for(int i=0; i<45; i++) // Оператор цикла for
    {
    break; // Оператор выхода из цикла
    if(x<y)e=4; // Оператор сравнения if
    ...
    }

  19. #1216

    Регистрация
    08.11.2009
    Адрес
    Екатеринбург
    Возраст
    36
    Сообщений
    5,330
    Цитата Сообщение от R2D2 Посмотреть сообщение
    if(x<y)e=4; // Оператор сравнения if
    Всегда вернёт true. Должно быть "==".
    Воизбежание подобных радостей надо ставить константу вперёд.
    if 4=(x<y)e компилятор не пропустит.

  20. #1217

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Это я просто бессмыслицу писал чтоб про операторы сказать.


    Урок №10 (Первая настоящая программа на Си для АТМЕГА32)
    Код:
    #include <avr/io.h>                 // Общая муть
    #include <avr/iom32.h>              // Мега 32
    #include <avr/wdt.h>                // Стандартные описатели собаки
    #include <util/delay.h>             // Стандартные описатели задержек
    #include "bit.h"                    // Обращение к битам портов по названию
    
    //------------------------------------------------------------------------------ 
    // Главная программа запускается по ресету
    int main(void)
    {
    // Это магические слова, чтобы ЗУ себя не спалило
    cli();          // Запрет всех прерываний
    WDTCR=15;       // Инициализация сторожевого таймера
    WDTCR=15;       // Инициализация сторожевого таймера
    PORTA=0;        // В порту A все нули 0000 0000
    PORTB=0x1c;     // В порту B все нули 0001 1100 кроме PB2 PB3 PB4 (клавиатура подтянута на +)
    PORTC=0x80;     // В порту C все нули 1000 0000 кроме PС7 (клавиатура подтянута на +)
    PORTD=0x02;     // В порту D все нули 0000 0010 кроме PD1 (подтяжка TXD на +)
    DDRA=0;         // Задаем направление работы ног порта A 0000 0000
    DDRB=0x43;      // Задаем направление работы ног порта B 0100 0011
    DDRC=0x7f;      // Задаем направление работы ног порта C 0111 1111
    DDRD=0xfe;      // Задаем направление работы ног порта D 1111 1110
    
    // Этот цикл выполняется бесконечно. То что нам надо!
    while(true)
      {
      wdt_reset();                   // Сброс собаки
      _delay_us(10000);              // Задержка 0.01 секунды
      PORTD_Bit7=1;                  // Подать напряжение на динамик
      _delay_us(10000);              // Задержка 0.01 секунды
      PORTD_Bit7=0;                  // Убрать напряжение с динамика
      }
    // Хотя сюда программа никогда не доберется, мы обязаны закрыть все скобки и соблюсти все правила хорошего тона.
    }
    // Конец главной программы
    //------------------------------------------------------------------------------
    После запуска этой программы мы услышим тарахтение динамика.

    Для того чтобы ехать быстро, приходится очень долго запрягать. Вот и в нашем случае, мы будем ставить эксперименты на ЗУ и, чтобы его не спалить, приходится писать лишний код (слэнг программеров обозначает программировать). А также в начале программы мы подключили очень много файлов описателей. Просто не обращайте на них внимание. В зависимости от того какие вы используете операторы в своей программе, необходимо подключать соответствующие файлы описателей. Этот вопрос решается экспериментально или читая хелп на операторы.

    Самое интересное в этой программе, то из-за чего все было затеяно, это внутренности оператора while
    АТМЕГА32 будет бесконечно выполнять все операторы внутри цикла, т.к. условие while(true) всегда истинно, значит дойдя до нижней скобки цикла "}" и проверив условие (true), программа начнет цикл заново от верхней скобки "{".
    Внутри цикла выполняются последовательно оператор wdt_reset(); - сброс собаки, _delay_us(10000); ничего не делать (выполнять пустой код, растрачивая время) в течение 10000 микросекунд, т.е. 0.01 секунды, потом установить на 16 ноге проца 5в PORTD_Bit7=1;, потом опять подождать и сбросить в 0в

    В этом месте можно спросить нестесняясь любой вопрос. Иногда какая-то мысль или недоразумение мешает, потому что захватывает на себя сознание и мешает понимать дальше.
    Последний раз редактировалось R2D2; 23.03.2010 в 15:41.

  21. #1218

    Регистрация
    08.11.2009
    Адрес
    Екатеринбург
    Возраст
    36
    Сообщений
    5,330
    Цитата Сообщение от R2D2 Посмотреть сообщение
    WDTCR=15; // Инициализация сторожевого таймера
    WDTCR=15; // Инициализация сторожевого таймера
    К логопеду пора...

  22. #1219

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Вопрос в точку, я про это стал забывать уже, а в коментах не написал.
    Здесь тонкий момент однако присутствует. Во избежание случайной записи в настройки таймера собаки, производится обращение к регистру таймера и непозднее чем через 4 такта производится запись значения. Точно не помню надо даташит смотреть. Но внешне это выглядит как задводвоение.

    И про
    if(x<y)e=4;
    здесь все верно написано. Это не Си-шный изворот это простая конструкция

    Код:
    if(x<y)
      {
      e=4;
      }
    Последний раз редактировалось R2D2; 23.03.2010 в 19:39.

  23. #1220

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Урок №11 (Вычисления выражений)


    1. Особенности вычисления длинных выражений:

    Рассмотрим пример:
    x= (...) / ((...) + ((...) * (...)));

    Как бы, вы, вычисляли данное выражение? ...
    Компилятор это делает немного иначе, но в целом тоже самое! Компилятор находит самые внутренние скобки и в них два операнда (т.е. числа слева и справа от знака операции (слагаемых, вычитаемых, умножаемых, деляемых) далее выполняет над ними операцию и получает результат. Результат хранится во временной переменной. Таким образом выражение упрощается вместо двух операндов и операции осталось вычисленное значение - временная переменная. Теперь опять компилятор ищет самые внутренние скобки и т.д. В конце концов от всего выражения остается одно значение - результат, лежащий во временной переменной, который вписывается в память где у нас должна располагаться переменная "x". Само вписывание и есть оператор присваивания.

    НО возникает два вопроса про детали вычислений:

    1. Если компилятор нашел внутренние скобки, а там a+b*c, то сначала складывать или умножать? То чему нас учили в школе в принципе компилятору известно, но жизнь и все возможные ситуации не укладываются в школьные представления, потому что есть и другие операции кроме +-/* и определить порядок вычислений на все случаи жизни бывает очень трудно, да и запоминать тот порядок который принят у компилятора трудно.

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

    2. А как компилятор будет складывать 5 груш и 4 яблока? Или, например, сколько будет 5/4? Что происходит с типами при вычислениях?

    Напоминаю, что если в вашей программе где либо встретится выражение 5/4, значит ваша программа неэкономная. Все что можно вычислить заранее, надо вычислить и вписать готовое в программу. В программе должны быть только переменные и несокращаемые коэффициенты. Я пишу 5/4 как пример, чтобы сразу было видно тип числа целое/целое.

    Отвечаю компилятор выполняет только те операции которые у него описаны внутри его создателями, все непонятки компилятор приводит к понятным типам "по умолчанию" (т.е. как попало, как было в памяти случайно, как предсказал Билли, как вы предсказали заранее не зная что будет, как считает правильным международное сообщество программеров Си). В данном случае последний вариант.

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

    И опять есть выход который позволит нам точно быть уверенными что компилятор все сделает правильно: мы можем явно подсказать компилятору что делать с типами. Например int(x) - превратит x в целое число, просто отбросит дробную часть без округления, а остатки как может запихает в целое число.

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

    3. Как понимать выражение "x=x+1" ? Это не уравнение. Это запись обычного выражения Си. И вообще в Си нет никаких уравнений. За уравнениями обращайтесь в маткад. Все выражения в Си - это порядок вычислений. Порядок "строго" задан все данные в наличии имеются, никаких колдований с решениями уравнений в программе нет. Вы уже все сколдовали заранее и в программу поместили готовые формулы расчета корней. Поэтому, компилятор, увидев x=x+1, делает следующее:
    достает из адреса где лежит x содержимое (значение х) добавляет 1 и кладет это значение назад в x.

    Кому может понадобиться добавлять 1 к переменной? Очень часто используется такое выражение, например перебирая массив данных, работая с каждым элементом, мы указываем номер элемента или меняем переменную цикла чтобы цикл выполнился ровно 100 раз. Для упрощения записи, только в Си, придумали записывать x=x+1 несколько иначе:

    x=x+1; или
    x++; или
    ++x; или
    x+=1;
    Все эти выражения означают одно и тоже x=x+1;

    Например если вам надо цикл выполнить 100 раз, то пишем:
    for(int x=0; x<100; x++)
    {
    Внутренности скобок выполнятся 100 раз и при каждом прохождении цикла переменная х будет содержать
    число от 0 до 99 по порядку
    }


    А если надо добавить 2, то:
    x=x+2; или
    x++; x++; или
    ++x; x++; или
    x+=2;
    Последний раз редактировалось R2D2; 24.03.2010 в 14:55.

  24. #1221
    msv
    msv вне форума

    Регистрация
    05.03.2008
    Адрес
    Новокузнецк
    Возраст
    58
    Сообщений
    2,376
    если в вашей программе где либо встретится выражение 5/4, значит ваша программа неэкономная.
    Вроде бы практически все компиляторы, такие вещи обрабатывают такие вещи на этапе прекомпиляции... А для программера бывает наглядее иной раз написать именно a=2/2; вместо a=1;// a=2/2=1;

  25. #1222

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Вы правы, если компилятор сможет увидеть, то он это сделает.
    Но иногда в формулах может быть достаточно сложное выражение и неоднозначно сокращение.
    Когда приходится экономить каждый байт лучше надеяться только на себя.

    В конце концов можно поставить эксперимент: попробовать так и так и сравнить длину кода.
    Если длина несущественна, то конечно понятийная сторона должна брать верх.

  26. #1223

    Регистрация
    26.12.2005
    Адрес
    Москва,Севастополь
    Возраст
    42
    Сообщений
    212
    все таки постинкремент и преинкремент разные вещи:

    a = 5;
    b = a++;
    в результате: а=6, b=5;

    a=5;
    b=++a;
    в результате: a=6, b=6;

  27. #1224

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Ага до этого еще не добрался.
    Хотел отдельно тему завести "выпендроны Си".

  28. #1225

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Урок №12 (философия Си)

    Создатели языка Си очень экстравагантные люди. Это видно по тем конструкциям, которые они придумали. Например чего стоят a++; или того хуже b=a++; или совсем плохо b=(a=a+1); или a=b=c=d+1; Таких конструкций нет ни в одном языке программирования. Подобного рода конструкции осуществляют присваивание справа на лево, т.е. сначала осуществляется расчет выражения и присвоение справа а потом все левее и левее.

    На этом создатели Си не остановились. В каком то ветхом году уже был придуман язык Си++ (поэтому названия файлов с кодом *.cpp) в котором была совершена революция в обобщении типов переменных и операций над ними.

    Было введено понятие "класса" и "объектно ориентированного программирования", которое потом было подхвачено другими языками, но так изящно не было реализовано ни у кого.

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

    Итак есть железяка - ЗУ или винчестер или флэшка или комп или замок с таблетками или жпс навигатор или любая другая железка с процессором внутри. Сама по себе железка ничего делать не умеет, в ней заложена возможность, но она недоступна без программы. Без программы мозг железки пуст. Чтобы она ожила, необходима программа. Программа формирует поведение устройства. Устройство либо спит и ждет команды человека, либо дежурит выполняя монотонные действия, ожидая сигналов от датчиков, кнопок клавиатуры, сигналов из сетки и т.д. Потом появляется человек, передает команды, устройство выполняет и возвращает результат в виде изображения, звуков или других воздействий на наши органы чувств. И нам кажется, что мы общаемся с искусственным разумом, который реагирует на наши команды и выдает нам результаты. А на самом деле мы общаемся с тенью программиста, который когда-то сформулировал все модели поведения программы.

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

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

    Старый способ программирования (до "классов") подразумевал, что есть строго ограниченное количество типов переменных и операций над ними. Например целые числа можно складывать делить умножать вычитать и т.д. при этом получаются тоже целые числа. Все многообразие мира описывается через эти переменные и типы которыми задаются свойства всех объектов мира.

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

    В языке Си++ можно создать класс Деревья (как тип переменной) объект Дерево (как саму переменную), описать все операции которые можно выполнять с деревом (как сложение вычитание и т.д.) Описать события, которые случаются с деревом (посадили, выросло до 3 метров, спилили, сожгли), описать свойства дерева (рост, вес, цвет и т.д.) Таким образом существует новый подход к описанию мира и созданию образов в программировании, более близкий к тому как думает человек, дающий новые возможности и удобства.

    В языке Си++ есть еще одна возможность - "наследование". Чтобы создать новый образ "березы" мне не надо заново описывать все что присуще березам, мне достаточно сказать компилятору, что березы это наследник деревьев и все что присуще деревьям присуще березам, но есть новые свойства, методы и события которые присущи только березам.

    Программы, написанные на Си++ и использующие классы имеют несколько другой облик. Они как набор подпрограмм которые выполняются при наступлении событий всех объектов, описанных в программе. Например есть лес, состоящий из уникальных деревьев-объектов. Вот как выглядит программа на Си++

    1. Тишина, лес погружен в дремоту.
    2. Ветерок пробежался по листве и где то падают листья.
    3. Дятел прилетел и раздолбал дупло.
    4. Старое сгнившее дерево упало и придавило 3 куста

    Объектно ориентированное программирование - это как бы сборник обработчиков всех возможных событий. А внутри этих событий выполняются методы/операции над объектами и их свойствами (создаются, уничтожаются, перекрашиваются, увеличиваются и уменьшаются). Чтобы все это многообразие однозначно описать для компилятора, понадобилось некоторое количество служебных слов и знаков типа "->", "::" и т.д.

    А теперь о грустном:
    Это конечно все хорошо, но не годится для маленького проца. А все эти возможности можно реализовать и в простом Си, но с несколько более тяжелой грамматикой и орфографией. Нам придется отказаться от классов из экономии, хотя как бы легко было программировать на Си++ например ЖКИ:

    LCD->Restart();
    LCD->SetLine(3);
    LCD->Print("Welcome!");
    LCD->Clear();
    LCD->LoadSymbol(0x04, 14, 45, 44, 1, 3, 6, 7, 1);

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

    Но это все прекрасно работает на большом компе на его Си++.

    Больше про классы пока говорить не буду.
    Сконцентрируемся например на ЖКИ и на использовании прерываний.
    Иметь аппарат для удобной работы с ЖКИ это полдела при написании программы для ЗУ.

    Еще несколько слов про Си++. Есть такой Си - микрософт Си++. После борланда он мне показался нелогичным, запутанным вобщем наверное я применил мало усилий чтобы разобраться. Так вот весь виндоус написан на этом Си++ и именно с применением классов. Все окна, все поля ввода, все диски, принтеры все устройства и драйвера и вообще все в виндоусе это классы. И у всех классов есть методы, свойства и события. Все эти объекты в виндоусе перевязаны между собой сообщениями. Сама операционная система это огромный генератор сообщений, все что вы ни делаете с клавиаторой мышкой и дисками и сетками, все это порождает тысячи сообщений от операционной системы всем открытым окнам и самому верхнему окну-программе. Сообщения принимаются окном и обрабатываются. Сообщение - это событие для окна. Система сообщила окну, что драйвер клавиатуры получил код нажатой кнопки. Окно вызвало обработчик события "кнопка нажата" и послала сообщение строке ввода там где сейчас моргает курсор, а строка приняла сообщение и послала сообщение драйверу видюхи отображай текст по адресу. Попутно все это было залогировано, попутно антивирус проверил нет ли вируса внутри кода кнопки (это конечно шутка, но если бы это был диск или сетка то это так).

    Все очень просто, но мне все больше в последнее время кажется, что это все суета.
    Последний раз редактировалось R2D2; 25.03.2010 в 20:27.

  29. #1226
    msv
    msv вне форума

    Регистрация
    05.03.2008
    Адрес
    Новокузнецк
    Возраст
    58
    Сообщений
    2,376
    ИМХО методологически неправильно объяснять про классы (даже вскользь), не разобравшись и даже не упомянув структуры. А ведь классы это всего лишь логическое развитие идеи структурирования, просто инкапсулировать туда еще и функции..
    Идеологию ООП вполне можно применять и в простом C, достаточно написать функции (методы), для которых в одном из параметров передавать указатель на структуру, описывающую объект.
    Так же неплохо дать представление о асме, и пару простейших примеров как конструкции C выглядят на асме. Для контроллера это представление мягко говоря будет не лишним..
    А вообще все-таки здорово у Вас получается!
    но мне все больше в последнее время кажется, что это все суета.
    Увы.. как и вся наша жизнь...
    Последний раз редактировалось msv; 26.03.2010 в 05:49.

  30. #1227

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Я просто хотел дать общий взгляд с высоты птичьего полета, так сказать перевязать знания о программировании, хотя и примитивном, с общими тенденциями и сложнейшими мировыми программами. Я помню как обычно дается язык Си в книжках в строгом изложении. Читаешь, читаешь, читаешь. Инфа горами скапливается в голове, связей нет или мало, начинаешь писать, много непоняток, опытов. Через несколько лет программирования со многими ошибками и глюками вдруг прояснение и виденье общей картины. Вот попытался дать картину.

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

    Что касается суеты это я просто вечером писал и на меня напал грех уныния. Неээ, думаю (хотя наверняка доказать не могу) смысл есть и он вне жизни и вне материи возможно. Каков смысл жизни Эйнштейна? Для нас очень даже большой: его идеи и его работа. Какой смысл, какая материальная выгода, для самого Эйнштейна никакой, все равно он умер. Если б не было Эйнштейна, что другой человек бы не добрался до этой мысли? Добрался бы рано или поздно. Значит смысл жизни Эйнштейна и не в том что он сделал, придумал раз это мог сделать другой. То что Эйнштейн сделал для своего тела ради выгоды - не известно и забыто, а то что делал для всех помнится. Где то здесь спрятан ответ. А еслиб он был вторым, что смысл потерян? Думаю нет. Смысл все время ускользает на следующий уровень за пределы жизни в материи. Может все таки есть еще вселенные: вселенная информации/мысли, вселенная непреклонной воли, вселенная доброты. Может быть что то есть внутри нашего тела или в пятом измерении нашего тела, может ради него и существует тело.

    Если так думать, то смысл есть и это не только смысл но и силы жить и оставаться человеком добрым, отзывчивым, сострадающим, любящим, не помешанным на вещах и удовольствиях и жертвующим ради них всем остальным. Как приятны открытые, чистые, душевные люди, которым ничего не надо, но если они попросят, то помочь не жалко и которые неподдельно могут позаботиться о нас. Что в этом притягательного? Почему мне трудно стать таким человеком? Почему приходится делать выбор в пользу выгоды для своих, отказываясь от роли доброго. А может выгода и мое личное здоровье и безопасность это вторично. Мать бросается спасать ребенка в горящий дом почему? Почему не думает о себе? Что ее движет? Какая главная сила? Эйнштейн зачем сидел дома и писал формулы? Ради славы? Ради денег? У нас есть примеры по телику кто живет ради славы, ради денег и ради власти. С такими людьми приятно дружить? Почему Эйнштейн не поехал на Канары, а продолжил копаться в формулах? Может им двигала сила та же, что движет матерью. Может эта сила, та которой делаются все хорошие дела на земле.

    Вывод: Смысл есть, смысл сложный (нам его не понять из понятий выгоды) и простой (все могут его искать). Жить надо. И стараться улучшать себя. Выследить, разобраться, сменить курс, приложить усилие и выплывать упорно в нужном направлении. Легко не будет, но помощь точно придет, а главное какая то наша часть вечная и нас ждет бесконечно много интересного и бесконечный рост.

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

    Нет не так! Наоборот откройтесь, отдавайте, работайте ради всех и всех любите даже врагов. Все что нужно для жизни приложится само, как у Эйнштейна. На всем человечестве лежит общая задача. "Бог не играет в кости". Где то здесь смысл, но точно не знаю.
    Последний раз редактировалось R2D2; 26.03.2010 в 12:39.

  31. #1228
    msv
    msv вне форума

    Регистрация
    05.03.2008
    Адрес
    Новокузнецк
    Возраст
    58
    Сообщений
    2,376
    Опять же увы... Но для меня пока ничего не опровергает, что человек всего лишь биологический робот, работающий по весьма сложной программе, но имеющую простейшую конечную цель- выживание вида. Иногда эта программа заходит в досточно причудливые ветки, как-то моделизм, создание ЗУ итп, но только на беглый взгляд это не относится впрямую к той-же конечной цели. И в этом (конечной цели) человек ничем не отличается от любой другой твари (не в отрицательном смысли) или какой-нибудь плесени (не в отрицательном смысли)...
    Много тыщ. (миллионов?) лет назад оказалось, что для успешного выживания возможно два пути- деструктивный/конструктивный. Вы активно пропагандируете второй вариант, который мне тоже ближе и кажется более перспективным. Хотя природа требует равновесия и белое без черного, увы, не бывает, законы развития требуют.

  32. #1229

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Мир на столько реален, а наш образ мыслей настолько впечатан в нашу нейронную сеть, сформированную социальными установками и "научными верованиями" взглядами, что ГИПЕР тяжко оторваться от "своего" био-восприятия, самоосознавания и самозаблуждения что я это я и я умный и я все делаю правильно.

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

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

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

    Восточный путь - путь исследования себя, само исцеления и подлинного освобождения. Россия - где то посередине.

    Не пугайтесь Выход есть.
    Последний раз редактировалось R2D2; 26.03.2010 в 14:39.

  33. #1230
    msv
    msv вне форума

    Регистрация
    05.03.2008
    Адрес
    Новокузнецк
    Возраст
    58
    Сообщений
    2,376
    А что пугаться.. мир таков, какой он есть. Вне зависимости от того, как мы его себе предствляем. А как такая банальная аналогия: тело -железо, разум - программа, мысли - "видимая" часть выполнения программы. Как и софт без железа мертв, так и наоборот. Зуб заболел- аппаратное прерывание высокого приоритета, призывающее болью что-то сделать, дабы устранить возникшую неисправность. Удовольствие- программное прерывание, по логики программы призывающее тело осуществлять ту самую, основную цель.. Удовольствия могут быть разные (полежать на диване перед теликом, написание этих букф итп), а цель одна..
    Ладно, побоюсь получить бан, прекращаю эту дискуссию... Хотя.. Я ж о программировании.. вроде..

  34. #1231

    Регистрация
    18.03.2010
    Адрес
    Москва
    Возраст
    45
    Сообщений
    4
    Уважаемый R2D2, а вы читали Ричарда Баха, книгу Миссия (ударение на второе и). У него возникает мысль, что мы здесь просто из-за того, что жить прикольно. Именно в этом теле, в конкретной стране. Т.е мы ведь играем в компьютерные игры (World of Warcraft к примеру). В этих играх принимаем любой образ, который выберем. Так же и в этом мире. Выбрали конкретное тело, конкретную судьбу и играем. Бах интересен тем, что он предложил совершенно новую концепцию религии. Ведь до него было всего 2 верования. Первое - делай хорошее, иначе тебя накажут (попадешь в ад). Второе - будешь кого то обижать, снова будешь рождаться и уже тебя будут также обижать, пока до тебя не дойдет, что так делать плохо (закон кармы) Прошу меня не банить, т.к я про программирование компьютерных игр, что относится к теме С и C++

  35. #1232

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Когда я пишу программу, я все время спрашиваю себя: А стоит ли такая цель таких сложностей программирования, может есть другой более простой более красивый подход.
    Эйнштейн тоже при создании ОТО и СТО думал А так ли все сложно задумал Создатель? Бог не мог создать мир избыточно сложно. Все создано максимально просто и в тоже время есть симметрия и подобие частей и целого, как подсказки, как способ приспособиться, как способ получать ответы там, где нам не дотянуться своим разумом. Продвинувшись так далеко в логике, он видел закономерности и подсказки и наверняка задумывался как рождаются мысли. Как рождать новые мысли?

    Как в Хрониках Амбера, я очнулся в этом мире человеком. Когда нибудь я умру. Совершенно закономерный вопрос, А зачем все это? Какой смысл? Ответ есть и в космосе и в каждом атоме и в моей программе и в каждом занятии. Нет ответа только там, где его не ищут.

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

    Заканчиваем с философией. Продолжаем прерывания высокого уровня.

    Урок №13 (прерывания)
    Прерывания - это еще один удобный способ разветвить нашу программу в зависимости от событий которые происходят с ЗУ.

    Где то ранее я утверждал, что при включении процессор начинает читать программу машинных кодов начиная с адреса 0. В процессоре ATMEGA32 все устроено несколько иначе. В начале памяти располагаются "ВЕКТОРА ПРЕРЫВАНИЙ" приблизительно 15 штук векторов по 2 байта на вектор. Каждый вектор - это адрес программы для обработки прерывания, т.е. адрес программы которая будет запущена при наступлении прерывания. Точно не уверен, для нас это не важно, чем ближе к началу вектор тем выше статус прерывания. Скорее всего процессор при наступлении какого нибудь события проверяет от нуля все прерывания может кто еще сработал и первым выполняет первое попавшееся от нуля, поэтому оно исполнятся первым.

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

    В нашей программе на Си мы просто сообщаем компилятору, что мы задействовали то или иное прерывание и пишем подпрограмму для обработки. Компилятор все расставит сам.

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

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

    После окончания обработки прерывания процессор восстанавливает свое душевное и материальное состояние и продолжает как ни в чем не бывало и почти не потратив времени на прерывание.

    Для того чтобы быстро распихать все свои данные перед прерыванием и восстановиться после, процессор использует СТЕК.
    СТЕК вообще используют многие. При вызове каждой подпрограммы используется стек. Чем глубже вызовы подпрограммы из подпрограммы из подпрограммы из подпрограммы.

    СТЕК - это память где то в ОЗУ (обычно в конце) где ее выделит компилятор. СТЕК работает по правилу последний вошел - первый вышел. Зная порядок как процессор запихивал в стек, процессор знает что он оттуда достает. Стек нужен для экономии быстродействия.

    Стек может переполняться по мере использования он может разрастись и залезть на область где хранятся переменные и тогда будет непредсказуемое поведение переменных и все повиснет и понадобится собака.
    Последний раз редактировалось R2D2; 26.03.2010 в 20:44.

  36. #1233

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Рас уж начали говорить про стек, немного поговорим про компилятор, чтобы иметь общее представление и знать что от него ждать.

    Урок №14 (компилятор)
    В предыдущем тексте очень много раз упоминалось слово компилятор. Не побоюсь повторения и еще раз опишем его образ:

    1. Компилятор это обычная программа, которая преобразует мысли программиста, сформулированные на каком нибудь языке в программу на машинных кодах, понятную процессору. Далее программа прошивается в память процессора (такое бывает только в SoC http://ru.wikipedia.org/wiki/SoC как наш АТМЕГА32) и работает самостоятельно в нашем ЗУ.

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

    3. Компиляторы бывают от разных производителей и бывают разные сборки у одного производителя. Все они работают по разному и имеют разные глюки.

    4. За компилятор как и за любую программу ни один автор не дает гарантий, поэтому, учитывая все многообразие возникающих проблем при программировании процессоров для различных устройств, вся ответственность лежит на нас и мы ее никогда не сможем оправдать на 100% как бы мы не старались, поэтому наше программирование должно быть максимально надежным и предусмотрительным.

    5. После компиляции программы всегда надо смотреть на результаты работы компилятора. На сколько удачно ему удалось выполнить свою работу и разместить в памяти программу, переменные, стек, постоянные данные. Нужно создать запас памяти и предусмотреть наиболее простую структуру программы и в тоже время все еще удобную для чтения и писания.

    Как же работает компилятор?

    Это приблизительное описание:
    1. Берется главный файл проекта и выполняются все команды препроцессора, т.е. внутрь главного файла набивается вся программа целиком со всеми файлами утилит и всеми файлами описателей и получается огромный файл всей программы.
    2. Выполняется первый проход по файлу выявляя все ошибки - лексический анализ, правильность расстановки разделяющих знаков, проверка скобок и т.д. проверяются простейшие правила, которые можно проверить не вникая в глубинный смысл программы.
    3. Выполняется синтаксический анализ. Вся программа превращается в древовидную структуру (как реестр в винде) или в нечто подобное с целью вынуть смысл программы из текста, разбить все по понятиям, кто кому приходится детьми и родителями и проверить соответствие типов, количества параметров, установить взаимосвязи между описанием и вызовом. Древовидный тип считается самым удобным для описания сложных логических построений.
    4. Оптимизация. Все это дерево анализируется на предмет лишних, подвешенных в воздухе веток и они отбрасываются или не отбрасываются (не всегда компилятор может понять все взаимосвязи) Происходит упрощение обобщение кода.
    5. Из этого голого смысла формируется текст программы в машинных кодах. Сначала мелкие подпрограммы превращаются в код известной длины. Потом все маленькие подпрограммы расставляются в памяти линковщиком, который вставляет перекрестные ссылки на подпрограммы. На этой стадии тоже происходит оптимизация по размеру или скорости. Возможно некоторые куски программы жмутся архиватором и гдето в тексте добавляется разархиватор.

    Вспомним что в АТМЕГА32 три вида памяти FLASH (здесь лежит программа и константы: таблицы символов, схема меню, все текстовые фразы), ОЗУ (здесь переменные, массивы, стек), ПЗУ (настройки пользователя, настройки аккумуляторов и химии). Компилятор делает файл с программой на машинных кодах, который выглядит как последовательность байтов, которая будет записана во FLASH. Компилятор также может сделать файл для ПЗУ с начальными установками аккумуляторов и химии, но компилятор ничего не делает для ОЗУ. ОЗУ при выключении полностью теряет все и при включении там неизвестно что - мусор. Процессор выполняет программу которая лежит во FLASH и никогда не меняется, а вот в ОЗУ творится жизнь, там непрерывно все меняется: меняется содержимое глобальных переменных, возникают и исчезают временные переменные, а в конце памяти растет и убывает стек. Верх и низ ОЗУ никогда не должны пересечься. А в ПЗУ что-то меняется только, если юзер сделал изменение параметров.

    Компилятор очень точно просчитывает где в ОЗУ и что будет храниться. Сначала идет область переменных и массивов глобальных (видных из всех функций и подпрограмм и живут всегда), потом идет область временных переменных (живут только на время выполнения функции), которая растет в сторону конца, потом идет пустота и весь конец ОЗУ используется под СТЕК. СТЕК начинает расти от конца к началу. То растет, то убывает. Это зависит от глубины ныряния процессора внутрь подпрограмм и от количества передаваемых параметров через функции, но самая глубина и самый большой размер стека, когда в самой глубине подпрограммы вызывается прерывание, которое спасает все состояние процессора в стек и занимает пространство ОЗУ под временные переменные.

    А ОЗУ у нашего процессора всего 2048 байт и это ну прям впритык мало, и мало 32768 байт под программу. Вот почему я такой жадный, потому что глупый, и не могу вместить удобство и функциональность, которые мне так важны.

    После работы компилятора winavr avr-gcc (GCC) 4.2.2 (WinAVR 20071221rc1) выдается сообщение:

    Program: 30316 bytes (92.5% Full) (.text + .data + .bootloader)
    Data: 1041 bytes (50.8% Full) (.data + .bss + .noinit)
    EEPROM: 914 bytes (89.3% Full) (.eeprom)

    Это означает что программа работать будет, потому что места хватит.
    А вот после работы последней версии компилятора и 1 и 2 строка зашкаливают за 100%, такую программу даже не пытайтесь прошивать.

    Одновременно с созданием машинного кода компилятор создает файл main.lst и main.lss в которых вы можете найти программу на ассемблере и таблицы размещения функций, переменных и констант.
    Последний раз редактировалось R2D2; 01.04.2010 в 20:10.

  37. #1234

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Мы приблизительно знаем как работает "инструмент" - язык Си. Теперь надо включить фантазию и увидеть какой будет наша программа для ЗУ (максимально лучшее, что мы можем пожелать). Заметьте, вся информация будет взята нами из опыта, все наше творчество заключается в выборе лучшего (как нам кажется) из того что знаем. Попробуйте найти какую мысль породил я или вы при составлении программы. Что конкретно новое? Где творчество?

    Урок №15 (Рецепт как написать программу для зарядного устройства)

    Наша программа для ЗУ должна уметь следующее (в порядке мысленного взгляда на чужие ЗУ):

    1. Понятное и безопасное меню без всяких там инструкций (на сколько позволит размер программы).
    2. Быстрый и удобный запуск зарядки.
    3. Исчерпывающая информация о результатах, которая никуда не пропадет при нажатии на не ту кнопку.
    4. Доступ к настройкам.
    5. Простота.
    6. Крутой и гибкий алгоритм зарядки. Проверка на неестественное поведение аккумулятора.
    7. Связь с большим компом и возможность отдать ему вообще всю инфу из ЗУ онлайн.
    8. Возможность без большого компа проводить настройку и отображение ошибок и всяческих переменных.

    Не смотря на то, что главный смысл ЗУ - качественно заряжать, большая часть программы будет посвящена интерфейсу с юзером. Сам алгоритм зарядки - это проверка текущего состояния датчиков, вычисление необходимой коррекции и посылка команд на исполняющее устройство (установка текущего тока зарядки) займет очень мало места.

    Если бы мы располагали исследованиями в области аккумуляторов да на русском языке, да имели экспериментальную базу, можно было бы нагородить огород с использованием скоростей температуры, напряжения или производных dV/dI dT/dV и т.д. И все равно существенно это не заняло бы места, если только там нет волшебных таблиц с критическими точками.

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

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

    Вывод: Первое чем займемся - это интерфейс на все случаи жизни с минимальной загрузкой процессора и с минимальными затратами на его использование.

    Должна получиться заготовка, которую можно будет легко использовать для любого устройства на АТМЕГА с прицепленным ЖКИ и с очень простыми функциями отображения инфы на ЖКИ.

    Для использования нашей заготовки надо всего лишь переопределить ножки процессора к которым подключено ЖКИ и писать программу с отображением отладочной информации на экран для самоконтроля.

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

    Лирическое отступление как делаются архиваторы:
    Когда то давно мне понадобилось сократить трафик между моими двумя программами, которые были удалены друг от друга. И тогда я начал читать про способы архивации и опять наткнулся на заумные рассуждения. Как везде все можно объяснить на пальцах. Во всех методах сжатия информации используется один и тот же принцип: очень умные дяди внимательно смотрят на эту информацию и ищут закономерность. Если закономерность есть, значит данные сжать можно, если закономерности нет - нет. Если какие то фрагменты данных повторяются, значит их можно один раз запомнить, а в то место где они стоят (в архивированном файле) поставить ссылку на одну эту копию (ссылка должна быть меньше по размеру чем повторяющийся фрагмент).

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

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

    Точно также каждый человек должен подумать про устройство мира. Если есть одинаковые события их надо обобщить и придумать правило/закономерность, чтобы работать не с самими событиями, а с их закономерностью.

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

    Кто то из ученых, исследуя музыку Баха, сделал заключение что Бог создал музыку, чтобы придать пропорции миру. Мы будем создавать красоту программы, чтобы придать ей пропорции. Мы движимы заботой о владельцах аккумуляторов и должны выбрать пропорцию между формой (интерфейсом) и содержанием (алгоритмами зарядки), чтоб было удобно и достаточно эффективно.
    Последний раз редактировалось R2D2; 02.04.2010 в 14:29.

  38. #1235

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Вывод информации на ЖКИ будет как бы состоять из 3 уровней:
    1. Самый высокий уровень (программиста) в тексте программы происходит формулирование требований к шаблону (передача параметров) и вызов самого шаблона по его номеру. Все шаблоны нами будут перенумерованы и заполнены заранее. Шаблон может обновляться сам, отслеживая изменения переменных.

    2. Уровень функции заполнения шаблона данными. При вызове шаблона с параметрами функция отрисовки шаблона заполняет шаблон текущими данными (фразами из словаря и переменными I,V,T...). Прорисованный шаблон помещается в видеопамять в ОЗУ в виде букв и символов для всех строчек ЖКИ. А также сигнализирует, что произошло обновление видеопамяти.

    3. Самый низкий уровень. Уровень прерывания производит передачу видеопамяти в ЖКИ со скоростью не более 1 экран целиком за 0.5 секунды. Причем прерывание передает за 1 сеанс не более 1 команды (ЖКИ) или буквы (ЖКИ) так, чтобы задержка отработки ЖКИ попадала на время работы основной программы. Все ожидания реакций ЖКИ наш процессор не ждет а работает с основной программой. Вот она феничка экономии. ЖКИ после приема буквы или команды задумывается, это время ему нужно для записи буквы в свою память. Так вот наш процессор должен ждать (пока там ЖКИ скушает букву), чтобы передать следующую. А мы ждать не будем. Передадим букву и закончим прерывание. Пока ЖКИ жует, мы выполняем основную программу.

    Т.о. нам нужно вызывать "видео-прерывание" 4строки*20символов*2раза_всекунду*2раза_прозапас=320 раз в секунду.

    Т.о. как во взрослых компьютерах у нас есть видеопамять и видеопрерывание (драйвер видюхи), только видеопамять мы используем из ОЗУ и самой прорисовкой видеопамяти занимается сам процессор а не посторонняя видеокарта. Но вцелом все идеи те же. Мы выполняем нашу второстепенную задачу: глобальная экономия всего. За счет усложнения структуры программы мы сэкономили время (ожиданий) и память программы (на многократных вызовах функции посылки фраз в ЖКИ).
    Последний раз редактировалось R2D2; 02.04.2010 в 15:07.

  39. #1236

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Чуть по подробнее расскажу про шаблон. Например при зарядке аккумулятора на экране отображается информация о ходе процесса зарядки. Такая информация постоянно отображается и обновляется в течение нескольких часов как для 1 канала так и для 2 канала. Циферки меняются а форма шаблона одна и та же, значит форму шаблона можно жестко описать.

    Те же рассуждения относительно всей отображаемой информации на ЖКИ. например экраны настройки или экраны отражения итогов зарядки или само главное меню, несмотря на то что разное, имеет в себе нечто общее.

    Чтобы описать шаблон мы придумаем коды-команды шаблона например такие:
    - отобразить в 1 строке в 5 столбце переменную номер 5 на 6 знакоместах причем последние 3 знакоместа отвести под дробную часть;
    - отобразить в 2 строке в 9 столбце фразу из списка фраз номер которой лежит в переменной номер 17

    // Шаблоны экрана
    // Описываются байтами - командами
    // 0xFF - Конец шаблона
    // 0 fc - Поставить курсор
    // fc=0xff -Курсора нет нигде CURSOR_OFF
    // 7b=1 -Курсор моргает квадратом CURSOR_BLINK_ON
    // 7b=0 -Курсор горит подчерком CURSOR_LINE_ON
    // 10b -Номер строки где стоит курсор
    // 65432b -Номер столбца где стоит курсор
    // 100 fc=0xff -Курсора нет нигде CURSOR_OFF

    // 1 - Очистить весь экран
    // 2 - Очистить первую строку
    // 3 - Очистить вторую строку
    // 4 - Очистить третью строку
    // 5 - Очистить четвертую строку
    // 6 XY NN - Очистить строку начиная с XY длинной NN
    // 7 XY NN KK - Напечатать переменную KK начиная с XY целым десятичным числом длинной NN
    // 8 XY NN KK - Напечатать переменную KK начиная с XY целым шестнадцатиричным длинной NN
    // 9 XY MN KK - Напечатать переменную KK начиная с XY FLOAT числом длинной M включая N знаков после запятой
    // 10 XY NN KK - Напечатать бинарную-переменную KK начиная с XY
    // 11 XY KK - Напечатать время-переменную KK начиная с XY
    // 12 XY KK NT - Напечатать KK текст начиная с NT
    // 20 XY KK - Напечатать название аккума
    // 21 XY KK - Напечатать название типа аккума
    // 14 XY na tt - Напечатать байт na из временного массива акк
    // 15 XY nt tt - Напечатать байт nt из временного массива типов акк

    // 16 XY TT - Напечатать текст TT начиная с XY
    // 22 XY f - Напечатать название акк(f=1) или типа акк(f=0) из временного массива
    // 17 XY MM - Напечатать меню MM начиная с XY
    // 18 - Изображаем 3-х уровневое меню
    // 19 - Изображаем 1-но уровневое меню


    Выбор принципа шаблонов - это достаточно сложный метод. Если ваша программа из 5 разных шаблонов, то возможно никакой экономии не произойдет, но если у вас шаблонов много...

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

    Если вы покопаетесь в моей программе вы увидите, что для того чтобы вызвать рисование шаблона я использовал функцию, заведенную мной для препроцессора SH(). Например мне надо, чтобы в каком то месте программы начал выводиться шаблон номер 5, тогда я в тексте программы пишу SH(5) и даже без обычной для Си ";" в конце. Препроцессор перед компиляцией изменяет мою указивку на следующее {nSh=5; pSh=255; cSh=2; sSh.first=1;} это делает директива препроцессора #define SH(n) {nSh=n; pSh=255; cSh=2; sSh.first=1;}

    nSh=5; - это тот самый код текущего шаблона номер 5.
    pSh=255; - этот шаблон нарисовать 1 раз, если бы <255, то перерисовывать шаблон каждые pSh/10 секунд.
    cSh=2; - счетчик для отсчитывания pSh со временем уменьшается, ему специально присваивается ненулевое значение, т.к. прерывание могло его уже уменьшить.
    sSh.first=1; - перерисовать шаблон полностью как в первый раз.

    Для управления шаблонным механизмом и вообще всем ЖКИ из основной программы я использую всего несколько команд, указанных ниже, все осталоное делает за меня функция рисования шаблонов в видеопамять и прерывание, отправляющее видеопамять в ЖКИ.
    Не пытайтесь вникнуть в Си этих команд просто почитайте коментарий и обратите внимание на первое слово после #define

    // Пометь строки в которых были изменения
    #define XYL switch((XY)&7){case 0: fv.s1=1; break; case 1: fv.s2=1; break; case 2: fv.s3=1; break; case 3: fv.s4=1; break;}
    // Сделать текищим шаблон n период перерисовки изменяемой части p
    #define SHABLON(n, p) {nSh=n; pSh=p; cSh=2; sSh.first=1;}
    // Сделать текищим шаблон n полностью прорисовать 1 раз
    #define SH(n) {nSh=n; pSh=255; cSh=2; sSh.first=1;}
    // Отобразить шаблон меню
    #define MENU nSh=1; pSh=255; cSh=2; sSh.first=1;
    // Сейчас перерисовать текущий шаблон полностью
    #define REFRESH_SHABLON cSh=2; sSh.first=1;
    // Сейчас перерисовать только изменяемую часть шаблона
    #define REFR_SHABLON cSh=1;
    // Поставить курсор и заставить моргать или неморгать
    #define CURSOR(x, y, type) (type==CUR_OFF)?fc=255:fc=((y)&3)+(((x)&31)<<(2))+(type==BLINK_ON?128:0);
    // Установка курсора при редактировании названия аккума или типа аккума для 4х строчного ЖКИ
    #define FC(x) ((x)<<(2))+3+128;
    // Рассчитать XY из x и y
    #define XYN(x, y) ((x)<<(3))+((y)&7)

    А вот как выглядит настоящий шаблон номер 3 (одна строка одна команда)
    // Шаблон отражения зарядки/разрядки первого канала (название аккума ток напряжение температура заряд в процентах время)
    FCHAR _s3[]=
    {
    1,
    12, 0, 108, 16,
    16, 1, 52,
    9, XYN(6, 1), 0x52, 101,
    16, XYN(12, 1), 92,
    9, XYN(15, 1), 0x51, 109,
    16, 2, 46,
    9, XYN(6, 2), 0x52, 102, 11, XYN(12, 2), 104,
    16, 3, 90,
    9, XYN(7, 3), 0x52, 103,
    100,
    255
    };

    Берем первую циферку из скобок и смотрим что она означает в командах чуть выше описанных
    Последний раз редактировалось R2D2; 05.04.2010 в 14:01.

  40. #1237

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Это очень сложный кусок объяснений был. Не все удалось расставить как следует и не везде исправил ошибки - не успел.

    Не стесняемся, спрашиваем. Все просто. Главное понять идею. Не парьтесь, что все до тонкости не ясно. Поймете идею, копайте глубже, спрашивайте.

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

    Все время приходится выявлять главное и второстепенное и в зависимости от времени и возможности отбрасывать все второстепенное и концентрироваться на главном исходя из цели.
    Последний раз редактировалось R2D2; 05.04.2010 в 15:15.

  41. #1238

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Хотя вся эта информация глубоко специфичная и почти никому не пригодится, но даже те кто никогда программировать не будут могут понять общий подход и использовать его гдето еще или чуть чуть приблизиться к программированию.
    Такой вот последовательностью чисел/байтов кодируется шаблон:

    1-й байт команда
    2-ой байт адрес строки и столбца ЖКИ XY=X(5 старших битов)+Y(3 бита младших). Ноль левый верхний угол экрана ЖКИ
    3-ий и 4 байты, если есть, задают специфику этой команды

    XYN() - это самодельная функция препроцессора которая помогает мне X и Y засунуть в 1 байт X(5 старших битов)+Y(3 бита младших)

    Код:
    FCHAR _s3[]=              // (FLASH CHAR) Обявляем указатель на массив байтов, расположенных во FLASH
    {                         // потом этот указатель мы включим в массив указателей, чтобы иметь возможность обращаться к шаблону по номеру
    1,                        // 1="Очистить весь экран"
                     // Строка 0
    12,XYN(0,  0), 108, 16,   // 12="Напечатать текстовую переменную" 108я переменная сдвиг16 "Зарядка/Разрядка"
                     // Строка 1
    16,XYN(0,  1), 52,        // 16="Напечатать текст" номер 52("I1(A)=")
    9, XYN(6,  1), 0x52, 101, // Напечатать float переменную 101(Ток1) на 5 знаках, два после запятой
    16,XYN(12, 1), 92,        // 16="Напечатать текст" номер 92("E%=")
    9, XYN(15, 1), 0x51, 109, // Напечатать float переменную 109(энергия) на 5 знаках, 1 после запятой
                     // Строка 2
    16,XYN(0,  2), 46,        // 16="Напечатать текст" номер 46("V1(В)=")
    9, XYN(6,  2), 0x52, 102, // Напечатать float переменную 102(напряжение1) на 5 знаках, 2 после запятой
    11,XYN(12, 2), 104,       // Напечатать время работы канала
                     // Строка 3
    16,XYN(0, 3), 90,         // 16="Напечатать текст" номер 46("T1(\x04С)=")
    9, XYN(7, 3), 0x52, 103,  // Напечатать переменную 103(температура1)
    100,                      // Отключить курсор
    255                       // Конец шаблона
    };

  42. #1239

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Урок №16 (Работа с памятью)

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

    Компьютером называется совокупность трех компонентов: процессор, память, периферия, доступная через порты ввода вывода. До нынешних времен под памятью в основном имели ввиду ОЗУ (Оперативное Запоминающее Устройство, SIMM, DIMM, SDRAM, DDR). Эта та самая память, которая теряет все при выключении, эта та самая память в которой ячейка памяти - мизерный конденсатор, который теряет свой заряд за доли секунды если его не подпитывать (регенерация памяти). Зато такая память обладает максимальным быстродействием и одна ячейка занимает на кристалле минимальное место. Плата за такие супер параметры - регенерация. На материнской плате есть специальный контроллер памяти, который периодически читает всю память и записывает (подпитывает) это же значение в память. Это делается параллельно обычной работе компьютера, поэтому вообще не заметно для пользователя.

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

    Оказывается, что такая память вполне подходит компьютеру для хранения ПЕРЕМЕННЫХ. Ни одна программа больше трех пальцев не может существовать без переменных. Чтобы посчитать а+б=с, необходимо где-то временно хранить а и б. Потом они уже не нужны, нужен результат. Результат будет высечен в мраморе на века, а временное забудется и уйдет. Но без этого временного компьютер работать не может. Любой процессор имеет кусочек ОЗУ прямо внутри себя. Такая внутренняя память называется регистры процессора - это самая быстрая память, самая необходимая, самая главная. Все логические операции совершаются там в голове, а потом хранятся в переменных в ОЗУ в более медленной памяти чем регистры, потому что надо оттуда читать, а на это уходит время. Нынешние процессоры имеют дополнительно к регистрам CASH - особую память в которую закачивают копию фрагмента ОЗУ наиболее часто используемую, чтобы сэкономить время, но это все детали.

    Язык Си работает в основном с обычной ОЗУ. Там создаются временные переменные необходимые для работы программы. Обращение к памяти происходит через обращение к переменным и массивам, размещенным в памяти. К памяти также можно обращаться прямо по адресу, но это надо делать осторожно (можно порушить данные системы), поэтому не приветствуется.

    Процессор работает не только с ОЗУ, но и с другими устройствами: с клавиатурой, мышкой, видеоплатой, сетевухой, COM-устройства, USB-устройства, винчестером, CD-ROM, DVD, BDROM, принтером, плоттером, ЗУ, дисководом, флэшкой, мобилой, фотиком и т.д. Все это переферия. Большинство этих устройств имеет единый механизм обращения к ним.

    Работа всех вышеперечисленных устройств зависит от параметров их работы, а это информация в виде байтов. Например: раскрутите диск до скорости 2000 об/мин, поставьте головку 1 на 145 цилиндр, прочитайте 49 сектор, информацию из сектора дайте мне. Все команды и вся прочая информация побайтово передается через порты ввода/вывода. И тот самый универсальный механизм - это механизм ПОТОКА ДАННЫХ.

    С памятью ясно как работать либо переменные либо прямая адресация, а со всеми неизвестными устройствами, через их драйвера открывается поток данных. "Все" драйвера "всех" устройств обязаны поддерживать стандартный набор команд, чтобы виндоуз мог дать доступ через системные процедуры к ним. А Си как раз прицепляется к системе и знает как с ней разговаривать. Си общается только с системой. Система общается через дрова со всей переферией.

    Так вот Си дает доступ к любому устройству через стандартный механизм потока с ограниченным набором команд. Вся ненужная информация и детали прячутся от юзера остается самое необходимое передача и получение данных из переферии. Где-то в этих данных может быть и управляющая информация.

    1. Открыть поток и получить указатель на него. Далее все во всех командах обязательно есть указатель на поток.
    2. Получить длину потока в байтах если есть.
    3. Встать на определенный элемент потока.
    4. Прочитать или записать данные в поток с текущего элемента.
    5. Закрыть поток.

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

    Это мы говорили про большие компьютеры, чтобы иметь общее представление, теперь вернемся опять к АТМЕГА32.

    У АТМЕГА32 три вида памяти ОЗУ(RAM) ППЗУ(EEPROM)(перепрограммируемая постоянное запоминающее устройство) ФЛЭШ(FLASH). Во ФЛЭШ лежит программа и некоторые данные для рисования на ЖКИ, в ОЗУ лежат переменные, в ППЗУ лежат настройки юзера для аккумуляторов. WinAvr Си работает с ОЗУ так же как и в больших компьютерах просто и легко, а вот FLASH и EEPROM имеют особенности. Во первых, 3 вида памяти и все имеют свою адресацию, у каждой памяти есть свой 0 и свой конец. Во вторых, команды чтения и записи разные, поэтому компилятор должен знать кто есть кто чтобы знать как писать туда.

    В компиляторе IAR Си все так и сделали. Описываем переменные, указывая где они лежат, и все, дальше просто работаем с переменными, не думая ни о чем. В WinAVR к сожалению это не так. Не только надо описать переменные, но и работать с ними особым образом, своими функциями записи и чтения для EEPROM(читаем и пишем) и FLASH(только читаем). С ОЗУ все как обычно проблем нет, все как в стандартах Си для любых компов.

    Ниже я приведу свои функции работы с EEPROM и FLASH.

    Начнем с FLASH:
    Последний раз редактировалось R2D2; 08.04.2010 в 13:29.

  43. #1240

    Регистрация
    31.03.2005
    Адрес
    Красногорск
    Возраст
    51
    Сообщений
    488
    Во FLASH у нас хранится:
    1. Все фразы меню и массив указателей на начало каждой строчки меню
    2. Все фразы шаблонов и массив указателей на начало каждой фразы
    3. Ноты музыки
    4. Таблица перекодировки ASCII символов в кодировку ЖКИ

    Со всей этой информацией мы работаем через нижеуказанный механизм чтения из FLASH

    Код:
    // Подключаем стандартный комплект функций WinAVR для работы с FLASH
    #include <avr/pgmspace.h>           // Работа с FLASH
    
    // Описание байта во флэш памяти и то и другое по сути одно и тоже
    // просто в разных подпрограммах из WinAVR требуется строго один из двух
    // приходится подстраиваться под бесплатные дары
    // Опять же назвал по своему, т.к. ихнее название некрасивое не логичное
    typedef prog_uchar FBYTE;           // Байт во FLASH памяти
    typedef prog_char FCHAR;            // Символ во FLASH памяти
    
    // Из флэш памяти только читаем.
    // Вот все функции чтения флэш
    // Я их немного переобозвал, чтоб все логично и компактно было
    #define FRB  pgm_read_byte          // Читаем байт из FLASH
    #define FRW  pgm_read_word          // Читаем ссылку из FLASH
    #define FRS  memcpy_P               // Читаем кусок из FLASH
    
    // Например так я описал меню
    // Сначала описываем указатели на фразы и размещаем сами фразы в памяти
    FCHAR _m0[]="I.Канал 1";
    FCHAR _m1[]="II.Канал 2";
    FCHAR _m2[]="III.Аккумуляторы";
    // Потом собираем указатели на фразы в массив указателей
    PGM_P PROGMEM Mn[3]={_m0, _m1, _m2};
    
    // Теперь, зная какую фразу нам надо вывести (ее номер), мы по номеру достаем 
    // указатель, а по указателю(адресу первой буквы фразы) копируем буквы
    // например в видеопамять которая будет прерыванием выведена в ЖКИ.
    PGM_P fadr=(PGM_P)FRW(&Mn[1]);   // Читаем указатель(адрес) первой фразы
    BYTE x=FRB(fadr);                // Можем прочитать первую букву из этой фразы
    FRS((BYTE*)V2, (PGM_P)fadr, len);// Копируем len байтов фразы в видеопамять
    Как я ранее говорил есть 3 уровня "низости":
    1. Верхний уровень - работа с шаблонами (очень простой способ полностью разрисовать ЖКИ пятым шаблоном: SH(5))
    2. Второй уровень - прорисовка шаблонов в видеопамять. Как раз этот уровень сегодня обсуждаем.
    3. Низкий уровень - уровень прерывания. Посылка видеопамяти в ЖКИ.


    P.S. На нашем нынешнем уровне развития считаем что: Сылка=Указатель=Адрес
    P.P.S. Уважаемые начинающие Си программисты, если чего то не ясно не парьтесь, спрашивайте или повторяйте как заклинания буковки, здесь написанные, в своих программах и смотрите как ругается компилятор.
    Последний раз редактировалось R2D2; 08.04.2010 в 14:56.

Закрытая тема

Похожие темы

  1. Продам универсальный зарядник
    от RDoc в разделе Барахолка. Аппаратура
    Ответов: 1
    Последнее сообщение: 10.09.2010, 12:28
  2. Нужен ли новичку универсальный зарядник?
    от kazakov_98 в разделе Аккумуляторы, зарядники
    Ответов: 6
    Последнее сообщение: 28.07.2007, 21:29
  3. Делаем универсальный зарядник (на 3 тока) своими руками.
    от Dimux в разделе Самодельная электроника, компьютерные программы
    Ответов: 21
    Последнее сообщение: 28.06.2002, 02:51

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения