Вопросы по С/С++ (СИ)
Перечеркнутый ноль мудрые люди давно придумали.
- Реклама
Снова подниму тему глобальных переменых... Прочитал я в этой теме, что это зло, но от него не могу отказаться. Тут один проектик разросся до того, что стал трудно "сопровождаемым" и я решил его побить по модулям. Вот с одной проблемой не знаю как справиться. Выделил в отдельный модуль обработчик клавиш - всё вроде внятно, но есть одна переменная у неё kbddelay - таймер задержки, которая декрементируется в таймерном прерывании. Пока оно было в одном файле - проблем не было. А теперь обработчик прерываний находится в главном файле проекта, а обработчик кнопок в другом. Где эту переменную объявить, описать итд.
Есть еще одна - буфер "видеоозу". Используется в главном модуле и в модуле конфигурации. Конечно, я могу в каждом модуле выделить свой буфер - на функционал не влияет, но прамяти жалко. Пока объявил в main.c а в configure.c написал как extern.
Есть еще одна - буфер "видеоозу". Используется в главном модуле и в модуле конфигурации. Конечно, я могу в каждом модуле выделить свой буфер - на функционал не влияет, но прамяти жалко. Пока объявил в main.c а в configure.c написал как extern.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
есть, как говорится, два способа: правильный и удобный 
удобный - это плевать на то, как говорят, делать так, чтобы работало. но тут следует помнить, что удобно одному, другому будет неудобно. да и собственные привычки могут поменяться с годами...
а правильный способ - это изолировать сущности друг от друга. с видеоозу, по правильному, не должны работать модули напрямую, как с массивом - только через предназначенные для этого функции. в этом случае и видеоозу, и функции для работы с ним будут в одном модуле, а для других модулей видеоозу существовать не будет - только функции, которые чтото там выводят/рисуют.
с обработчиками прерываний все похуже, т.к. у них особый статус "невидимок для всех". поэтому, с моей точки зрения, идеальным был бы вариант, когда прерывание для работы с клавиатурой определено в модуле работы с клавиатурой. но если одно прерывание занимается обслуживанием интересов нескольких модулей - так не выйдет. и тут городить излишние "изолирующие прокладки" в виде промежуточных модулей, не очень хорошая идея: попрёт оверхед памяти, снизится производительность... тут нужно искать компромиссы, например, по типу, как у вас
удобный - это плевать на то, как говорят, делать так, чтобы работало. но тут следует помнить, что удобно одному, другому будет неудобно. да и собственные привычки могут поменяться с годами...
а правильный способ - это изолировать сущности друг от друга. с видеоозу, по правильному, не должны работать модули напрямую, как с массивом - только через предназначенные для этого функции. в этом случае и видеоозу, и функции для работы с ним будут в одном модуле, а для других модулей видеоозу существовать не будет - только функции, которые чтото там выводят/рисуют.
с обработчиками прерываний все похуже, т.к. у них особый статус "невидимок для всех". поэтому, с моей точки зрения, идеальным был бы вариант, когда прерывание для работы с клавиатурой определено в модуле работы с клавиатурой. но если одно прерывание занимается обслуживанием интересов нескольких модулей - так не выйдет. и тут городить излишние "изолирующие прокладки" в виде промежуточных модулей, не очень хорошая идея: попрёт оверхед памяти, снизится производительность... тут нужно искать компромиссы, например, по типу, как у вас
uldemir писал(а):объявил в main.c а в configure.c написал как extern
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 3604
- Зарегистрирован: Пн июл 28, 2008 22:12:01
- Реклама
[uquote="uldemir",url="/forum/viewtopic.php?p=3361993#p3361993"]есть одна переменная у неё kbddelay - таймер задержки, которая декрементируется в таймерном прерывании. Пока оно было в одном файле - проблем не было. А теперь обработчик прерываний находится в главном файле проекта, а обработчик кнопок в другом. Где эту переменную объявить, описать итд.[/uquote]
объявлять там, где непосредственно используется. Так же иметь в "модуле" функцию, декрементирующую сию переменную, и дергать ее из прерывания или откуда угодно еще.
[uquote="uldemir",url="/forum/viewtopic.php?p=3361993#p3361993"]Есть еще одна - буфер "видеоозу". Используется в главном модуле и в модуле конфигурации. Конечно, я могу в каждом модуле выделить свой буфер - на функционал не влияет, но прамяти жалко[/uquote]
храните и используйте указатели на буфер, заносите в них актуальный адрес при инициализации.
[uquote="ARV",url="/forum/viewtopic.php?p=3362035#p3362035"]с видеоозу, по правильному, не должны работать модули напрямую, как с массивом - только через предназначенные для этого функции. в этом случае и видеоозу, и функции для работы с ним будут в одном модуле, а для других модулей видеоозу существовать не будет - только функции, которые чтото там выводят/рисуют[/uquote]
это даже на "больших" компах далеко не всегда проканывает. Зачастую вывод чего-нибудь графического начинается с обращения к вышележащей софтине (драйверу/интерфейсу/части тулкита) типа "дай мне буфер для непосредственных манипуляций".
объявлять там, где непосредственно используется. Так же иметь в "модуле" функцию, декрементирующую сию переменную, и дергать ее из прерывания или откуда угодно еще.
[uquote="uldemir",url="/forum/viewtopic.php?p=3361993#p3361993"]Есть еще одна - буфер "видеоозу". Используется в главном модуле и в модуле конфигурации. Конечно, я могу в каждом модуле выделить свой буфер - на функционал не влияет, но прамяти жалко[/uquote]
храните и используйте указатели на буфер, заносите в них актуальный адрес при инициализации.
[uquote="ARV",url="/forum/viewtopic.php?p=3362035#p3362035"]с видеоозу, по правильному, не должны работать модули напрямую, как с массивом - только через предназначенные для этого функции. в этом случае и видеоозу, и функции для работы с ним будут в одном модуле, а для других модулей видеоозу существовать не будет - только функции, которые чтото там выводят/рисуют[/uquote]
это даже на "больших" компах далеко не всегда проканывает. Зачастую вывод чего-нибудь графического начинается с обращения к вышележащей софтине (драйверу/интерфейсу/части тулкита) типа "дай мне буфер для непосредственных манипуляций".
Всем привет!
Пытаюсь написать алгоритм работы с SPI EEPROM, но из-за недостатка опыта сомневаюсь в правильности алгоритмов, потому требуется помощь.
Контроллер STM32F103C8 (Reference manual)
Память M95M01 (pdf)
В общем, начал с низкоуровневых функций. Настройка SPI2, поднятие преываний на прием и окончание передачи.
Как я понимаю передача и приём идет одновременно. В интернете полно примеров, но там используются всякие костыли типа что, откровенно, вызывает кровь из глаз. Хотя мой быдлокодинг еще больше кровоточит. Ну да ладно, ближе к теме.
В общем, функция для отправки байта
Смысл такой, что если циклически вызывать и чекать что вернула функция, то можно рулить тем, что бы данные отправлялись тогда, когда предыдущие гарантированно уйдут. Такая конструкция приемлема или есть более интересная реализация?
Функция прерывания
vSetSpiEepromFlag взводит флаг в битовом поле (через битбанд). Таким образом происходит обмен мессаджами между функциями.
Реализованное битовое поле
В целом, цель поднять FAT на SPI EEPROM и определить её как USB, потому в этом контексте, подобная реализация низкоуровневых функций норм? Или же мне отправляемые/принимаемые данные через кольцевой буфер гонять? Или исходящий поток нет смысла через кольцевой буфер гнать? Вообще, общение с EEPROM постраничное? т.е. прежде чем изменить байт (-ты), я должен прочитать всю страницу, изменить нужную информацию и записать вновь?
Пытаюсь написать алгоритм работы с SPI EEPROM, но из-за недостатка опыта сомневаюсь в правильности алгоритмов, потому требуется помощь.
Контроллер STM32F103C8 (Reference manual)
Память M95M01 (pdf)
В общем, начал с низкоуровневых функций. Настройка SPI2, поднятие преываний на прием и окончание передачи.
Как я понимаю передача и приём идет одновременно. В интернете полно примеров, но там используются всякие костыли типа
Код: Выделить всё
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET); В общем, функция для отправки байта
Код: Выделить всё
typedef enum
{
SPI_EEPROM_STATUS_BSY, // Spi is busy
SPI_EEPROM_STATUS_RDY
} SpiEepromStatus;
typedef struct
{
unsigned spiByteReseived: 1;
unsigned spiByteTransmited: 1;
} SpiState_TypeDef;
SpiEepromStatus ui8EepromSendByte(uint8_t byte)
{
SpiEepromStatus Status = SPI_EEPROM_STATUS_BSY;
if (SPI2->SR & SPI_SR_TXE)
{
SPI2->DR = byte;
Status = SPI_EEPROM_STATUS_RDY;
}
else
Status = SPI_EEPROM_STATUS_BSY;
return Status;
}
Код: Выделить всё
ui8EepromSendByte Функция прерывания
Код: Выделить всё
void SPI2_IRQHandler (void)
{
if (SPI2->SR & SPI_SR_RXNE)
{
ui8ByteFromSpiEeprom = SPI2->DR;
vSetSpiEepromFlag (&SpiState, SPI_BYTE_RECEIVED);
}
if (SPI2->SR & SPI_SR_TXE)
{
SPI2->SR &= ~SPI_SR_TXE;
}
}Реализованное битовое поле
Код: Выделить всё
typedef struct
{
unsigned spiByteReseived: 1;
unsigned spiByteTransmited: 1;
} SpiState_TypeDef;
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
© Альберт Эйнштейн
[uquote="Chip115",url="/forum/viewtopic.php?p=3364936#p3364936"]В интернете полно примеров, но там используются всякие костыли типа что, откровенно, вызывает кровь из глаз.[/uquote]
вполне нормальная конструкция
[uquote="Chip115",url="/forum/viewtopic.php?p=3364936#p3364936"]Смысл такой, что если циклически вызывать и чекать что вернула функция, то можно рулить тем, что бы данные отправлялись тогда, когда предыдущие гарантированно уйдут. Такая конструкция приемлема или есть более интересная реализация?[/uquote]
каноничный подход - сначала дождаться взведения флага TXE, потом чего-то пытаться отправить
Код: Выделить всё
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET); вполне нормальная конструкция
[uquote="Chip115",url="/forum/viewtopic.php?p=3364936#p3364936"]Смысл такой, что если циклически вызывать
Код: Выделить всё
ui8EepromSendByte каноничный подход - сначала дождаться взведения флага TXE, потом чего-то пытаться отправить
Код: Выделить всё
void ui8EepromSendByte(uint8_t byte)
{
while (!(SPI2->SR & SPI_SR_TXE)); // ждем
SPI2->DR = byte;
}
[uquote="Z_h_e",url="/forum/viewtopic.php?p=3364944#p3364944"]Вопрос то не по Сям.
Надо было здесь топик создавать, сразу бы про DMA разговор бы пошел
.[/uquote]
Точно. Виноват. Подумал что алгоритмические вопросы тоже сюда )) Наверное передислацируюсь туда. Если есть возможноть, то удалите, пожалуйста, мой пост, что бы не захламлять.
Надо было здесь топик создавать, сразу бы про DMA разговор бы пошел
Точно. Виноват. Подумал что алгоритмические вопросы тоже сюда )) Наверное передислацируюсь туда. Если есть возможноть, то удалите, пожалуйста, мой пост, что бы не захламлять.
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
© Альберт Эйнштейн
Так не сработает. Бит только для чтения.Chip115 писал(а):SPI2->SR &= ~SPI_SR_TXE;
Понял, спасибо.
Еще вопрос.
Что значит эта запись?
Интересует правая запись
Еще вопрос.
Что значит эта запись?
Код: Выделить всё
#define SPI_SendData8(SPIx, data) *(__IO uint8_t *)&SPIx->DR = dataТеория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
© Альберт Эйнштейн
А что за магия с указателями? Почему нельзя написать SPIx->DR = data и зачем нужна операция И?
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
© Альберт Эйнштейн
Почитайте про указатели.Chip115 писал(а): зачем нужна операция И
Кто сказал что нельзя?Chip115 писал(а):Почему нельзя написать SPIx->DR = data
Ну так если можно, то зачем пляска с указателями?
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
© Альберт Эйнштейн
ну программист немного заработался. DR там уже должен быть __IO, просто лишний каст.
- Сообщения: 2089
- Зарегистрирован: Вс июн 19, 2016 09:32:03
[uquote="Chip115",url="/forum/viewtopic.php?p=3365299#p3365299"]Ну так если можно, то зачем пляска с указателями?[/uquote]
В старой реализации SPI, как у F1, достаточно было выбрать 8-ми битный формат в CR1 и тогда при записи байта в DR байт и оправлялся, а в новом SPI все иначе, там чтобы ушел байт нужно привести 16-ти битный DR к указателю на байт, иначе отправятся сразу два байта.
В старой реализации SPI, как у F1, достаточно было выбрать 8-ми битный формат в CR1 и тогда при записи байта в DR байт и оправлялся, а в новом SPI все иначе, там чтобы ушел байт нужно привести 16-ти битный DR к указателю на байт, иначе отправятся сразу два байта.
Спасибо! Это и хотел узнать.
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
© Альберт Эйнштейн
Пытаюсь изучить работу таймера и прерываний. MK AT89C2051, кварц 4 МГц. Компилятор языка Си ICC8051. По задумке таймер должен перезагружаться каждые 0,05 с (предустановка таймера 0xBEE5 - 48869). Для визуализации на портах P3.7 и P1.3 подвешены светодиоды. По поему (вероятно ошибочному мнению) HG2 на P3.7 должен одну сек. гореть, одну сек. быть потушенным. А HG1 на P1.3 мигать с частотой около 20 Гц. Но что-то пошло не так... Не могу разобраться сам в чём косяк.
Практическая работа программы: https://yadi.sk/i/gbIkzjEZ3Uw8Bv
Практическая работа программы: https://yadi.sk/i/gbIkzjEZ3Uw8Bv



