Ну вот теперь видим - программы для армов можно писать и с HAL и без или сочетая и то и то. Ну мигать светодиодом точно ;). Мне кажется написание такой программы для начинающего будет приятным вдохновением перед решением более трудных задач. Наверное HAL будет нужен для написания боле сложных программ, типа работы с графикой для Chrom-ART Accelerator, TCP/IP, USB, RTOS где производитель предлагает свои библиотечные решения на основе HAL
И так теперь у нас есть таймер с прерываниями, точно так же как и у стареньких микроконтроллеров, теперь можно попробовать применить старые разработки, отлично работающие на пиках и аврах. Для отображения часов на индикаторе нам понадобится динамическая индикация - тут и пригодится таймер с прерываниями. Забегая вперед, скажу - у стм32 есть другая замечательная возможность организовать динамическую индикацию. Но вначале проверим работают ли устаревшие технологии. Ну в общем занимаемся копипастом своих, а может чужих решений. Програмка простая - считает секунды и должна показывать на семисегментном индикаторе:
#define SegA (uint8_t)1<<0
#define SegB (uint8_t)1<<1
#define SegC (uint8_t)1<<2
#define SegD (uint8_t)1<<3
#define SegE (uint8_t)1<<4
#define SegF (uint8_t)1<<5
#define SegG (uint8_t)1<<6
#define SegH (uint8_t)1<<7
#define digit_0 (uint8_t)(SegA | SegB | SegC | SegD | SegE | SegF)
#define digit_1 (uint8_t)(SegB | SegC)
#define digit_2 (uint8_t)(SegA | SegB | SegG | SegE | SegD)
#define digit_3 (uint8_t)(SegA | SegB | SegG | SegC | SegD)
#define digit_4 (uint8_t)(SegF | SegG | SegB | SegC)
#define digit_5 (uint8_t)(SegA | SegF | SegG | SegC | SegD)
#define digit_6 (uint8_t)(SegA | SegF | SegE | SegD | SegC | SegG)
#define digit_7 (uint8_t)(SegA | SegB | SegC)
#define digit_8 (uint8_t)(SegA | SegB | SegC | SegD | SegE | SegF | SegG)
#define digit_9 (uint8_t)(SegA | SegB | SegC | SegD | SegF | SegG)
const uint8_t seg7[10] =
{
digit_0,
digit_1,
digit_2,
digit_3,
digit_4,
digit_5,
digit_6,
digit_7,
digit_8,
digit_9
};
#define SEG_GPIO_ODR GPIOB->ODR
#define SEGA GPIO_ODR_0
#define SEGB GPIO_ODR_1
#define SEGC GPIO_ODR_2
#define SEGD GPIO_ODR_3
#define SEGE GPIO_ODR_4
#define SEGF GPIO_ODR_5
#define SEGG GPIO_ODR_6
#define AN_GPIO_ODR GPIOB->ODR
#define AN1 GPIO_ODR_7
#define AN2 GPIO_ODR_8
#define AN3 GPIO_ODR_9
#define AN4 GPIO_ODR_10
#define DOT_GPIO_ODR GPIOB->ODR
#define CDOT GPIO_ODR_11
#define ADOT GPIO_ODR_11
__IO uint8_t SegmentIndex = 0x01;
__IO uint8_t DigitIndex = 0;
__IO uint32_t Tick = 0;
uint16_t Counter = 0;
uint8_t DigitBuffer[4];
void SystemClock_Config(void);
//=============================================================================
// TIM3 Interrupt Handler
//=============================================================================
void TIM3_IRQHandler(void)
{
if(TIM3->SR & TIM_SR_UIF) // if UIF flag is set
{
TIM3->SR &= ~TIM_SR_UIF; // clear UIF flag
AN_GPIO_ODR &= ~( AN1 | AN2 | AN3 | AN4); // anodes off
SEG_GPIO_ODR |= (SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG); //segment off
SEG_GPIO_ODR &= (uint8_t)~SegmentIndex; // on one segment
switch(DigitIndex)
{
case 0:
if(DigitBuffer[3] & SegmentIndex) AN_GPIO_ODR |= AN1;
break;
case 1:
if(DigitBuffer[2] & SegmentIndex) AN_GPIO_ODR |= AN2;
break;
case 2:
if(DigitBuffer[1] & SegmentIndex) AN_GPIO_ODR |= AN3;
break;
case 3:
if(DigitBuffer[0] & SegmentIndex) AN_GPIO_ODR |= AN4;
break;
default:
break;
}
SegmentIndex <<= (uint8_t)0x01;
if (SegmentIndex == 0)
{
SegmentIndex = (uint8_t)0x01;
if(++DigitIndex == 4) DigitIndex = 0;
}
if(Tick > 0) Tick--;
//GPIOB->ODR ^= GPIO_ODR_11;
}
}
void Bin2Bcd(uint16_t value) // HHIMERA(c) copypast
{
uint8_t *p = DigitBuffer;
while (value > 0)
{
*p++ = seg7[value % 10];
value /= 10;
}
}
int main(void)
{
//HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* System interrupt init*/
//HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
/* GPIOB Periph clock enable */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
GPIOB->MODER |= (GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 |
GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 |
GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 |
GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0 |
GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_0 |
GPIO_MODER_MODER11_0 | GPIO_MODER_MODER12_0) ; /* Configure PB0-PB12 in output mode */
GPIOB->OTYPER &= ~( GPIO_OTYPER_OT_0 | GPIO_OTYPER_OT_1 |
GPIO_OTYPER_OT_2 | GPIO_OTYPER_OT_3 |
GPIO_OTYPER_OT_4 | GPIO_OTYPER_OT_5 |
GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7 |
GPIO_OTYPER_OT_8 | GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10 |
GPIO_OTYPER_OT_11 | GPIO_OTYPER_OT_12) ; // Ensure push pull mode selected--default
GPIOB->OSPEEDR |= ( GPIO_OSPEEDER_OSPEEDR0 | GPIO_OSPEEDER_OSPEEDR1 |
GPIO_OSPEEDER_OSPEEDR2 | GPIO_OSPEEDER_OSPEEDR3 |
GPIO_OSPEEDER_OSPEEDR4 | GPIO_OSPEEDER_OSPEEDR5 |
GPIO_OSPEEDER_OSPEEDR6 | GPIO_OSPEEDER_OSPEEDR7 |
GPIO_OSPEEDER_OSPEEDR8 | GPIO_OSPEEDER_OSPEEDR9 | GPIO_OSPEEDER_OSPEEDR10 |
GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12); //Ensure maximum speed setting (even though it is unnecessary)
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR0 | GPIO_PUPDR_PUPDR1 |
GPIO_PUPDR_PUPDR2 | GPIO_PUPDR_PUPDR3 |
GPIO_PUPDR_PUPDR4 | GPIO_PUPDR_PUPDR5 |
GPIO_PUPDR_PUPDR6 | GPIO_PUPDR_PUPDR7 |
GPIO_PUPDR_PUPDR8 | GPIO_PUPDR_PUPDR9 | GPIO_PUPDR_PUPDR10 |
GPIO_PUPDR_PUPDR11 | GPIO_PUPDR_PUPDR12); //Ensure all pull up pull down resistors are disabled
GPIOB->BSRRL = GPIO_BRR_BR_12; // Set
/* TIM3 clock enable */
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->PSC = 48 - 1; // Set prescaler to 48 = 48000000Hz/48 = 1000000 Hz = 1 us
TIM3->ARR = 500 - 1; // Auto reload value 500 = 500us
TIM3->DIER = TIM_DIER_UIE; // Enable update interrupt (timer level)
TIM3->CR1 = TIM_CR1_CEN; // Enable timer
NVIC_EnableIRQ(TIM3_IRQn); // Enable interrupt from TIM3 (NVIC level)
while (1)
{
Bin2Bcd(Counter);
Counter++;
Tick = 2000;
while (Tick);
}
}
Работает: