stm32f4 cmsis delay как сделать задержку для lcd
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Кто подскажет как правильно написать задержку для LCD
- Реклама
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
тупо - "пустым" циклом
менее тупо - на основе аппаратного или программного счетчика "системных тиков".
а совсем правильно (имхо, не утверждаю, что для всех LCD приемлемо) - на основе считывания регистра состояния LCD, т.е. работа не по задержке, а по готовности дисплея.
Код: Выделить всё
volatile int delay = 123;
while(delay) delay--;а совсем правильно (имхо, не утверждаю, что для всех LCD приемлемо) - на основе считывания регистра состояния LCD, т.е. работа не по задержке, а по готовности дисплея.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
- Реклама
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
[uquote="ivan dimir",url="/forum/viewtopic.php?p=3871875#p3871875"]а программно?[/uquote]
А что КА — железо?
Миллисекундные задержки очень удобно делать на КА: заводим внутренний счетчик и сравниваем на каждом прогоне с SysTick, который системные миллисекунды считает. Вряд ли у вас один прогон "суперлупа" будет длиться больше 1мс, поэтому получаем точность не хуже 1мс.
А вот микросекунды зачастую прямо на месте и отсчитывают — при помощи вспомогательного таймера или тупыми nop'ами в цикле (правда, в этом случае точность будет паршивой). Обычно такие паузы нужны лишь на инициализации, которая все равно в начале проходит и можно считать, что пользователю пофиг, что в течение пяти секунд устройство вообще ни на что не реагирует..
Но, как уже написали, лучший вариант — читать регистры и принимать решение на основе этого.
Или вернуться к конечным автоматам: экранчикам не нужно точных пауз, достаточно (если нет регистра состояний) выдержать определенную. Вот и проходимся по массиву инициализации плавно: дошли до паузы, внутренний счетчик в нужное значение выставили, и ждем. Потом следующий кусок отправляем. И так далее. При этом нет блокирующих пауз, и железяка вовсю будет работать, пока инициализируется экран.
А что КА — железо?
Миллисекундные задержки очень удобно делать на КА: заводим внутренний счетчик и сравниваем на каждом прогоне с SysTick, который системные миллисекунды считает. Вряд ли у вас один прогон "суперлупа" будет длиться больше 1мс, поэтому получаем точность не хуже 1мс.
А вот микросекунды зачастую прямо на месте и отсчитывают — при помощи вспомогательного таймера или тупыми nop'ами в цикле (правда, в этом случае точность будет паршивой). Обычно такие паузы нужны лишь на инициализации, которая все равно в начале проходит и можно считать, что пользователю пофиг, что в течение пяти секунд устройство вообще ни на что не реагирует..
Но, как уже написали, лучший вариант — читать регистры и принимать решение на основе этого.
Или вернуться к конечным автоматам: экранчикам не нужно точных пауз, достаточно (если нет регистра состояний) выдержать определенную. Вот и проходимся по массиву инициализации плавно: дошли до паузы, внутренний счетчик в нужное значение выставили, и ждем. Потом следующий кусок отправляем. И так далее. При этом нет блокирующих пауз, и железяка вовсю будет работать, пока инициализируется экран.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Я на гитхабе, в ЖЖ
Делаю через DWT
Код: Выделить всё
void DelayMs(uint32_t nTime)
{
volatile uint32_t CounterTick = nTime * (SystemCoreClock / 1000);
SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; //разрешаем использовать счётчик
DWT_CYCCNT = 0; //обнуляем значение счётного регистра
DWT_CONTROL |= DWT_CTRL_CYCCNTENA_Msk; //запускаем счётчик
while(DWT_CYCCNT < CounterTick);
DWT_CONTROL &= ~DWT_CTRL_CYCCNTENA_Msk; //останавливаем счётчик
}
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
В реферес мануал его нет где прочитать про него?DWT
сорри, забыл добавить дефайны:
Код: Выделить всё
#define DWT_CYCCNT *(volatile unsigned long *)0xE0001004
#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
- Сообщения: 41
- Зарегистрирован: Вс мар 21, 2021 11:06:04
[uquote="ivan dimir",url="/forum/viewtopic.php?p=4013156#p4013156"]а на базовом таймере как єто сделать?[/uquote]
Обычно это делается на любом свободном аппаратном таймере методом вычитывания и обработки значения его счетного регистра. Без использования прерываний. Подробнее про реализацию можно прочитать тут. Максимальный интервал времени для такого таймера определяется периодом перезагрузки его счетного регистра.
Обычно это делается на любом свободном аппаратном таймере методом вычитывания и обработки значения его счетного регистра. Без использования прерываний. Подробнее про реализацию можно прочитать тут. Максимальный интервал времени для такого таймера определяется периодом перезагрузки его счетного регистра.
облагороженная версия ардуиновского millis() и ардуиновского же подхода...Professor Chaos писал(а):Подробнее про реализацию можно прочитать тут.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 1849
- Зарегистрирован: Вс дек 25, 2016 08:34:54
1 вариант:2 вариант:
Спойлер
Код: Выделить всё
void Delay(uint32_t ms)
{
volatile uint32_t nCount;
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq (&RCC_Clocks);
nCount=(RCC_Clocks.HCLK_Frequency/10000)*ms;
for (; nCount!=0; nCount--);
}Спойлер
версия ардуиновского millis()Код: Выделить всё
// Конфигурируем и запуск системного таймера
// для генерации каждую 1 мс.
SysTick->LOAD = 48000000UL/1000 - 1; // Загрузка значения в 1 ms
SysTick->VAL = 48000000UL/1000 - 1; // Устанавливаем текущее значение
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
volatile uint32_t currentMillis = 0;
//Обработчик прерывания системного таймера
void SysTick_Handler(void)
{
currentMillis++;
}
uint32_t millis (void)
{
return currentMillis;
}
uint32_t previousMillis = 0;
if((millis() - previousMillis) > 500){
previousMillis = millis();
//делаем что-то
}- Сообщения: 41
- Зарегистрирован: Вс мар 21, 2021 11:06:04
Вы строите этот код исходя из предположения, что одна итерация цикла for будет исполняться строго за 1 период тактовой частоты ядра? А если это не так? А это, в общем случае не так, и зависит от настроек оптимизации - тогда что?Dimon456 писал(а):nCount=(RCC_Clocks.HCLK_Frequency/10000)*ms;
for (; nCount!=0; nCount--);
Во втором варианте не учитывается событие переполнения счетчика: пусть последнее предыдущее значение 0хFFFFFFFF, текущее прочитанное 0. Сколько прошло времени? А что покажет условие?
- Сообщения: 1849
- Зарегистрирован: Вс дек 25, 2016 08:34:54
А вот мне "на.... с глубокой горки", главное работает и ладно, просто из вас ни кто ни чего не предложил, кроме слов конечно.Professor Chaos писал(а):Вы строите этот код исходя из предположения,
Делаю так:
Спойлер
-OsКод: Выделить всё
while(1)
{
GPIOA->ODR |= GPIO_Pin_2;
Delay(100); // Delay(1); Delay(10);
GPIOA->ODR &= ~GPIO_Pin_2;
}Код: Выделить всё
RCC_Clocks.HCLK_Frequency/10000А смотреть по осциллографу, или частотомеру
Да плевать и на этоProfessor Chaos писал(а):Во втором варианте не учитывается событие переполнения счетчика
Спойлер
Код: Выделить всё
if((millis() - previousMillis) > 500){
previousMillis = millis();
blink = !blink;
}
LCDI2C_setCursor (10,0);
if (blink) LCDI2C_write(0x22); else LCDI2C_write(0x20);Не нравится, делайте на конечных автоматах, там все учитывается, да же размер кода.
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
- Сообщения: 41
- Зарегистрирован: Вс мар 21, 2021 11:06:04
[uquote="ivan dimir",url="/forum/viewtopic.php?p=4016305#p4016305"]а как сделать задержку таймером базовым?[/uquote]
Что такое базовый таймер? Вы, вообще, какой МК имеете ввиду? У ARM много разных ядер, и куча производителей используют их в своих контроллерах/процессорах. И понятие базового таймера везде разное. В ядре есть системный таймер. Другие таймеры каждый производитель реализует как хочет в качестве периферийных устройств.
Что такое базовый таймер? Вы, вообще, какой МК имеете ввиду? У ARM много разных ядер, и куча производителей используют их в своих контроллерах/процессорах. И понятие базового таймера везде разное. В ядре есть системный таймер. Другие таймеры каждый производитель реализует как хочет в качестве периферийных устройств.
есть еще варианты как слова в вопросе переставить
или такой ответ сойдет:

или такой ответ сойдет:
Код: Выделить всё
TIM3->PSC = 56-1; // предварительная
TIM3->ARR = 10-1; // подготовка
TIM3->EGR = TIM_EGR_UG; // таймера
...
TIM3->CR1 = TIM_CR1_CEN|TIM_CR1_OPM; // старт таймера
...
if (!(TIM3->CR1&TIM_CR1_CEN)) {...;} // проверка с выполнением, если оттикал
или заLoopить на тупой опрос бита:
while(TIM3->CR1&TIM_CR1_CEN){}; // висеть если еще тикает- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
TIM3->CR1 = TIM_CR1_CEN|TIM_CR1_OPM; и будет один импулс.Этот бит _OPM; один импулс


