Аналоговые часы на STM32F429I-DISCO (теперь с TS)


Используется стандартная периферия и драйвера к STM32F429I-DISCO.
Настроим светодиоды на плате:
void RCC_Configuration (void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG, &GPIO_InitStructure);
}
Инициализируем RTC:
void RTC_Configuration (void)
{
RTC_TimeTypeDef RTC_TimeStructure;
RTC_InitTypeDef RTC_InitStructure;
RTC_DateTypeDef RTC_DateStructure;
uint8_t RTC_Error = 0;
LCD_DisplayStringLine(1, (uint8_t*)"Starting Init RTC");
if (RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2)
{
LCD_DisplayStringLine(20, (uint8_t*)"RTC After COLD Start");
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){};
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
//RCC_LSICmd(ENABLE);
//while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) {};
//RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_InitStructure.RTC_AsynchPrediv = 0x7F;
RTC_InitStructure.RTC_SynchPrediv = 0xFF;
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
if (RTC_Init(&RTC_InitStructure) == ERROR)
{
LCD_DisplayStringLine(40, (uint8_t*)"RTC Prescaler Config failed");
}
RTC_TimeStructure.RTC_H12 = RTC_H12_AM;
RTC_TimeStructure.RTC_Hours = 14;
RTC_TimeStructure.RTC_Minutes = 9;
RTC_TimeStructure.RTC_Seconds = 50;
if(RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure) == ERROR)
{
LCD_DisplayStringLine(60, (uint8_t*)"RTC Set Time failed");
RTC_Error = 1;
}
else
{
LCD_DisplayStringLine(60, (uint8_t*)"RTC Set Time success");
}
RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Sunday;
RTC_DateStructure.RTC_Date = 11;
RTC_DateStructure.RTC_Month = RTC_Month_September;
RTC_DateStructure.RTC_Year = 14;
if(RTC_SetDate(RTC_Format_BIN, &RTC_DateStructure) == ERROR)
{
LCD_DisplayStringLine(80, (uint8_t*)"RTC Set Date failed");
RTC_Error = 1;
}
else
{
LCD_DisplayStringLine(80, (uint8_t*)"RTC Set Date success");
}
if (!RTC_Error)
{
RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
}
}
else
{
LCD_DisplayStringLine(20, (uint8_t*)"RTC After HOT Start");
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_WaitForSynchro();
RTC_ClearFlag(RTC_FLAG_ALRAF);
EXTI_ClearITPendingBit(EXTI_Line17);
}
}
Код стандартный, честно вытянутый из примеров ST. В инициализации устанавливаем время и дату «по-умолчанию».
void PrintTimeDate (void)
{
uint8_t LCDTime[9] = "00:00:00";
uint8_t LCDDate[11] = "00:00:0000";
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
sprintf ((char*)LCDTime, "%0.2d:%0.2d:%0.2d", RTC_TimeStruct.RTC_Hours, RTC_TimeStruct.RTC_Minutes, RTC_TimeStruct.RTC_Seconds);
sprintf ((char*)LCDDate, "%0.2d:%0.2d:%0.2d", RTC_DateStruct.RTC_Date, RTC_DateStruct.RTC_Month, (2000 + RTC_DateStruct.RTC_Year));
LCD_DisplayStringLineColumn(LCD_PIXEL_HEIGHT/2-60, LCD_PIXEL_WIDTH/2-30, 8, LCDTime);
}
Считываем время дату из RTC, переводим их в текстовый формат и выводим в центр часов. LCD_PIXEL_HEIGHT = 320, LCD_PIXEL_WIDTH = 240.
Дальше, рисуем часы. Вся работа основывается на 2-х формулах, нахождение 2-х катетов при известной гипотенузе и угле. С помощью них находятся x и у часовых, минутных и секундных отметок.
ClockX = LCD_PIXEL_WIDTH/2;
ClockY = LCD_PIXEL_HEIGHT/2-45;
ClockRadius = LCD_PIXEL_WIDTH/2-15;
Задается центр часов и максимальный радиус. На нем будут располагаться часовые отметки.
halfPi = ((asin(1))*2)/2;
PiH = ((asin(1))*2)/6;;
PiM = ((asin(1))*2)/30;
PiHalf = ((asin(1))*2)/180;
Облегчим жизнь контроллеру, заранее посчитаем Pi и смещения часовых, минутных/секундных отметок.
LCD_DrawCircle((uint16_t) ClockX, (uint16_t) ClockY, 1);
for (angle = 0; angle < 12; angle = angle + 1)
{
modf ((ClockX + ClockRadius * cos(PiH*angle - halfPi)), &Nx);
modf ((ClockY + ClockRadius * sin(PiH*angle - halfPi)), &Ny);
LCD_DrawCircle((uint16_t) Nx, (uint16_t) Ny, 3);
}
for (angle = 0; angle < 60; angle = angle + 1)
{
modf ((ClockX + (ClockRadius - 23) * cos(PiM*angle - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 23) * sin(PiM*angle - halfPi)), &Ny);
LCD_DrawCircle((uint16_t) Nx, (uint16_t) Ny, 1);
}
for (angle = 0; angle < 60; angle = angle + 1)
{
modf ((ClockX + (ClockRadius - 45) * cos(PiM*angle - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 45) * sin(PiM*angle - halfPi)), &Ny);
LCD_DrawCircle((uint16_t) Nx, (uint16_t) Ny, 0);
}
Рисуем центр часов, потом часовые, минутные и секундные отметки в виде окружностей. Радиус меняем для каждого типа.
LCD_SetTextColor(LCD_COLOR_BLACK);
modf ((ClockX + (ClockRadius - 45) * cos(PiM*(RTC_TimeStruct.RTC_Seconds-1) - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 45) * sin(PiM*(RTC_TimeStruct.RTC_Seconds-1) - halfPi)), &Ny);
LCD_DrawFullCircle((uint16_t) Nx, (uint16_t) Ny, 3);
LCD_SetTextColor(LCD_COLOR_CYAN);
modf ((ClockX + (ClockRadius - 45) * cos(PiM*RTC_TimeStruct.RTC_Seconds - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 45) * sin(PiM*RTC_TimeStruct.RTC_Seconds - halfPi)), &Ny);
LCD_DrawFullCircle((uint16_t) Nx, (uint16_t) Ny, 3);
LCD_SetTextColor(LCD_COLOR_GREY);
modf ((ClockX + (ClockRadius - 45) * cos(PiM*(RTC_TimeStruct.RTC_Seconds-1) - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 45) * sin(PiM*(RTC_TimeStruct.RTC_Seconds-1) - halfPi)), &Ny);
LCD_DrawCircle((uint16_t) Nx, (uint16_t) Ny, 0);
LCD_SetTextColor(LCD_COLOR_BLACK);
modf ((ClockX + (ClockRadius - 23) * cos(PiM*(RTC_TimeStruct.RTC_Minutes-1) - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 23) * sin(PiM*(RTC_TimeStruct.RTC_Minutes-1) - halfPi)), &Ny);
LCD_DrawFullCircle((uint16_t) Nx, (uint16_t) Ny, 5);
LCD_SetTextColor(LCD_COLOR_CYAN);
modf ((ClockX + (ClockRadius - 23) * cos(PiM*RTC_TimeStruct.RTC_Minutes - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 23) * sin(PiM*RTC_TimeStruct.RTC_Minutes - halfPi)), &Ny);
LCD_DrawFullCircle((uint16_t) Nx, (uint16_t) Ny, 5);
LCD_SetTextColor(LCD_COLOR_GREY);
modf ((ClockX + (ClockRadius - 23) * cos(PiM*(RTC_TimeStruct.RTC_Minutes-1) - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 23) * sin(PiM*(RTC_TimeStruct.RTC_Minutes-1) - halfPi)), &Ny);
LCD_DrawCircle((uint16_t) Nx, (uint16_t) Ny, 1);
LCD_SetTextColor(LCD_COLOR_BLACK);
modf ((ClockX + (ClockRadius - 0) * cos(PiHalf*(RTC_TimeStruct.RTC_Hours*30+RTC_TimeStruct.RTC_Minutes/2-1) - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 0) * sin(PiHalf*(RTC_TimeStruct.RTC_Hours*30+RTC_TimeStruct.RTC_Minutes/2-1) - halfPi)), &Ny);
LCD_DrawFullCircle((uint16_t) Nx, (uint16_t) Ny, 6);
LCD_SetTextColor(LCD_COLOR_CYAN);
modf ((ClockX + (ClockRadius - 0) * cos(PiHalf*(RTC_TimeStruct.RTC_Hours*30+RTC_TimeStruct.RTC_Minutes/2) - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 0) * sin(PiHalf*(RTC_TimeStruct.RTC_Hours*30+RTC_TimeStruct.RTC_Minutes/2) - halfPi)), &Ny);
LCD_DrawFullCircle((uint16_t) Nx, (uint16_t) Ny, 6);
LCD_SetTextColor(LCD_COLOR_GREY);
modf ((ClockX + (ClockRadius - 0) * cos(PiH*(RTC_TimeStruct.RTC_Hours-1) - halfPi)), &Nx);
modf ((ClockY + (ClockRadius - 0) * sin(PiH*(RTC_TimeStruct.RTC_Hours-1) - halfPi)), &Ny);
LCD_DrawCircle((uint16_t) Nx, (uint16_t) Ny, 3);
Стрелок нет, вместо них цветные окружности увеличенного радиуса. Если нужны стрелки, просто строим линию от центра часов до вычисленного центра окружности. Каждая отрисовка в 3 этапа, стираем окружность на предыдущей временной отметке, восстанавливаем отметку, рисуем на новом месте.
void ReadTS (void)
{
uint16_t KeyDelay = 200;
tState = IOE_TP_GetState();
if (tState->TouchDetected)
{
if ((tState->Y <= LCD_PIXEL_HEIGHT/2-14+15) && (tState->Y >= LCD_PIXEL_HEIGHT/2-14))
{
if ((tState->X >= LCD_PIXEL_WIDTH/2-32) && (tState->X <= LCD_PIXEL_WIDTH/2-32+12))
{
RTC_TimeStruct.RTC_Hours = RTC_TimeStruct.RTC_Hours+1;
if (RTC_TimeStruct.RTC_Hours > 23)
{
RTC_TimeStruct.RTC_Hours = 0;
}
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
LCD_Clear(LCD_COLOR_BLACK);
Delay_MS (KeyDelay);
}
if ((tState->X >= LCD_PIXEL_WIDTH/2-32) && (tState->X <= LCD_PIXEL_WIDTH/2-32+23+12))
{
RTC_TimeStruct.RTC_Minutes = RTC_TimeStruct.RTC_Minutes+1;
if (RTC_TimeStruct.RTC_Minutes > 59)
{
RTC_TimeStruct.RTC_Minutes = 0;
}
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
LCD_Clear(LCD_COLOR_BLACK);
Delay_MS (KeyDelay);
}
if ((tState->X >= LCD_PIXEL_WIDTH/2-32) && (tState->X <= LCD_PIXEL_WIDTH/2-32+47+12))
{
RTC_TimeStruct.RTC_Seconds = 0;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
LCD_Clear(LCD_COLOR_BLACK);
Delay_MS (KeyDelay);
}
}
}
}
Простой обработчик тача. Определяются нажатия, если нажатие происходит в области электронных часов (отдельно часы, минуты и секунды), происходит увеличение часов, минут на 1, секунды сбрасываются в 0.
LCD_Init();
LCD_LayerInit();
LCD_SetLayer(LCD_BACKGROUND_LAYER);
LCD_SetTransparency(0);
LCD_SetLayer(LCD_FOREGROUND_LAYER);
LTDC_ReloadConfig(LTDC_IMReload);
LTDC_Cmd(ENABLE);
LCD_Clear(LCD_COLOR_BLACK);
LCD_SetTextColor(LCD_COLOR_GREY);
LCD_SetBackColor(LCD_COLOR_BLACK);
LCD_SetFont(&Font8x12);
if (IOE_Config())
{
LCD_Clear(LCD_COLOR_RED);
LCD_SetFont(&Font12x12);
LCD_DisplayStringLineColumn(120, 25, 12, (uint8_t*) "!!! ERROR TS !!!");
while (1) {};
}
Инициализируем LCD и TS.
Все. Запускаем бесконечный цикл:
while (1)
{
AnalogClock ();
PrintTimeDate ();
ReadTS ();
GPIOG->ODR ^= GPIO_Pin_14;
Delay_MS (100);
}
К топику прикреплю архив с проектом для KEIL-a. Там, правда, все под RTOS-ом, но, все тоже самое.
PS. Вопрос по RTC-у. У меня на плате нет внешнего часового кварца. Соответствующие перемычки с обратной стороны открыты. Но, Инициализация LSE происходит и часы тикают. Проверено на 2-х платах с одной закупочной партии. Как так?
- +6
- 15 сентября 2014, 22:00
- lexanet
- 1
Файлы в топике:
stm32f429.zip
Приветствую, уважаемый Алексей!
Очень понравилась Ваша реалезация аналоговых часов на STM32F429!
Хочу повторить Ваш проект! Я скомпилил, то, что в архиве, без ошибок, но тачСкрин не работает(((
Помогите, пожалуйста!
PS: Я уже собрал настенные часы из матрицы от ноутбука 12" на Андройд стике — работает хорошо, но слишком спецефично, хотелось бы упрастить, используя STM32F429.
Очень понравилась Ваша реалезация аналоговых часов на STM32F429!
Хочу повторить Ваш проект! Я скомпилил, то, что в архиве, без ошибок, но тачСкрин не работает(((
Помогите, пожалуйста!
PS: Я уже собрал настенные часы из матрицы от ноутбука 12" на Андройд стике — работает хорошо, но слишком спецефично, хотелось бы упрастить, используя STM32F429.
Можешь выложить Реальное видео «Соревнований по забиванию гвоздей микроскопом»?
кто то Думает на этой платке… но пока никто не Квакал
кто то делает разные мелкие осцилографы
www.youtube.com/results?search_query=STM32F429I-DISCO
кто то как тс — аналоговые часы без стрелок но с цифрами
кто то Думает на этой платке… но пока никто не Квакал
кто то делает разные мелкие осцилографы
www.youtube.com/results?search_query=STM32F429I-DISCO
кто то как тс — аналоговые часы без стрелок но с цифрами
Позвольте с Вами не согласиться!
На AVR32 7000-й серии, ЕМНИП, таки квакали! Так что и М4 ему должно хватить, с его-то FPU. Тем паче что и десктопные камни на момент выхода Quake I имели производительность, сопоставимую с таковой у героя статьи (шел даже на всяких К5 и Цырикс, фризил, но шел). А вот 3D-ускорителей в те времена можно сказать и не было, как класса… По крайней мере, для потребительского рынка.
На AVR32 7000-й серии, ЕМНИП, таки квакали! Так что и М4 ему должно хватить, с его-то FPU. Тем паче что и десктопные камни на момент выхода Quake I имели производительность, сопоставимую с таковой у героя статьи (шел даже на всяких К5 и Цырикс, фризил, но шел). А вот 3D-ускорителей в те времена можно сказать и не было, как класса… По крайней мере, для потребительского рынка.
- SINtheTHICK
- 27 января 2016, 23:38
- ↑
- ↓
На AVR32 7000-й серии, ЕМНИП, таки квакали!Линк?
А вот 3D-ускорителей в те времена можно сказать и не было, как класса…Были, Voodoo, например, да и первые nVidia тогда примерно вышли. А требовать топовое железо — традиция для игр id.
Не вижу, правда, инфы о требованиях оригинального квейка, но вышедший на его движке годом позже Half-Life хотел, ЕМНИП, 266МГц пенек и 3D ускоритель (был и софтверный режим, но, помнится, на разрешениях выше 640х480 атлон гигагерцовый его уже не тянул).
У мну в гугли под нумером 1 сцылко
di-halt.livejournal.com/364062.html?thread=5933342
оригинал на тытрубе
www.youtube.com/watch?v=vvOyixL8BRM
Ща будет многабукаф…
Выход Quake как раз и породил всплеск развития 3D-ускорителей. Тот же 3DFx Voodoo вышел где-то на полгода позже, со своим API Glide. Позже iD запилили версию под Glide для Voodoo, еще позже — QuakeGL под OpenGL. nVidia же выпустила свой первый ускоритель Riva 128 практически одновременно с Voodoo 2.
Одно несомненно — Quake был эпохален! Толчок к качественно новому развитию индустрии игр на ПК, отправная точка.
di-halt.livejournal.com/364062.html?thread=5933342
оригинал на тытрубе
www.youtube.com/watch?v=vvOyixL8BRM
Ща будет многабукаф…
Выход Quake как раз и породил всплеск развития 3D-ускорителей. Тот же 3DFx Voodoo вышел где-то на полгода позже, со своим API Glide. Позже iD запилили версию под Glide для Voodoo, еще позже — QuakeGL под OpenGL. nVidia же выпустила свой первый ускоритель Riva 128 практически одновременно с Voodoo 2.
Одно несомненно — Quake был эпохален! Толчок к качественно новому развитию индустрии игр на ПК, отправная точка.
- SINtheTHICK
- 28 января 2016, 02:25
- ↑
- ↓
У мну в гугли под нумером 1 сцылкоНеплохо. Хотя и заметно тормозит даже в QVGA.
По остальному — есть что почитать в плане описания технологической стороны квейка?
HL был написан под D3D, потому и требовал наличие ускорителяВообще, он был мультирендерным — SW, D3D, OGL (не помню насчет Glide). По крайней мере те версии, с которых началось мое знакомство с оным.
Тормозит, но работает! Делалось-то поди не игры ради, а с целью доказать саму возможность от нефиг делать… )))
Насчет почитать — ничего нету ( Знаю только, что был для Q1 запилен свой аналог Си сблэкджеком и шлюхами компилятором и отладчиком — QuakeC, доступный в свободном доступе на момент выхода самой игры. С 1999 сорцы движка также выложены в сеть (ща на github есть), только без графики.
Блин, как давно это было! Какой же я старый (((
Насчет почитать — ничего нету ( Знаю только, что был для Q1 запилен свой аналог Си с
Блин, как давно это было! Какой же я старый (((
- SINtheTHICK
- 29 января 2016, 00:28
- ↑
- ↓
HL был написан под D3D, потому и требовал наличие ускорителя, в оригинальном же Quake все обрабатывалось исключительно силами ЦП, минимум — Pentium и 16МБ оперативы.
- SINtheTHICK
- 28 января 2016, 02:33
- ↑
- ↓
Можно на ней и радио послушать (правда, не в этой стране — здесь ДВ/СВ вещание прекратили)
armradio.weaksignals.com/
armradio.weaksignals.com/
Лучше уж тогда WEB-радио. Опять-таки, производительности хватит и на программное декодирование МР3, и на всякие «улучшайзеры» звука еще останется. Если уж говорить про эфирное радио/ТВ, то можно, например, запилить телетекст для старого «Рубина» или «Горизонта»… ЕМНИП, подмешивание в видеосигнал когда-то давным-давно делали на «дохлой» Меге32 корнелльские студенты.
- SINtheTHICK
- 27 января 2016, 23:48
- ↑
- ↓
Комментарии (17)
RSS свернуть / развернуть