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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

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

Сообщение Z_h_e »

Перечеркнутый ноль мудрые люди давно придумали.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

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

Сообщение WiseLord »

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

Изображение
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

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

Сообщение uldemir »

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

Есть еще одна - буфер "видеоозу". Используется в главном модуле и в модуле конфигурации. Конечно, я могу в каждом модуле выделить свой буфер - на функционал не влияет, но прамяти жалко. Пока объявил в main.c а в configure.c написал как extern.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

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

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

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

Мой уютный бложик... заходите!
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

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

Сообщение dosikus »

ARV, у тебя с uldemir одна общая проблема - вы мыслите на уровне avr ...
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

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

Сообщение arkhnchul »

[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]
это даже на "больших" компах далеко не всегда проканывает. Зачастую вывод чего-нибудь графического начинается с обращения к вышележащей софтине (драйверу/интерфейсу/части тулкита) типа "дай мне буфер для непосредственных манипуляций".
Аватара пользователя
Chip115
Сверлит текстолит когтями
Сообщения: 1132
Зарегистрирован: Пт фев 16, 2007 14:18:20
Откуда: Новосибирск
Контактная информация:

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

Сообщение Chip115 »

Всем привет!
Пытаюсь написать алгоритм работы с 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 постраничное? т.е. прежде чем изменить байт (-ты), я должен прочитать всю страницу, изменить нужную информацию и записать вновь?
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

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

Сообщение Z_h_e »

Вопрос то не по Сям.
Надо было здесь топик создавать, сразу бы про DMA разговор бы пошел :).
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

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

Сообщение arkhnchul »

[uquote="Chip115",url="/forum/viewtopic.php?p=3364936#p3364936"]В интернете полно примеров, но там используются всякие костыли типа

Код: Выделить всё

while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET); 
что, откровенно, вызывает кровь из глаз.[/uquote]
вполне нормальная конструкция :dont_know:

[uquote="Chip115",url="/forum/viewtopic.php?p=3364936#p3364936"]Смысл такой, что если циклически вызывать

Код: Выделить всё

ui8EepromSendByte 
и чекать что вернула функция, то можно рулить тем, что бы данные отправлялись тогда, когда предыдущие гарантированно уйдут. Такая конструкция приемлема или есть более интересная реализация?[/uquote]
каноничный подход - сначала дождаться взведения флага TXE, потом чего-то пытаться отправить

Код: Выделить всё

void ui8EepromSendByte(uint8_t byte)
{
  while (!(SPI2->SR & SPI_SR_TXE)); // ждем
  SPI2->DR = byte;
}
Аватара пользователя
Chip115
Сверлит текстолит когтями
Сообщения: 1132
Зарегистрирован: Пт фев 16, 2007 14:18:20
Откуда: Новосибирск
Контактная информация:

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

Сообщение Chip115 »

[uquote="Z_h_e",url="/forum/viewtopic.php?p=3364944#p3364944"]Вопрос то не по Сям.
Надо было здесь топик создавать, сразу бы про DMA разговор бы пошел :).[/uquote]
Точно. Виноват. Подумал что алгоритмические вопросы тоже сюда )) Наверное передислацируюсь туда. Если есть возможноть, то удалите, пожалуйста, мой пост, что бы не захламлять.
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

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

Сообщение Z_h_e »

Chip115 писал(а):SPI2->SR &= ~SPI_SR_TXE;
Так не сработает. Бит только для чтения.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
Chip115
Сверлит текстолит когтями
Сообщения: 1132
Зарегистрирован: Пт фев 16, 2007 14:18:20
Откуда: Новосибирск
Контактная информация:

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

Сообщение Chip115 »

Понял, спасибо.
Еще вопрос.
Что значит эта запись?

Код: Выделить всё

#define SPI_SendData8(SPIx, data)   *(__IO uint8_t *)&SPIx->DR = data
Интересует правая запись
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
uk8amk
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

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

Сообщение uk8amk »

Это значит запись байта data по адресу SPIx->DR
Аватара пользователя
Chip115
Сверлит текстолит когтями
Сообщения: 1132
Зарегистрирован: Пт фев 16, 2007 14:18:20
Откуда: Новосибирск
Контактная информация:

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

Сообщение Chip115 »

А что за магия с указателями? Почему нельзя написать SPIx->DR = data и зачем нужна операция И?
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

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

Сообщение Z_h_e »

Chip115 писал(а): зачем нужна операция И
Почитайте про указатели.
Chip115 писал(а):Почему нельзя написать SPIx->DR = data
Кто сказал что нельзя?
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
Chip115
Сверлит текстолит когтями
Сообщения: 1132
Зарегистрирован: Пт фев 16, 2007 14:18:20
Откуда: Новосибирск
Контактная информация:

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

Сообщение Chip115 »

Ну так если можно, то зачем пляска с указателями?
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

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

Сообщение arkhnchul »

ну программист немного заработался. DR там уже должен быть __IO, просто лишний каст.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

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

Сообщение Reflector »

[uquote="Chip115",url="/forum/viewtopic.php?p=3365299#p3365299"]Ну так если можно, то зачем пляска с указателями?[/uquote]
В старой реализации SPI, как у F1, достаточно было выбрать 8-ми битный формат в CR1 и тогда при записи байта в DR байт и оправлялся, а в новом SPI все иначе, там чтобы ушел байт нужно привести 16-ти битный DR к указателю на байт, иначе отправятся сразу два байта.
Аватара пользователя
Chip115
Сверлит текстолит когтями
Сообщения: 1132
Зарегистрирован: Пт фев 16, 2007 14:18:20
Откуда: Новосибирск
Контактная информация:

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

Сообщение Chip115 »

Спасибо! Это и хотел узнать.
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
Аватара пользователя
Amigosam
Встал на лапы
Сообщения: 94
Зарегистрирован: Пт фев 14, 2014 20:45:33
Откуда: Северный Кавказ

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

Сообщение Amigosam »

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

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

Вернуться в «Разные вопросы по МК»