Микропроцесорски системи/К2 2021 — разлика између измена
(→Решење) |
(Преправљено и проширено решење) |
||
Ред 21: | Ред 21: | ||
* У случају проблема рада седмосегментог дисплеја додати <code>GPIOC->ODR &= ~0xFFF</code> пре постављања вредности на дисплеј. | * У случају проблема рада седмосегментог дисплеја додати <code>GPIOC->ODR &= ~0xFFF</code> пре постављања вредности на дисплеј. | ||
==== ''CubeMX'' ==== | ==== ''CubeMX'' опште ==== | ||
Прво је под ''Project Manager'' у ''Project'' подешена путања пројекта и ''Makefile'' за ''Toolchain'', а затим у ''Code Generator'' штиклирана опција за генерисање одвојених изворних фајлова и заглавља за сваку периферију | Прво је под ''Project Manager'' у ''Project'' подешена путања пројекта и ''Makefile'' за ''Toolchain'', а затим у ''Code Generator'' штиклирана опција за генерисање одвојених изворних фајлова и заглавља за сваку периферију. Урадити иницијално генерисање кода. | ||
==== ''Makefile'' ==== | ==== ''Eclipse'' опште ==== | ||
* Отворити ''Eclipse'' и поставити радно окружење на фолдер ''CubeMX'' унутар фолдера пројекта. | |||
* ''Window->Preferences->MCU'': | |||
** Workspace Arm -> поставити питању до <code>''interna_putanja_na_vašem_računaru''\GNU MCU\arm-none-eabi-gcc-10.2.1-1.1\bin</code>. | |||
** Workspace BuildTools -> поставити питању до <code>''interna_putanja_na_vašem_računaru''\GNU MCU\build-tools-4.2.1-2\bin</code>. | |||
* Путем опције import увести генерисан код из фолдера ''Code'', као постојећи C/C++ пројекат који користи ''makefile''. Обавезно означити ''Arm Cross GCC''. | |||
* Након учитавања, десни клик на учитани пројекат, ''properties->C/C++ Build->Setting'', а затим ''Apply and close''. | |||
* Опет десни клик на учитани пројекат, ''properties->C/C++ General->Paths and symbols'', и додати C симболе ''STM32F103x6'' и ''USE_HAL_DRIVER''. | |||
==== ''Makefile'' опште ==== | |||
У ''Makefile'' је померен <code>tim.c</code> на дно <code>C_SOURCES</code> променљиве, следећи блок: | У ''Makefile'' је померен <code>tim.c</code> на дно <code>C_SOURCES</code> променљиве, следећи блок: | ||
<syntaxhighlight lang="makefile"> | <syntaxhighlight lang="makefile"> | ||
Ред 55: | Ред 59: | ||
и <code>startup_stm32f103x6.s</code> је промењено на <code>Core/Src/startup_stm32f103x6.s</code> унутар <code>ASM_SOURCES</code>. | и <code>startup_stm32f103x6.s</code> је промењено на <code>Core/Src/startup_stm32f103x6.s</code> унутар <code>ASM_SOURCES</code>. | ||
==== <code> | ==== Ставка 1 ==== | ||
===== ''CubeMX'' ===== | |||
< | * Пинове <code>PB0</code> и <code>PB2</code> подесити као <code>GPIO_EXTI</code>. | ||
* Пинове <code>PB1</code> и <code>PB3</code> подесити као <code>GPIO_Output</code>. | |||
* У <code>NVIC</code> омогућити прекиде по <code>EXTI0</code> и <code>EXTI2</code>. | |||
* Генерисати код. | |||
===== ''Eclipse'' ===== | |||
<code>stm32f1xx_it.c</code> | |||
<syntaxhighlight> | |||
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { | |||
switch (GPIO_Pin) { | |||
case GPIO_PIN_0: | |||
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1); | |||
break; | |||
case GPIO_PIN_2: | |||
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3); | |||
break; | |||
} | |||
} | |||
</syntaxhighlight> | |||
===== ''Proteus'' ===== | |||
* Додати микотроконтрлер и поставити сигнале према референтној шеми. | |||
* Диода је <code>LED-YELLOW</code> из библиотеке <code>ACTIVE</code>. Диоде је потребно поставити да буду дигиталне. | |||
* За дугме се користи <code>BUTTON</code> из библиотеке <code>ACTIVE</code>. ''Switching time'' поставити на ''1n''. | |||
* Поставити отпорнике у складу са референтном шемом. | |||
* Поставити ''.efl'' или ''.hex'' фајл у микроконтролеру и тестирати исправан рад. | |||
==== Ставка 2 ==== | |||
===== ''CubeMX'' ===== | |||
* Тајмер <code>TIM1</code>: | |||
** ''Clock Source''->''Internal clock'', | |||
** ''Prescaler (PSC)''->999 | |||
** ''Counter Period (AutoReload Register)''->79 | |||
* Поставке изнад обезбеђују на сваких 10ms да се деси ''update interrupt'', 8MHz/''PSC'' је број тактова у једној секунди, а ''ARR'' на колико тактова се генерише ''update interrupt''. | |||
* У <code>NVIC</code> омогућити ''update interrupt'' за <code>TIM1</code>. | |||
* Подесити пинове <code>PC0-PC11</code> као <code>GPIO_Output</code>. | |||
* Генерисати код. | |||
===== ''Eclipse'' ===== | |||
<code>main.c</code> | |||
<syntaxhighlight> | |||
(&htim1)->Instance->SR = ~TIM_SR_UIF; // Чисти иницијалани update interrupt flag по покретању пројекта | |||
HAL_TIM_Base_Start_IT(&htim1); // Стартује TIM1 | |||
</syntaxhighlight> | |||
<code>tim.c</code> | |||
<syntaxhighlight> | |||
uint8_t digits[4] = { 1, 2, 3, 4 }; | |||
uint8_t sevenSeg[] = { 0x81, 0xCF, 0x92, 0x86, 0xCC, 0xA4, 0xA0, 0x8F, 0x80, 0x84 }; | |||
uint8_t currentDigit = 0; | |||
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { | |||
if (htim->Instance == TIM1) { | |||
GPIOC->ODR &= ~0xF00; // Чисти приказ свих цигара (чисти пинове за аноде 7seg дисплега) | |||
GPIOC->ODR &= ~0xFF; //Чисти стару вредност текуће цифре | |||
GPIOC->ODR |= sevenSeg[digits[currentDigit]]; // Поставља нову вредност текуће цифре | |||
GPIOC->ODR |= 0x1 << (currentDigit + 8); // Приказује текућу цифреу активирањем пина аноде на одговарајућој позицији | |||
currentDigit = (currentDigit + 1) % 4; | |||
} | |||
} | |||
</syntaxhighlight> | |||
===== ''Proteus'' ===== | |||
* Користи се <code>7SEG-MPX4-CA</code>из библиотеке <code>DISPLAY</code>. | |||
* Повезати седмосегменти дисплеј у складу са референтном шемом. | |||
* Тестирати исправан рад. | |||
==== Ставка 3 ==== | |||
===== ''CubeMX'' ===== | |||
* Тајмер <code>TIM1</code>: | |||
** ''Channel1''->''IPWM Generation CH1'', | |||
** ''Counter Period (AutoReload Register)''->9 | |||
** ''Pulse''->0 | |||
** ''CH Polarity''->''Low'' | |||
* Поставке изнад обезбеђују на сваких 10ms да се деси ''update interrupt'', 8MHz/''PSC'' је број тактова у једној секунди, а ''ARR'' на колико тактова се генерише ''update interrupt''. | |||
* У <code>NVIC</code> омогућити ''caprute compare interrupt''. | |||
* Генерисати код. | |||
===== ''Eclipse'' ===== | |||
<code>main.c</code> | |||
<syntaxhighlight> | |||
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<code>stm32f1xx_it.c</code> | |||
<syntaxhighlight> | |||
< | void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { | ||
switch (GPIO_Pin) { | |||
case GPIO_PIN_0: | |||
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1); | |||
if (power < 9) { | |||
power++; | |||
} | |||
htim1.Instance->CCR1 = power; | |||
break; | |||
case GPIO_PIN_2: | |||
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3); | |||
if (power > 0) { | |||
power--; | |||
} | |||
htim1.Instance->CCR1 = power; | |||
break; | |||
} | |||
} | |||
</syntaxhighlight> | |||
===== ''Proteus'' ===== | |||
* Поставити коло са мотором у складу са референтном шемом. | |||
* За батерију се користи <code>CELL</code> из библиотеке <code>DEVICE</code>, а за мотор <code>MOTOR</code> из библиотеке <code>ACTIVE</code>. | |||
* Диода овде '''не треба''' да буде дигитална. | |||
* Обратити пажњу да је напон батерија 12V. | |||
==== Ставка 4 ==== | |||
===== ''CubeMX'' ===== | |||
* Тајмер <code>TIM3</code>: | |||
** ''Clock Source''->''Internal clock'', | |||
** ''Channel1''->''Input Capture direct mode'', | |||
** ''Prescaler (PSC)''->7999 | |||
** ''Counter Period (AutoReload Register)''->65565 | |||
** ''Polarity Selection канала 1''->''Rising edge'' | |||
* У <code>NVIC</code> омогућити ''general interrupt'' од <code>TIM3</code>. | |||
* Генерисати код. | |||
===== ''Eclipse'' ===== | |||
<code>main.c</code> | |||
<syntaxhighlight> | |||
(&htim3)->Instance->SR = ~TIM_SR_UIF; | |||
HAL_TIM_Base_Start_IT(&htim3); | |||
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<code>tim.c</code> | |||
<syntaxhighlight> | |||
<syntaxhighlight | |||
uint8_t digits[4] = { 1, 2, 3, 4 }; | uint8_t digits[4] = { 1, 2, 3, 4 }; | ||
uint8_t sevenSeg[] = { 0x81, 0xCF, 0x92, 0x86, 0xCC, 0xA4, 0xA0, 0x8F, 0x80, 0x84 }; | uint8_t sevenSeg[] = { 0x81, 0xCF, 0x92, 0x86, 0xCC, 0xA4, 0xA0, 0x8F, 0x80, 0x84 }; | ||
Ред 128: | Ред 237: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
===== ''Proteus'' ===== | |||
* Поставити преостале компоненте у складу са референтном шемом. | |||
* На ''DCLOCK''-у се испробавају фреквенције мање од 8000. | |||
== Напомене == | == Напомене == |
Верзија на датум 10. децембар 2023. у 22:04
Први колоквијум 2021. године нема поставку доступну са странице предмета. Није много познато о овом року, осим задатка наведеног испод. Исти задатак појавио се и на другом колоквијуму 2022. године.
Задатак
Поставка
Користећи алате arm-none-eabi-*, build-tools и Eclipse CDT, Proteus симулатор и CubeMX алат потребно је испунити ставке које се налазе у наставку.
- [6 поена] Направити CubeMX и Proteus пројекте за микроконтролер STM32F103R6. Додати два дугмета и повезати их на пинове
PB0
иPB2
(погледати референтну шему) тако да се могу користити за генерисање прекида. Извршити неопходну конфигурацију тако да се генеришу захтеви за обраду прекида уколико се на улазном сигналу ових пинова препозна узлазна ивица. Додати две LED (light emitting diode) и повезати их на пиновеPB1
иPB3
(погледати референтну шему). Извршити неопходну конфигурацију и затим у оквиру прекидне рутине за дугме које је везано на пинPB0
написати програмски код који врши промену стања на пинуPB1
, а у оквиру прекидне рутине за дугме које је везано на пинPB2
написати програмски код који врши промену стању[sic] на пинуPB3
(погледати референтни снимак).[1] - [6 поена] Додати седмосегментни екран ширине четири цифара, повезати га на одговарајуће пинове према референтној шеми, извршити неопходну конфигурацију и написати програмски код за приказ цифара 1234 на екрану. Освежавање екрана вршити у update event прекидној рутини тајмера TIM1. Уколико се ставка (4) уради у потпуности исправно приказ на екрану ускладити са захтевима из ставке (4) а поени за ставку (2) биће признати у целости.
- [6 поена] Додати електромотор и осцилоскоп у складу са референтном шемом. Потребно је проширити постојеће прекидне рутине из ставке (1) на начин да се контролише брзина рада електромотра.[sic] Улога дугмета повезаног на пин
PB0
јесте да повећа брзину, а улога дугмета повезаног на пинPB2
јесте да смањи брзину (погледати референтни снимак).[1] За генерисање сигнала којим се контролише електромотор користити тајмер TIM1 и његов канал CH1. Појединачни инкремент односно декремент за који се мења брзина представља 10% од максималне брзине електромотора. - [6 поена] Потребно је додати генератор сигнала према референтној шеми. Имплементирати израчунавање тренутне фреквенције сигнала са генератора и приказ израчунате фреквенције на седмосегментном екрану из ставке (2) уместо цифара 1234 (погледати референтни снимак).[1] Фреквенција приказана на екрану треба да буде изражена у Hz. За имплементацију ове ставке користити тајмер TIM3 а могуће је користити његове канале CH1 и CH2. Уколико се ставка (4) уради у потпуности исправно приказ на екрану ускладити са захтевима из ставке (4) а поени за ставку (2) биће признати у целости.
Решење
Цело решење може се преузети одавде.
Сви релевантни измењени фајлови са кодом налазе се у cubemx/code/Core/Src
директоријуму.
Опште напомене
- Потребно је урадити Refresh пројекта у Eclipse окружењу након поновног генерисања кода у CubeMX-у како би све радило исправно.
- За пинове се оставља подразумевана опција no pull-up, no pull-down за разлику од вежби.
- У случају проблема рада седмосегментог дисплеја додати
GPIOC->ODR &= ~0xFFF
пре постављања вредности на дисплеј.
CubeMX опште
Прво је под Project Manager у Project подешена путања пројекта и Makefile за Toolchain, а затим у Code Generator штиклирана опција за генерисање одвојених изворних фајлова и заглавља за сваку периферију. Урадити иницијално генерисање кода.
Eclipse опште
- Отворити Eclipse и поставити радно окружење на фолдер CubeMX унутар фолдера пројекта.
- Window->Preferences->MCU:
- Workspace Arm -> поставити питању до
interna_putanja_na_vašem_računaru\GNU MCU\arm-none-eabi-gcc-10.2.1-1.1\bin
. - Workspace BuildTools -> поставити питању до
interna_putanja_na_vašem_računaru\GNU MCU\build-tools-4.2.1-2\bin
.
- Workspace Arm -> поставити питању до
- Путем опције import увести генерисан код из фолдера Code, као постојећи C/C++ пројекат који користи makefile. Обавезно означити Arm Cross GCC.
- Након учитавања, десни клик на учитани пројекат, properties->C/C++ Build->Setting, а затим Apply and close.
- Опет десни клик на учитани пројекат, properties->C/C++ General->Paths and symbols, и додати C симболе STM32F103x6 и USE_HAL_DRIVER.
Makefile опште
У Makefile је померен tim.c
на дно C_SOURCES
променљиве, следећи блок:
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif
# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
је промењен на:
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2 -fdebug-prefix-map==../
endif
# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
CFLAGS += -mlong-calls
CFLAGS += -Wall -Wextra
и startup_stm32f103x6.s
је промењено на Core/Src/startup_stm32f103x6.s
унутар ASM_SOURCES
.
Ставка 1
CubeMX
- Пинове
PB0
иPB2
подесити каоGPIO_EXTI
. - Пинове
PB1
иPB3
подесити каоGPIO_Output
. - У
NVIC
омогућити прекиде поEXTI0
иEXTI2
. - Генерисати код.
Eclipse
stm32f1xx_it.c
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
switch (GPIO_Pin) {
case GPIO_PIN_0:
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
break;
case GPIO_PIN_2:
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
break;
}
}
Proteus
- Додати микотроконтрлер и поставити сигнале према референтној шеми.
- Диода је
LED-YELLOW
из библиотекеACTIVE
. Диоде је потребно поставити да буду дигиталне. - За дугме се користи
BUTTON
из библиотекеACTIVE
. Switching time поставити на 1n. - Поставити отпорнике у складу са референтном шемом.
- Поставити .efl или .hex фајл у микроконтролеру и тестирати исправан рад.
Ставка 2
CubeMX
- Тајмер
TIM1
:- Clock Source->Internal clock,
- Prescaler (PSC)->999
- Counter Period (AutoReload Register)->79
- Поставке изнад обезбеђују на сваких 10ms да се деси update interrupt, 8MHz/PSC је број тактова у једној секунди, а ARR на колико тактова се генерише update interrupt.
- У
NVIC
омогућити update interrupt заTIM1
. - Подесити пинове
PC0-PC11
каоGPIO_Output
. - Генерисати код.
Eclipse
main.c
(&htim1)->Instance->SR = ~TIM_SR_UIF; // Чисти иницијалани update interrupt flag по покретању пројекта
HAL_TIM_Base_Start_IT(&htim1); // Стартује TIM1
tim.c
uint8_t digits[4] = { 1, 2, 3, 4 };
uint8_t sevenSeg[] = { 0x81, 0xCF, 0x92, 0x86, 0xCC, 0xA4, 0xA0, 0x8F, 0x80, 0x84 };
uint8_t currentDigit = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM1) {
GPIOC->ODR &= ~0xF00; // Чисти приказ свих цигара (чисти пинове за аноде 7seg дисплега)
GPIOC->ODR &= ~0xFF; //Чисти стару вредност текуће цифре
GPIOC->ODR |= sevenSeg[digits[currentDigit]]; // Поставља нову вредност текуће цифре
GPIOC->ODR |= 0x1 << (currentDigit + 8); // Приказује текућу цифреу активирањем пина аноде на одговарајућој позицији
currentDigit = (currentDigit + 1) % 4;
}
}
Proteus
- Користи се
7SEG-MPX4-CA
из библиотекеDISPLAY
. - Повезати седмосегменти дисплеј у складу са референтном шемом.
- Тестирати исправан рад.
Ставка 3
CubeMX
- Тајмер
TIM1
:- Channel1->IPWM Generation CH1,
- Counter Period (AutoReload Register)->9
- Pulse->0
- CH Polarity->Low
- Поставке изнад обезбеђују на сваких 10ms да се деси update interrupt, 8MHz/PSC је број тактова у једној секунди, а ARR на колико тактова се генерише update interrupt.
- У
NVIC
омогућити caprute compare interrupt. - Генерисати код.
Eclipse
main.c
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
stm32f1xx_it.c
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
switch (GPIO_Pin) {
case GPIO_PIN_0:
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
if (power < 9) {
power++;
}
htim1.Instance->CCR1 = power;
break;
case GPIO_PIN_2:
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
if (power > 0) {
power--;
}
htim1.Instance->CCR1 = power;
break;
}
}
Proteus
- Поставити коло са мотором у складу са референтном шемом.
- За батерију се користи
CELL
из библиотекеDEVICE
, а за моторMOTOR
из библиотекеACTIVE
. - Диода овде не треба да буде дигитална.
- Обратити пажњу да је напон батерија 12V.
Ставка 4
CubeMX
- Тајмер
TIM3
:- Clock Source->Internal clock,
- Channel1->Input Capture direct mode,
- Prescaler (PSC)->7999
- Counter Period (AutoReload Register)->65565
- Polarity Selection канала 1->Rising edge
- У
NVIC
омогућити general interrupt одTIM3
. - Генерисати код.
Eclipse
main.c
(&htim3)->Instance->SR = ~TIM_SR_UIF;
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
tim.c
uint8_t digits[4] = { 1, 2, 3, 4 };
uint8_t sevenSeg[] = { 0x81, 0xCF, 0x92, 0x86, 0xCC, 0xA4, 0xA0, 0x8F, 0x80, 0x84 };
uint8_t currentDigit = 0;
uint32_t timestamp = 0;
uint32_t overflowCounter = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance != TIM3 && htim->Channel != HAL_TIM_ACTIVE_CHANNEL_1) {
return;
}
uint32_t currentTimestamp = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
// Прво мерење не треба да ажурира дисплеј, већ само измери време.
if (timestamp != 0) {
// Број откуцаја који су прошли од претходног мерења, а један откуцај је
// једна милисекунда.
uint32_t periodMs = currentTimestamp - timestamp + overflowCounter * 65536;
// фреквенција = 1 / периода у секундама = 1000 / периода у милисекундама
uint32_t frequency = 1000 / periodMs;
digits[0] = frequency / 1000;
digits[1] = frequency / 100 % 10;
digits[2] = frequency / 10 % 10;
digits[3] = frequency % 10;
}
timestamp = currentTimestamp;
overflowCounter = 0;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM1) {
// У нижих осам битова (PC7..0) иду битови тренутне цифре, а у виших четири
// (PC11..8) иде један бит који каже на коју цифру тренутно исписујемо.
GPIOC->ODR = sevenSeg[digits[currentDigit]] | (1 << (8 + currentDigit));
currentDigit = (currentDigit + 1) % 4;
} else if (htim->Instance == TIM3) {
++overflowCounter;
}
}
Proteus
- Поставити преостале компоненте у складу са референтном шемом.
- На DCLOCK-у се испробавају фреквенције мање од 8000.