03.03.2018, 10:21
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: <avr/eeprom.h>
Один маленький деталь дает два большой проблем в том, что структура большого проекта становится визуально непонятной. Правда, в языке Си хреново обстоят дела со структурированием в целом - всё, что написано без static (имею ввиду функции и глобальные переменные) - является общим достоянием проекта и неявно доступно из любого файла, правда иногда с ошибками параметров, если не прописать явно путь до функции.
Но тут больше дело в другом - в визуальном представлении связей проекта. Подключая один общий myf.h ко всем файлам, вы создаете визуальную кашу - к файлу дисплея у вас подключен вдобавок и заголовок клавиатуры, и заголовок АЦП, и заголовок УАРТа... Повторно использовать такие файлы в других проектах затруднительно - они требуют ручной редактуры.
И насколько проще было бы, если бы вы взяли файлы дисплея, а в них - только ссылки на файлы дисплея, и вам надо лишь прописать один #include на самый верхний уровень драйвера дисплея - и вы получаете простым путем вывод в дисплей, без ручной редактуры.
Да, я тоже в процессе изучения пробовал вариант с одним общим заголовочником. Скажу честно - фигня полная, если не сказать больше. Когда начинаешь делать что-то чуть более сложное по структуре, то общий заголовочник разрастается в кашу и норовит завязать связи в такой узел, что хер разгребешь. Отлавливание своих ошибок или процесс "сотворения мира" становится очень запутанным, некомфортным.
Поэтому общий myf.h должен быть признан большим злом.
Предупреждающие описания об extern - тоже не есть хорошо. Знаете ли, задалбывает писать лишние буквы, это раз, а во-вторых - а вдруг вы изменили путь к файлу или вообще решили сделать иначе?
extern-ы можно применять лишь в некоторых случаях, в дополнение к подключениям, чтобы наоборот упростить межпроектные связи, а не запутывать их.
Например, пусть в файле main.c есть простая функция программной блокирующей задержки void Delay(int time). Ну не создавать же под нее отдельную пару файлов. Так вот с помощью extern мы подключаем функцию к некоторым файлам, где она нужна. Конечно, мы должны сами помнить, что эта функция у нас была прописана в main.c и там она и лежит.
А если мы еще в каком-нибудь файле напишем новую функцию с таким же именем void Delay(int time), то у нас будут проблемы. И мы будем искать, а где же у нас лежит первая функция. Либо вторую придется обособить через static.
Хорошим делом будет научиться структурировать свой проект еще до начала писания в коде. Чтобы сразу создавать структуру файлов и подключений, а потом просто заполнять файлы. Легче будет потом добавлять новые файлы, будет сразу понятно, куда их включить, куда прописать и откуда вызывать функции.
А тут еще выплывает такая штука, как typedef - пользовательские типы, которые особенно для структур подходят.
typedef struct {
int x;
int y;
int z;
} coord_t;
- хорошая штука, но с помощью extern ее не запишешь, только #include заголовочника, в котором и прописан этот typedef
Касательно темы темы, файл eeprom.h нужен только там, откуда идет непосредственная запись в еепром. Понятно, что из файла драйвера дисплея запись в еепром не нужна.
Последний раз редактировалось NewWriter; 03.03.2018 в 10:46.
|
|
|
Сказали "Спасибо" NewWriter
|
|
|
03.03.2018, 10:41
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.03.2010
Сообщений: 2,897
Сказал спасибо: 498
Сказали Спасибо 3,061 раз(а) в 1,425 сообщении(ях)
|
Re: <avr/eeprom.h>
Сообщение от NewWriter
|
Да, я тоже в процессе изучения пробовал вариант с одним общим заголовочником. Скажу честно - фигня полная, если не сказать больше. Когда начинаешь делать что-то чуть более сложное по структуре, то общий заголовочник разрастается в кашу и норовит завязать связи в такой узел, что хер разгребешь. Отлавливание своих ошибок или процесс "сотворения мира" становится очень запутанным, некомфортным.
Поэтому общий myf.h должен быть признан большим злом.
|
Отлично работает этот вариант. И очень экономит время. Не знаю, у кого какие проблемы с этим.
Сообщение от NewWriter
|
Например, пусть в файле main.c есть простая функция программной блокирующей задержки void Delay(int time). Ну не создавать же под нее отдельную пару файлов.
|
Если она нужна не в одном модуле, а в разных - создавать. Иначе всегда надо будет помнить, где таковая лежит.
Последний раз редактировалось AR_Favorit; 03.03.2018 в 10:47.
|
|
|
|
03.03.2018, 11:14
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: <avr/eeprom.h>
В Си понятие модульности вообще очень примитивное и скупое. Я уже писал, почему. Потому что любая функция, прописанная без static, становится доступной вообще из любого файла, из любого модуля, даже там, где явно не прописано ее подключение через extern или #include. Как максимум, если вы вызываете функцию, вас попросят всё-же подключить её явно, чтобы соотнести передаваемые параметры,
Однако, если уж у языка каша, то не стоило бы делать такую же кашу чисто визуально для самого себя. Чисто визуально в файле main.c ну нахрен вам не нужны функции из какого-нить spi_drv.c. Поскольку, исходя из вашей же модульности, в main.c вы никогда не вызовите напрямую функцию SPI_Send(), а в крайнем случае будете вызывать функцию DisplayOn() из файла display_drv.c, содержащую несколько вызовов функций SPI_Send с разными параметрами, да еще и с какой-нить вызов Delay_ms(10).
А теперь попробуйте графически изобразить структуру проекта, полагаясь на подключения #include. Как думаете, в каком из нескольких вариантов вам будет легче это сделать, и в каком случае нарисованное будет действительно отображать реальные связи по функционалу?
|
|
|
|
03.03.2018, 11:33
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.03.2010
Сообщений: 2,897
Сказал спасибо: 498
Сказали Спасибо 3,061 раз(а) в 1,425 сообщении(ях)
|
Re: <avr/eeprom.h>
Сообщение от NewWriter
|
В Си понятие модульности вообще очень примитивное и скупое. Я уже писал, почему. Потому что любая функция, прописанная без static, становится доступной вообще из любого файла, из любого модуля, даже там, где явно не прописано ее подключение через extern или #include.
|
Так а какая проблема не забывать использовать static, если глобальная видимость мешает? Это получается недостаток не Си, а программиста)))
Ну и не так все однозначно с доступностью без подключения)))
Сообщение от NewWriter
|
Чисто визуально в файле main.c ну нахрен вам не нужны функции из какого-нить spi_drv.c. Поскольку, исходя из вашей же модульности, в main.c вы никогда не вызовите напрямую функцию SPI_Send(), а в крайнем случае будете вызывать функцию DisplayOn() из файла display_drv.c, содержащую несколько функций SPI_Send с разными параметрами, да еще и с какой-нить Delay_ms(10).
|
Полностью согласен.
Сообщение от NewWriter
|
А теперь попробуйте графически изобразить структуру проекта, полагаясь на подключения #include. Как думаете, в каком из нескольких вариантов вам будет легче это сделать, и в каком случае нарисованное будет действительно отображать реальные связи по функционалу?
|
А зачем графически изображать структуру проекта, который уже сделан?
Когда проект только планируется - никто не мешает разрисовывать стрелочки красиво. При этом на стадии реализации общая доступность всех модулей из всех работе никак не мешает при педантичном подходе к именованию функций и переменных.
|
|
|
|
03.03.2018, 12:18
|
|
Прописка
Регистрация: 25.11.2008
Сообщений: 114
Сказал спасибо: 3
Сказали Спасибо 9 раз(а) в 9 сообщении(ях)
|
Re: <avr/eeprom.h>
Вот тут я показал, как соединил все файлы.
Вроде и работает, но... Нюансы, мать их...
Расскажите на этом, конкретном примере как правильно надо делать.
Пожалуйста.
|
|
|
|
03.03.2018, 13:23
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: <avr/eeprom.h>
Так вот как раз всеобщая доступность любой функции и мешает модульности. По-хорошему, функции, доступные в одной группе модулей, должны быть недоступны в других модулях. И это не static! Чисто логически, модуль дисплея не имеет прямого выхода на модуль клавиатуры. Завязываться они могут только через более высокий уровень, через модуль ввода-вывода. Это реализуется в некоторых языках более высокого уровня. Но в Си - пофик. Только визуально.
Составление структуры проекта - это вообще хорошая практика. Научившись это делать на простых проектах, легко будет делать на сложных и объемных. Поэтому я не согласен с тем, что не надо рисовать схемки. Делая простые проекты, вы создаете себе некую базу знаний, наработки. И чтобы было легко их переносить в дальнейшие сложные проекты, полезно иметь четкое структурирование.
Даже как бы не обязательно прям рисовать стрелочки. Вполне даже можно взглянуть на список #include, чтобы представить связи. И эти #include должны отражать реальную картину, а не просто список внавалку всего и вся.
Вот как бы две картинки, слева структура при простом сваливании в одну кучу всех заголовочников, а справа - структурированная, с четким пониманием, что куда и откуда, и что именно надо брать, чтобы перенести кусок в другой проект и куда ставить в другом проекте и на что завязываться.
Языку Си конечно глубоко насрать на уровни вложенности и разделение, но нам, как кодописателям, это очень важно. Как думаете, какая картинка более правильно передает замысел проекта и более точно соответствует действительному положению дел?
Еще учитывайте, что на левой картинке должно быть еще как-то прописано межмодульное взаимодействие. Неужели это делать на extern-ах? можно конечно, но если вдруг че-то придется поменять, то это жопа. Так что извините ребята, но схема слева - это лажа и каша.
PS. забыл про чтение с клавиатуры, но будем считать, что kbd - это просто пара-тройка кнопок.
Последний раз редактировалось NewWriter; 03.03.2018 в 13:53.
|
|
|
|
03.03.2018, 14:06
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.03.2010
Сообщений: 2,897
Сказал спасибо: 498
Сказали Спасибо 3,061 раз(а) в 1,425 сообщении(ях)
|
Re: <avr/eeprom.h>
Сообщение от NewWriter
|
По-хорошему, функции, доступные в одной группе модулей, должны быть недоступны в других модулях. И это не static!
|
Но проблем. Компилите статические библиотеки и линкуйте их, будет нужная модульность достигаться Никто не называл Си идеальным языком, но наиболее распространенные жалобы на него (ну типа как на хабре периодически вылазит очередное "за что я ненавижу си"))) на поверку всегда оказываются жалобами на собственную лень или криворукость.
Сообщение от NewWriter
|
Составление структуры проекта - это вообще хорошая практика. Научившись это делать на простых проектах, легко будет делать на сложных и объемных. Поэтому я не согласен с тем, что не надо рисовать схемки.
|
Вы меня не поняли. Я спрсил - зачем рисовать структуру проекта после его написания? "По существующим инклюдам" - это именно оно. До написания - вполне полезно.
Хотя ценность именно рисования диаграммок сильно преувеличена - должно бы абстрактное мышление работать и без картинок. Но тут все люди разные, у одного в голове структура проги без визуализации складывается, другой визуал - и ему надо увидеть.
Но самое главное, что я имел в виду следующее: Ради бога, разрисовываем взаимодействие между модулями, это нам очень хорошо поможет, когда будем делать эти модули. И если мы всё правильно делаем - мы не вызываем функций spi.drv ниоткуда, кроме display.drv, функций adc.drv ниоткуда, кроме как из voltmeter и т.д. - то есть пишем программу в соответствии со спланированноё ее структурой.
Вопрос: как нам при этом потом помешает тот факт, что из main.c на самом деле можно было бы напрямую вызвать функции spi.drv или adc.drv, если мы этого не делали? Ответ: никак. Жаловаться на то, что компилятор не следит за этим - все равно, что жаловаться, что он не следит за границами массива))) Инструмент низкоуровневый, в нем так и должно быть.
|
|
|
|
03.03.2018, 14:37
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: <avr/eeprom.h>
Дело в том, что гениев - единицы на миллион. И сколь не был бы умным и опытным проггер, он все же человек, а человеку свойственно ошибаться и забывать. Работая над большими проектами, невозможно всё удержать в голове. Да и приходится возвращаться через некоторое время, что-то брать из проекта, работать над чем-то другим.
Абстрактное мышление - это как раз не то, что "уметь работать без картинок". Это, скорее, даже НАОБОРОТ! Да стопудово, наоборот! ) На блок-схемах со стрелочками уровень абстракции от кода гораздо выше! Вот как раз схемы то и дают очень высокий уровень абстракции, ведь в них нету конкретных функций, конкретных переменных и параметров. Всё слишком абстрактно, в виде "черных ящиков". А вот записывая текстом на языке, вы уже вводите конкретику, явную конкретность "что взял, куда послал, чего вернул, чем дернул, что включил". Всё очень конкретно!
Для примера - посмотрите в даташитах flowchart-ы и схемы состояний. Там нет конкретного кода на конкретном языке. Там - очень абстрактрые кружочки, ромбики и стрелочки.
Независимо от того, визуал ли человек или нет, но как через документ кратко передать порядок действий и возможные состояния? Чаще всего они передаются картинками. Могут еще дополняться и текстовым описанием на литературном языке.
Как раз я о том и писал, что сам язык Си имеет хреновую модульность, и ничего не мешает вызывать функции из соседних модулей. Максимум, вы увидите "горчичник" о неявном объявлении функции, и в некоторых случаях параметры вызываемой функции будут переданы неверно.
Но если вы скидаете заголовочники все в main.с и в каждый модуль тоже, и будете иметь возможность вызывать в main и в любом модуле любые функции без предупреждений, то это будет чисто логически неправильно. Зачем вы сами себя то обманываете? Сами же говорите, что это низкоуровневый язык, и тут многое зависит от программиста. Так сам программист зачем же будет сам себя заставлять делать лажу, если есть возможность ее не делать?
Сообщение от AR_Favorit
|
Но проблем. Компилите статические библиотеки и линкуйте их, .
|
В этом и есть "проблем". Это - обходной путь, от невозможности сделать иначе.
Сообщение от AR_Favorit
|
Так а какая проблема не забывать использовать static, если глобальная видимость мешает? Это получается недостаток не Си, а программиста)))
|
Да нет уж. Если напишите static - вы не сможете эту функцию вывести в ИНТЕРФЕЙС модуля. Она видна только в пределах модуля (текстового файла). А если пишите без static, выводя в интерфейс, то эта функция становится глобальной для ВСЕГО проекта, и попутно требует уникальности своего имени.
То есть вот в чем "есть биг проблем" - нельзя средствами языка разделить принадлежность модулей. Остается разделять только руками самого кодописателя. И посему, основной посыл тут в том, что надо ПРАВИЛЬНО сделать ИМЕННО ЭТО.
Вариант с пиханием всех-всех инклюдов в один общий-преобщий заголовочник и подключением оного в каждый файл, в каждую дырку - этот вариант как раз и противоречит задаче кодописателя сделать вручную то, что не может сделать автоматом язык.
Последний раз редактировалось NewWriter; 03.03.2018 в 15:14.
|
|
|
|
03.03.2018, 15:02
|
|
Прописка
Регистрация: 25.11.2008
Сообщений: 114
Сказал спасибо: 3
Сказали Спасибо 9 раз(а) в 9 сообщении(ях)
|
Re: <avr/eeprom.h>
Ёпрст.
Мужики!
При всём уважении...
Не забывайте, что пишете чАЙНИКУ.
Конкретные ответы на конкретные вопросы.
А?
Вопрос:
Если я переменную делаю не EEMEM ( uint16_t freq1e; ) - всё ОК.
А если ( uint16_t freq1e EEMEM; ), то "multiple".
Всё, разница в пять букв.
Ужель причина в корявеньком подключении?
Да. Пустые инклюды в моих примерах - форум сожрал треугольные стрелки ‹› и всё, что в них. Стандартные библиотеки.
|
|
|
|
03.03.2018, 15:07
|
|
Гражданин KAZUS.RU
Регистрация: 02.06.2003
Адрес: Челябинск
Сообщений: 545
Сказал спасибо: 10
Сказали Спасибо 341 раз(а) в 202 сообщении(ях)
|
Re: <avr/eeprom.h>
Сообщение от DPANYTA
|
Расскажите на этом, конкретном примере как правильно надо делать.
Пожалуйста.
|
Мой личный пример
Нажмите, чтобы открыть спойлер
Код:
|
#include ‹iostm8s003f3.h› // MCU type
/* Constant definitions */
#define FOSC 16000000 // MCU clock frequency (Hz)
/* Port definitions */
#define LED_PORT PB_ODR // PORTB is used as LED control port
#define LED_DDR PB_DDR //
#define LED_CR1 PB_CR1 //
#define LED_RED MASK_PB_ODR_ODR4 // Red LED
#define LED_GRN MASK_PB_ODR_ODR5 // Green LED
#define LED_MASK (LED_RED | LED_GRN)
#define RELAY_2_PORT PA_ODR // Relay 2 control port
#define RELAY_2_DDR PA_DDR //
#define RELAY_2_CR1 PA_CR1 //
#define RELAY_2_BIT (1‹‹3) // -- relay 2
#define RELAY_1_PORT PC_ODR // Relay 1 control port
#define RELAY_1_DDR PC_DDR //
#define RELAY_1_CR1 PC_CR1 //
#define RELAY_1_BIT (1‹‹7) // -- relay 1
#define INPUT_PORT PC_IDR // Input control port
#define INPUT_PULLUP PC_CR1 //
#define INPUT_DDR PC_DDR //
#define FAIL_BIT (1‹‹2) // -- "Power fail" signal
#define ENTER_BTN (1‹‹3) // -- "Enter" button
#define SETUP_BTN (1‹‹4) // -- "Setup" button
#define PROG_BTN (1‹‹5) // -- "Program" button
#define BUTN_MSK (ENTER_BTN | SETUP_BTN | PROG_BTN)
#define TIM1_BIT (1 ‹‹ 0) // Timer1 interrupt event flag
#define TIM2_BIT (1 ‹‹ 1) // Timer2 interrupt event flag
#define _025_SEC_BIT (1 ‹‹ 2) // 0.25 S time interval flag
#define CAPTURE_BIT (1 ‹‹ 4) // Capture event flag
#define BUTTON_BIT (1 ‹‹ 5) // To check buttons flag
#define _100MS_BIT (1 ‹‹ 6) // 0.1 S time interval flag
#define TMO_BIT (1 ‹‹ 7) // Time out event flag
/* LED symbol definitions */
#define MINUS_SYM 0x0A // '-'
#define PI_SYM 0x0B // 'Ï'
#define H_SYM 0x0D // 'H'
#define P_SYM 0x0E // 'P'
#define I_SYM 0x0B // 'I'
#define II_SYM 0x0E // 'II'
#define A_SYM 0x10 // 'A'
#define D_SYM 0x11 // 'd'
//#define C_SYM 0x0C // 'C'
#define L_SYM 0x0C // 'L'
/* Mode bit definitions */
#define LOW_EN (1‹‹4) // Low limit setup enable
#define HIGH_EN (1‹‹1) // High limit setup enable
#define PASWRD_BIT (1‹‹2) // Password entering flag
#define CH1_DSPLY (1 ‹‹ 3) // Display channel 1
#define HEAT_BIT (1 ‹‹ 0) // Heater/Cooler mode bit
#define WAIT_EN (1‹‹5) // Waiting for the limits
#define PROG_EN (1‹‹7) // Program enable
/* Event flag bit definitios */
#define DOWN_BIT (1‹‹0) // Input '-' pulse flag
#define ALARM_BIT (1 ‹‹ 1)
#define SETUP_BIT (1‹‹2) // Setup entering flag
#define RSTRT_BIT (1‹‹3) // Restart condition flag
#define RELAY_ON (1 ‹‹ 6) // Relay on state
#define DELAY_BIT (1 ‹‹ 7) // Restart after delay flag
/* Sensor relative constant definitions */
#define T_MAX 60 // Maximum temperature value
#define T_MIN 0 // Minimum temperature value
#define TMP_RNG (T_MAX - T_MIN) // Temperature range values
#define UT_60 3300 // Temperature sensor output @ 60 dgs (mV)
#define UT_0 1500 // Temperature sensor output @ 0 dgs (mV)
#define UT_M40 300. // Temperature sensor output @ -40 dgs (mV)
#define UT_RNG (UT_60 - UT_0) // Sensor output values range
#define T_SLOPE (UT_RNG / TMP_RNG) //
#define UREF 5000L // ADC values range
/* Common constant definitions */
#define ERROR 0xFF // Bad function return
#define FAIL 0x00 // Alternative bad function return
#define OK 0x01 // Good function return
#define DONE 0x02 // The work is done completely
/* EEPROM relative definitions */
#define SETUP_SAV (1‹‹6) // Setup is saved
#define LIMIT_SAV (1‹‹2) // Limit value is saved
#define STATE_SAV (1‹‹4) // Current state saved (if Power fail)
/* Data type definitions */
typedef enum {
stStop = 1, // Initial state
stProg, // Program mode
stWork, // Work state
stDelay, // Delay before restart
stPasswrd // Input password state
}
TState;
/* RAM variables */
extern char BlinkedDigit;
extern __tiny volatile char IntFlags;
extern __tiny char Digits[4];
extern char DigitPos[];
extern char DotDigit; // Display dot digit
extern __tiny char TimoutCnt; // Time-out counter
extern unsigned Delay;
extern __tiny char Mode; // Counter mode flags
//extern volatile
extern __tiny int T1_low, T1_high, // Temperature channel 1 low and high thresholds
T2_low, T2_high; // Temperature channel 2 low and high thresholds
extern __tiny signed char
Adjst1, Adjst2; // Temperature adjustments
//
// EEPROM data
//
extern __no_init __eeprom char eMode; // Mode copy
extern __no_init __eeprom char eSave; // Data saved in EEPROM flag
extern __no_init __eeprom unsigned eDelay; // Delay copy
extern __no_init __eeprom unsigned eLowLimit; // Limit value copies
extern __no_init __eeprom unsigned eHighLimit; //
extern __no_init __eeprom int eT1_low, eT1_high, // Temperature low and high thresholds
eT2_low, eT2_high; // Humidity low and high thresholds
extern __no_init __eeprom signed char eAdjst1, eAdjst2; // Temperature adjustments
/* Function prototypes */
//
// main.c
//
void SetRelay2(char);
//
// ADC.s
//
void ADCinit(void); // ADC initialization
unsigned ADC_ch1(void); // Read temperature channel 1
unsigned ADC_ch2(void); // Read temperature channel 2
//
// BUTTONS.c
//
void InitButtons(void);
char GetButtons(void);
char ReadBtns(void);
//
// timers.s
//
void InitTimers(); // Timers initialazation
//
// system.s
//
void InitMCU(void); // MCU initialization
//
// setup.c
//
void Setup(void);
void SetMode(void);
//
// bcd.s
//
unsigned BinToBCD(char);
void BCDnumber(unsigned);
char Mod10(unsigned);
unsigned Div10(unsigned);
//
// BTTONS.c
//
void InitButtons(void);
char GetButtons(void);
//
// EEPROM.s
//
void EEPROM_wr1(char __eeprom *address, char data);
void EEPROM_wr2(unsigned __eeprom *address, unsigned data);
//
// LED.s
//
void LEDinit(void);
//
// setup.c
//
void Setup(void); |
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 16:00.
|
|