Mikroprocesorski sistemi/K2 2021
Prvi kolokvijum 2021. godine nema postavku dostupnu sa stranice predmeta. Nije mnogo poznato o ovom roku, osim zadatka navedenog ispod. Isti zadatak pojavio se i na drugom kolokvijumu 2022. godine.
Zadatak
Postavka
Koristeći alate arm-none-eabi-*, build-tools i Eclipse CDT, Proteus simulator i CubeMX alat potrebno je ispuniti stavke koje se nalaze u nastavku.
- [6 poena] Napraviti CubeMX i Proteus projekte za mikrokontroler STM32F103R6. Dodati dva dugmeta i povezati ih na pinove
PB0iPB2(pogledati referentnu šemu) tako da se mogu koristiti za generisanje prekida. Izvršiti neophodnu konfiguraciju tako da se generišu zahtevi za obradu prekida ukoliko se na ulaznom signalu ovih pinova prepozna uzlazna ivica. Dodati dve LED (light emitting diode) i povezati ih na pinovePB1iPB3(pogledati referentnu šemu). Izvršiti neophodnu konfiguraciju i zatim u okviru prekidne rutine za dugme koje je vezano na pinPB0napisati programski kod koji vrši promenu stanja na pinuPB1, a u okviru prekidne rutine za dugme koje je vezano na pinPB2napisati programski kod koji vrši promenu stanju[sic] na pinuPB3(pogledati referentni snimak).[1] - [6 poena] Dodati sedmosegmentni ekran širine četiri cifara, povezati ga na odgovarajuće pinove prema referentnoj šemi, izvršiti neophodnu konfiguraciju i napisati programski kod za prikaz cifara 1234 na ekranu. Osvežavanje ekrana vršiti u update event prekidnoj rutini tajmera TIM1. Ukoliko se stavka (4) uradi u potpunosti ispravno prikaz na ekranu uskladiti sa zahtevima iz stavke (4) a poeni za stavku (2) biće priznati u celosti.
- [6 poena] Dodati elektromotor i osciloskop u skladu sa referentnom šemom. Potrebno je proširiti postojeće prekidne rutine iz stavke (1) na način da se kontroliše brzina rada elektromotra.[sic] Uloga dugmeta povezanog na pin
PB0jeste da poveća brzinu, a uloga dugmeta povezanog na pinPB2jeste da smanji brzinu (pogledati referentni snimak).[1] Za generisanje signala kojim se kontroliše elektromotor koristiti tajmer TIM1 i njegov kanal CH1. Pojedinačni inkrement odnosno dekrement za koji se menja brzina predstavlja 10% od maksimalne brzine elektromotora. - [6 poena] Potrebno je dodati generator signala prema referentnoj šemi. Implementirati izračunavanje trenutne frekvencije signala sa generatora i prikaz izračunate frekvencije na sedmosegmentnom ekranu iz stavke (2) umesto cifara 1234 (pogledati referentni snimak).[1] Frekvencija prikazana na ekranu treba da bude izražena u Hz. Za implementaciju ove stavke koristiti tajmer TIM3 a moguće je koristiti njegove kanale CH1 i CH2. Ukoliko se stavka (4) uradi u potpunosti ispravno prikaz na ekranu uskladiti sa zahtevima iz stavke (4) a poeni za stavku (2) biće priznati u celosti.
Rešenje
Celo rešenje može se preuzeti odavde.
Svi relevantni izmenjeni fajlovi sa kodom nalaze se u cubemx/code/Core/Src direktorijumu.
Opšte napomene
- Potrebno je uraditi Refresh projekta u Eclipse okruženju nakon ponovnog generisanja koda u CubeMX-u kako bi sve radilo ispravno.
- Za pinove se ostavlja podrazumevana opcija no pull-up, no pull-down za razliku od vežbi.
- U slučaju problema rada sedmosegmentog displeja dodati
GPIOC->ODR &= ~0xFFFpre postavljanja vrednosti na displej.
CubeMX
Prvo je pod Project Manager u Project podešena putanja projekta i Makefile za Toolchain, a zatim u Code Generator štiklirana opcija za generisanje odvojenih izvornih fajlova i zaglavlja za svaku periferiju, a zatim u Pinout & Configuration podešeno:
PC11..0su podešeni kaoGPIO_Outputpinovi.PB0iPB2su podešeni kaoGPIO_EXTI0iGPIO_EXTI2pinovi a u NVIC su uključeni EXTI line0 interrupt i EXTI line2 interrupt.PB1iPB3su podešeni kaoGPIO_Outputpinovi.- U
TIM1je kao Clock Source podešen Internal Clock, na Channel1 je podešeno PWM Generation CH1, kao prescaler vrednost je podešeno 7999 (kako bi jedan otkucaj bila jedna milisekunda radi lakšeg računanja) a kao period je podešeno 9 (tako da se prekoračenje brojača, odnosno update event, dešava na svakih deset milisekundi). U PWM podešavanjima puls je podešen na 0 a polaritet na nizak (tako da se motor na početku neće okretati). U NVIC je izabran TIM1 update interrupt. - U
TIM3je kao Clock Source podešen Internal Clock, na Channel1 je podešen Input Capture direct mode, kao prescaler vrednost je podešeno 7999 (kako bi jedan otkucaj bila jedna milisekunda radi lakšeg računanja) a kao period je podešeno 65535. Kao polaritet input capture kanala izabrana je uzlazna ivica. U NVIC je izabran TIM3 global interrupt.
Makefile
U Makefile je pomeren tim.c na dno C_SOURCES promenljive, sledeći blok:
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif
# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
je promenjen na:
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
i startup_stm32f103x6.s je promenjeno na Core/Src/startup_stm32f103x6.s unutar ASM_SOURCES.
main.c
Dodato je:
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
ispod inicijalizacije periferija.
stm32f1xx_it.c
U odeljku za korisnički kod na dnu fajla je dodato:
uint8_t currentMotorSpeed = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_0) {
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
if (currentMotorSpeed < 9) {
++currentMotorSpeed;
}
TIM1->CCR1 = currentMotorSpeed;
} else if (GPIO_Pin == GPIO_PIN_2) {
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
if (currentMotorSpeed > 0) {
--currentMotorSpeed;
}
TIM1->CCR1 = currentMotorSpeed;
}
}
tim.c
U odeljku za korisnički kod na dnu fajla je dodato (komentari dodati naknadno):
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;
}
}