Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Re: Вопросы по С/С++ (СИ)

Пт апр 20, 2018 21:08:14

Перечеркнутый ноль мудрые люди давно придумали.

Re: Вопросы по С/С++ (СИ)

Пт апр 20, 2018 21:36:58

На смартфоне разница была почти незаметна:

Изображение

Re: Вопросы по С/С++ (СИ)

Вт апр 24, 2018 16:52:50

Снова подниму тему глобальных переменых... Прочитал я в этой теме, что это зло, но от него не могу отказаться. Тут один проектик разросся до того, что стал трудно "сопровождаемым" и я решил его побить по модулям. Вот с одной проблемой не знаю как справиться. Выделил в отдельный модуль обработчик клавиш - всё вроде внятно, но есть одна переменная у неё kbddelay - таймер задержки, которая декрементируется в таймерном прерывании. Пока оно было в одном файле - проблем не было. А теперь обработчик прерываний находится в главном файле проекта, а обработчик кнопок в другом. Где эту переменную объявить, описать итд.

Есть еще одна - буфер "видеоозу". Используется в главном модуле и в модуле конфигурации. Конечно, я могу в каждом модуле выделить свой буфер - на функционал не влияет, но прамяти жалко. Пока объявил в main.c а в configure.c написал как extern.

Re: Вопросы по С/С++ (СИ)

Вт апр 24, 2018 17:55:11

есть, как говорится, два способа: правильный и удобный :)
удобный - это плевать на то, как говорят, делать так, чтобы работало. но тут следует помнить, что удобно одному, другому будет неудобно. да и собственные привычки могут поменяться с годами...

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

с обработчиками прерываний все похуже, т.к. у них особый статус "невидимок для всех". поэтому, с моей точки зрения, идеальным был бы вариант, когда прерывание для работы с клавиатурой определено в модуле работы с клавиатурой. но если одно прерывание занимается обслуживанием интересов нескольких модулей - так не выйдет. и тут городить излишние "изолирующие прокладки" в виде промежуточных модулей, не очень хорошая идея: попрёт оверхед памяти, снизится производительность... тут нужно искать компромиссы, например, по типу, как у вас
uldemir писал(а):объявил в main.c а в configure.c написал как extern

Re: Вопросы по С/С++ (СИ)

Вт апр 24, 2018 18:41:53

ARV, у тебя с uldemir одна общая проблема - вы мыслите на уровне avr ...

Re: Вопросы по С/С++ (СИ)

Вт апр 24, 2018 20:41:23

есть одна переменная у неё kbddelay - таймер задержки, которая декрементируется в таймерном прерывании. Пока оно было в одном файле - проблем не было. А теперь обработчик прерываний находится в главном файле проекта, а обработчик кнопок в другом. Где эту переменную объявить, описать итд.

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

храните и используйте указатели на буфер, заносите в них актуальный адрес при инициализации.

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

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

Re: Вопросы по С/С++ (СИ)

Сб апр 28, 2018 15:29:31

Всем привет!
Пытаюсь написать алгоритм работы с 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;
     }
}


vSetSpiEepromFlag взводит флаг в битовом поле (через битбанд). Таким образом происходит обмен мессаджами между функциями.
Реализованное битовое поле
Код:
typedef struct
{
  unsigned spiByteReseived: 1;
  unsigned spiByteTransmited: 1;
} SpiState_TypeDef;


В целом, цель поднять FAT на SPI EEPROM и определить её как USB, потому в этом контексте, подобная реализация низкоуровневых функций норм? Или же мне отправляемые/принимаемые данные через кольцевой буфер гонять? Или исходящий поток нет смысла через кольцевой буфер гнать? Вообще, общение с EEPROM постраничное? т.е. прежде чем изменить байт (-ты), я должен прочитать всю страницу, изменить нужную информацию и записать вновь?

Re: Вопросы по С/С++ (СИ)

Сб апр 28, 2018 15:43:40

Вопрос то не по Сям.
Надо было здесь топик создавать, сразу бы про DMA разговор бы пошел :).

Re: Вопросы по С/С++ (СИ)

Сб апр 28, 2018 15:47:05

В интернете полно примеров, но там используются всякие костыли типа
Код:
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);
что, откровенно, вызывает кровь из глаз.

вполне нормальная конструкция :dont_know:

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

каноничный подход - сначала дождаться взведения флага TXE, потом чего-то пытаться отправить
Код:
void ui8EepromSendByte(uint8_t byte)
{
  while (!(SPI2->SR & SPI_SR_TXE)); // ждем
  SPI2->DR = byte;
}

Re: Вопросы по С/С++ (СИ)

Сб апр 28, 2018 15:59:14

Вопрос то не по Сям.
Надо было здесь топик создавать, сразу бы про DMA разговор бы пошел :).

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

Re: Вопросы по С/С++ (СИ)

Сб апр 28, 2018 16:04:08

Chip115 писал(а):SPI2->SR &= ~SPI_SR_TXE;
Так не сработает. Бит только для чтения.

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 02:39:44

Понял, спасибо.
Еще вопрос.
Что значит эта запись?
Код:
#define SPI_SendData8(SPIx, data)   *(__IO uint8_t *)&SPIx->DR = data

Интересует правая запись

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 09:01:31

Это значит запись байта data по адресу SPIx->DR

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 10:35:29

А что за магия с указателями? Почему нельзя написать SPIx->DR = data и зачем нужна операция И?

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 10:37:58

Chip115 писал(а): зачем нужна операция И
Почитайте про указатели.
Chip115 писал(а):Почему нельзя написать SPIx->DR = data
Кто сказал что нельзя?

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 11:55:52

Ну так если можно, то зачем пляска с указателями?

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 13:53:40

ну программист немного заработался. DR там уже должен быть __IO, просто лишний каст.

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 14:19:30

Ну так если можно, то зачем пляска с указателями?

В старой реализации SPI, как у F1, достаточно было выбрать 8-ми битный формат в CR1 и тогда при записи байта в DR байт и оправлялся, а в новом SPI все иначе, там чтобы ушел байт нужно привести 16-ти битный DR к указателю на байт, иначе отправятся сразу два байта.

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 15:18:18

Спасибо! Это и хотел узнать.

Re: Вопросы по С/С++ (СИ)

Вс апр 29, 2018 21:13:21

Пытаюсь изучить работу таймера и прерываний. MK AT89C2051, кварц 4 МГц. Компилятор языка Си ICC8051. По задумке таймер должен перезагружаться каждые 0,05 с (предустановка таймера 0xBEE5 - 48869). Для визуализации на портах P3.7 и P1.3 подвешены светодиоды. По поему (вероятно ошибочному мнению) HG2 на P3.7 должен одну сек. гореть, одну сек. быть потушенным. А HG1 на P1.3 мигать с частотой около 20 Гц. Но что-то пошло не так... Не могу разобраться сам в чём косяк.

Практическая работа программы: https://yadi.sk/i/gbIkzjEZ3Uw8Bv
Ответить